import { Application, BackendSession, HandlerService, } from 'pinus'; import { BattleRecordModel } from '../../../db/BattleRecord'; import { BattleSweepRecordModel } from '../../../db/BattleSweepRecord'; import { genCode, getReasonByWarType, getWarTypeName } from '../../../pubUtils/util'; import { WAR_TYPE, EVENT_STATUS, REDIS_KEY, KING_EXP_RATIO_TYPE, TA_EVENT, ITEM_CHANGE_REASON } from '../../../consts'; import { checkDaily, checkDailyAndIncrease } from '../../../services/dailyBattleService'; import { checkTowerWar, towerBattleEnd } from '../../../services/battleService'; import { WarReward } from '../../../services/warRewardService'; import { getAp, setAp } from '../../../services/actionPointService'; import { setBattleStatus, checkEventBattle } from '../../../services/eventSercive'; import { STATUS } from '../../../consts/statusCode'; import { resResult } from '../../../pubUtils/util'; import { RoleModel } from '../../../db/Role'; import { RScriptRecordModel } from '../../../db/RScriptRecord'; import { checkBattleHeroes, roleLevelup, calculateWarStar, getBattleListOfTypes, getMainChapter, getStarOfChapter, checkWarCountAndInc } from '../../../services/normalBattleService'; import { checkDungeonNum, checkDungeonAndIncrease, saveDungeonFirst } from '../../../services/dungeonService'; // import { switchOnFunc } from '../../../services/funcSwitchService'; import { gameData } from '../../../pubUtils/data'; import { pushMysteryFirstMsg, pushVestigeFirstMsg } from '../../../services/chatService'; import { getSeconds, nowSeconds } from '../../../pubUtils/timeUtil'; import { Rank } from '../../../services/rankService'; import { checkTaskInBattleEnd, checkTaskInBattleStart, checkTaskInBattleSweep } from '../../../services/task/taskService'; import { ActivitySelfServiceModel } from '../../../db/ActivitySelfService'; import { getSelfServiceShopActivityData } from '../../../services/activity/selfServiceShopActivityService'; import { challengeDailyGK } from '../../../services/activity/dailyGKService'; import { challengeNewHeroGK } from '../../../services/activity/newHeroService'; import { reportTAEvent } from '../../../services/sdkService'; import { getVipRegretCnt } from '../../../services/activity/monthlyTicketService'; import { isArray, isNumber } from 'underscore'; import { RewardInter } from '../../../pubUtils/interface'; import { addItems } from '../../../services/role/rewardService'; import { treasureHuntChallengeConsume } from '../../../services/activity/treasureHuntService'; import { combineItems } from '../../../services/role/util'; export default function (app: Application) { new HandlerService(app, {}); return new NormalBattleHandler(app); } export class NormalBattleHandler { constructor(private app: Application) { } // 获取关卡列表 async checkBattle(msg: { battleId: number, heroes: Array }, session: BackendSession) { const { battleId, heroes: seqIds = [] } = msg; let roleId = session.get('roleId'); let roleName = session.get('roleName'); let serverId = session.get('serverId'); let sid = session.get('sid'); let ip = session.get('ip'); let warInfo = gameData.war.get(battleId); if (!warInfo) { return resResult(STATUS.BATTLE_MISS_INFO); } let role = await RoleModel.findByRoleId(roleId, 'lv warStar warCount roleId refWarCount'); let apJson = await getAp(roleId, ip, role.lv); let { ap } = apJson; if (ap < warInfo.cost) { return resResult(STATUS.BATTLE_ACTION_POINT_LACK); } if(role.lv < warInfo.lvLimited) { return resResult(STATUS.COM_BATTLE_LV_NOT_ENOUGH); } // 前置关卡是否挑战过 let { warStar } = role; let previousGk = warInfo.previousGk; if (previousGk) { let preBattle = warStar.findIndex(cur => cur.id == previousGk); if (preBattle == -1) return resResult(STATUS.BATTLE_NEED_PREVIOUS_GK); } let { isOK, hids, heroes, lineup } = await checkBattleHeroes(roleId, seqIds); if (!isOK) return resResult(STATUS.BATTLE_HERO_NOT_FOUND); const battleCode = genCode(8); // 关卡唯一值 let dailyNum = {}; let towerData = {}; let dungeonNum = {}; if (warInfo.warType == WAR_TYPE.NORMAL || warInfo.warType == WAR_TYPE.MAIN_ELITE) { let checkResult = await checkWarCountAndInc(battleId, 0, role, true); if (checkResult.code != 0) { return checkResult } } else if (warInfo.warType == WAR_TYPE.DAILY) { let checkResult = await checkDaily(roleId, battleId, 1); if (checkResult.status == -1) { return checkResult.resResult } dailyNum = Object.assign(dailyNum, checkResult.data); } else if (warInfo.warType == WAR_TYPE.TOWER) { let checkResult = await checkTowerWar(roleId, battleId, seqIds, heroes); if (checkResult.status == -1) { return checkResult.resResult } towerData = Object.assign(towerData, checkResult.data); } else if (warInfo.warType == WAR_TYPE.EVENT) { // 记录事件状态 let eventStatus = session.get('eventStatus') || EVENT_STATUS.WAITING; let checkResult = await checkEventBattle(roleId, eventStatus, battleId, battleCode); if (checkResult.status == -1) { return checkResult.resResult } } else if (warInfo.warType == WAR_TYPE.MYSTERY || warInfo.warType == WAR_TYPE.MYSTERY_ELITE) { let checkResult = await checkDungeonNum(roleId, 1, battleId); if (checkResult.status == -1) { return checkResult.resResult } dungeonNum = Object.assign(dungeonNum, checkResult.data); } const BattleRecord = await BattleRecordModel.updateBattleRecordByCode(battleCode, { $set: { roleId, roleName, battleId, status: 0, warName: warInfo.gk_name, warType: warInfo.warType, record: { heroes: hids, seqIds, lineup } } }, true); let { status } = BattleRecord; await checkTaskInBattleStart(serverId, roleId, sid, battleId); return resResult(STATUS.SUCCESS, { battleId, battleCode, status, dailyNum, towerData, dungeonNum }); } // 关卡列表 async getBattleList(msg: { types: number[] }, session: BackendSession) { const { types } = msg; let roleId = session.get('roleId'); let role = await RoleModel.findByRoleId(roleId); let result = await getBattleListOfTypes(role, types); return resResult(STATUS.SUCCESS, { result }); } // 关卡结算,记录使用的武将,获得奖励 async battleEnd(msg: { battleCode: string, battleId: number, isSuccess: boolean, stars: number[], heroes: number[], activityId: number, pageIndex: number }, session: BackendSession) { const { battleCode, battleId, isSuccess, heroes = [], stars = [], activityId, pageIndex } = msg; let roleId = session.get('roleId'); let roleName = session.get('roleName'); let sid = session.get('sid'); let ip = session.get('ip'); let serverId = session.get('serverId'); let skipReward = false;//是否跳过奖励结算 let warInfo = gameData.war.get(battleId); if (!warInfo) { return resResult(STATUS.BATTLE_MISS_INFO); } // 寻宝不使用通用战斗模块结算 if (warInfo.warType == WAR_TYPE.COM_BATTLE) { return resResult(STATUS.BATTLE_END_WRONG_TYPE); } const BattleRecord = await BattleRecordModel.getBattleRecordByCode(battleCode, true); if (!BattleRecord || BattleRecord.status != 0) { return resResult(STATUS.BATTLE_STATUS_WRONG); } let flag = 1; // 对比hero信息 let { record: { heroes: dbHeroes, seqIds: dbSeqIds }, createdAt } = BattleRecord; for (let seqId of dbSeqIds) { if (dbSeqIds.indexOf(seqId) == -1) flag = 0; } if (!flag) { return resResult(STATUS.BATTLE_INFO_VALIDATE_ERR); } let role = await RoleModel.findByRoleId(roleId, 'lv vipStartTime warStar warCount refWarCount roleId'); let apJson = await setAp(serverId, roleId, ip, role.lv, isSuccess? -1 * warInfo.cost: 0, sid, getReasonByWarType(warInfo.warType)); // 扣除体力 if (!apJson) { return resResult(STATUS.BATTLE_ACTION_POINT_LACK); } let { warStar } = role; let warReward = new WarReward(roleId, roleName, sid, battleId, isSuccess); let dailyNum = {}; let towerStatus = null; let dungeonNum = {}; if(warInfo.warType == WAR_TYPE.NORMAL || warInfo.warType == WAR_TYPE.MAIN_ELITE) { let isFirst = warStar.findIndex(cur => cur.id == battleId) == -1; if(!isFirst) { let checkResult = await checkWarCountAndInc(battleId, isSuccess?1:0, role, false); if (checkResult.code != 0) { return checkResult } } } if (warInfo.warType == WAR_TYPE.DAILY) { let checkResult = await checkDailyAndIncrease(roleId, warStar, battleId, isSuccess?1:0, false, stars, role); if (checkResult.status == -1) { return checkResult.resResult; } dailyNum = Object.assign(dailyNum, checkResult.data) } else if (warInfo.warType == WAR_TYPE.EVENT) { // 记录事件状态 await setBattleStatus(session, roleId, battleId, isSuccess, battleCode); } else if (warInfo.warType == WAR_TYPE.TOWER) { let towerEndResult = await towerBattleEnd(sid, roleId, serverId, battleCode, battleId, isSuccess, heroes); if (towerEndResult) { if (towerEndResult.status == -1) { return towerEndResult.resResult; } towerStatus = towerEndResult.data.towerStatus; if (towerEndResult.data.towerReward) warReward.setFixReward(towerEndResult.data.towerReward) } } else if (warInfo.warType == WAR_TYPE.MYSTERY || warInfo.warType == WAR_TYPE.MYSTERY_ELITE) { let checkResult = await checkDungeonAndIncrease(roleId, isSuccess?1:0, false, battleId); let role = await RoleModel.saveDungeonHero(roleId, battleId, heroes, isSuccess); if (role) { await saveDungeonFirst(role, battleId, BattleRecord); } if (checkResult.status == -1) { return checkResult.resResult; } dungeonNum = Object.assign(dungeonNum, checkResult.data) } else if (warInfo.warType == WAR_TYPE.NORMAL) { if(isSuccess) { let role = await RoleModel.updateMainWarId(roleId, battleId, nowSeconds()); if (role) { let r = new Rank(REDIS_KEY.MAIN_RANK, { serverId }); await r.setRankWithRoleInfo(roleId, role.mainWarId, role.mainUpdatedAt, role); } } } else if (warInfo.warType == WAR_TYPE.MAIN_ELITE) { if(isSuccess) { let role = await RoleModel.updateMainEliteWarId(roleId, battleId, nowSeconds()); if (role) { let r = new Rank(REDIS_KEY.MAIN_ELITE_RANK, { serverId }); await r.setRankWithRoleInfo(roleId, role.mainEliteWarId, role.mainEliteUpdatedAt, role); } } } else if (warInfo.warType == WAR_TYPE.ACT_SELF_SHOP) { //糜家商队挑战成功后记录挑战次数 if (isSuccess) { let playerData = await getSelfServiceShopActivityData(serverId, roleId) await ActivitySelfServiceModel.addChallengeRecord(serverId, playerData.activityId, roleId, playerData.roundIndex, 1, new Date()) } } else if (warInfo.warType == WAR_TYPE.ACT_DAILY_GK) { if (isSuccess) { await challengeDailyGK(serverId, roleId, activityId, battleId) } } else if (warInfo.warType == WAR_TYPE.ACT_NEW_HERO_GK) { if (isSuccess) { let isFirst = await challengeNewHeroGK(serverId, roleId, activityId, pageIndex, battleId) skipReward = !isFirst; } } else if (warInfo.warType == WAR_TYPE.ACT_TREASURE_HUNT) { if(isSuccess) { await treasureHuntChallengeConsume(serverId, roleId, sid); } } let curWarStar = warStar.find(cur => cur.id == battleId); let { newWarStars, newStar } = calculateWarStar(warStar, battleId, stars); if (isSuccess) { // 挑战胜利 // 是否首通 let condition1 = warStar.find(cur => cur.id == battleId); if (!condition1) { // await switchOnFunc(roleId, FUNC_OPT_TYPE.BATTLE_END, battleId, session); warReward.setCondition(0, true); reportTAEvent(roleId, TA_EVENT.GK_FIRST_PASS, { war_id: battleId, war_type: getWarTypeName(warInfo.warType), pass_time: Date.now(), pass_duration: nowSeconds() - getSeconds(createdAt), hero_list: dbHeroes }); pushMysteryFirstMsg(roleId, roleName, serverId, warInfo.warType, warInfo.war_id); pushVestigeFirstMsg(roleId, roleName, serverId, warInfo.warType, warInfo.war_id); } // 是否首次3星 if (newStar == 3 && (!condition1 || condition1.star != 3)) { warReward.setCondition(1, true); } if (!curWarStar || newStar > curWarStar.star) { await RoleModel.updateRoleInfo(roleId, { warStar: newWarStars }); } } let reward = null; if (!skipReward) { reward = await warReward.saveReward(1); } const updateResult = await BattleRecordModel.updateBattleRecordByCode(battleCode, { $set: { status: isSuccess ? 1 : 2, star: newStar, stars, record: { heroes } } }, true); let { status } = updateResult; let actordata = await roleLevelup(KING_EXP_RATIO_TYPE.BATTLE, roleId, isSuccess ? warInfo.kingExp : 0, session);// 主公升级经验 await checkTaskInBattleEnd(serverId, roleId, sid, battleId, dbHeroes, newStar, isSuccess); // 返回值: // towerStatus: false-本层未通过, true-本层已通过 return resResult(STATUS.SUCCESS, { battleCode, battleId, status, battleGoods: reward, towerStatus, dailyNum, dungeonNum, createdAt: getSeconds(createdAt), ...actordata }); } async battleSweep(msg: { battleId: number, count: number }, session: BackendSession) { const { battleId, count } = msg; let roleId = session.get('roleId'); let roleName = session.get('roleName'); let sid = session.get('sid'); let serverId = session.get('serverId'); let ip = session.get('ip'); let warInfo = gameData.war.get(battleId); if (!warInfo) { return resResult(STATUS.BATTLE_MISS_INFO); } // 校验是否三星通关过 let { warStar } = await RoleModel.findByRoleId(roleId); let curWar = warStar.find(cur => cur.id == battleId); if (!curWar || curWar.star < 3) { return resResult(STATUS.BATTLE_SWEEP_CONDITION_STAR); } let role = await RoleModel.findByRoleId(roleId, 'lv warCount refWarCount roleId'); // 扫荡次数 let dailyNum = {}; let dungeonNum = {}; if(warInfo.warType == WAR_TYPE.NORMAL || warInfo.warType == WAR_TYPE.MAIN_ELITE) { let checkResult = await checkWarCountAndInc(battleId, count, role, true); if (checkResult.code != 0) { return checkResult } } else if (warInfo.warType == WAR_TYPE.DAILY) { let checkResult = await checkDailyAndIncrease(roleId, warStar, battleId, count, true); if (checkResult.status == -1) { return checkResult.resResult } dailyNum = Object.assign(dailyNum, checkResult.data) } else if (warInfo.warType == WAR_TYPE.MYSTERY || warInfo.warType == WAR_TYPE.MYSTERY_ELITE) { let checkResult = await checkDungeonAndIncrease(roleId, count, true, battleId); if (checkResult.status == -1) { return checkResult.resResult } dungeonNum = Object.assign(dungeonNum, checkResult.data) } // 扣体力 let apJson = await setAp(serverId, roleId, ip, role.lv, -1 * warInfo.cost * count, sid, getReasonByWarType(warInfo.warType)); // 扣除体力 if (!apJson) { return resResult(STATUS.BATTLE_ACTION_POINT_LACK); } // 发奖励 let warReward = new WarReward(roleId, roleName, sid, battleId, true); let result = await warReward.saveReward(count, true); let actordata = await roleLevelup(KING_EXP_RATIO_TYPE.BATTLE, roleId, warInfo.kingExp * count, session)// 主公升级经验 // 扫荡记录 await BattleSweepRecordModel.saveBattleSweepRecordById(roleId, battleId, { $set: { roleName, warName: warInfo.gk_name, warType: warInfo.warType }, $inc: { count } }); await checkTaskInBattleSweep(serverId, roleId, sid, battleId, count); return resResult(STATUS.SUCCESS, { battleId, count, battleGoods: result, dailyNum, dungeonNum, ...actordata }); } async saveScript(msg: { battleId: number, type: number, script: string }, session: BackendSession) { const { battleId, type, script } = msg; let roleId = session.get('roleId'); let warInfo = gameData.war.get(battleId); let result = await RScriptRecordModel.setScript(roleId, battleId, warInfo.warType, type, script); if (result) { if (!result.scriptBefore) result.scriptBefore = ''; if (!result.scriptAfter) result.scriptAfter = ''; return resResult(STATUS.SUCCESS, result); } else { console.error('script not created'); return resResult(STATUS.INTERNAL_ERR); } } async getScriptByBattle(msg: { battleIds: Array }, session: BackendSession) { const { battleIds } = msg; let roleId = session.get('roleId'); let list = new Array(); for (let battleId of battleIds) { let result = await RScriptRecordModel.findbyRoleAndBattle(roleId, battleId); if (result) { let { scriptBefore = '', scriptAfter = '' } = result; list.push({ battleId, scriptBefore, scriptAfter }); } else { list.push({ battleId, scriptBefore: '', scriptAfter: '' }); } } return resResult(STATUS.SUCCESS, { list }); } // 获取悔棋次数 async getRegretCnt(msg: { warId: number, battleCode: string }, session: BackendSession) { const { warId, battleCode } = msg; let roleId: string = session.get('roleId'); let vipStartTime: number = session.get('vipStartTime'); let battleRecord = await BattleRecordModel.getBattleRecordByCode(battleCode); if(!battleRecord || battleRecord.roleId != roleId || battleRecord.battleId != warId) { return resResult(STATUS.WRONG_PARMS); } let maxRegretCnt = getVipRegretCnt(vipStartTime); return resResult(STATUS.SUCCESS, { regretCnt: battleRecord.regretCnt||0, maxRegretCnt }); } // 记录悔棋次数 async incRegretCnt(msg: { warId: number, battleCode: string, count: number }, session: BackendSession) { const { warId, battleCode, count } = msg; let roleId: string = session.get('roleId'); let vipStartTime: number = session.get('vipStartTime'); let battleRecord = await BattleRecordModel.getBattleRecordByCode(battleCode); if(!battleRecord || battleRecord.roleId != roleId || battleRecord.battleId != warId) { return resResult(STATUS.WRONG_PARMS); } let maxRegretCnt = getVipRegretCnt(vipStartTime); let regretCnt = battleRecord.regretCnt||0; if(regretCnt + count > maxRegretCnt) { return resResult(STATUS.BATTLE_REGRET_MAX); } battleRecord = await BattleRecordModel.incRegretCnt(battleCode, count); return resResult(STATUS.SUCCESS, { regretCnt: battleRecord.regretCnt||0, maxRegretCnt }); } async getMainStarBox(msg: {}, session: BackendSession) { let roleId = session.get('roleId'); let role = await RoleModel.findByRoleId(roleId, 'warStar receivedBox'); let result = getMainChapter(role); return resResult(STATUS.SUCCESS, result); } // 关卡列表 async receiveChapterBox(msg: { chapter: number, id: number, warType: number }, session: BackendSession) { const { id, chapter, warType } = msg; if(!isNumber(id)) return resResult(STATUS.WRONG_PARMS); let roleId = session.get('roleId'); let roleName = session.get('roleName'); let sid = session.get('sid'); let role = await RoleModel.findByRoleId(roleId, 'warStar receivedBox'); let ids: number[] = []; let rewards: RewardInter[] = []; let star = getStarOfChapter(role.warStar, warType, chapter); let boxIds = id == 0? gameData.mainBoxByChapter.get(`${warType}_${chapter}`): [id]; for(let id of boxIds) { let dicBox = gameData.mainBox.get(id); if(dicBox && dicBox.chapter == chapter && dicBox.warType == warType) { if(star >= dicBox.star) { rewards.push(...dicBox.reward); ids.push(id); } } } if(ids.length <= 0) return resResult(STATUS.BATTLE_NO_BOX_CAN_RECEIVE); role = await RoleModel.receivedBox(roleId, ids); let goods = await addItems(roleId, roleName, sid, rewards, ITEM_CHANGE_REASON.RECEIVE_CHAPTER_BOX) let result = getMainChapter(role); return resResult(STATUS.SUCCESS, { ...result, goods }); } // 关卡列表 async receiveWarReward(msg: { chapter: number, warType: number }, session: BackendSession) { const { chapter, warType } = msg; let roleId = session.get('roleId'); let roleName = session.get('roleName'); let sid = session.get('sid'); let role = await RoleModel.findByRoleId(roleId, 'receivedWarIds warStar'); let { warStar, receivedWarIds = [] } = role; let warIds: number[] = []; let rewards: RewardInter[] = []; let mainWarRewards = gameData.mainWarReward.get(`${warType}_${chapter}`)??[]; for(let { warId, cityReward } of mainWarRewards) { let index = warStar.findIndex(cur => cur.id == warId); if(index != -1 && receivedWarIds.indexOf(warId) == -1) { rewards.push(...cityReward); warIds.push(warId); } } if(warIds.length <= 0) return resResult(STATUS.BATTLE_NO_WAR_REWARD_CAN_RECEIVE); role = await RoleModel.receiveWarRewards(roleId, warIds); let goods = await addItems(roleId, roleName, sid, rewards, ITEM_CHANGE_REASON.RECEIVE_CHAPTER_BOX) return resResult(STATUS.SUCCESS, { receivedWarIds: warIds, goods: combineItems(goods) }); } }