import { STATUS } from './../../../consts/statusCode'; import { HANG_UP_CONSTS, ITEM_CHANGE_REASON, MSG_SOURCE, REDIS_KEY, TASK_TYPE } 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 } 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, getHangSpdUpCostGold, getManyHangSpdUpCostGold, getTaskStatus, checkForbiddenChar, checkAndStartHungUp, createNewTowerRecord, getTowerRecByLv } 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 { isNumber } from 'underscore'; import { HeroModel } from '../../../db/Hero'; import { vipCanSkipTower } from '../../../services/activity/monthlyTicketService'; import { pushTowerMsg } from '../../../services/sysChatService'; import { WarStar } from '../../../domain/dbGeneral'; import { RewardInter } from '../../../pubUtils/interface'; import { combineItems } from '../../../services/role/util'; import { checkTask, checkTaskInSkipTower } from '../../../services/task/taskService'; import { Rank } from '../../../services/rankService'; 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; if (!isNumber(speedUpCnt) || speedUpCnt <= 0) { return resResult(STATUS.WRONG_PARMS); } 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 role = await RoleModel.findByRoleId(roleId); let result = await getTasks(role); 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}); } async sendTaskHero(msg: {batchCode: string, tasks: {taskCode: string, heroes: number[]}[]}, session: BackendSession) { let roleId = session.get('roleId'); 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); }); 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 } = await checkBattleHeroes(roleId, seqIds); if(!isOK) return resResult(STATUS.BATTLE_HERO_NOT_FOUND); 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, msg.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: { }, session: BackendSession) { 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 dicTower = gameData.tower.get(role.towerLv); if(!dicTower.canSkip) { return resResult(STATUS.TOWER_CANNOT_SKIP); } let { warStatus, heroes: recHeroes } = await getTowerRecByLv(roleId, role.towerLv); // 检查战力是否足够 let heroes = await HeroModel.findByRole(roleId, [{ field: 'ce', sortBy: -1 }], 'hid ce', true); let recommendCeSum = 0, heroesCeSum = 0; let newWarStar: WarStar[] = []; for(let { warId, status } of warStatus) { if(!status) { let dicWar = gameData.war.get(warId); recommendCeSum += dicWar.recommendedPower; let heroNum = 0; for(let hero of heroes) { if(recHeroes.indexOf(hero.hid) == -1 && !checkForbiddenChar(hero.hid, dicWar.fobiddenCharactor)) { heroNum++; recHeroes.push(hero.hid); heroesCeSum += hero.ce; } if(heroNum >= dicWar.minHeroNum) break; } newWarStar.push({ id: warId, warType: dicWar.warType, star: 0, stars: [] }) } } if(!vipCanSkipTower(recommendCeSum, heroesCeSum, role.vipStartTime)) { return resResult(STATUS.TOWER_SKIP_POWER_NOT_ENOUGH) } // 更新玩家表 role = await RoleModel.towerLvUp(roleId, newWarStar); // 更新towerRecord await TowerRecordModel.skipTower(roleId, role.towerLv - 1, recHeroes); await createNewTowerRecord(roleId, role.towerLv); await checkAndStartHungUp(roleId, roleName, role.towerLv); let goods = 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); return resResult(STATUS.SUCCESS, { ...data, goods }); } /** * 获取节点奖励 * @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 }); } }