Files
ZYZ/game-server/app/servers/battle/handler/expeditionBattleHandler.ts
2023-09-04 12:03:16 +08:00

421 lines
18 KiB
TypeScript

import { Application, BackendSession, HandlerService, } from 'pinus';
import { BattleRecordModel } from '../../../db/BattleRecord';
import { ExpeditionRecordModel } from '../../../db/ExpeditionRecord';
import { ExpeditionWarRecordModel } from '../../../db/ExpeditionWarRecord';
import { ExpeditionPointModel } from '../../../db/ExpeditionPoint';
import { RoleModel } from '../../../db/Role';
import { genCode, getWarTypeName } from '../../../pubUtils/util';
import { getPointRewardStatus, getResetRemainCnt, findOrCreateEnemies, getExpeditionStatus } from '../../../services/expeditionService';
import { DEBUG_MAGIC_WORD, EXPEDITION_WAR_RECORD_STATUS, ITEM_CHANGE_REASON, KING_EXP_RATIO_TYPE, TASK_TYPE, TA_EVENT } from '../../../consts';
import { WarReward } from '../../../services/warRewardService';
import { addItems } from '../../../services/role/rewardService';
import { getAp, setAp } from '../../../services/actionPointService';
import { STATUS } from '../../../consts/statusCode';
import { resResult } from '../../../pubUtils/util';
import { calculateWarStar, checkBattleHeroes, getBattleRecordParam, roleLevelup } from '../../../services/normalBattleService';
import { checkTask, checkTaskInBattleEnd, checkTaskInBattleStart, checkTaskInSkipExpedition } from '../../../services/task/taskService';
import { gameData } from '../../../pubUtils/data';
import * as dicParam from '../../../pubUtils/dicParam';
import { getSeconds, nowSeconds } from '../../../pubUtils/timeUtil';
import { reportTAEvent } from '../../../services/sdkService';
import { getSumCe } from '../../../services/playerCeService';
import { vipCanSkipExpedition } from '../../../services/activity/monthlyTicketService';
import { isHeroHidden } from '../../../services/dataService';
import { pvpEndParamInter } from '../../../pubUtils/interface';
export default function (app: Application) {
new HandlerService(app, {});
return new ExpeditionBattleHandler(app);
}
export class ExpeditionBattleHandler {
constructor(private app: Application) {
}
/**
* 获取初始数据
* 获取当前远征挑战情况,远征点数,点数宝箱领取情况 */
async getStatus(msg: {}, session: BackendSession) {
let roleId = session.get('roleId');
let roleName = session.get('roleName');
let res = await getExpeditionStatus(roleId, roleName);
if (!res) return resResult(STATUS.ROLE_IS_NOT_INIT);
return resResult(STATUS.SUCCESS, res);
}
/**
* 重置远征本
* 每天5点可以重置远征本 */
async resetStatus(msg: {}, session: BackendSession) {
let roleId = session.get('roleId');
let roleName = session.get('roleName');
let curTime = new Date();
let { needRefresh, resetCnt } = await getResetRemainCnt(curTime, roleId);
if (resetCnt <= 0) {
return resResult(STATUS.EXPEDITION_RESET_NUM_NOT_ENOUGH)
}
await ExpeditionRecordModel.hideRecord(roleId); // 刷掉旧关卡
// 我方战力
let myCe = await getSumCe(roleId);
// 每一关的挑战状态
let { expeditionCode, heroes } = await ExpeditionRecordModel.createRecord({
roleId, roleName, heroes: [], myCe
});
await findOrCreateEnemies(roleId, myCe, expeditionCode, 1, EXPEDITION_WAR_RECORD_STATUS.WAITING);
await RoleModel.increaseExpeditionResetCnt(roleId, needRefresh, curTime);
let expeditionWarRecord = await ExpeditionWarRecordModel.getRecordByCode(expeditionCode);
let curLv = 0;
if (expeditionWarRecord.length > 0) {
curLv = expeditionWarRecord[expeditionWarRecord.length - 1].expeditionId;
}
return resResult(STATUS.SUCCESS, {
expeditionCode,
curLv,
expeditionWarRecord,
heroes,
resetCnt: resetCnt - 1
});
}
/**
* 获取敌军数据
* 匹配其他玩家,或机器人数据
*/
async getEnemies(msg: { expeditionCode: string, expeditionId: number }, session: BackendSession) {
const roleId = session.get('roleId');
// const roleName = session.get('roleName');
const { expeditionCode, expeditionId } = msg;
let expeditionWarRecord = await ExpeditionWarRecordModel.getRecordByCodeAndId(expeditionCode, expeditionId);
if (expeditionWarRecord && (expeditionWarRecord.battleStatus == EXPEDITION_WAR_RECORD_STATUS.SUCCESS)) {
return resResult(STATUS.EXPEDITION_DUPLICATE_CHALLENGE);
}
let { myCe } = await ExpeditionRecordModel.getExpeditionRecordByCode(expeditionCode);
let curExpeditionWarRecord = await findOrCreateEnemies(roleId, myCe, expeditionCode, expeditionId, EXPEDITION_WAR_RECORD_STATUS.WAITING);
if (!curExpeditionWarRecord) {
return resResult(STATUS.EXPEDITION_MATCH_NO_PLAYER);
}
let { battleId, mapseid, enemyFrom, enemies, battleStatus, ce: curCe } = curExpeditionWarRecord;
let nextCe = 0; // 下一关战力
if (gameData.expedition.has(expeditionId + 1)) {
let nextExpeditionWarRecord = await findOrCreateEnemies(roleId, myCe, expeditionCode, expeditionId + 1, EXPEDITION_WAR_RECORD_STATUS.HIDE);
if (nextExpeditionWarRecord) nextCe = nextExpeditionWarRecord.ce;
}
return resResult(STATUS.SUCCESS, {
expeditionCode, expeditionId, battleId, mapseid,
battleStatus,
enemyFrom,
enemies,
curCe,
nextCe
});
}
/**
* 进入战斗
* 记录我军数据,生成战斗唯一表示,记录状态
*/
async checkBattle(msg: { expeditionCode: string, expeditionId: number, battleId: number, heroes: number[] }, session: BackendSession) {
const { expeditionCode, expeditionId, battleId, heroes: seqIds = [] } = msg;
let roleId = session.get('roleId');
let roleName = session.get('roleName');
let ip = session.get('ip');
let serverId = session.get('serverId');
let sid = session.get('sid');
let warInfo = gameData.war.get(battleId);
if (!warInfo) {
return resResult(STATUS.BATTLE_MISS_INFO);
}
let role = await RoleModel.findByRoleId(roleId, 'lv warStar');
let apJson = await getAp(roleId, ip, role.lv);
let { ap } = apJson;
if (ap < warInfo.cost) {
return resResult(STATUS.BATTLE_ACTION_POINT_LACK);
}
// 前置关卡是否挑战过
let previousGk = warInfo.previousGk;
if (previousGk) {
let preBattle = role.warStar.findIndex(cur => cur.id == previousGk);
if (preBattle == -1) return resResult(STATUS.BATTLE_NEED_PREVIOUS_GK);
}
let { isOK, hids } = await checkBattleHeroes(roleId, seqIds);
if (!isOK) return resResult(STATUS.BATTLE_HERO_NOT_FOUND);
if(isHeroHidden(...hids)) return resResult(STATUS.HERO_IS_HIDDEN);
let expeditionWarRecord = await ExpeditionWarRecordModel.getRecordByCodeAndId(expeditionCode, expeditionId);
if (!expeditionWarRecord) {
return resResult(STATUS.EXPEDITION_MISS_WAR_RECORD);
}
if (expeditionWarRecord.battleStatus == EXPEDITION_WAR_RECORD_STATUS.SUCCESS) {
return resResult(STATUS.EXPEDITION_DUPLICATE_CHALLENGE);
}
const battleCode = genCode(8);
await BattleRecordModel.updateBattleRecordByCode(battleCode, {
$set: {
roleId, roleName, battleId,
status: 0,
warName: warInfo.gk_name,
warType: warInfo.warType,
record: { heroes: hids, seqIds }
}
}, true);
let result = await ExpeditionWarRecordModel.updateBattleCode(expeditionCode, expeditionId, EXPEDITION_WAR_RECORD_STATUS.WAITING, battleCode);
await checkTaskInBattleStart(serverId, roleId, sid, battleId);
return resResult(STATUS.SUCCESS, {
expeditionCode,
expeditionId,
battleId,
battleCode,
battleStatus: result.battleStatus
});
}
/**
* 跳过
*/
async skipExpedition(msg: { expeditionCode: string, expeditionId: number, battleId: number }, session: BackendSession) {
const { expeditionCode, expeditionId, battleId } = msg;
let roleId = session.get('roleId');
let roleName = session.get('roleName');
let serverId = session.get('serverId');
let sid = session.get('sid');
let dicExpedition = gameData.expedition.get(expeditionId);
if(dicExpedition.warId != battleId) return resResult(STATUS.WRONG_PARMS);
let dicWar = gameData.war.get(battleId);
if(!dicWar) return resResult(STATUS.DIC_DATA_NOT_FOUND);
// 前置关卡是否挑战过
let role = await RoleModel.findByRoleId(roleId, 'warStar topLineupCe vipStartTime')
let { warStar, topLineupCe, vipStartTime } = role;
let previousGk = dicWar.previousGk;
if (previousGk) {
let preBattle = warStar.findIndex(cur => cur.id == previousGk);
if (preBattle == -1) return resResult(STATUS.BATTLE_NEED_PREVIOUS_GK);
}
// 检查record
let expeditionRecord = await ExpeditionRecordModel.getExpeditionRecordByCode(expeditionCode);
let expeditionWarRecord = await ExpeditionWarRecordModel.getRecordByCodeAndId(expeditionCode, expeditionId);
if (!expeditionRecord || !expeditionWarRecord) {
return resResult(STATUS.EXPEDITION_MISS_WAR_RECORD);
}
if(expeditionWarRecord.battleStatus == EXPEDITION_WAR_RECORD_STATUS.SUCCESS) {
return resResult(STATUS.EXPEDITION_DUPLICATE_CHALLENGE);
}
// 检查战力是否足够
if(!vipCanSkipExpedition(expeditionWarRecord.ce, topLineupCe, vipStartTime)) {
return resResult(STATUS.EXPEDITION_SKIP_POWER_NOT_ENOUGH)
}
// 更新敌人剩余状态及战斗状态
expeditionWarRecord = await ExpeditionWarRecordModel.updateEnemiesStatus(expeditionCode, expeditionId, EXPEDITION_WAR_RECORD_STATUS.SUCCESS, []);
// 更新点数
role = await RoleModel.increaseExpeditionPoint(roleId, dicParam.EXPEDITION_CONST.EXPEDITION_CONST_POINTS);
// 关卡奖励
let warReward = new WarReward(roleId, roleName, sid, battleId, true);
let reward = await warReward.saveReward(1);
let curWarStar = warStar.find(cur => cur.id == battleId);
let { newWarStars, newStar } = calculateWarStar(warStar, battleId, []);
if (!curWarStar || newStar > curWarStar.star) {
role = await RoleModel.updateRoleInfo(roleId, { warStar: newWarStars });
}
// 更新下一关状态
if (gameData.expedition.has(expeditionId + 1)) {
await findOrCreateEnemies(roleId, expeditionRecord.myCe, expeditionCode, expeditionId + 1, EXPEDITION_WAR_RECORD_STATUS.WAITING);
}
await checkTaskInSkipExpedition(serverId, roleId, sid, battleId);
return resResult(STATUS.SUCCESS, {
expeditionCode,
expeditionId,
battleId,
goods: reward,
expeditionPoint: role.expeditionPoint
});
}
/**
* 战斗结算
* 结算战斗奖励,更新远征状态
*/
async battleEnd(msg: { expeditionCode: string, expeditionId: number, battleCode: string, battleId: number, isSuccess: boolean, heroes: Array<{ dataId: number, hp: number, ap: number, shield: number, others: string }>, enemies: Array<{ dataId: number, hp: number, ap: number }>, star: number, stars: number[], damageRecords: pvpEndParamInter[], round: number }, session: BackendSession) {
const { expeditionCode, battleCode, battleId, expeditionId, isSuccess, heroes = [], star, stars = [], enemies, damageRecords, round } = msg;
let roleId = session.get('roleId');
let roleName = session.get('roleName');
const 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);
}
const BattleRecord = await BattleRecordModel.getBattleRecordByCode(battleCode);
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 { dataId } of heroes) {
if (dbSeqIds.indexOf(dataId) == -1) flag = 0;
}
if (!flag) {
return resResult(STATUS.BATTLE_INFO_VALIDATE_ERR);
}
let role = await RoleModel.findByRoleId(roleId, 'lv');
let apJson = await setAp(serverId, roleId, ip, role.lv, isSuccess?-1 * warInfo.cost: 0, sid, ITEM_CHANGE_REASON.EXPEDITION_BATTLE_END); // 扣除体力
if (!apJson) {
return resResult(STATUS.BATTLE_ACTION_POINT_LACK);
}
// 检查record
let expeditionRecord = await ExpeditionRecordModel.getExpeditionRecordByCode(expeditionCode);
let expeditionWarRecord = await ExpeditionWarRecordModel.getRecordByCodeAndId(expeditionCode, expeditionId);
if (!expeditionRecord || !expeditionWarRecord) {
return resResult(STATUS.EXPEDITION_MISS_WAR_RECORD);
}
// 更新我方剩余血量
await ExpeditionRecordModel.updateHeroStatus(expeditionCode, expeditionRecord.heroes, heroes);
// 更新敌人剩余状态及战斗状态
let battleStatus = isSuccess ? EXPEDITION_WAR_RECORD_STATUS.SUCCESS : EXPEDITION_WAR_RECORD_STATUS.FAIL;
expeditionWarRecord = await ExpeditionWarRecordModel.updateEnemiesStatus(expeditionCode, expeditionId, battleStatus, enemies);
// 更新battleRecord状态
await BattleRecordModel.updateBattleRecordByCode(battleCode, {
$set: { status: isSuccess ? 1 : 2, star, ...getBattleRecordParam(damageRecords, round) }
}, true);
// 更新点数
role = await RoleModel.increaseExpeditionPoint(roleId, isSuccess ? dicParam.EXPEDITION_CONST.EXPEDITION_CONST_POINTS : 0);
let { expeditionPoint = 0, warStar = [] } = role;
// 关卡奖励
let warReward = new WarReward(roleId, roleName, sid, battleId, isSuccess);
let reward = await warReward.saveReward(1);
let actordata = await roleLevelup(KING_EXP_RATIO_TYPE.BATTLE, roleId, isSuccess ? warInfo.kingExp : 0, session);// 主公升级经验
let curWarStar = warStar.find(cur => cur.id == battleId);
let { newWarStars, newStar } = calculateWarStar(warStar, battleId, stars);
if (isSuccess) {
// 更新下一关状态
await ExpeditionWarRecordModel.updateStatus(expeditionCode, expeditionId + 1, EXPEDITION_WAR_RECORD_STATUS.WAITING);
if(!curWarStar) { // 首通
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 });
}
if (!curWarStar || newStar > curWarStar.star) {
await RoleModel.updateRoleInfo(roleId, { warStar: newWarStars });
}
}
await checkTaskInBattleEnd(serverId, roleId, sid, battleId, dbHeroes, star, isSuccess);
return resResult(STATUS.SUCCESS, {
expeditionCode, expeditionId,
battleCode, battleId,
battleStatus: expeditionWarRecord.battleStatus,
battleGoods: reward,
expeditionPoint,
createdAt: getSeconds(createdAt),
...actordata
});
}
/**
* 领取点数宝箱
* 领取点数宝箱,不扣除点数,那么就需要记录领取状态并且有返回
*/
async pointReward(msg: { point: number }, session: BackendSession) {
const { point } = msg;
let roleId = session.get('roleId');
let roleName = session.get('roleName');
let sid = session.get('sid');
const serverId = session.get('serverId');
let role = await RoleModel.findByRoleId(roleId);
let { expeditionPoint } = role;
let dicExpeditionPoint = gameData.expeditionPoint;
let curDicExpeditionPoint = dicExpeditionPoint.get(point);
if (!curDicExpeditionPoint) {
return resResult(STATUS.EXPEDITION_MISS_POINT_INFO);
}
if (point > expeditionPoint) {
return resResult(STATUS.EXPEDITION_POINT_NOT_ENOUGH);
}
let pointStatusInDatabase = await ExpeditionPointModel.getExpeditionPoint(roleId);
if (pointStatusInDatabase) {
let { rewards } = pointStatusInDatabase;
let curReward = rewards.find(cur => cur.point == point);
if (curReward && curReward.received) {
return resResult(STATUS.EXPEDITION_WRONG_RECEIVE_STATUS);
}
}
// 标记状态
let { rewards: resultRewards } = await ExpeditionPointModel.updatePointStatus(roleId, point, curDicExpeditionPoint.reward);
let hasReceivedAll = true, maxPoint = 0;
for (let [point] of dicExpeditionPoint) {
let curReward = resultRewards.find(cur => cur.point == point);
if (!curReward || !curReward.received) {
hasReceivedAll = false;
}
if (point > maxPoint) maxPoint = point;
}
if (hasReceivedAll) { // 全部领取了,刷新
await ExpeditionPointModel.completeStatus(roleId);
await RoleModel.increaseExpeditionPoint(roleId, maxPoint * -1);
}
let pointRewards = await getPointRewardStatus(roleId);
// 任务
await checkTask(serverId, roleId, sid, TASK_TYPE.BATTLE_EXPEDITION_BOX, { point });
let goods = await addItems(roleId, roleName, sid, curDicExpeditionPoint.reward, ITEM_CHANGE_REASON.EXPEDITION_POINT_REWARD);
return resResult(STATUS.SUCCESS, {
costPoint: hasReceivedAll ? maxPoint : 0,
pointRewards,
goods
})
}
async debugResetResetNum(msg: { magicWord: string }, session: BackendSession) {
const { magicWord } = msg;
if (magicWord !== DEBUG_MAGIC_WORD) {
return resResult(STATUS.TOKEN_ERR);
}
let roleId = session.get('roleId');
await RoleModel.updateRoleInfo(roleId, { expeditionResetCnt: 0 });
return resResult(STATUS.SUCCESS);
}
}