FootballMatchLogic.lua 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876
  1. --------------------------------
  2. -- 文件名 : FootballMatchLogic.lua
  3. -- 文件说明 : 足球竞赛运营活动
  4. -- 配置表 : excel/ssecy/footballMatch.lua
  5. -- var[1]: costItem, winReward, loseReward
  6. -- task[id]: desc, reward
  7. -- reward[id]: desc, progressVal, reward
  8. -- gift[id]: buyId, limitCnt, reward
  9. --[[
  10. 玩法说明:
  11. 1. 每次开始消耗1个足球道具, 与人机对战5轮(每轮玩家射门+扑救各1次)
  12. 2. 射门/扑救方向: 1左 2中 3右; 人机非特殊轮次按1/3概率随机
  13. 3. 提前结束: 第3轮结束领先>=3、第4轮>=2、第5轮>=1
  14. 4. 第5轮玩家射门后防平局: 玩家领先1球则人机射向玩家扑救方向; 平局则人机不射向玩家扑救方向
  15. 5. 进行中退界面/断线, 重进后通过查询协议恢复进度
  16. DB: human.db.absAct[id] = {
  17. winCnt = 0, -- 累计胜场
  18. reward = {}, -- 仅记录已领取档位 [rewardId]=2
  19. task = {}, -- [taskId]=state(0未达成/1可领/2已领); 任务1/2每日重置, 任务3跨周重置
  20. gift = { [giftId] = buyCnt }, -- 礼包已购次数
  21. match = { -- 当前比赛(无比赛或已结束时 phase=0)
  22. opponentName = "",
  23. round = 1, -- 当前轮次 1-5
  24. phase = 1, -- 1待射门 2待扑救 0未开始/已结束
  25. playerScore = 0, -- 服务端内部用(提前结束/防平局判断), 不下发
  26. aiScore = 0,
  27. roundResults = { -- 5轮结果 player/ai: 0没进 1进球 2未出
  28. { player = 2, ai = 2 }, ...
  29. },
  30. isEnd = 0, -- 上一场是否刚结束(QUERY state=3, 新开一局时清除)
  31. },
  32. }
  33. 协议推送:
  34. CG_ABS_FOOTBALL_QUERY / START成功 / 分出胜负后 -> GC_ABS_FOOTBALL_QUERY
  35. CG_ABS_FOOTBALL_ACTION -> GC_ABS_FOOTBALL_ACTION(分出胜负时附带奖励展示)
  36. 客户端请求(由 Handler.lua 调用):
  37. getAndSendMsg() -- CG_ABS_FOOTBALL_QUERY
  38. startMatch() -- CG_ABS_FOOTBALL_START
  39. playerAction() -- CG_ABS_FOOTBALL_ACTION
  40. queryTask() -- CG_ABS_FOOTBALL_TASK_QUERY
  41. getTaskReward() -- CG_ABS_FOOTBALL_TASK_GET
  42. queryReward() -- CG_ABS_FOOTBALL_REWARD_QUERY
  43. getReachReward() -- CG_ABS_FOOTBALL_REWARD_GET
  44. queryGift() -- CG_ABS_FOOTBALL_GIFT_QUERY
  45. 服务器模块接口:
  46. genAbsActData() -- 初始化活动DB
  47. isOpen() -- 活动是否开启
  48. isActive() -- 活动是否未开启(图标用)
  49. isRed() -- 红点
  50. onLogin() -- 登录补检任务
  51. updateDaily() -- 跨天重置任务1/2
  52. OnHuoYueReach100() -- 日/周活跃达标(由DailyTaskLogic/WeekTaskLogic触发)
  53. onCharge() -- 充值购买礼包回调
  54. GetRemainNum() -- 获取礼包剩余可购买次数(供其他模块调用)
  55. --]]
  56. --------------------------------
  57. local AbsActExcel = require("excel.absAct")
  58. local FootballExcel = require("excel.footballMatch")
  59. local AbsActLogic = require("absAct.AbsActLogic")
  60. local Msg = require("core.Msg")
  61. local Grid = require("bag.Grid")
  62. local BagLogic = require("bag.BagLogic")
  63. local Broadcast = require("broadcast.Broadcast")
  64. local Lang = require("common.Lang")
  65. local YunYingLogic = require("yunying.YunYingLogic")
  66. local BuyLogic = require("topup.BuyLogic")
  67. local CommonDefine = require("common.CommonDefine")
  68. local DataCache = require("core.DataCache")
  69. local RoleLogic = require("role.RoleLogic")
  70. local CreateRole = require("role.CreateRole")
  71. local LOGTAG = "football_match"
  72. local ACT_ID = 7801 -- 足球竞赛活动ID
  73. local VAR_INDEX = 1 -- footballMatch.var 配置索引
  74. -- 比赛阶段(DB)
  75. local PHASE_IDLE = 0 -- 未开始/已结束
  76. local PHASE_SHOOT = 1 -- 等待玩家射门
  77. local PHASE_SAVE = 2 -- 等待玩家扑救
  78. -- 协议 state
  79. local STATE_IDLE = 0
  80. local STATE_SHOOT = 1
  81. local STATE_SAVE = 2
  82. local STATE_ROUND_END = 3
  83. -- 玩家行动类型
  84. local ACTION_TYPE_SHOOT = 1
  85. local ACTION_TYPE_SAVE = 2
  86. -- 行动结果 ret
  87. local RET_NOT_END = 0
  88. local RET_PLAYER_WIN = 1
  89. local RET_PLAYER_LOSE = 2
  90. -- 单轮射门结果
  91. local RESULT_MISS = 0 -- 没进球
  92. local RESULT_GOAL = 1 -- 进球
  93. local RESULT_PENDING = 2 -- 还没有结果
  94. local MAX_ROUND = 5
  95. -- 射门/扑救方向: 1左 2中 3右
  96. local DIR_LEFT = 1
  97. local DIR_CENTER = 2
  98. local DIR_RIGHT = 3
  99. -- 提前结束胜差: 第3轮>=3, 第4轮>=2, 第5轮>=1
  100. local EARLY_WIN_GAP = {
  101. [3] = 3,
  102. [4] = 2,
  103. [5] = 1,
  104. }
  105. -- 任务ID: 1登录 2日活跃100 3周活跃100
  106. local TASK_ID_LOGIN = 1
  107. local TASK_ID_DAILY_HUOYUE = 2
  108. local TASK_ID_WEEK_HUOYUE = 3
  109. --------------------------------
  110. -- local 内部函数
  111. --------------------------------
  112. -- 获取玩法 var 配置
  113. local function getVarConfig()
  114. return (FootballExcel.var or {})[VAR_INDEX] or {}
  115. end
  116. -- 获取单场消耗道具 itemId, itemCnt
  117. local function getCostItemInfo()
  118. local costItem = getVarConfig().costItem or {}
  119. return costItem[1] or 0, costItem[2] or 0
  120. end
  121. -- 拷贝道具列表, 避免直接传配置表引用
  122. local function copyItemList(itemList)
  123. local items = {}
  124. for _, v in ipairs(itemList or {}) do
  125. items[#items + 1] = {v[1], v[2], v[3]}
  126. end
  127. return items
  128. end
  129. -- 初始化5轮比赛结果(默认未出结果)
  130. local function initMatchResults()
  131. local results = {}
  132. for i = 1, MAX_ROUND do
  133. results[i] = {player = RESULT_PENDING, ai = RESULT_PENDING}
  134. end
  135. return results
  136. end
  137. -- 获取活动DB, 不存在则初始化后返回
  138. local function getOrInitActData(human, id)
  139. if not human.db.absAct[id] then
  140. human.db.absAct[id] = genAbsActData(AbsActExcel.absActivity[id], human)
  141. end
  142. return human.db.absAct[id]
  143. end
  144. -- 随机射门/扑救方向(1-3)
  145. local function randomDirection()
  146. return math.random(DIR_LEFT, DIR_RIGHT)
  147. end
  148. -- 射门方向与扑救方向不同则进球
  149. local function isGoal(shootDir, saveDir)
  150. return shootDir ~= saveDir
  151. end
  152. -- 随机选取一名在线玩家名字作为对手名, 失败则用系统随机名
  153. local function getRandomOpponentName(myUuid)
  154. local playerUidList = DataCache.Get_PlayerUuidList()
  155. if not playerUidList or not next(playerUidList) then
  156. return CreateRole.getRandomName()
  157. end
  158. local candidates = {}
  159. local len = 0
  160. for uuid in pairs(playerUidList) do
  161. if uuid ~= myUuid then
  162. len = len + 1
  163. candidates[len] = uuid
  164. end
  165. end
  166. if len < 1 then
  167. return CreateRole.getRandomName()
  168. end
  169. for _ = 1, math.min(30, len) do
  170. local uuid = candidates[math.random(1, len)]
  171. local roleBase = {}
  172. RoleLogic.getRoleBaseByUuid(uuid, roleBase)
  173. if roleBase.name and roleBase.name ~= "" then
  174. return roleBase.name
  175. end
  176. end
  177. return CreateRole.getRandomName()
  178. end
  179. -- 计算人机射门方向; 第5轮防平局: 玩家领先1球则射向玩家扑救方向, 平局则不射向该方向
  180. local function calcAiShootDir(round, playerScore, aiScore, playerSaveDir)
  181. if round == MAX_ROUND then
  182. if playerScore - aiScore == 1 then
  183. return playerSaveDir
  184. elseif playerScore == aiScore then
  185. local dirs = {}
  186. for d = DIR_LEFT, DIR_RIGHT do
  187. if d ~= playerSaveDir then
  188. dirs[#dirs + 1] = d
  189. end
  190. end
  191. return dirs[math.random(1, #dirs)]
  192. end
  193. end
  194. return randomDirection()
  195. end
  196. -- 检查是否满足提前结束条件, 返回1玩家胜/2人机胜/nil继续
  197. local function checkEarlyWin(round, playerScore, aiScore)
  198. local gap = EARLY_WIN_GAP[round]
  199. if not gap then return end
  200. if playerScore - aiScore >= gap then
  201. return 1
  202. end
  203. if aiScore - playerScore >= gap then
  204. return 2
  205. end
  206. end
  207. -- 根据胜负获取本场奖励道具列表
  208. local function getMatchReward(isWin)
  209. local conf = getVarConfig()
  210. if isWin then
  211. return conf.winReward or {}
  212. end
  213. return conf.loseReward or {}
  214. end
  215. -- 获取任务状态
  216. local function getTaskState(absAct, taskId)
  217. return absAct.task and absAct.task[taskId]
  218. end
  219. -- 任务是否未达成(未记录或状态为0)
  220. local function isTaskPending(absAct, taskId)
  221. local state = getTaskState(absAct, taskId)
  222. return state == nil or state == CommonDefine.COMMON_PRIZE_STATE_NOGET
  223. end
  224. -- 刷新任务相关红点
  225. local function notifyTaskRed(human, id)
  226. YunYingLogic.sendBanner(human)
  227. local actConfig = AbsActExcel.absActivity[id]
  228. if actConfig then
  229. YunYingLogic.sendGroupUpdate(YYInfo[id], human, actConfig.panelID)
  230. end
  231. end
  232. -- 将任务标记为可领取并刷新红点
  233. local function tryCompleteTask(human, id, taskId)
  234. local absAct = human.db.absAct[id]
  235. if not absAct or not (FootballExcel.task or {})[taskId] then
  236. return
  237. end
  238. local state = getTaskState(absAct, taskId)
  239. if state == CommonDefine.COMMON_PRIZE_STATE_CANGET or state == CommonDefine.COMMON_PRIZE_STATE_GET then
  240. return
  241. end
  242. absAct.task[taskId] = CommonDefine.COMMON_PRIZE_STATE_CANGET
  243. notifyTaskRed(human, id)
  244. end
  245. -- 跨天重置任务1(登录)和任务2(日活跃)
  246. local function resetDailyTasks(absAct)
  247. absAct.task[TASK_ID_LOGIN] = CommonDefine.COMMON_PRIZE_STATE_NOGET
  248. absAct.task[TASK_ID_DAILY_HUOYUE] = CommonDefine.COMMON_PRIZE_STATE_NOGET
  249. end
  250. -- 跨周重置任务3(周活跃)
  251. local function checkWeekTaskReset(human, absAct)
  252. local WeekTaskLogic = require("dailyTask.WeekTaskLogic")
  253. if not WeekTaskLogic.isNeedWeekRefsh(human) then
  254. return
  255. end
  256. absAct.task[TASK_ID_WEEK_HUOYUE] = CommonDefine.COMMON_PRIZE_STATE_NOGET
  257. end
  258. -- 登录/查询时补检任务完成状态; 勿在 updateDaily 中调用, 此时 dailyTask 可能尚未清空
  259. local function tryInitTasks(human, id)
  260. local absAct = human.db.absAct[id]
  261. if not absAct then
  262. return
  263. end
  264. checkWeekTaskReset(human, absAct)
  265. if isTaskPending(absAct, TASK_ID_LOGIN) then
  266. tryCompleteTask(human, id, TASK_ID_LOGIN)
  267. end
  268. if isTaskPending(absAct, TASK_ID_DAILY_HUOYUE) then
  269. local DailyTaskLogic = require("dailyTask.DailyTaskLogic")
  270. if DailyTaskLogic.isReachMaxDailyHuoYue(human) then
  271. tryCompleteTask(human, id, TASK_ID_DAILY_HUOYUE)
  272. end
  273. end
  274. if isTaskPending(absAct, TASK_ID_WEEK_HUOYUE) then
  275. local WeekTaskLogic = require("dailyTask.WeekTaskLogic")
  276. if WeekTaskLogic.isReachMaxWeekHuoYue(human) then
  277. tryCompleteTask(human, id, TASK_ID_WEEK_HUOYUE)
  278. end
  279. end
  280. end
  281. -- 获取累计胜场档位奖励状态
  282. local function getReachRewardState(absAct, rewardId, progressVal)
  283. if absAct.reward[rewardId] == CommonDefine.COMMON_PRIZE_STATE_GET then
  284. return CommonDefine.COMMON_PRIZE_STATE_GET
  285. end
  286. if absAct.winCnt >= progressVal then
  287. return CommonDefine.COMMON_PRIZE_STATE_CANGET
  288. end
  289. return CommonDefine.COMMON_PRIZE_STATE_NOGET
  290. end
  291. -- 结束比赛: 更新胜场、发放奖励、重置比赛状态
  292. local function finishMatch(human, id, match, winner)
  293. local absAct = getOrInitActData(human, id)
  294. local isWin = winner == 1
  295. if isWin then
  296. absAct.winCnt = absAct.winCnt + 1
  297. end
  298. for _, item in ipairs(getMatchReward(isWin)) do
  299. BagLogic.addItem(human, item[1], item[2], LOGTAG, nil, item[3])
  300. end
  301. match.phase = PHASE_IDLE
  302. match.isEnd = 1
  303. YunYingLogic.sendBanner(human)
  304. local config = AbsActExcel.absActivity[id]
  305. if config then
  306. YunYingLogic.sendGroupUpdate(YYInfo[id], human, config.panelID)
  307. end
  308. end
  309. -- 填充单轮比赛结果到协议结构
  310. local function fillRoundResultNet(net, roundData)
  311. net.player = roundData.player or RESULT_PENDING
  312. net.ai = roundData.ai or RESULT_PENDING
  313. end
  314. -- 填充5轮比赛结果
  315. local function fillAllRoundResults(msgRet, match)
  316. for i = 1, MAX_ROUND do
  317. local roundData = match and match.roundResults and match.roundResults[i]
  318. if not roundData then
  319. roundData = {player = RESULT_PENDING, ai = RESULT_PENDING}
  320. end
  321. fillRoundResultNet(msgRet.roundResults[i], roundData)
  322. end
  323. msgRet.roundResults[0] = MAX_ROUND
  324. end
  325. -- DB phase 转查询协议 state
  326. local function phaseToQueryState(phase)
  327. if phase == PHASE_SHOOT then
  328. return STATE_SHOOT
  329. end
  330. if phase == PHASE_SAVE then
  331. return STATE_SAVE
  332. end
  333. return STATE_IDLE
  334. end
  335. -- 任务分页是否有红点
  336. local function hasTaskPageRedDot(absAct)
  337. for taskId in pairs(FootballExcel.task or {}) do
  338. if getTaskState(absAct, taskId) == CommonDefine.COMMON_PRIZE_STATE_CANGET then
  339. return true
  340. end
  341. end
  342. return false
  343. end
  344. -- 奖励分页是否有红点
  345. local function hasRewardPageRedDot(absAct)
  346. for index, v in pairs(FootballExcel.reward or {}) do
  347. if getReachRewardState(absAct, index, v.progressVal) == CommonDefine.COMMON_PRIZE_STATE_CANGET then
  348. return true
  349. end
  350. end
  351. return false
  352. end
  353. -- 填充分页红点
  354. local function fillPageRedDotArr(msgRet, absAct)
  355. msgRet.pageRedDotArr[0] = 2
  356. msgRet.pageRedDotArr[1] = hasTaskPageRedDot(absAct) and 1 or 0
  357. msgRet.pageRedDotArr[2] = hasRewardPageRedDot(absAct) and 1 or 0
  358. end
  359. -- 填充单场消耗道具
  360. local function fillCostItem(msgRet)
  361. local itemId, itemCnt = getCostItemInfo()
  362. Grid.makeItem(msgRet.costItem, itemId, itemCnt)
  363. end
  364. -- 填充道具列表到协议结构
  365. local function fillItemList(netList, itemList)
  366. local len = #itemList
  367. for i = 1, len do
  368. Grid.makeItem(netList[i], itemList[i][1], itemList[i][2])
  369. end
  370. netList[0] = len
  371. end
  372. -- 填充 GC_ABS_FOOTBALL_QUERY
  373. local function fillQueryNet(msgRet, human, id)
  374. local absAct = getOrInitActData(human, id)
  375. local match = absAct.match
  376. msgRet.playerName = human.db.name or ""
  377. msgRet.winCnt = absAct.winCnt
  378. fillPageRedDotArr(msgRet, absAct)
  379. fillCostItem(msgRet)
  380. if match and match.phase ~= PHASE_IDLE then
  381. msgRet.opponentName = match.opponentName or ""
  382. msgRet.round = match.round or 1
  383. msgRet.state = phaseToQueryState(match.phase)
  384. fillAllRoundResults(msgRet, match)
  385. return
  386. end
  387. if match and match.isEnd == 1 then
  388. msgRet.opponentName = match.opponentName or ""
  389. msgRet.round = match.round or 0
  390. msgRet.state = STATE_ROUND_END
  391. fillAllRoundResults(msgRet, match)
  392. return
  393. end
  394. msgRet.opponentName = ""
  395. msgRet.round = 0
  396. msgRet.state = STATE_IDLE
  397. fillAllRoundResults(msgRet, match)
  398. end
  399. -- 填充 GC_ABS_FOOTBALL_ACTION
  400. local function fillActionNet(msgRet, match, extra)
  401. msgRet.ret = extra.ret or RET_NOT_END
  402. msgRet.actionType = extra.actionType or 0
  403. msgRet.playerDir = extra.playerDir or 0
  404. msgRet.opponentDir = extra.opponentDir or 0
  405. msgRet.isGoal = extra.isGoal or 0
  406. msgRet.round = extra.round or 0
  407. msgRet.state = extra.state or STATE_IDLE
  408. fillAllRoundResults(msgRet, match)
  409. if msgRet.ret == RET_NOT_END then
  410. msgRet.item[0] = 0
  411. else
  412. local isWin = msgRet.ret == RET_PLAYER_WIN
  413. fillItemList(msgRet.item, getMatchReward(isWin))
  414. end
  415. end
  416. -- 下发比赛查询协议 GC_ABS_FOOTBALL_QUERY
  417. local function sendQuery(human, id)
  418. local msgRet = Msg.gc.GC_ABS_FOOTBALL_QUERY
  419. fillQueryNet(msgRet, human, id)
  420. Msg.send(msgRet, human.fd)
  421. end
  422. -- 下发行动结果 GC_ABS_FOOTBALL_ACTION
  423. local function sendActionResult(human, match, extra)
  424. local msgRet = Msg.gc.GC_ABS_FOOTBALL_ACTION
  425. fillActionNet(msgRet, match, extra)
  426. Msg.send(msgRet, human.fd)
  427. end
  428. -- 检查活动是否开启, 未开启则下发错误
  429. local function checkActStarted(human, id)
  430. if AbsActLogic.isStarted(human, id) then
  431. return true
  432. end
  433. Broadcast.sendErr(human, Lang.YUNYING_ERR_TIME)
  434. return false
  435. end
  436. --------------------------------
  437. -- 服务器模块接口
  438. --------------------------------
  439. -- 初始化活动DB
  440. function genAbsActData(config, human)
  441. return {
  442. winCnt = 0,
  443. reward = {},
  444. task = {},
  445. gift = {},
  446. }
  447. end
  448. -- 活动是否开启
  449. function isOpen(human, YYInfo, funcConfig)
  450. local state, endTime, startTime = AbsActLogic.isStarted(human, funcConfig.funcID)
  451. if not state then return end
  452. return true, endTime, startTime
  453. end
  454. -- 活动是否未开启(运营图标置灰用)
  455. function isActive(human, YYInfo, funcConfig)
  456. return not isOpen(human, YYInfo, funcConfig)
  457. end
  458. -- 红点: 有可领奖励/任务(有道具可开赛不再显示红点, 逻辑暂屏蔽)
  459. function isRed(human, YYInfo, funcConfig)
  460. local id = funcConfig.funcID
  461. local state = AbsActLogic.isStarted(human, id)
  462. if not state then return end
  463. local absAct = human.db.absAct[id]
  464. if not absAct then return end
  465. if hasRewardPageRedDot(absAct) or hasTaskPageRedDot(absAct) then
  466. return true
  467. end
  468. --[[ 有足球道具且当前无进行中比赛时显示红点, 暂不需要
  469. local itemId, itemCnt = getCostItemInfo()
  470. if itemId > 0 and itemCnt > 0 and (not absAct.match or absAct.match.phase == PHASE_IDLE) then
  471. if BagLogic.getItemCnt(human, itemId) >= itemCnt then
  472. return true
  473. end
  474. end
  475. --]]
  476. return false
  477. end
  478. -- 登录时补检任务状态
  479. function onLogin(human, funcID)
  480. local state = AbsActLogic.isStarted(human, funcID)
  481. if not state then
  482. return
  483. end
  484. getOrInitActData(human, funcID)
  485. tryInitTasks(human, funcID)
  486. end
  487. -- 跨天回调: 重置日任务并补检登录任务
  488. function updateDaily(human, funcID)
  489. local state = AbsActLogic.isStarted(human, funcID)
  490. if not state then
  491. return
  492. end
  493. local absAct = human.db.absAct[funcID]
  494. if not absAct then
  495. return
  496. end
  497. resetDailyTasks(absAct)
  498. checkWeekTaskReset(human, absAct)
  499. tryCompleteTask(human, funcID, TASK_ID_LOGIN)
  500. end
  501. -- 日/周活跃达100时触发(由 DailyTaskLogic/WeekTaskLogic 调用)
  502. function OnHuoYueReach100(human)
  503. if not AbsActLogic.isStarted(human, ACT_ID) then
  504. return
  505. end
  506. getOrInitActData(human, ACT_ID)
  507. local DailyTaskLogic = require("dailyTask.DailyTaskLogic")
  508. if DailyTaskLogic.isReachMaxDailyHuoYue(human) then
  509. tryCompleteTask(human, ACT_ID, TASK_ID_DAILY_HUOYUE)
  510. end
  511. local WeekTaskLogic = require("dailyTask.WeekTaskLogic")
  512. if WeekTaskLogic.isReachMaxWeekHuoYue(human) then
  513. tryCompleteTask(human, ACT_ID, TASK_ID_WEEK_HUOYUE)
  514. end
  515. end
  516. -- 充值购买礼包回调
  517. function onCharge(human, price, funcID, buyID, buyNum)
  518. local state = AbsActLogic.isStarted(human, funcID)
  519. if not state then return end
  520. local absAct = getOrInitActData(human, funcID)
  521. buyNum = buyNum or 1
  522. for index, v in pairs(FootballExcel.gift or {}) do
  523. if v.buyId == buyID then
  524. absAct.gift = absAct.gift or {}
  525. local nowCnt = absAct.gift[index] or 0
  526. if nowCnt + buyNum > (v.limitCnt or 0) then
  527. return
  528. end
  529. absAct.gift[index] = nowCnt + buyNum
  530. local items = copyItemList(v.reward)
  531. for _, item in ipairs(items) do
  532. item[2] = item[2] * buyNum
  533. end
  534. BagLogic.addItemList(human, items, LOGTAG)
  535. queryGift(human, funcID)
  536. return
  537. end
  538. end
  539. end
  540. -- 获取礼包剩余可购买次数(供 BuyLogic 等模块调用)
  541. function GetRemainNum(human, buyId)
  542. if not AbsActLogic.isStarted(human, ACT_ID) then
  543. return 0
  544. end
  545. for index, v in pairs(FootballExcel.gift or {}) do
  546. if v.buyId == buyId then
  547. local maxCnt = v.limitCnt or 0
  548. local absAct = human.db.absAct[ACT_ID]
  549. if not absAct then
  550. return maxCnt
  551. end
  552. local nowCnt = absAct.gift and absAct.gift[index] or 0
  553. return nowCnt >= maxCnt and 0 or (maxCnt - nowCnt)
  554. end
  555. end
  556. return 0
  557. end
  558. --------------------------------
  559. -- 客户端请求处理
  560. --------------------------------
  561. -- CG_ABS_FOOTBALL_QUERY 查询比赛进度(断线重进恢复用)
  562. function getAndSendMsg(human, id)
  563. if not checkActStarted(human, id) then return end
  564. getOrInitActData(human, id)
  565. sendQuery(human, id)
  566. end
  567. -- CG_ABS_FOOTBALL_START 开始比赛, 消耗1个足球道具
  568. function startMatch(human, id)
  569. if not checkActStarted(human, id) then return end
  570. local absAct = getOrInitActData(human, id)
  571. if absAct.match and absAct.match.phase ~= PHASE_IDLE then
  572. return Broadcast.sendErr(human, Lang.COMMON_ARGUMENT_ERROR)
  573. end
  574. local itemId, itemCnt = getCostItemInfo()
  575. if itemId <= 0 or itemCnt <= 0 or BagLogic.getItemCnt(human, itemId) < itemCnt then
  576. return Broadcast.sendErr(human, Lang.COMMON_ITEM_NOT_ENOUGH)
  577. end
  578. BagLogic.delItem(human, itemId, itemCnt, LOGTAG)
  579. absAct.match = {
  580. opponentName = getRandomOpponentName(human.db._id),
  581. round = 1,
  582. phase = PHASE_SHOOT,
  583. playerScore = 0,
  584. aiScore = 0,
  585. roundResults = initMatchResults(),
  586. isEnd = 0,
  587. }
  588. sendQuery(human, id)
  589. end
  590. -- 玩家射门
  591. local function playerShoot(human, id, shootDir)
  592. local absAct = getOrInitActData(human, id)
  593. local match = absAct.match
  594. if not match or match.phase ~= PHASE_SHOOT then
  595. return Broadcast.sendErr(human, Lang.COMMON_ARGUMENT_ERROR)
  596. end
  597. local round = match.round
  598. local aiSaveDir = randomDirection()
  599. local goal = isGoal(shootDir, aiSaveDir)
  600. if goal then
  601. match.playerScore = match.playerScore + 1
  602. match.roundResults[round].player = RESULT_GOAL
  603. else
  604. match.roundResults[round].player = RESULT_MISS
  605. end
  606. match.phase = PHASE_SAVE
  607. sendActionResult(human, match, {
  608. ret = RET_NOT_END,
  609. actionType = ACTION_TYPE_SHOOT,
  610. playerDir = shootDir,
  611. opponentDir = aiSaveDir,
  612. isGoal = goal and 1 or 0,
  613. round = round,
  614. state = STATE_SAVE,
  615. })
  616. end
  617. -- 玩家扑救; 每轮结束检查提前结束或进入下一轮
  618. local function playerSave(human, id, saveDir)
  619. local absAct = getOrInitActData(human, id)
  620. local match = absAct.match
  621. if not match or match.phase ~= PHASE_SAVE then
  622. return Broadcast.sendErr(human, Lang.COMMON_ARGUMENT_ERROR)
  623. end
  624. local round = match.round
  625. local aiShootDir = calcAiShootDir(round, match.playerScore, match.aiScore, saveDir)
  626. local goal = isGoal(aiShootDir, saveDir)
  627. if goal then
  628. match.aiScore = match.aiScore + 1
  629. match.roundResults[round].ai = RESULT_GOAL
  630. else
  631. match.roundResults[round].ai = RESULT_MISS
  632. end
  633. local winner = checkEarlyWin(round, match.playerScore, match.aiScore)
  634. if not winner and round >= MAX_ROUND then
  635. if match.playerScore > match.aiScore then
  636. winner = 1
  637. elseif match.aiScore > match.playerScore then
  638. winner = 2
  639. else
  640. winner = 1
  641. end
  642. end
  643. if winner then
  644. finishMatch(human, id, match, winner)
  645. sendActionResult(human, match, {
  646. ret = winner == 1 and RET_PLAYER_WIN or RET_PLAYER_LOSE,
  647. actionType = ACTION_TYPE_SAVE,
  648. playerDir = saveDir,
  649. opponentDir = aiShootDir,
  650. isGoal = goal and 1 or 0,
  651. round = round,
  652. state = STATE_ROUND_END,
  653. })
  654. -- sendQuery(human, id)
  655. return
  656. end
  657. match.round = round + 1
  658. match.phase = PHASE_SHOOT
  659. sendActionResult(human, match, {
  660. ret = RET_NOT_END,
  661. actionType = ACTION_TYPE_SAVE,
  662. playerDir = saveDir,
  663. opponentDir = aiShootDir,
  664. isGoal = goal and 1 or 0,
  665. round = match.round,
  666. state = STATE_SHOOT,
  667. })
  668. end
  669. -- CG_ABS_FOOTBALL_ACTION 玩家行动(射门/扑救)
  670. function playerAction(human, id, actionType, dir)
  671. if not checkActStarted(human, id) then return end
  672. if dir < DIR_LEFT or dir > DIR_RIGHT then
  673. return Broadcast.sendErr(human, Lang.COMMON_ARGUMENT_ERROR)
  674. end
  675. if actionType == ACTION_TYPE_SHOOT then
  676. playerShoot(human, id, dir)
  677. elseif actionType == ACTION_TYPE_SAVE then
  678. playerSave(human, id, dir)
  679. else
  680. return Broadcast.sendErr(human, Lang.COMMON_ARGUMENT_ERROR)
  681. end
  682. end
  683. -- CG_ABS_FOOTBALL_TASK_QUERY 查询任务列表
  684. function queryTask(human, id)
  685. if not checkActStarted(human, id) then return end
  686. local absAct = getOrInitActData(human, id)
  687. tryInitTasks(human, id)
  688. local msgRet = Msg.gc.GC_ABS_FOOTBALL_TASK_QUERY
  689. local len = 0
  690. for index, v in pairs(FootballExcel.task or {}) do
  691. len = len + 1
  692. local net = msgRet.list[len]
  693. local taskState = getTaskState(absAct, index) or CommonDefine.COMMON_PRIZE_STATE_NOGET
  694. net.id = index
  695. net.desc = v.desc or ""
  696. net.needCnt = 1
  697. net.nowCnt = taskState >= CommonDefine.COMMON_PRIZE_STATE_CANGET and 1 or 0
  698. net.state = taskState
  699. fillItemList(net.item, v.reward or {})
  700. end
  701. msgRet.list[0] = len
  702. Msg.send(msgRet, human.fd)
  703. end
  704. -- CG_ABS_FOOTBALL_TASK_GET 领取任务奖励
  705. function getTaskReward(human, id, taskId)
  706. if not checkActStarted(human, id) then return end
  707. local config = (FootballExcel.task or {})[taskId]
  708. if not config then
  709. return Broadcast.sendErr(human, Lang.COMMON_ARGUMENT_ERROR)
  710. end
  711. local absAct = getOrInitActData(human, id)
  712. local taskState = getTaskState(absAct, taskId)
  713. if taskState == CommonDefine.COMMON_PRIZE_STATE_GET then
  714. return Broadcast.sendErr(human, Lang.YUNYING_GET_ERR_HADGET)
  715. end
  716. if taskState ~= CommonDefine.COMMON_PRIZE_STATE_CANGET then
  717. return Broadcast.sendErr(human, Lang.YUNYING_GET_ERR_CONDITION)
  718. end
  719. absAct.task[taskId] = CommonDefine.COMMON_PRIZE_STATE_GET
  720. BagLogic.addItemList(human, copyItemList(config.reward), LOGTAG)
  721. queryTask(human, id)
  722. getAndSendMsg(human, id)
  723. YunYingLogic.sendBanner(human)
  724. end
  725. -- CG_ABS_FOOTBALL_REWARD_QUERY 查询累计胜场奖励
  726. function queryReward(human, id)
  727. if not checkActStarted(human, id) then return end
  728. local absAct = getOrInitActData(human, id)
  729. local msgRet = Msg.gc.GC_ABS_FOOTBALL_REWARD_QUERY
  730. msgRet.winCnt = absAct.winCnt
  731. local len = 0
  732. for index, v in pairs(FootballExcel.reward or {}) do
  733. len = len + 1
  734. local net = msgRet.list[len]
  735. net.id = index
  736. net.desc = v.desc or ""
  737. net.needCnt = v.progressVal or 0
  738. net.nowCnt = absAct.winCnt
  739. net.state = getReachRewardState(absAct, index, v.progressVal)
  740. fillItemList(net.item, v.reward or {})
  741. end
  742. msgRet.list[0] = len
  743. Msg.send(msgRet, human.fd)
  744. end
  745. -- CG_ABS_FOOTBALL_REWARD_GET 领取累计胜场奖励
  746. function getReachReward(human, id, rewardId)
  747. if not checkActStarted(human, id) then return end
  748. local config = (FootballExcel.reward or {})[rewardId]
  749. if not config then
  750. return Broadcast.sendErr(human, Lang.COMMON_ARGUMENT_ERROR)
  751. end
  752. local absAct = getOrInitActData(human, id)
  753. local rewardState = getReachRewardState(absAct, rewardId, config.progressVal)
  754. if rewardState == CommonDefine.COMMON_PRIZE_STATE_GET then
  755. return Broadcast.sendErr(human, Lang.YUNYING_GET_ERR_HADGET)
  756. end
  757. if rewardState ~= CommonDefine.COMMON_PRIZE_STATE_CANGET then
  758. return Broadcast.sendErr(human, Lang.YUNYING_GET_ERR_CONDITION)
  759. end
  760. absAct.reward[rewardId] = CommonDefine.COMMON_PRIZE_STATE_GET
  761. BagLogic.addItemList(human, copyItemList(config.reward), LOGTAG)
  762. queryReward(human, id)
  763. getAndSendMsg(human, id)
  764. YunYingLogic.sendBanner(human)
  765. end
  766. -- CG_ABS_FOOTBALL_GIFT_QUERY 查询礼包列表
  767. function queryGift(human, id)
  768. if not checkActStarted(human, id) then return end
  769. local absAct = getOrInitActData(human, id)
  770. local msgRet = Msg.gc.GC_ABS_FOOTBALL_GIFT_QUERY
  771. local len = 0
  772. for index, v in pairs(FootballExcel.gift or {}) do
  773. len = len + 1
  774. local net = msgRet.list[len]
  775. net.id = index
  776. net.maxCnt = v.limitCnt or 0
  777. net.nowCnt = absAct.gift and absAct.gift[index] or 0
  778. fillItemList(net.item, v.reward or {})
  779. if v.buyId then
  780. BuyLogic.fontBuyItem(human, net.buyMsg, v.buyId)
  781. end
  782. end
  783. msgRet.list[0] = len
  784. Msg.send(msgRet, human.fd)
  785. end