FootballMatchLogic.lua 28 KB

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