import { STATUS } from './../../../consts/statusCode'; import { HANG_UP_CONSTS, ITEM_CHANGE_REASON, MSG_SOURCE, POP_UP_SHOP_CONDITION_TYPE, REDIS_KEY } from './../../../consts'; import { TaskHero, TowerTaskRecModel, TowerTaskRecType } from './../../../db/TowerTaskRec'; import { HangUpSpdUpRecModel } from './../../../db/HangUpSpdUpRec'; import { HangUpRecordModel } from './../../../db/HangUpRecord'; import { RoleModel } from './../../../db/Role'; import { TowerRecordModel, WarStatus } from './../../../db/TowerRecord'; import { Application, BackendSession } from 'pinus'; import { resResult, genCode, shouldRefresh } from '../../../pubUtils/util'; import { calcuHangUpReward, refreshTasks, treatTask, getRemainTime, getTowerStatus, getHungupRewards, getTasks, checkTaskRewards, getTowerTaskCostGold, getManyHangSpdUpCostGold, getTaskStatus, checkForbiddenChar, checkAndStartHungUp, createNewTowerRecord, getTowerRecByLv, getTowerStatusByWarId, getTowerHeroCe, getWarStatusByLv } from '../../../services/battleService'; import { addItems, getGoldObject, handleCost } from '../../../services/role/rewardService'; import { checkBattleHeroes } from '../../../services/normalBattleService'; import { gameData } from '../../../pubUtils/data'; import * as dicParam from '../../../pubUtils/dicParam'; import { HeroModel } from '../../../db/Hero'; import { vipCanSkipTower } from '../../../services/activity/monthlyTicketService'; import { pushTowerMsg } from '../../../services/sysChatService'; import { WarStar } from '../../../domain/dbGeneral'; import { ItemInter, RewardInter } from '../../../pubUtils/interface'; import { combineItems } from '../../../services/role/util'; import { checkTaskInSkipTower } from '../../../services/task/taskService'; import { Rank } from '../../../services/rankService'; import { checkPopUpCondition } from '../../../services/activity/popUpShopService'; import { isHeroHidden } from '../../../services/dataService'; export default function(app: Application) { return new TowerBattleHandler(app); } export class TowerBattleHandler { constructor(private app: Application) { } /** * 获取天梯当前挑战状态 * @param session */ async getStatus(msg: {}, session: BackendSession) { let roleId = session.get('roleId'); let serverId = session.get('serverId'); let role = await RoleModel.findByRoleId(roleId, 'roleId serverId towerLv towerReceived'); let data = await getTowerStatus(role); return resResult(STATUS.SUCCESS, data); } /** * 重置天梯当前层的挑战记录 * @param towerLv 要重置的天梯层数 * @param session */ async resetLv(msg: {towerLv: number}, session: BackendSession) { let roleId = session.get('roleId'); let { towerLv } = await RoleModel.findByRoleId(roleId); if (msg.towerLv !== towerLv) { return resResult(STATUS.TOWER_RESET_ERR); } const record = await TowerRecordModel.resetRecordByLv(roleId, towerLv); if (!record) { return resResult(STATUS.TOWER_NOT_FOUND); } return resResult(STATUS.SUCCESS, { roleId: record.roleId, curLv: record.lv, heroes: record.heroes, warStatus: record.warStatus, speedUpCnt: record.speedUpCnt, speedUpTime: record.speedUpTime, hangUpTime: record.hangUpTime, passed: record.passed }); } /** * 查询当前挂机可得奖励 * @param msg * @param session * @returns */ async checkHangUpRewards(msg: {}, session: BackendSession) { let roleId = session.get('roleId'); let result = await getHungupRewards(roleId); if(!result) { return resResult(STATUS.TOWER_HANG_UP_NOT_START); } return resResult(STATUS.SUCCESS, result); } /** * 领取当前挂机可得奖励 * @param msg * @param session * @returns */ async recHangUpRewards(msg: {}, session: BackendSession) { let roleId = session.get('roleId'); let roleName = session.get('roleName'); let sid = session.get('sid'); let role = await RoleModel.findByRoleId(roleId); const result = await calcuHangUpReward(role); if(!result) { return resResult(STATUS.TOWER_HANG_UP_NOT_START); } let { timeReward, endLv, endTime, deltaTime, needReceiveGoods } = result; const goods = await addItems(roleId, roleName, sid, timeReward, ITEM_CHANGE_REASON.TOWER_HUNG_UP_REWARD); await HangUpRecordModel.updateRec(roleId, roleName, endLv, endTime, needReceiveGoods); return resResult(STATUS.SUCCESS, { endTime, hangUpPassTime: Math.floor((deltaTime%HANG_UP_CONSTS.UNIT_TIME)/1000), goods }); } /** * 加速挂机 * @param {{speedUpCnt: number}} msg 加速次数 * @param session * @returns */ async hangUpSpeedUp(msg: {speedUpCnt: number}, session: BackendSession) { let roleId = session.get('roleId'); let roleName = session.get('roleName'); let sid = session.get('sid'); let { speedUpCnt } = msg; const curTime = new Date(); let role = await RoleModel.findByRoleId(roleId); let { hangUpSpdUpCnt, gold, lastSpdUpTime } = role; if (shouldRefresh(lastSpdUpTime, curTime)) { hangUpSpdUpCnt = 0; } if (speedUpCnt + hangUpSpdUpCnt > dicParam.TOWER_BOOST.TOWER_BOOSTTIME) { return resResult(STATUS.TOWER_NOT_ENOUGH_HANG_UP_TIME) } const calResult = await calcuHangUpReward(role, true, msg.speedUpCnt, curTime); if(!calResult) { return resResult(STATUS.TOWER_HANG_UP_FAILED); } let { timeReward, endLv, deltaTime, needReceiveGoods } = calResult; const costGold = getManyHangSpdUpCostGold(hangUpSpdUpCnt, msg.speedUpCnt); if(costGold > gold) { return resResult(STATUS.TOWER_GOLD_NOT_ENOUGH); } await handleCost(roleId, sid, [getGoldObject(costGold)], ITEM_CHANGE_REASON.TOWER_HUNG_UP_SDP_UP) const spdUpResult = await RoleModel.hangUpSpdUp(roleId, msg.speedUpCnt, curTime); if (!spdUpResult) { return resResult(STATUS.TOWER_HANG_UP_FAILED); } const spdUpRec = await HangUpSpdUpRecModel.updateRec(roleId, roleName, msg.speedUpCnt, endLv, needReceiveGoods); const goods = await addItems(roleId, roleName, sid, timeReward, ITEM_CHANGE_REASON.TOWER_HUNG_UP_REWARD); let nextCostGold = getManyHangSpdUpCostGold(spdUpResult.hangUpSpdUpCnt, 1); return resResult(STATUS.SUCCESS, { goods, hangUpSpdUpCnt: dicParam.TOWER_BOOST.TOWER_BOOSTTIME - spdUpResult.hangUpSpdUpCnt, nextCostGold, hangUpPassTime: Math.floor(deltaTime/1000), rewardLv: endLv, costGold }); } async getTasks(msg: {}, session: BackendSession) { let roleId = session.get('roleId'); let roleName = session.get('roleName'); let result = await getTasks(roleId); return resResult(STATUS.SUCCESS, result); } async refreshTasks(msg: {}, session: BackendSession) { let roleId = session.get('roleId'); let roleName = session.get('roleName'); let curTime = new Date(); let { towerLv, towerTaskRefTime, towerTaskReCnt=0 } = await RoleModel.findByRoleId(roleId); if(towerTaskReCnt >= dicParam.TOWER_SEARCH.TOWER_SEARCH_REFRESHRULE) { // 付费刷新次数 return resResult(STATUS.TOWER_REF_CNT_NOT_ENOUGH); } let costGold = getTowerTaskCostGold(towerTaskReCnt, towerTaskRefTime); let {gold} = await RoleModel.findByRoleId(roleId); if(costGold > gold) { return resResult(STATUS.TOWER_GOLD_NOT_ENOUGH); } // 只刷掉当前面板上没有做派遣的任务 let batchCode = genCode(8); let curTasks = await TowerTaskRecModel.getCurTasks(roleId); // 当前显示中的任务 for(let task of curTasks) { if(task) batchCode = task.batchCode; } curTasks = await refreshTasks(towerLv, batchCode, roleId, roleName, curTasks); let newRole = await RoleModel.increaseTowerRefCnt(roleId, 1); let refRemainTime = getRemainTime(curTime); let nextCostGold = getTowerTaskCostGold(newRole.towerTaskReCnt, newRole.towerTaskRefTime); return resResult(STATUS.SUCCESS, { curTasks: treatTask(curTasks, curTime), costGold, nextCostGold, refRemainTime, towerTaskReCnt: newRole.towerTaskReCnt }); } async sendTaskHero(msg: {batchCode: string, tasks: {taskCode: string, heroes: number[]}[]}, session: BackendSession) { let roleId = session.get('roleId'); let batchCode = msg.batchCode; const curTime = new Date(); let curTasks = await TowerTaskRecModel.getCurTasks(roleId); // 当前一批的任务 if (!curTasks || curTasks.length == 0) { return resResult(STATUS.TOWER_TASK_NOT_FOUND); } let usedHeroes: number[] = [], tasks: {taskCode:string, heroes: TaskHero[], completeTime: number}[] = []; const tasksCode: string[] = []; const taskMap = new Map() curTasks.forEach(task => { let getStatusResult = getTaskStatus(task.status, task.completeTime, curTime); if(getStatusResult.status == 1) { for(let { seqId } of task.heroes) { usedHeroes.push(seqId); } } tasksCode.push(task.taskCode); taskMap.set(task.taskCode, task); batchCode = task.batchCode; }); for (let { taskCode, heroes: seqIds } of msg.tasks) { let curTask = taskMap.get(taskCode); // 数据库中,这个任务的数据 if(!curTask) { return resResult(STATUS.TOWER_TASK_MISSING) } let dicTask = gameData.towerTask.get(curTask.taskId); if (seqIds.length !== dicTask.actorNeeded) { // 武将数,从策划表中读取 return resResult(STATUS.TOWER_TASK_MAX_HERO); } let { isOK, heroes, hids } = await checkBattleHeroes(roleId, seqIds); if(!isOK) return resResult(STATUS.BATTLE_HERO_NOT_FOUND); if(isHeroHidden(...hids)) return resResult(STATUS.HERO_IS_HIDDEN); if (tasksCode.indexOf(taskCode) === -1) { return resResult(STATUS.TOWER_TASK_CODE_NOT_FOUND); } if (usedHeroes.length > 0) { // 是否在其他任务重使用了武将 let used = !!seqIds.find(seqId => usedHeroes.indexOf(seqId) !== -1); if (used) { return resResult(STATUS.TOWER_TASK_HERO_HAS_USED); } } let taskHeroes = heroes.map(hero => { return new TaskHero(hero); }); tasks.push({ taskCode, heroes: taskHeroes, completeTime: dicTask.completeTime}) } const recs = await TowerTaskRecModel.sendHeroes(roleId, batchCode, tasks, curTime,); if (!recs || recs.length === 0) { return resResult(STATUS.TOWER_TASK_SEND_ERR); } let role = await RoleModel.increaseTowerCnt(roleId, tasks.length) let refRemainTime = getRemainTime(curTime); curTasks = await TowerTaskRecModel.getCurTasks(roleId); // 当前显示中的任务 let costGold = getTowerTaskCostGold(role.towerTaskReCnt, role.towerTaskRefTime); return resResult(STATUS.SUCCESS, { curTasks: treatTask(curTasks, curTime), refRemainTime, nextCostGold: costGold }); } async settleTask(msg: {batchCode: string, taskCode: string}, session: BackendSession) { let roleId = session.get('roleId'); let roleName = session.get('roleName'); let sid = session.get('sid'); const { batchCode, taskCode } = msg; let allFlag = !taskCode; const curTime = new Date(); let tasks: TowerTaskRecType[] = []; if(allFlag) { tasks = await TowerTaskRecModel.getCurTasks(roleId); } else { let task = await TowerTaskRecModel.getTaskByCode(roleId, taskCode); if(task) tasks.push(task); } if (!tasks || tasks.length == 0) { return resResult(STATUS.TOWER_TASK_NOT_FOUND); } const checkResult = checkTaskRewards(batchCode, tasks); if (!checkResult) { return resResult(STATUS.TOWER_TASK_CANNOT_RECEIVE); } const { compTasks, rewards } = checkResult; if(compTasks.length <= 0) return resResult(STATUS.TOWER_TASK_CANNOT_RECEIVE) let goods = await addItems(roleId, roleName, sid, rewards, ITEM_CHANGE_REASON.TOWER_TASK_REWARD); await TowerTaskRecModel.finishTask(msg.batchCode, compTasks); let refRemainTime = getRemainTime(curTime); let curTasks = await TowerTaskRecModel.getCurTasks(roleId); // 当前显示中的任务 let role = await RoleModel.findByRoleId(roleId); let costGold = getTowerTaskCostGold(role.towerTaskReCnt, role.towerTaskRefTime); return resResult(STATUS.SUCCESS, { curTasks: treatTask(curTasks, curTime), goods, refRemainTime, nextCostGold: costGold }); } async skipTower(msg: { toLv: number }, session: BackendSession) { const { toLv } = msg; let roleId = session.get('roleId'); let roleName = session.get('roleName'); let serverId = session.get('serverId'); let sid = session.get('sid'); let role = await RoleModel.findByRoleId(roleId); let oldTowerLv = role.towerLv; let dicTower = gameData.tower.get(oldTowerLv); if(!dicTower.canSkip) { return resResult(STATUS.TOWER_CANNOT_SKIP); } // 检查战力是否足够 let towerRec = await TowerRecordModel.getRecordByLv(roleId, oldTowerLv); let heroes = await HeroModel.findByRole(roleId, [{ field: 'ce', sortBy: -1 }], 'hid ce job', true); let newWarStar: WarStar[] = [], resultGoods: { towerLv: number, goods: { id: number, count: number }[] }[] = [], rewards: ItemInter[] = []; for(let lv = oldTowerLv; lv < toLv; lv++) { let dicTower = gameData.tower.get(lv); let warArray = dicTower?.warArray||[]; let recommendCeSum = 0, heroesCeSum = 0; for(let warId of warArray) { if(!getTowerStatusByWarId(warId, towerRec?.warStatus)) { let dicWar = gameData.war.get(warId); recommendCeSum += dicWar.recommendedPower; heroesCeSum += getTowerHeroCe(warId, heroes, towerRec.heroes); newWarStar.push({ id: warId, warType: dicWar.warType, star: 0, stars: [] }) } } if(!vipCanSkipTower(recommendCeSum, heroesCeSum, role.vipStartTime)) { return resResult(STATUS.TOWER_SKIP_POWER_NOT_ENOUGH) } resultGoods.push({ towerLv: lv, goods: dicTower.reward }); rewards.push(...dicTower.reward); } // 更新towerRecord let warStatus: WarStatus[] = getWarStatusByLv(toLv); await TowerRecordModel.skipTower(roleId, role.towerLv, toLv, warStatus); await checkAndStartHungUp(roleId, roleName, role.towerLv); // 更新玩家表 role = await RoleModel.setTowerLv(roleId, toLv, newWarStar); await addItems(roleId, roleName, sid, dicTower.reward, ITEM_CHANGE_REASON.TOWER_BATTLE_END); pushTowerMsg(roleId, roleName, serverId, MSG_SOURCE.TOWER_SUC, role.towerLv - 1); let data = await getTowerStatus(role); // 更新redis let r = new Rank(REDIS_KEY.TOWER_RANK, { serverId }); await r.setRankWithRoleInfo(roleId, role.towerLv - 1, role.towerUpTime.getTime(), role); await checkTaskInSkipTower(serverId, roleId, sid, role.towerLv); await checkPopUpCondition(serverId, roleId, POP_UP_SHOP_CONDITION_TYPE.TOWER, { oldLv: oldTowerLv - 1, newLv: role.towerLv - 1 }) return resResult(STATUS.SUCCESS, { ...data, resultGoods }); } /** * 获取节点奖励 * @param session */ async receiveBox(msg: { id: number }, session: BackendSession) { let roleId = session.get('roleId'); let roleName = session.get('roleName'); let sid = session.get('sid'); let { id } = msg; // id为0表示一键领取 let role = await RoleModel.findByRoleId(roleId, 'towerLv towerReceived'); if(!role) return resResult(STATUS.ROLE_NOT_FOUND); let { towerLv, towerReceived = [] } = role; let rewards: RewardInter[] = [], newReceived: number[] = []; if(id == 0) { for(let [ id, dicTowerGift ] of gameData.towerGift) { if(towerLv > dicTowerGift.towerLv && towerReceived.indexOf(id) == -1) { rewards.push(...dicTowerGift.reward); newReceived.push(id); } } if(newReceived.length <= 0) return resResult(STATUS.TOWER_BOX_NO_RECEIVE); } else { let dicTowerGift = gameData.towerGift.get(id); if(!dicTowerGift) return resResult(STATUS.WRONG_PARMS); if(towerLv <= dicTowerGift.towerLv) { return resResult(STATUS.TOWER_LV_NOT_ENOUGH); } if(towerReceived.indexOf(id) != -1) { return resResult(STATUS.TOWER_BOX_HAS_RECEIVED); } rewards.push(...dicTowerGift.reward); newReceived.push(id); } role = await RoleModel.receiveTowerBox(roleId, newReceived); let goods = await addItems(roleId, roleName, sid, combineItems(rewards), ITEM_CHANGE_REASON.RECEIVE_TOWER_BOX); return resResult(STATUS.SUCCESS, { goods, receivedBox: newReceived }); } }