-- 百战成神(普通服 NS) -- -- 玩法: 跨服 5v5 积分 PvP, 五族独立阵容 COMBAT_TYPE39~43, 5 局 3 胜。 -- 开服>=45 天; 周六 0:10~周日 23:00; 每 21 天新轮。 -- -- 数据分工: -- 跨服 DB: 积分、排行、匹配池、玩家展示(REGISTER/UPDATE_SHOW) -- 本地 human.db.baiZhanChengShen: 免费次数、战报、crossRegistered -- human.bzcs_Match_Cache: 匹配列表/积分内存缓存(TTL 见 BZCS_MATCH_CACHE_TTL, 不持久化) -- CommonDB.KEY_BZCS_START_TIME: 本服活动轮次标记(与跨服 WL_BZCS_ACT_START 同步) -- -- 跨服同步策略: -- 首次完成挑战 -> 先 LW_BZCS_REGISTER 再 LW_BZCS_FIGHT_END (crossRegistered=true, 每轮仅一次) -- 阵容/战力变更 -> LW_BZCS_UPDATE_SHOW (须已注册) -- 每场战斗结束 -> LW_BZCS_FIGHT_END (不重复 REGISTER) -- -- 战斗: -- 挑战一次依次走 CG_COMBAT_BEGIN(COMBAT_TYPE39~43); 仅首场校验次数/道具并请求跨服 -- 扣次在 C2N_CanFight; onFightEnd 链式 nextCombatType 打满 5 族或 3 胜, 整场结束发 fightReward -- 机器人: combatBegin; 真人: MiddleCommonLogic_CombatBegin_LW -- -- 文件结构: -- 本地辅助 -> 客户端请求(BZCS_*) -> 跨服通知(C2N_*) -> 战斗相关 -> 对外接口 local Config = require("Config") local Msg = require("core.Msg") local Lang = require("common.Lang") local Util = require("common.Util") local ObjHuman = require("core.ObjHuman") local Broadcast = require("broadcast.Broadcast") local CombatDefine = require("combat.CombatDefine") local CombatLogic = require("combat.CombatLogic") local CombatPosLogic = require("combat.CombatPosLogic") local RoleDBLogic = require("role.RoleDBLogic") local RoleHeadLogic = require("role.RoleHeadLogic") local RoleAttr = require("role.RoleAttr") local InnerMsg = require("core.InnerMsg") local MailManager = require("mail.MailManager") local MailExcel = require("excel.mail") local Timer = require("core.Timer") local Grid = require("bag.Grid") local BagLogic = require("bag.BagLogic") local CommonDB = require("common.CommonDB") local MiddleConnect = require("middle.MiddleConnect") local MiddleCommonLogic = require("middle.MiddleCommonLogic") local HeroExcel = require("excel.hero") local BaiZhanChengShenDefine = require("baiZhanChengShen.BaiZhanChengShenDefine") local BzcsLog = require("baiZhanChengShen.BaiZhanChengShenLog") local BzcsConfig = require("excel.baiZhanChengShen") local SkillExcel = require("excel.skill") local Skill = require("combat.Skill") local HeroLogic local MoshouLogic local ElfLogic local LOGTAG = "BaiZhanChengShen" -- 战斗类型 -> 种族 camp, 用于 checkUpdatePos 限制上阵 local COMBATTYPE_2_CAMP = { [CombatDefine.COMBAT_TYPE39] = 1, [CombatDefine.COMBAT_TYPE40] = 2, [CombatDefine.COMBAT_TYPE41] = 3, [CombatDefine.COMBAT_TYPE42] = 4, [CombatDefine.COMBAT_TYPE43] = 5, } ------------------------------------ 本地辅助 ------------------------------------ -- 逻辑服与跨服链路是否可用(WL_HELLO 成功后为 true) local function isMiddleReady() if _G.is_middle then return true end return MiddleConnect.IS_MIDDLE_CONNECT == true end -- 发送 LW 到跨服; 断连时提示玩家并返回 false local function sendLwToMiddle(human, msgData) if not isMiddleReady() then if human and human.fd then Broadcast.sendErr(human, Lang.MIDDLE_SVR_ERR_CONNECT) end return false end InnerMsg.sendMsg(0, msgData) return true end -- 当前星期(Util.getWeekDay: 1=周日, 7=周六) local function getWDay() return Util.getWeekDay() end -- 开服天数是否满足参与条件 local function isServerEligible() return CommonDB.getServerOpenDay() >= BaiZhanChengShenDefine.BZCS_OPEN_SVR_DAY end -- 本服是否在活动期(跨服已广播 KEY_BZCS_START_TIME 且 IsRunning) local function actStartTimeCheck() local wDay = getWDay() if wDay > BaiZhanChengShenDefine.BZCS_OPEN_WDAY_AREA[2] and wDay < BaiZhanChengShenDefine.BZCS_OPEN_WDAY_AREA[1] then return false end local startTime = CommonDB.getValueByKey(CommonDB.KEY_BZCS_START_TIME) if not startTime or startTime == 0 then return false end return IsRunning(startTime) end -- 新活动轮次时清空本地战报 local function clearRoundLocalData(db) db.warReport = {} db.crossRegistered = false end -- 清除匹配内存缓存(积分变化/新轮/强制刷新) local function clearMatchCache(human) if human then human.bzcs_Match_Cache = nil end end -- 活动开始时间变化(新轮开启/结束)时重置本地轮次数据 local function resetRoundLocalIfNeeded(human, db) local actStart = CommonDB.getValueByKey(CommonDB.KEY_BZCS_START_TIME) or 0 if (db.actStartTime or 0) ~= actStart then db.actStartTime = actStart clearRoundLocalData(db) clearMatchCache(human) end end -- 玩家本地百战成神数据 (不入跨服 Mongo) -- freeTimes 今日剩余免费挑战次数(跨天由 updateDaily 重置) -- actStartTime 已同步的活动轮开始时间(与 KEY_BZCS_START_TIME 对比清轮次数据) -- crossRegistered 本轮是否已向跨服 REGISTER -- warReport 本地战报 {warType,...}, 按时间尾插(最老在[1]), 下发时倒序为新在前 local function getBzcsDb(human) human.db.baiZhanChengShen = human.db.baiZhanChengShen or { freeTimes = BaiZhanChengShenDefine.BZCS_FREE_TIMES, actStartTime = 0, crossRegistered = false, warReport = {}, } resetRoundLocalIfNeeded(human, human.db.baiZhanChengShen) return human.db.baiZhanChengShen end local function getMatchCache(human) return human and human.bzcs_Match_Cache end local function setMatchCache(human, myScore, opponentList, myRank) human.bzcs_Match_Cache = { myScore = myScore, myRank = myRank or 0, matchScore = myScore, opponentList = opponentList or {}, cacheTime = os.time(), } end -- 展示刷新: 保留 matchScore(匹配基准), 更新对手展示并重置 TTL local function refreshMatchCacheDisplay(human, myScore, opponentList, myRank) local cache = getMatchCache(human) if myRank == nil then myRank = cache and cache.myRank or 0 end human.bzcs_Match_Cache = { myScore = myScore, myRank = myRank, matchScore = cache and cache.matchScore or myScore, opponentList = opponentList or {}, cacheTime = os.time(), } end -- 积分变动: 清空对手列表, 重置 matchScore/TTL(从变动时刻重新计时) local function resetMatchCacheOnScoreChange(human, newScore) if not human then return end newScore = newScore or BaiZhanChengShenDefine.BZCS_INIT_SCORE human.bzcs_Match_Cache = { myScore = newScore, myRank = 0, matchScore = newScore, opponentList = {}, cacheTime = os.time(), } end local function isMatchCacheFresh(human) local cache = getMatchCache(human) if not cache or not cache.opponentList or not next(cache.opponentList) then return false end if (cache.myScore or 0) ~= (cache.matchScore or 0) then return false end local ttl = BaiZhanChengShenDefine.BZCS_MATCH_CACHE_TTL or 30 return (os.time() - (cache.cacheTime or 0)) < ttl end local function collectRefreshRanks(opponentList) local ranks = {} for _, opp in ipairs(opponentList or {}) do if opp.rank and opp.rank > 0 then ranks[#ranks + 1] = opp.rank end end return ranks end -- 校验 rank 是否属于当前匹配缓存(全服名次, 非列表下标 1~3) local function resolveMatchOpponentByRank(human, rank) if not rank or rank < 1 then return nil end local cache = getMatchCache(human) for _, opp in ipairs(cache and cache.opponentList or {}) do if opp.rank == rank and opp.uuid then return opp end end return nil end -- 指定种族阵容是否至少上阵 1 名英雄(空位 "0"/"" 不算) local function hasRaceLineupHero(human, race) local combatType = BaiZhanChengShenDefine.BZCS_RACE_COMBAT_TYPE[race] if not combatType then return false end local heroList = CombatPosLogic.getCombatHeros(human, combatType) if not heroList then return false end for _, heroUuid in pairs(heroList) do if heroUuid and heroUuid ~= "" and heroUuid ~= "0" then return true end end return false end -- 五族阵容是否均已至少上阵 1 名英雄(供 GC_BZCS_MATCH_LIST.allLineupReady) local function isAllRaceLineupReady(human) for _, race in ipairs(BaiZhanChengShenDefine.BZCS_RACE_ORDER) do if not hasRaceLineupHero(human, race) then return false end end return true end -- 挑战前校验五族阵容均已上阵英雄 local function checkAllRaceLineupForFight(human) for _, race in ipairs(BaiZhanChengShenDefine.BZCS_RACE_ORDER) do if not hasRaceLineupHero(human, race) then local raceName = BaiZhanChengShenDefine.BZCS_RACE_NAME[race] or "" Broadcast.sendErr(human, Util.format(Lang.BZCS_NEED_RACE_LINEUP, raceName)) return false end end return true end -- 组装并下发 GC_BZCS_MATCH_LIST local function resolveMatchOpponentPower(opp) if not opp then return 0 end local power = opp.power or 0 if power > 0 then return power end local uuid = opp.uuid if uuid and uuid ~= "" and BaiZhanChengShenDefine.GetRobotListIndex(uuid) then return BaiZhanChengShenDefine.CalcRobotPowerByUuid(uuid) end return power end local function sendMatchListGC(human, myScore, opponentList, myRank) local db = getBzcsDb(human) local msgRet = Msg.gc.GC_BZCS_MATCH_LIST msgRet.myRank = myRank or 0 msgRet.myScore = myScore or BaiZhanChengShenDefine.BZCS_INIT_SCORE msgRet.freeTimes = db.freeTimes or 0 Grid.makeItem( msgRet.ticketCost, BaiZhanChengShenDefine.BZCS_TICKET_ITEM_ID, BaiZhanChengShenDefine.BZCS_TICKET_COST ) msgRet.allLineupReady = isAllRaceLineupReady(human) and 1 or 0 msgRet.opponentList[0] = #(opponentList or {}) for i, opp in ipairs(opponentList or {}) do local net = msgRet.opponentList[i] net.rank = opp.rank or 0 net.name = opp.name net.body = opp.body or 0 net.power = resolveMatchOpponentPower(opp) net.score = opp.score net.serverId = BaiZhanChengShenDefine.ToClientServerId(opp.serverId, opp.isRobot) end Msg.send(msgRet, human.fd) end -- 单个英雄展示字段(阵容/协议用) local function getHeroInfo(human, heroUuid) HeroLogic = HeroLogic or require("hero.HeroLogic") local heroGrid = HeroLogic.getHeroGridByUuid(human, heroUuid) if not heroGrid then return end local heroCfg = HeroExcel.hero[heroGrid.id] RoleAttr.calcHeroGrid(heroGrid, nil, human) return { heroUuid = heroUuid, heroStar = heroGrid.star, heroLevel = heroGrid.lv, heroCamp = heroGrid.camp or heroCfg.camp, heroBody = heroCfg.body, heroIcon = heroGrid.head or heroCfg.head, heroPower = heroGrid.zhandouli, heroId = heroGrid.id, heroQuality = heroCfg.grade, } end -- 某战斗类型阵容内已上阵英雄展示列表 local function getRaceHeroListInfo(human, combatType) local heroArr = {} local len = 0 local heroList = CombatPosLogic.getCombatHeros(human, combatType) if not heroList then return heroArr end for _, heroUuid in pairs(heroList) do if heroUuid ~= "" and heroUuid ~= "0" then local heroInfo = getHeroInfo(human, heroUuid) if heroInfo then len = len + 1 heroArr[len] = heroInfo end end end return heroArr end -- 技能 icon(助阵凤凰 moshouSkill 用) local function getBzcsSkillIcon(skillId) if not skillId or skillId < 1 then return "" end local skillConfig = SkillExcel.skill[skillId] or Skill.GetSkillConfig(skillId) return skillConfig and skillConfig.icon or "" end -- 填充精灵位展示(同 CombatPosLogic.Elf_Pos_Query) local function fillBzcsElfPosArr(msgElfPosArr, elfList, elfSkillIds, human) ElfLogic = ElfLogic or require("elf.ElfLogic") msgElfPosArr[0] = CombatDefine.COMBAT_ELF_NOW_CNT for i = 1, CombatDefine.COMBAT_ELF_NOW_CNT do local net = msgElfPosArr[i] net.elfId = 0 net.nowSkillDesc = "" net.nowSkillIcon = "" local elfId = elfList and elfList[i] if elfId and elfId > 0 then local skillId if human then skillId = ElfLogic.GetElfSkill(human, elfId) else skillId = elfSkillIds and elfSkillIds[i] end if skillId and skillId > 0 then local skillConfig = Skill.GetSkillConfig(skillId) if skillConfig then net.elfId = elfId net.nowSkillDesc = skillConfig.desc net.nowSkillIcon = skillConfig.icon end end end end end -- 填充 BZCS_TEAM_INFO(英雄/助阵 icon/精灵展示) local function fillBzcsTeamNet(teamNet, show, human, combatType) show = BaiZhanChengShenDefine.ExpandBzcsRaceShow(show) or show local heroList = show.heroArr or {} teamNet.power = BaiZhanChengShenDefine.CalcRaceTeamPower(show) teamNet.formation = show.formation or 1 teamNet.heroArr[0] = #heroList for j, h in ipairs(heroList) do local net = teamNet.heroArr[j] net.heroBody = h.heroBody or 0 net.heroStar = h.heroStar or 0 net.heroLv = h.heroLevel or h.heroLv or 0 net.heroCamp = h.heroCamp or 0 net.heroIcon = h.heroIcon or 0 net.heroId = h.heroId or 0 net.heroQuality = h.heroQuality or 1 end local helpSkillId = show.helpSkillId or 0 if human and combatType and helpSkillId < 1 then MoshouLogic = MoshouLogic or require("moshou.MoshouLogic") local combatHeroDB = CombatPosLogic.getCombatHeroDB(human, combatType) if combatHeroDB and combatHeroDB.helpList then helpSkillId = MoshouLogic.getPutMoshouSkillID(human, combatType, combatHeroDB.helpList) or 0 end end teamNet.moshouSkill = getBzcsSkillIcon(helpSkillId) fillBzcsElfPosArr(teamNet.elfPosArr, show.elfList, show.elfSkillIds, human) end -- 单种族阵容展示(跨服仅存 heroArr/阵法/助阵技能id/精灵id+技能id; 战力见各英雄 heroPower) local function getRaceLineupShow(human, race) local combatType = BaiZhanChengShenDefine.BZCS_RACE_COMBAT_TYPE[race] local heroArr = getRaceHeroListInfo(human, combatType) local combatHeroDB = CombatPosLogic.getCombatHeroDB(human, combatType) local helpSkillId = 0 local elfList, elfSkillIds if combatHeroDB then MoshouLogic = MoshouLogic or require("moshou.MoshouLogic") ElfLogic = ElfLogic or require("elf.ElfLogic") if combatHeroDB.helpList then helpSkillId = MoshouLogic.getPutMoshouSkillID(human, combatType, combatHeroDB.helpList) or 0 end if combatHeroDB.elfList then elfList = {} elfSkillIds = {} for i = 1, CombatDefine.COMBAT_ELF_NOW_CNT do local elfId = combatHeroDB.elfList[i] if elfId and elfId > 0 then elfList[i] = elfId elfSkillIds[i] = ElfLogic.GetElfSkill(human, elfId) or 0 end end end end return { heroArr = heroArr, formation = combatHeroDB and combatHeroDB.formation or 1, helpSkillId = helpSkillId, elfList = elfList, elfSkillIds = elfSkillIds, } end -- 跨服展示包: 外观 + 五族阵容(存入 DB.playerList[].showInfo, 仅 REGISTER 全量使用) local function buildShowInfo(human) local heroArr = {} for _, race in ipairs(BaiZhanChengShenDefine.BZCS_RACE_ORDER) do heroArr[race] = getRaceLineupShow(human, race) end return { name = human.db.name, head = RoleHeadLogic.getRoleAppearance(human, RoleHeadLogic.HEAD_TYPE_1), headFrame = RoleHeadLogic.getRoleAppearance(human, RoleHeadLogic.HEAD_TYPE_2), body = RoleHeadLogic.getRoleAppearance(human, RoleHeadLogic.HEAD_TYPE_3), heroArr = heroArr, } end -- 按 updateType 组装增量 showInfo(仅含本次变更字段) local function buildShowPatch(human, updateType, race) if updateType == BaiZhanChengShenDefine.BZCS_UPDATE_SHOW_NAME then return {name = human.db.name} elseif updateType == BaiZhanChengShenDefine.BZCS_UPDATE_SHOW_HEAD then return {head = RoleHeadLogic.getRoleAppearance(human, RoleHeadLogic.HEAD_TYPE_1)} elseif updateType == BaiZhanChengShenDefine.BZCS_UPDATE_SHOW_HEAD_FRAME then return {headFrame = RoleHeadLogic.getRoleAppearance(human, RoleHeadLogic.HEAD_TYPE_2)} elseif updateType == BaiZhanChengShenDefine.BZCS_UPDATE_SHOW_BODY then return {body = RoleHeadLogic.getRoleAppearance(human, RoleHeadLogic.HEAD_TYPE_3)} elseif updateType == BaiZhanChengShenDefine.BZCS_UPDATE_SHOW_LINEUP then if not race then return end return {heroArr = {[race] = getRaceLineupShow(human, race)}} end end -- 按排名取周期奖励道具配置 local function getRankReward(rank) for _, v in ipairs(BzcsConfig.rankReward) do if rank >= v.rankArea[1] and rank <= v.rankArea[2] then return v.awardList end end end -- 道具列表转日志串 itemId:cnt,... local function formatAwardList(awardList) if not awardList or #awardList < 1 then return "" end local parts = {} for i, item in ipairs(awardList) do parts[i] = string.format("%s:%s", item[1] or 0, item[2] or 0) end return table.concat(parts, ",") end -- 整场挑战结束发放道具奖励(读 excel fightReward: 1=胜 2=负) -- combatInfo.rewardItem 供 GC_COMBAT_FINISH 展示, 参考 BattleLogic.onFightEnd local function grantFightReward(human, atkWin, combatInfo) if not human or not human.db then return end local rewardId = atkWin and BaiZhanChengShenDefine.BZCS_FIGHT_REWARD_WIN_ID or BaiZhanChengShenDefine.BZCS_FIGHT_REWARD_LOSE_ID local fightReward = BzcsConfig.fightReward local cfg = fightReward and fightReward[rewardId] if not cfg or not cfg.awardList or not next(cfg.awardList) then BzcsLog.logAction("fight_reward_miss", string.format( "uuid=%s atkWin=%s rewardId=%s", human.db._id, atkWin and 1 or 0, rewardId )) return end if combatInfo then combatInfo.rewardItem = {} end local awardList = {} for i, itemInfo in ipairs(cfg.awardList) do local itemID = itemInfo[1] local itemCnt = itemInfo[2] awardList[i] = {itemID, itemCnt} if combatInfo then combatInfo.rewardItem[i] = {itemID, itemCnt} end BagLogic.addItem(human, itemID, itemCnt, LOGTAG) end BzcsLog.logAction("fight_reward", string.format( "uuid=%s atkWin=%s rewardId=%s itemCnt=%s items=%s", human.db._id, atkWin and 1 or 0, rewardId, #awardList, formatAwardList(awardList) )) end -- 发周期结算邮件(排名写入正文) local function sendMail(mailId, receiverUuid, itemArray, rank) local mailCfg = MailExcel.mail[mailId] if not mailCfg then BzcsLog.logAction("reward_mail_miss", string.format( "uuid=%s rank=%s mailId=%s", receiverUuid or "", rank or 0, mailId or 0 )) return end if not itemArray or not next(itemArray) then BzcsLog.logAction("reward_mail_empty", string.format( "uuid=%s rank=%s mailId=%s", receiverUuid or "", rank or 0, mailId )) return end local content = mailCfg.content if rank then if rank > BaiZhanChengShenDefine.BZCS_RANK_MAX then rank = "100+" end content = Util.format(content, rank) end MailManager.add(MailManager.SYSTEM, receiverUuid, mailCfg.title, content, itemArray, mailCfg.senderName or "GM") BzcsLog.logAction("reward_mail_ok", string.format( "uuid=%s rank=%s mailId=%s itemCnt=%s items=%s", receiverUuid, rank or 0, mailId, #itemArray, formatAwardList(itemArray) )) end -- 批量发奖队列(分批发邮件, 失败重试) local function createRewardQueue() local q = {playerArray = {}, insertMaxNum = 100, repeatMaxTimes = 3, repeatTb = {}} function q:add(info) table.insert(self.playerArray, info) end function q:insertDB() local maxNum = math.min(self.insertMaxNum, #self.playerArray) for _ = 1, maxNum do local info = table.remove(self.playerArray) local uuid, rank = info[1], info[2] local itemArray = getRankReward(rank) if not itemArray then BzcsLog.logAction("reward_cfg_miss", string.format("uuid=%s rank=%s", uuid or "", rank or 0)) else local ok, err = pcall(sendMail, BaiZhanChengShenDefine.BZCS_AWARD_MAIL_ID, uuid, itemArray, rank) if not ok then local retry = (self.repeatTb[uuid] or 0) + 1 if retry <= self.repeatMaxTimes then self.repeatTb[uuid] = retry q:add(info) BzcsLog.logAction("reward_mail_fail", string.format( "uuid=%s rank=%s retry=%s err=%s", uuid, rank, retry, err )) else BzcsLog.logAction("reward_mail_giveup", string.format( "uuid=%s rank=%s retry=%s err=%s", uuid, rank, retry, err )) end end end end if #self.playerArray > 0 then Timer.addLater(3, self.insertDB, self) end end return q end -- bzcs_Battle_Cache: defRank/defUuid/defServerId/defName/defScore/isRobot, raceIdx, atkW/defW, rounds -- 战报尾插; 超上限删最老; 下发 GC 时倒序 local function addWarReport(human, report) local db = getBzcsDb(human) db.warReport = db.warReport or {} db.warReport[#db.warReport + 1] = report if #db.warReport > BaiZhanChengShenDefine.BZCS_WARREPORT_MAX then table.remove(db.warReport, 1) end end -- 是否仍有挑战次数(免费或道具115); 仅校验不扣 local function canChallenge(human) local db = getBzcsDb(human) if db.freeTimes > 0 then return true end return BagLogic.getItemCnt(human, BaiZhanChengShenDefine.BZCS_TICKET_ITEM_ID) >= BaiZhanChengShenDefine.BZCS_TICKET_COST end -- 优先扣免费次数, 否则扣门票; 整场仅在 C2N_CanFight 扣 1 次 local function deductChallengeTimes(human) local db = getBzcsDb(human) if db.freeTimes > 0 then db.freeTimes = db.freeTimes - 1 return true end if BagLogic.getItemCnt(human, BaiZhanChengShenDefine.BZCS_TICKET_ITEM_ID) < BaiZhanChengShenDefine.BZCS_TICKET_COST then return false end BagLogic.delItem(human, BaiZhanChengShenDefine.BZCS_TICKET_ITEM_ID, BaiZhanChengShenDefine.BZCS_TICKET_COST, LOGTAG) return true end -- 本轮首次完成挑战时向跨服注册, 每轮仅一次 local function tryRegisterToCross(human) local db = getBzcsDb(human) if db.crossRegistered then return end local reg = InnerMsg.lw.LW_BZCS_REGISTER reg.playerInfo = { uuid = human.db._id, serverId = Config.SVR_INDEX, firstJoinTime = os.time(), showInfo = buildShowInfo(human), } InnerMsg.sendMsg(0, reg) BzcsLog.logAction("register_send", string.format("uuid=%s serverId=%s", human.db._id, Config.SVR_INDEX)) end -- 按 raceIdx 开打当前族; 机器人本地战, 真人跨服 local function startRaceCombat(human, cache) local raceIdx = cache.raceIdx local combatType = BaiZhanChengShenDefine.BZCS_RACE_COMBAT_TYPE[raceIdx] if cache.isRobot == 1 then CombatLogic.combatBegin(human, nil, {cache.defUuid, raceIdx}, combatType) else MiddleCommonLogic.MiddleCommonLogic_CombatBegin_LW(human, { combatType = combatType, nServerIndex = cache.defServerId, param = cache.defUuid, }) end end -- 5 局系列结束: 注册跨服(首次) -> LW_BZCS_FIGHT_END; 战报待 WL 回包后写入 local function challengeFinish(human, cache) if not isMiddleReady() then BzcsLog.logAction("fight_end_middle_down", string.format("uuid=%s def=%s", human.db._id, cache.defUuid or "")) if human.fd then Broadcast.sendErr(human, Lang.MIDDLE_SVR_ERR_CONNECT) end human.bzcs_Battle_Cache = nil return end -- 须先于 FIGHT_END: 跨服 UpdateScore 依赖 playerList 中已有攻方 tryRegisterToCross(human) local atkWin = cache.atkW >= BaiZhanChengShenDefine.BZCS_WIN_TARGET local msgData = InnerMsg.lw.LW_BZCS_FIGHT_END msgData.atkUuid = human.db._id msgData.atkServerId = Config.SVR_INDEX msgData.atkName = human.db.name msgData.defUuid = cache.defUuid msgData.defName = cache.defName msgData.defServerId = cache.defServerId msgData.atkWin = atkWin and 1 or 0 msgData.raceResults = cache.rounds InnerMsg.sendMsg(0, msgData) BzcsLog.logAction("fight_end_send", string.format( "atk=%s def=%s atkWin=%s isRobot=%s atkW=%s defW=%s", human.db._id, cache.defUuid or "", msgData.atkWin, cache.isRobot or 0, cache.atkW, cache.defW )) human.bzcs_Battle_Cache = nil end ------------------------------------ 客户端请求 (Handler.lua -> BZCS_*) ------------------------------------ -- 由 Handler.lua 转发; 需跨服的走 sendLwToMiddle, 仅本地数据的直接 GC -- 请求跨服匹配列表; forceRefresh=true 时全量重匹配 local function requestMatchList(human, forceRefresh) if human.fd then ObjHuman.updateDaily(human) end getBzcsDb(human) if not isServerEligible() then return Broadcast.sendErr(human, Lang.COMMOM_NOT_ENABLED) end if not actStartTimeCheck() then return Broadcast.sendErr(human, Lang.COMMOM_NOT_ENABLED) end if forceRefresh then clearMatchCache(human) end if isMatchCacheFresh(human) then local cache = getMatchCache(human) return sendMatchListGC(human, cache.myScore, cache.opponentList, cache.myRank) end if not isMiddleReady() then return Broadcast.sendErr(human, Lang.MIDDLE_SVR_ERR_CONNECT) end local cache = getMatchCache(human) local msgData = InnerMsg.lw.LW_BZCS_MATCH msgData.sourceServerId = Config.SVR_INDEX msgData.playerUuid = human.db._id msgData.refreshRanks = {} if cache and cache.opponentList and next(cache.opponentList) and (cache.myScore or 0) == (cache.matchScore or 0) then msgData.refreshRanks = collectRefreshRanks(cache.opponentList) end if not sendLwToMiddle(human, msgData) then return end end -- 匹配主界面: 下发 myScore + 3 名对手(score/name/power) -- 内存缓存未过期直返; 过期则跨服按 rank 刷新展示; 无缓存则全量匹配 function BZCS_MatchList(human) requestMatchList(human, false) end -- 客户端刷新匹配对手(清缓存后跨服按积分±500步进重匹配3人, 回包 GC_BZCS_MATCH_LIST) function BZCS_MatchRefresh(human) if not actStartTimeCheck() then return Broadcast.sendErr(human, Lang.COMMOM_NOT_ENABLED) end if human.bzcs_Battle_Cache then return Broadcast.sendErr(human, Lang.DATA_ERR) end requestMatchList(human, true) end -- 排行榜前 100 function BZCS_RankList(human) local msgData = InnerMsg.lw.LW_BZCS_RANK_LIST msgData.sourceServerId = Config.SVR_INDEX msgData.playerUuid = human.db._id sendLwToMiddle(human, msgData) end -- 对手头像/战力/积分(按全服名次 rank, 跨服实时解析该名次上的玩家) function BZCS_OpponentInfo(human, rank) local opp = resolveMatchOpponentByRank(human, rank) if not opp then return Broadcast.sendErr(human, Lang.BZCS_MATCH_OPPONENT_INVALID) end local msgData = InnerMsg.lw.LW_BZCS_OPPONENT_INFO msgData.sourceServerId = Config.SVR_INDEX msgData.playerUuid = human.db._id msgData.targetRank = rank sendLwToMiddle(human, msgData) end -- 对手五族阵容(按全服名次 rank) function BZCS_OpponentLineup(human, rank) local opp = resolveMatchOpponentByRank(human, rank) if not opp then return Broadcast.sendErr(human, Lang.BZCS_MATCH_OPPONENT_INVALID) end local msgData = InnerMsg.lw.LW_BZCS_OPPONENT_LINEUP msgData.sourceServerId = Config.SVR_INDEX msgData.playerUuid = human.db._id msgData.targetRank = rank sendLwToMiddle(human, msgData) end -- 己方五族阵容(仅读本地, 不访问跨服) function BZCS_MyLineup(human) local msgRet = Msg.gc.GC_BZCS_MY_LINEUP msgRet.teamList[0] = BaiZhanChengShenDefine.BZCS_RACE_CNT for i, race in ipairs(BaiZhanChengShenDefine.BZCS_RACE_ORDER) do local combatType = BaiZhanChengShenDefine.BZCS_RACE_COMBAT_TYPE[race] local show = getRaceLineupShow(human, race) msgRet.teamList[i].race = race fillBzcsTeamNet(msgRet.teamList[i], show, human, combatType) end Msg.send(msgRet, human.fd) end -- 本地战报列表(存储最老->最新, 协议仍新记录在前) function BZCS_WarReport(human) local db = getBzcsDb(human) local list = db.warReport or {} local total = #list local cnt = math.min(total, BaiZhanChengShenDefine.BZCS_WARREPORT_MAX, #Msg.gc.GC_BZCS_WAR_REPORT.reportList) local msgRet = Msg.gc.GC_BZCS_WAR_REPORT msgRet.reportList[0] = cnt for j = 1, cnt do local r = list[total - j + 1] local net = msgRet.reportList[j] net.warType = r.warType or 0 local isRobot = r.isRobot or 0 if isRobot ~= 1 and (r.oppServerId or 0) == 0 then local warType = r.warType or 0 if warType == BaiZhanChengShenDefine.BZCS_WAR_TYPE_ATK_WIN or warType == BaiZhanChengShenDefine.BZCS_WAR_TYPE_ATK_LOSE then isRobot = 1 end end net.oppServerId = BaiZhanChengShenDefine.ToClientServerId(r.oppServerId, isRobot) net.oppName = r.oppName or "" net.scoreChange = r.scoreChange or 0 end Msg.send(msgRet, human.fd) end -- 排名奖励配置预览(读 excel) function BZCS_RankReward(human) local msgRet = Msg.gc.GC_BZCS_RANK_REWARD msgRet.rewardList[0] = #BzcsConfig.rankReward for k, v in ipairs(BzcsConfig.rankReward) do msgRet.rewardList[k].rankLeft = v.rankArea[1] msgRet.rewardList[k].rankRight = v.rankArea[2] local items = msgRet.rewardList[k].itemList items[0] = #v.awardList for idx, itemCfg in ipairs(v.awardList) do Grid.makeItem(items[idx], itemCfg[1], itemCfg[2]) end end Msg.send(msgRet, human.fd) end ------------------------------------ 跨服通知本地服 (InnerHandler.lua -> C2N_*) ------------------------------------ -- 跨服 WL 回调, 组装 GC 或写本地数据 -- WL_BZCS_ACT_START: 记录本轮开始时间(重连补偿广播也会走到这里) function C2N_Act_Start(msg) local oldStart = CommonDB.getValueByKey(CommonDB.KEY_BZCS_START_TIME) or 0 local resetCnt = 0 if msg.startTime and msg.startTime > 0 then CommonDB.updateValue(CommonDB.KEY_BZCS_START_TIME, msg.startTime) for uuid, human in pairs(ObjHuman.onlineUuid) do if human.db and human.db.baiZhanChengShen then local actStart = msg.startTime if (human.db.baiZhanChengShen.actStartTime or 0) ~= actStart then human.db.baiZhanChengShen.actStartTime = actStart clearRoundLocalData(human.db.baiZhanChengShen) clearMatchCache(human) resetCnt = resetCnt + 1 end end end end BzcsLog.logAction("act_open", string.format( "svr=%s start=%s end=%s oldStart=%s online=%s resetCnt=%s", Config.SVR_INDEX, msg.startTime or 0, msg.endTime or 0, oldStart, Util.getTableCount(ObjHuman.onlineUuid), resetCnt )) end -- WL_BZCS_ACT_END: 清除活动开始时间, 并清空在线玩家本轮本地战报/匹配缓存 function C2N_Act_End(msg) local oldStart = CommonDB.getValueByKey(CommonDB.KEY_BZCS_START_TIME) or 0 CommonDB.updateValue(CommonDB.KEY_BZCS_START_TIME, nil) local resetCnt = 0 for uuid, human in pairs(ObjHuman.onlineUuid) do if human.db and human.db.baiZhanChengShen then clearRoundLocalData(human.db.baiZhanChengShen) human.db.baiZhanChengShen.actStartTime = 0 clearMatchCache(human) resetCnt = resetCnt + 1 end end BzcsLog.logAction("act_close", string.format( "svr=%s oldStart=%s online=%s resetCnt=%s", Config.SVR_INDEX, oldStart, Util.getTableCount(ObjHuman.onlineUuid), resetCnt )) end -- WL_BZCS_TIPS: 跨服业务错误(活动未开/对手无效等) function C2N_ErrTips(msg) local human = ObjHuman.onlineUuid[msg.playerUuid] if not human then return end local errCode = msg.errCode if errCode == BaiZhanChengShenDefine.BZCS_ERR_NOT_OPEN then return Broadcast.sendErr(human, Lang.COMMOM_NOT_ENABLED) elseif errCode == BaiZhanChengShenDefine.BZCS_ERR_TARGET_INVALID then return Broadcast.sendErr(human, Lang.BZCS_MATCH_OPPONENT_INVALID) elseif errCode == BaiZhanChengShenDefine.BZCS_ERR_NO_TIMES then return Broadcast.sendErr(human, Lang.ITEM_NOT_ENOUGH) end Broadcast.sendErr(human, Lang.DATA_ERR) end -- WL_BZCS_MATCH -> GC_BZCS_MATCH_LIST, 写入内存匹配缓存 function C2N_Match(msg) local human = ObjHuman.onlineUuid[msg.playerUuid] if not human then return end local myScore = msg.myScore or BaiZhanChengShenDefine.BZCS_INIT_SCORE local myRank = msg.myRank or 0 local opponentList = msg.opponentList or {} local cache = getMatchCache(human) local isDisplayRefresh = cache and cache.matchScore and cache.matchScore == myScore and cache.opponentList and next(cache.opponentList) if isDisplayRefresh then refreshMatchCacheDisplay(human, myScore, opponentList, myRank) else setMatchCache(human, myScore, opponentList, myRank) end sendMatchListGC(human, myScore, opponentList, myRank) end local function fillBzcsRankNet(net, info) info = info or {} net.rank = info.rank or 0 net.name = info.name or "" net.head = info.head or 0 net.headFrame = info.headFrame or 0 net.power = info.power or 0 net.score = info.score or BaiZhanChengShenDefine.BZCS_INIT_SCORE net.serverId = BaiZhanChengShenDefine.ToClientServerId(info.serverId, info.isRobot or 0) net.uuid = info.uuid or "" end -- 未上榜/未注册跨服时, 用本地五族阵容实时战力(同 CombatPosLogic.getCombatHeroZDL) local function calcLocalBzcsPower(human) local total = 0 for _, race in ipairs(BaiZhanChengShenDefine.BZCS_RACE_ORDER) do local combatType = BaiZhanChengShenDefine.BZCS_RACE_COMBAT_TYPE[race] total = total + CombatPosLogic.getCombatHeroZDL(human, combatType) end return total end local function enrichMyRankInfoForClient(human, myInfo) myInfo = myInfo or {} if (myInfo.rank or 0) > 0 then return myInfo end return { rank = 0, uuid = human.db._id, name = human.db.name or "", head = RoleHeadLogic.getRoleAppearance(human, RoleHeadLogic.HEAD_TYPE_1), headFrame = RoleHeadLogic.getRoleAppearance(human, RoleHeadLogic.HEAD_TYPE_2), serverId = Config.SVR_INDEX, power = calcLocalBzcsPower(human), score = myInfo.score or BaiZhanChengShenDefine.BZCS_INIT_SCORE, } end -- WL_BZCS_RANK_LIST -> GC_BZCS_RANK_LIST function C2N_RankList(msg) local human = ObjHuman.onlineUuid[msg.playerUuid] if not human then return end local msgRet = Msg.gc.GC_BZCS_RANK_LIST local myInfo = enrichMyRankInfoForClient(human, msg.myRankInfo) fillBzcsRankNet(msgRet.myRankInfo, myInfo) msgRet.rankList[0] = #(msg.rankList or {}) for i, info in ipairs(msg.rankList or {}) do fillBzcsRankNet(msgRet.rankList[i], info) end Msg.send(msgRet, human.fd) end -- WL_BZCS_OPPONENT_INFO -> GC_BZCS_OPPONENT_INFO function C2N_OpponentInfo(msg) local human = ObjHuman.onlineUuid[msg.playerUuid] if not human then return end if msg.res ~= 0 then return Broadcast.sendErr(human, Lang.DATA_ERR) end local t = msg.targetInfo or {} local msgRet = Msg.gc.GC_BZCS_OPPONENT_INFO msgRet.name = t.name or "" msgRet.head = t.head or 0 msgRet.headFrame = t.headFrame or 0 msgRet.power = t.power or 0 msgRet.score = t.score or BaiZhanChengShenDefine.BZCS_INIT_SCORE Msg.send(msgRet, human.fd) end -- WL_BZCS_OPPONENT_LINEUP -> GC_BZCS_OPPONENT_LINEUP function C2N_OpponentLineup(msg) local human = ObjHuman.onlineUuid[msg.playerUuid] if not human then return end local msgRet = Msg.gc.GC_BZCS_OPPONENT_LINEUP msgRet.teamList[0] = BaiZhanChengShenDefine.BZCS_RACE_CNT local heroArr = msg.showInfo and msg.showInfo.heroArr or {} for i, race in ipairs(BaiZhanChengShenDefine.BZCS_RACE_ORDER) do local show = heroArr[race] or {} msgRet.teamList[i].race = race fillBzcsTeamNet(msgRet.teamList[i], show, nil, nil) end Msg.send(msgRet, human.fd) end -- WL_BZCS_ISSUE_REWARD: 本服批量发周期结算邮件(rewardList={{uuid,rank},...}) function C2N_IssueReward(msg) local rewardList = msg.rewardList if not rewardList or #rewardList == 0 then return end BzcsLog.logAction("reward_issue_ns", string.format("cnt=%s svr=%s", #rewardList, Config.SVR_INDEX)) local q = createRewardQueue() for _, info in ipairs(rewardList) do q:add({info[1], info[2]}) end q:insertDB() end ------------------------------------ 战斗相关 (CombatLogic / InnerHandler) ------------------------------------ -- CG_COMBAT_BEGIN / CombatLogic.moduleFn / CombatPosLogic / InnerHandler C2N 战斗回调 -- combatType -> 五族场次下标(1~5) local function getBzcsRaceIdxByCombatType(combatType) for raceIdx, t in ipairs(BaiZhanChengShenDefine.BZCS_RACE_COMBAT_TYPE) do if t == combatType then return raceIdx end end end -- CG_COMBAT_BEGIN: 挑战一次依次调用 TYPE39~43; param=全服名次rank(须在内存匹配缓存中) function fight(human, args, combatType) local raceIdx = getBzcsRaceIdxByCombatType(combatType) if not raceIdx then return Broadcast.sendErr(human, Lang.DATA_ERR) end if raceIdx == 1 then -- 首场: 校验次数/道具、五族阵容, 请求跨服 CAN_FIGHT(扣次在 C2N_CanFight) ObjHuman.updateDaily(human) local rank = tonumber(args[1]) if not rank or rank < 1 then return Broadcast.sendErr(human, Lang.BZCS_MATCH_OPPONENT_INVALID) end if human.bzcs_Battle_Cache then return Broadcast.sendErr(human, Lang.BZCS_FIGHT_STATE_ERR) end if not actStartTimeCheck() then return Broadcast.sendErr(human, Lang.COMMOM_NOT_ENABLED) end if not isMiddleReady() then return Broadcast.sendErr(human, Lang.MIDDLE_SVR_ERR_CONNECT) end if not canChallenge(human) then return Broadcast.sendErr(human, Lang.ITEM_NOT_ENOUGH) end if not checkAllRaceLineupForFight(human) then return end if not resolveMatchOpponentByRank(human, rank) then return Broadcast.sendErr(human, Lang.BZCS_MATCH_OPPONENT_INVALID) end local msgData = InnerMsg.lw.LW_BZCS_CAN_FIGHT msgData.sourceServerId = Config.SVR_INDEX msgData.playerUuid = human.db._id msgData.targetRank = rank sendLwToMiddle(human, msgData) return end -- 第 2~5 场: 已有 bzcs_Battle_Cache 则直接开打, 不再请求跨服/扣次 local cache = human.bzcs_Battle_Cache if not cache then return Broadcast.sendErr(human, Lang.BZCS_FIGHT_STATE_ERR) end if cache.atkW >= BaiZhanChengShenDefine.BZCS_WIN_TARGET or cache.defW >= BaiZhanChengShenDefine.BZCS_WIN_TARGET then return Broadcast.sendErr(human, Lang.BZCS_FIGHT_STATE_ERR) end cache.raceIdx = raceIdx startRaceCombat(human, cache) end function getCombatMonsterOutID(human, side, args) if side ~= CombatDefine.DEFEND_SIDE then return end local defUuid = args[1] local raceIdx = args[2] if not defUuid or not raceIdx then return end local cfg = BaiZhanChengShenDefine.GetRobotListCfg(defUuid) if not cfg or not cfg.monsterOutIDs then return end local monsterOutID = cfg.monsterOutIDs[raceIdx] if not monsterOutID then return end return monsterOutID, BaiZhanChengShenDefine.CalcMonsterOutPower(monsterOutID) end function getCombatObjList(human, side, args, combatType) if side == CombatDefine.ATTACK_SIDE then if not human then return end return CombatLogic.getHumanObjList(human, combatType) end -- 防守方: args[2]=raceIdx 为本地机器人, 返回 nil 走 getCombatMonsterOutID if args[2] then return nil end local defUuid = args[1] if not defUuid then return end local db = RoleDBLogic.getDb(defUuid) if not db then return end return CombatLogic.getHumanObjList({db = db}, combatType) end function onFightEnd(human, result, combatType, cbParam, combatInfo) local cache = human.bzcs_Battle_Cache if not cache then return end local roundResult = (result == CombatDefine.RESULT_WIN) and 1 or 2 cache.rounds[cache.raceIdx] = roundResult if result == CombatDefine.RESULT_WIN then cache.atkW = cache.atkW + 1 else cache.defW = cache.defW + 1 end combatInfo.defender.name = cache.defName local seriesOver = cache.atkW >= BaiZhanChengShenDefine.BZCS_WIN_TARGET or cache.defW >= BaiZhanChengShenDefine.BZCS_WIN_TARGET or cache.raceIdx >= BaiZhanChengShenDefine.BZCS_RACE_CNT if not seriesOver then cache.raceIdx = cache.raceIdx + 1 combatInfo.nextCombatType = BaiZhanChengShenDefine.BZCS_RACE_COMBAT_TYPE[cache.raceIdx] return end -- 整场结束: 发挑战奖励并写入 combatInfo.rewardItem(GC_COMBAT_FINISH 展示) local atkWin = cache.atkW >= BaiZhanChengShenDefine.BZCS_WIN_TARGET grantFightReward(human, atkWin, combatInfo) challengeFinish(human, cache) end function checkUpdatePos(human, msg) local condiCamp = COMBATTYPE_2_CAMP[msg.type] if not condiCamp then return false end HeroLogic = HeroLogic or require("hero.HeroLogic") local heroList = Util.split(msg.heroList, ",") for i = 1, CombatDefine.COMBAT_HERO_CNT do local uuid = heroList[i] or "" if uuid ~= "0" and uuid ~= "" then local heroGrid = HeroLogic.getHeroGridByUuid(human, uuid) if not heroGrid then return false end local heroCfg = HeroExcel.hero[heroGrid.id] if not heroCfg or heroCfg.camp ~= condiCamp then return false end end end return true end function onCombatPosUpdate(human, combatType) local race = COMBATTYPE_2_CAMP[combatType] if not race then return end UpdateShowInfo(human, BaiZhanChengShenDefine.BZCS_UPDATE_SHOW_LINEUP, race) end -- 百战成神阵容精灵位变更(CombatPosLogic.Elf_Pos_Update 调用) function onElfPosUpdate(human, combatType) onCombatPosUpdate(human, combatType) end -- 该族阵容精灵位是否包含指定 elfId local function raceLineupHasElf(elfList, elfId) if not elfList or not elfId or elfId < 1 then return false end for i = 1, CombatDefine.COMBAT_ELF_NOW_CNT do if elfList[i] == elfId then return true end end return false end -- 精灵升星后同步所有上阵了该精灵的百战成神队伍(同精灵可出现在多族阵容) function onElfStarUp(human, elfId) if not elfId or elfId < 1 then return end if not actStartTimeCheck() or not isMiddleReady() then return end local db = getBzcsDb(human) if not db.crossRegistered then return end for _, race in ipairs(BaiZhanChengShenDefine.BZCS_RACE_ORDER) do local combatType = BaiZhanChengShenDefine.BZCS_RACE_COMBAT_TYPE[race] local combatHeroDB = CombatPosLogic.getCombatHeroDB(human, combatType) if raceLineupHasElf(combatHeroDB and combatHeroDB.elfList, elfId) then UpdateShowInfo(human, BaiZhanChengShenDefine.BZCS_UPDATE_SHOW_LINEUP, race) end end end -- 该族阵容是否包含指定英雄 uuid local function raceLineupHasHero(heroList, heroUuid) if not heroUuid or heroUuid == "" or heroUuid == "0" then return false end if not heroList then return false end for _, uuid in pairs(heroList) do if uuid == heroUuid then return true end end return false end -- 收集百战成神五族中上阵了该英雄的种族列表(删除英雄前调用) function collectBzcsRacesWithHero(human, heroUuid) local races = {} if not heroUuid or heroUuid == "" or heroUuid == "0" then return races end for _, race in ipairs(BaiZhanChengShenDefine.BZCS_RACE_ORDER) do local combatType = BaiZhanChengShenDefine.BZCS_RACE_COMBAT_TYPE[race] local heroList = CombatPosLogic.getCombatHeros(human, combatType) if raceLineupHasHero(heroList, heroUuid) then races[#races + 1] = race end end return races end -- 英雄数据变更后同步跨服阵容; raceList 可选(重生等删除英雄后传入删除前收集的种族) function onHeroDataUpdate(human, heroUuid, raceList) if not actStartTimeCheck() or not isMiddleReady() then return end local db = getBzcsDb(human) if not db.crossRegistered then return end local races = raceList if not races or #races < 1 then if not heroUuid or heroUuid == "" or heroUuid == "0" then return end races = collectBzcsRacesWithHero(human, heroUuid) end if #races < 1 then return end for _, race in ipairs(races) do UpdateShowInfo(human, BaiZhanChengShenDefine.BZCS_UPDATE_SHOW_LINEUP, race) end end -- WL_BZCS_CAN_FIGHT: 扣次并初始化 bzcs_Battle_Cache, 开打第一族 function C2N_CanFight(msg) local human = ObjHuman.onlineUuid[msg.playerUuid] if not human then return end if msg.res ~= 0 then return Broadcast.sendErr(human, Lang.DATA_ERR) end if not deductChallengeTimes(human) then return Broadcast.sendErr(human, Lang.ITEM_NOT_ENOUGH) end human.bzcs_Battle_Cache = { defRank = msg.targetRank, defUuid = msg.defUuid, defServerId = msg.defServerId, defName = msg.defName, defScore = msg.defScore, isRobot = msg.isRobot, raceIdx = 1, atkW = 0, defW = 0, rounds = {}, } BzcsLog.logAction("can_fight", string.format( "atk=%s defRank=%s def=%s defScore=%s isRobot=%s defSvr=%s", msg.playerUuid or "", msg.targetRank or 0, msg.defUuid or "", msg.defScore or 0, msg.isRobot or 0, msg.defServerId or 0 )) startRaceCombat(human, human.bzcs_Battle_Cache) end -- WL_BZCS_FIGHT_END: 攻方积分变化, 写战报, 重置匹配缓存与 TTL function C2N_FightEnd(msg) local human = ObjHuman.onlineUuid[msg.playerUuid] local offlineSave = false if not human then local db = RoleDBLogic.getDb(msg.playerUuid, {baiZhanChengShen = 1}) if not db then return end human = {db = db} offlineSave = true end local db = getBzcsDb(human) db.crossRegistered = true local atkWin = msg.atkWin == 1 addWarReport(human, { warType = atkWin and BaiZhanChengShenDefine.BZCS_WAR_TYPE_ATK_WIN or BaiZhanChengShenDefine.BZCS_WAR_TYPE_ATK_LOSE, oppServerId = msg.defServerId or 0, oppName = msg.defName or "", scoreChange = msg.scoreChange or 0, isRobot = msg.defIsRobot or 0, }) if human.fd then resetMatchCacheOnScoreChange(human, msg.myScore) elseif offlineSave then RoleDBLogic.saveRoleSset(human.db) end BzcsLog.logAction("fight_end_ns", string.format("uuid=%s atkWin=%s scoreChange=%s myScore=%s", msg.playerUuid or "", msg.atkWin or 0, msg.scoreChange or 0, msg.myScore or 0)) end -- WL_BZCS_DEF_NOTIFY: 防守方战报(在线/离线) function C2N_DefNotify(msg) local human = ObjHuman.onlineUuid[msg.playerUuid] local offlineSave = false if not human then local db = RoleDBLogic.getDb(msg.playerUuid, {baiZhanChengShen = 1}) if not db then return end human = {db = db} offlineSave = true end local defWin = msg.atkWin == 1 addWarReport(human, { warType = defWin and BaiZhanChengShenDefine.BZCS_WAR_TYPE_DEF_WIN or BaiZhanChengShenDefine.BZCS_WAR_TYPE_DEF_LOSE, oppServerId = msg.atkServerId or 0, oppName = msg.atkName or "", scoreChange = msg.scoreChange or 0, }) if human.fd then resetMatchCacheOnScoreChange(human, msg.myScore) elseif offlineSave then RoleDBLogic.saveRoleSset(human.db) end end ------------------------------------ 对外接口 ------------------------------------ -- 供红点/活动状态/阵容展示同步等其它模块调用 -- 跨天重置免费挑战次数(由 ObjHuman.updateDaily 调用) function updateDaily(human) if not human.db.baiZhanChengShen then return end human.db.baiZhanChengShen.freeTimes = BaiZhanChengShenDefine.BZCS_FREE_TIMES end local ACT_STATE_NOOPEN = 0 -- 活动未开启 local ACT_STATE_START = 2 -- 活动进行中(与 JjcActLogic.STATE_START 一致) -- 本轮活动剩余秒数(至周日23:00) local function calcActLeftSec() local startTime = CommonDB.getValueByKey(CommonDB.KEY_BZCS_START_TIME) if not startTime or startTime == 0 or not IsRunning(startTime) then return 0 end local endDayOffset = BaiZhanChengShenDefine.GetOpenEndDayOffset() local endTime = Util.getDayStartTime(startTime) + endDayOffset * 86400 + BaiZhanChengShenDefine.BZCS_END_SEC local now = os.time() if endTime > now then return endTime - now end return 0 end -- 百战成神活动是否处于开启状态(挑战日 + 跨服已开轮且在活动期内) -- function ModuleisOpen(human) -- return actStartTimeCheck() -- end -- 玩法状态与剩余时间: state 0=未开启 2=进行中; leftSec=剩余秒数 function getActState(human) if not actStartTimeCheck() then return ACT_STATE_NOOPEN, 0 end return ACT_STATE_START, calcActLeftSec() end -- 活动红点: 可参与且仍有免费挑战次数 function isActRed(human) if not isServerEligible() then return false end if not actStartTimeCheck() then return false end local db = getBzcsDb(human) return db.freeTimes > 0 end -- joinTime 为跨服下发的本轮开始时间; 无参时仅判断星期 function IsRunning(joinTime) if not joinTime then return true end local wDay = getWDay() if wDay > BaiZhanChengShenDefine.BZCS_OPEN_WDAY_AREA[2] and wDay < BaiZhanChengShenDefine.BZCS_OPEN_WDAY_AREA[1] then return false end local now = os.time() if now < joinTime then return false end local endDayOffset = BaiZhanChengShenDefine.GetOpenEndDayOffset() local endTime = Util.getDayStartTime(joinTime) + endDayOffset * 86400 + BaiZhanChengShenDefine.BZCS_END_SEC if now > endTime then return false end local dayStart = Util.getDayStartTime(now) if wDay == BaiZhanChengShenDefine.BZCS_OPEN_WDAY_AREA[2] and now > (dayStart + BaiZhanChengShenDefine.BZCS_END_SEC) then return false end local diffDays = Util.diffDay(joinTime) if diffDays > BaiZhanChengShenDefine.BZCS_OPEN_DAYS then return false end return true end -- 增量同步跨服展示(LW_BZCS_UPDATE_SHOW, 须已注册) -- updateType: BZCS_UPDATE_SHOW_NAME/HEAD/HEAD_FRAME/BODY/LINEUP; LINEUP 时 race 必填(1~5) function UpdateShowInfo(human, updateType, race) if not actStartTimeCheck() or not isMiddleReady() then return end if not updateType then return end local db = getBzcsDb(human) if not db.crossRegistered then return end local patch = buildShowPatch(human, updateType, race) if not patch then return end local msgData = InnerMsg.lw.LW_BZCS_UPDATE_SHOW msgData.playerUuid = human.db._id msgData.updateType = updateType msgData.race = race or 0 msgData.showInfo = patch InnerMsg.sendMsg(0, msgData) BzcsLog.logAction("update_show_send", string.format("uuid=%s type=%s race=%s", human.db._id, updateType, race or 0)) end