FootballMatchLogic.lua 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867
  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; 分出胜负后再推 GC_ABS_FOOTBALL_QUERY
  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 = 7701 -- 足球竞赛活动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. BagLogic.addItemList(human, copyItemList(getMatchReward(isWin)), LOGTAG)
  299. match.phase = PHASE_IDLE
  300. match.isEnd = 1
  301. YunYingLogic.sendBanner(human)
  302. local config = AbsActExcel.absActivity[id]
  303. if config then
  304. YunYingLogic.sendGroupUpdate(YYInfo[id], human, config.panelID)
  305. end
  306. end
  307. -- 填充单轮比赛结果到协议结构
  308. local function fillRoundResultNet(net, roundData)
  309. net.player = roundData.player or RESULT_PENDING
  310. net.ai = roundData.ai or RESULT_PENDING
  311. end
  312. -- 填充5轮比赛结果
  313. local function fillAllRoundResults(msgRet, match)
  314. for i = 1, MAX_ROUND do
  315. local roundData = match and match.roundResults and match.roundResults[i]
  316. if not roundData then
  317. roundData = {player = RESULT_PENDING, ai = RESULT_PENDING}
  318. end
  319. fillRoundResultNet(msgRet.roundResults[i], roundData)
  320. end
  321. msgRet.roundResults[0] = MAX_ROUND
  322. end
  323. -- DB phase 转查询协议 state
  324. local function phaseToQueryState(phase)
  325. if phase == PHASE_SHOOT then
  326. return STATE_SHOOT
  327. end
  328. if phase == PHASE_SAVE then
  329. return STATE_SAVE
  330. end
  331. return STATE_IDLE
  332. end
  333. -- 任务分页是否有红点
  334. local function hasTaskPageRedDot(absAct)
  335. for taskId in pairs(FootballExcel.task or {}) do
  336. if getTaskState(absAct, taskId) == CommonDefine.COMMON_PRIZE_STATE_CANGET then
  337. return true
  338. end
  339. end
  340. return false
  341. end
  342. -- 奖励分页是否有红点
  343. local function hasRewardPageRedDot(absAct)
  344. for index, v in pairs(FootballExcel.reward or {}) do
  345. if getReachRewardState(absAct, index, v.progressVal) == CommonDefine.COMMON_PRIZE_STATE_CANGET then
  346. return true
  347. end
  348. end
  349. return false
  350. end
  351. -- 填充分页红点
  352. local function fillPageRedDotArr(msgRet, absAct)
  353. msgRet.pageRedDotArr[0] = 2
  354. msgRet.pageRedDotArr[1] = hasTaskPageRedDot(absAct) and 1 or 0
  355. msgRet.pageRedDotArr[2] = hasRewardPageRedDot(absAct) and 1 or 0
  356. end
  357. -- 填充单场消耗道具
  358. local function fillCostItem(msgRet)
  359. local itemId, itemCnt = getCostItemInfo()
  360. Grid.makeItem(msgRet.costItem, itemId, itemCnt)
  361. end
  362. -- 填充 GC_ABS_FOOTBALL_QUERY
  363. local function fillQueryNet(msgRet, human, id)
  364. local absAct = getOrInitActData(human, id)
  365. local match = absAct.match
  366. msgRet.playerName = human.db.name or ""
  367. msgRet.winCnt = absAct.winCnt
  368. fillPageRedDotArr(msgRet, absAct)
  369. fillCostItem(msgRet)
  370. if match and match.phase ~= PHASE_IDLE then
  371. msgRet.opponentName = match.opponentName or ""
  372. msgRet.round = match.round or 1
  373. msgRet.state = phaseToQueryState(match.phase)
  374. fillAllRoundResults(msgRet, match)
  375. return
  376. end
  377. if match and match.isEnd == 1 then
  378. msgRet.opponentName = match.opponentName or ""
  379. msgRet.round = match.round or 0
  380. msgRet.state = STATE_ROUND_END
  381. fillAllRoundResults(msgRet, match)
  382. return
  383. end
  384. msgRet.opponentName = ""
  385. msgRet.round = 0
  386. msgRet.state = STATE_IDLE
  387. fillAllRoundResults(msgRet, match)
  388. end
  389. -- 填充 GC_ABS_FOOTBALL_ACTION
  390. local function fillActionNet(msgRet, match, extra)
  391. msgRet.ret = extra.ret or RET_NOT_END
  392. msgRet.actionType = extra.actionType or 0
  393. msgRet.playerDir = extra.playerDir or 0
  394. msgRet.opponentDir = extra.opponentDir or 0
  395. msgRet.isGoal = extra.isGoal or 0
  396. msgRet.round = extra.round or 0
  397. msgRet.state = extra.state or STATE_IDLE
  398. fillAllRoundResults(msgRet, match)
  399. end
  400. -- 下发比赛查询协议 GC_ABS_FOOTBALL_QUERY
  401. local function sendQuery(human, id)
  402. local msgRet = Msg.gc.GC_ABS_FOOTBALL_QUERY
  403. fillQueryNet(msgRet, human, id)
  404. Msg.send(msgRet, human.fd)
  405. end
  406. -- 下发行动结果 GC_ABS_FOOTBALL_ACTION
  407. local function sendActionResult(human, match, extra)
  408. local msgRet = Msg.gc.GC_ABS_FOOTBALL_ACTION
  409. fillActionNet(msgRet, match, extra)
  410. Msg.send(msgRet, human.fd)
  411. end
  412. -- 填充道具列表到协议结构
  413. local function fillItemList(netList, itemList)
  414. local len = #itemList
  415. for i = 1, len do
  416. Grid.makeItem(netList[i], itemList[i][1], itemList[i][2])
  417. end
  418. netList[0] = len
  419. end
  420. -- 检查活动是否开启, 未开启则下发错误
  421. local function checkActStarted(human, id)
  422. if AbsActLogic.isStarted(human, id) then
  423. return true
  424. end
  425. Broadcast.sendErr(human, Lang.YUNYING_ERR_TIME)
  426. return false
  427. end
  428. --------------------------------
  429. -- 服务器模块接口
  430. --------------------------------
  431. -- 初始化活动DB
  432. function genAbsActData(config, human)
  433. return {
  434. winCnt = 0,
  435. reward = {},
  436. task = {},
  437. gift = {},
  438. }
  439. end
  440. -- 活动是否开启
  441. function isOpen(human, YYInfo, funcConfig)
  442. local state, endTime, startTime = AbsActLogic.isStarted(human, funcConfig.funcID)
  443. if not state then return end
  444. return true, endTime, startTime
  445. end
  446. -- 活动是否未开启(运营图标置灰用)
  447. function isActive(human, YYInfo, funcConfig)
  448. return not isOpen(human, YYInfo, funcConfig)
  449. end
  450. -- 红点: 有可领奖励/任务(有道具可开赛不再显示红点, 逻辑暂屏蔽)
  451. function isRed(human, YYInfo, funcConfig)
  452. local id = funcConfig.funcID
  453. local state = AbsActLogic.isStarted(human, id)
  454. if not state then return end
  455. local absAct = human.db.absAct[id]
  456. if not absAct then return end
  457. if hasRewardPageRedDot(absAct) or hasTaskPageRedDot(absAct) then
  458. return true
  459. end
  460. --[[ 有足球道具且当前无进行中比赛时显示红点, 暂不需要
  461. local itemId, itemCnt = getCostItemInfo()
  462. if itemId > 0 and itemCnt > 0 and (not absAct.match or absAct.match.phase == PHASE_IDLE) then
  463. if BagLogic.getItemCnt(human, itemId) >= itemCnt then
  464. return true
  465. end
  466. end
  467. --]]
  468. return false
  469. end
  470. -- 登录时补检任务状态
  471. function onLogin(human, funcID)
  472. local state = AbsActLogic.isStarted(human, funcID)
  473. if not state then
  474. return
  475. end
  476. getOrInitActData(human, funcID)
  477. tryInitTasks(human, funcID)
  478. end
  479. -- 跨天回调: 重置日任务并补检登录任务
  480. function updateDaily(human, funcID)
  481. local state = AbsActLogic.isStarted(human, funcID)
  482. if not state then
  483. return
  484. end
  485. local absAct = human.db.absAct[funcID]
  486. if not absAct then
  487. return
  488. end
  489. resetDailyTasks(absAct)
  490. checkWeekTaskReset(human, absAct)
  491. tryCompleteTask(human, funcID, TASK_ID_LOGIN)
  492. end
  493. -- 日/周活跃达100时触发(由 DailyTaskLogic/WeekTaskLogic 调用)
  494. function OnHuoYueReach100(human)
  495. if not AbsActLogic.isStarted(human, ACT_ID) then
  496. return
  497. end
  498. getOrInitActData(human, ACT_ID)
  499. local DailyTaskLogic = require("dailyTask.DailyTaskLogic")
  500. if DailyTaskLogic.isReachMaxDailyHuoYue(human) then
  501. tryCompleteTask(human, ACT_ID, TASK_ID_DAILY_HUOYUE)
  502. end
  503. local WeekTaskLogic = require("dailyTask.WeekTaskLogic")
  504. if WeekTaskLogic.isReachMaxWeekHuoYue(human) then
  505. tryCompleteTask(human, ACT_ID, TASK_ID_WEEK_HUOYUE)
  506. end
  507. end
  508. -- 充值购买礼包回调
  509. function onCharge(human, price, funcID, buyID, buyNum)
  510. local state = AbsActLogic.isStarted(human, funcID)
  511. if not state then return end
  512. local absAct = getOrInitActData(human, funcID)
  513. buyNum = buyNum or 1
  514. for index, v in pairs(FootballExcel.gift or {}) do
  515. if v.buyId == buyID then
  516. absAct.gift = absAct.gift or {}
  517. local nowCnt = absAct.gift[index] or 0
  518. if nowCnt + buyNum > (v.limitCnt or 0) then
  519. return
  520. end
  521. absAct.gift[index] = nowCnt + buyNum
  522. local items = copyItemList(v.reward)
  523. for _, item in ipairs(items) do
  524. item[2] = item[2] * buyNum
  525. end
  526. BagLogic.addItemList(human, items, LOGTAG)
  527. queryGift(human, funcID)
  528. YunYingLogic.sendBanner(human)
  529. return
  530. end
  531. end
  532. end
  533. -- 获取礼包剩余可购买次数(供 BuyLogic 等模块调用)
  534. function GetRemainNum(human, buyId)
  535. if not AbsActLogic.isStarted(human, ACT_ID) then
  536. return 0
  537. end
  538. for index, v in pairs(FootballExcel.gift or {}) do
  539. if v.buyId == buyId then
  540. local maxCnt = v.limitCnt or 0
  541. local absAct = human.db.absAct[ACT_ID]
  542. if not absAct then
  543. return maxCnt
  544. end
  545. local nowCnt = absAct.gift and absAct.gift[index] or 0
  546. return nowCnt >= maxCnt and 0 or (maxCnt - nowCnt)
  547. end
  548. end
  549. return 0
  550. end
  551. --------------------------------
  552. -- 客户端请求处理
  553. --------------------------------
  554. -- CG_ABS_FOOTBALL_QUERY 查询比赛进度(断线重进恢复用)
  555. function getAndSendMsg(human, id)
  556. if not checkActStarted(human, id) then return end
  557. getOrInitActData(human, id)
  558. sendQuery(human, id)
  559. end
  560. -- CG_ABS_FOOTBALL_START 开始比赛, 消耗1个足球道具
  561. function startMatch(human, id)
  562. if not checkActStarted(human, id) then return end
  563. local absAct = getOrInitActData(human, id)
  564. if absAct.match and absAct.match.phase ~= PHASE_IDLE then
  565. return Broadcast.sendErr(human, Lang.COMMON_ARGUMENT_ERROR)
  566. end
  567. local itemId, itemCnt = getCostItemInfo()
  568. if itemId <= 0 or itemCnt <= 0 or BagLogic.getItemCnt(human, itemId) < itemCnt then
  569. return Broadcast.sendErr(human, Lang.COMMON_ITEM_NOT_ENOUGH)
  570. end
  571. BagLogic.delItem(human, itemId, itemCnt, LOGTAG)
  572. absAct.match = {
  573. opponentName = getRandomOpponentName(human.db._id),
  574. round = 1,
  575. phase = PHASE_SHOOT,
  576. playerScore = 0,
  577. aiScore = 0,
  578. roundResults = initMatchResults(),
  579. isEnd = 0,
  580. }
  581. sendQuery(human, id)
  582. end
  583. -- 玩家射门
  584. local function playerShoot(human, id, shootDir)
  585. local absAct = getOrInitActData(human, id)
  586. local match = absAct.match
  587. if not match or match.phase ~= PHASE_SHOOT then
  588. return Broadcast.sendErr(human, Lang.COMMON_ARGUMENT_ERROR)
  589. end
  590. local round = match.round
  591. local aiSaveDir = randomDirection()
  592. local goal = isGoal(shootDir, aiSaveDir)
  593. if goal then
  594. match.playerScore = match.playerScore + 1
  595. match.roundResults[round].player = RESULT_GOAL
  596. else
  597. match.roundResults[round].player = RESULT_MISS
  598. end
  599. match.phase = PHASE_SAVE
  600. sendActionResult(human, match, {
  601. ret = RET_NOT_END,
  602. actionType = ACTION_TYPE_SHOOT,
  603. playerDir = shootDir,
  604. opponentDir = aiSaveDir,
  605. isGoal = goal and 1 or 0,
  606. round = round,
  607. state = STATE_SAVE,
  608. })
  609. end
  610. -- 玩家扑救; 每轮结束检查提前结束或进入下一轮
  611. local function playerSave(human, id, saveDir)
  612. local absAct = getOrInitActData(human, id)
  613. local match = absAct.match
  614. if not match or match.phase ~= PHASE_SAVE then
  615. return Broadcast.sendErr(human, Lang.COMMON_ARGUMENT_ERROR)
  616. end
  617. local round = match.round
  618. local aiShootDir = calcAiShootDir(round, match.playerScore, match.aiScore, saveDir)
  619. local goal = isGoal(aiShootDir, saveDir)
  620. if goal then
  621. match.aiScore = match.aiScore + 1
  622. match.roundResults[round].ai = RESULT_GOAL
  623. else
  624. match.roundResults[round].ai = RESULT_MISS
  625. end
  626. local winner = checkEarlyWin(round, match.playerScore, match.aiScore)
  627. if not winner and round >= MAX_ROUND then
  628. if match.playerScore > match.aiScore then
  629. winner = 1
  630. elseif match.aiScore > match.playerScore then
  631. winner = 2
  632. else
  633. winner = 1
  634. end
  635. end
  636. if winner then
  637. finishMatch(human, id, match, winner)
  638. sendActionResult(human, match, {
  639. ret = winner == 1 and RET_PLAYER_WIN or RET_PLAYER_LOSE,
  640. actionType = ACTION_TYPE_SAVE,
  641. playerDir = saveDir,
  642. opponentDir = aiShootDir,
  643. isGoal = goal and 1 or 0,
  644. round = round,
  645. state = STATE_ROUND_END,
  646. })
  647. sendQuery(human, id)
  648. return
  649. end
  650. match.round = round + 1
  651. match.phase = PHASE_SHOOT
  652. sendActionResult(human, match, {
  653. ret = RET_NOT_END,
  654. actionType = ACTION_TYPE_SAVE,
  655. playerDir = saveDir,
  656. opponentDir = aiShootDir,
  657. isGoal = goal and 1 or 0,
  658. round = match.round,
  659. state = STATE_SHOOT,
  660. })
  661. end
  662. -- CG_ABS_FOOTBALL_ACTION 玩家行动(射门/扑救)
  663. function playerAction(human, id, actionType, dir)
  664. if not checkActStarted(human, id) then return end
  665. if dir < DIR_LEFT or dir > DIR_RIGHT then
  666. return Broadcast.sendErr(human, Lang.COMMON_ARGUMENT_ERROR)
  667. end
  668. if actionType == ACTION_TYPE_SHOOT then
  669. playerShoot(human, id, dir)
  670. elseif actionType == ACTION_TYPE_SAVE then
  671. playerSave(human, id, dir)
  672. else
  673. return Broadcast.sendErr(human, Lang.COMMON_ARGUMENT_ERROR)
  674. end
  675. end
  676. -- CG_ABS_FOOTBALL_TASK_QUERY 查询任务列表
  677. function queryTask(human, id)
  678. if not checkActStarted(human, id) then return end
  679. local absAct = getOrInitActData(human, id)
  680. tryInitTasks(human, id)
  681. local msgRet = Msg.gc.GC_ABS_FOOTBALL_TASK_QUERY
  682. local len = 0
  683. for index, v in pairs(FootballExcel.task or {}) do
  684. len = len + 1
  685. local net = msgRet.list[len]
  686. local taskState = getTaskState(absAct, index) or CommonDefine.COMMON_PRIZE_STATE_NOGET
  687. net.id = index
  688. net.desc = v.desc or ""
  689. net.needCnt = 1
  690. net.nowCnt = taskState >= CommonDefine.COMMON_PRIZE_STATE_CANGET and 1 or 0
  691. net.state = taskState
  692. fillItemList(net.item, v.reward or {})
  693. end
  694. msgRet.list[0] = len
  695. Msg.send(msgRet, human.fd)
  696. end
  697. -- CG_ABS_FOOTBALL_TASK_GET 领取任务奖励
  698. function getTaskReward(human, id, taskId)
  699. if not checkActStarted(human, id) then return end
  700. local config = (FootballExcel.task or {})[taskId]
  701. if not config then
  702. return Broadcast.sendErr(human, Lang.COMMON_ARGUMENT_ERROR)
  703. end
  704. local absAct = getOrInitActData(human, id)
  705. local taskState = getTaskState(absAct, taskId)
  706. if taskState == CommonDefine.COMMON_PRIZE_STATE_GET then
  707. return Broadcast.sendErr(human, Lang.YUNYING_GET_ERR_HADGET)
  708. end
  709. if taskState ~= CommonDefine.COMMON_PRIZE_STATE_CANGET then
  710. return Broadcast.sendErr(human, Lang.YUNYING_GET_ERR_CONDITION)
  711. end
  712. absAct.task[taskId] = CommonDefine.COMMON_PRIZE_STATE_GET
  713. BagLogic.addItemList(human, copyItemList(config.reward), LOGTAG)
  714. queryTask(human, id)
  715. YunYingLogic.sendBanner(human)
  716. end
  717. -- CG_ABS_FOOTBALL_REWARD_QUERY 查询累计胜场奖励
  718. function queryReward(human, id)
  719. if not checkActStarted(human, id) then return end
  720. local absAct = getOrInitActData(human, id)
  721. local msgRet = Msg.gc.GC_ABS_FOOTBALL_REWARD_QUERY
  722. msgRet.winCnt = absAct.winCnt
  723. local len = 0
  724. for index, v in pairs(FootballExcel.reward or {}) do
  725. len = len + 1
  726. local net = msgRet.list[len]
  727. net.id = index
  728. net.desc = v.desc or ""
  729. net.needCnt = v.progressVal or 0
  730. net.nowCnt = absAct.winCnt
  731. net.state = getReachRewardState(absAct, index, v.progressVal)
  732. fillItemList(net.item, v.reward or {})
  733. end
  734. msgRet.list[0] = len
  735. Msg.send(msgRet, human.fd)
  736. end
  737. -- CG_ABS_FOOTBALL_REWARD_GET 领取累计胜场奖励
  738. function getReachReward(human, id, rewardId)
  739. if not checkActStarted(human, id) then return end
  740. local config = (FootballExcel.reward or {})[rewardId]
  741. if not config then
  742. return Broadcast.sendErr(human, Lang.COMMON_ARGUMENT_ERROR)
  743. end
  744. local absAct = getOrInitActData(human, id)
  745. local rewardState = getReachRewardState(absAct, rewardId, config.progressVal)
  746. if rewardState == CommonDefine.COMMON_PRIZE_STATE_GET then
  747. return Broadcast.sendErr(human, Lang.YUNYING_GET_ERR_HADGET)
  748. end
  749. if rewardState ~= CommonDefine.COMMON_PRIZE_STATE_CANGET then
  750. return Broadcast.sendErr(human, Lang.YUNYING_GET_ERR_CONDITION)
  751. end
  752. absAct.reward[rewardId] = CommonDefine.COMMON_PRIZE_STATE_GET
  753. BagLogic.addItemList(human, copyItemList(config.reward), LOGTAG)
  754. queryReward(human, id)
  755. YunYingLogic.sendBanner(human)
  756. end
  757. -- CG_ABS_FOOTBALL_GIFT_QUERY 查询礼包列表
  758. function queryGift(human, id)
  759. if not checkActStarted(human, id) then return end
  760. local absAct = getOrInitActData(human, id)
  761. local msgRet = Msg.gc.GC_ABS_FOOTBALL_GIFT_QUERY
  762. local len = 0
  763. for index, v in pairs(FootballExcel.gift or {}) do
  764. len = len + 1
  765. local net = msgRet.list[len]
  766. net.id = index
  767. net.maxCnt = v.limitCnt or 0
  768. net.nowCnt = absAct.gift and absAct.gift[index] or 0
  769. fillItemList(net.item, v.reward or {})
  770. if v.buyId and v.buyId > 0 then
  771. BuyLogic.fontBuyItem(human, net.buyMsg, v.buyId)
  772. end
  773. end
  774. msgRet.list[0] = len
  775. Msg.send(msgRet, human.fd)
  776. end