Files
ZYZ/game-server/app/servers/battle/handler/comBattleHandler.ts
2020-12-18 17:13:49 +08:00

829 lines
37 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* @Author: 梁桐川
* @Date: 2020-11-30 15:05:48
* @Last Modified by: 梁桐川
* @Last Modified time: 2020-12-03 21:36:00
*/
import { IT_TYPE, CURRENCY_BY_TYPE, CURRENCY_TYPE, COM_TEAM_STATUS, COM_BTL_CONST, GOOD_QUALITY, CONSUME_TYPE } from './../../../consts';
import { getGoodById, getBossHpByBlueprtId, getComBtlSetByQuality, getBlueprtComposeByQuality, getBluePrtByQuality, getWarById, getWarIdByBlueprtId } from '../../../pubUtils/gamedata';
import { ComBattleTeamModel, BossHp } from '../../../db/ComBattleTeam';
import Role, { RoleModel } from '../../../db/Role';
import { STATUS } from '../../../consts/statusCode';
import { Application, BackendSession } from 'pinus';
import { resResult, getRandomByLen, calculateNum, getRandValue, ratioReward } from '../../../pubUtils/util';
import { RoleStatus } from '../../../db/ComBattleTeam';
import { ItemModel } from '../../../db/Item';
import { handleFixedReward, addItems } from '../../../services/rewardService';
import { checkRoleInQueue, getTeamSearchByQuality, rmRoleFromQueue, setTeamSearchReq } from '../../../services/redisService';
import { transBossHpArr } from '../../../services/battleService';
import { getRandBlueprtId, getRandComBtlRobots, checkComBattleResult, clearComBtlTimer, getRealReward, getAssistTimesByQuality, getFrd } from '../../../services/comBattleService';
import { setAp } from '../../../services/actionPointService';
import { roleLevelup } from '../../../services/normalBattleService';
export default function(app: Application) {
return new ComBattleHandler(app);
}
class ComTeam {
// 队伍唯一编号
teamCode: string;
// 玩家列表
roleIds: Array<string>
// 队伍是否开放加入
pub: boolean;
// 对应藏宝图 Id
blueprtId: number;
// 战斗状态 0未开始1已开始2胜利3失败
status: number;
// 玩家状态
roleStatus: Array<RoleStatus>;
// 队长 roleId
capId: string;
// 战力限制
ceLimit: number;
// boss 总血量
bossHp: number;
// boss 当前血量
bossCurHp: number;
// 单个 boss 血量状态
bossHpArr: Array<BossHp>;
// 品质
quality: number;
// 当前回合
curRnd: number;
// 队伍中人数
roleCnt: number;
constructor(teamCode: string, pub: boolean, blueprtId: number, status: number, capId: string, ceLimit: number, bossHp: number, quality: number, bossHpArr:Array<BossHp> ) {
this.teamCode = teamCode;
this.pub = pub;
this.blueprtId = blueprtId;
this.status = status;
this.capId = capId;
this.ceLimit = ceLimit;
this.bossHp = bossHp;
this.bossCurHp = bossHp;
this.quality = quality;
this.bossHpArr = bossHpArr;
this.curRnd = 0;
this.roleCnt = 1;
}
}
export class ComBattleHandler {
constructor(private app: Application) {
}
private teamMap: Map<string, ComTeam> = new Map();
private teamDisTimer: Map<string, NodeJS.Timer> = new Map();
/**
* @description 队长创建队伍
* @param {{blueprtId: number, pub: boolean, ceLimit: number}} msg 藏宝图Id是否公开战力限制
* @param {BackendSession} session
* @returns
* @memberof ComBattleHandler
*/
async createTeam(msg: {blueprtId: number, pub: boolean, ceLimit: number}, session: BackendSession) {
let roleId = session.get('roleId');
let roleName = session.get('roleName');
let sid = session.get('sid');
let teamCode = session.get('teamCode');
const { blueprtId, pub, ceLimit } = msg;
console.log('createTeam msg: ', msg);
// 检查藏宝图Id是否合法
let goodData = getGoodById(blueprtId);
if (!goodData || goodData.itid !== IT_TYPE.BLUEPRT) return resResult(STATUS.COM_BATTLE_BLUEPRT_INVALID);
// 检查藏宝图是否足够
let { lv, headHid = 19, topFiveCe = 100, sHid = 19 } = await RoleModel.findByRoleId(roleId);
if (lv < COM_BTL_CONST.ENABLE_LV) return resResult(STATUS.COM_BATTLE_LV_NOT_ENOUGH);
let blueprt = await ItemModel.findbyRoleAndGidAndCount(roleId, blueprtId, 1);
if (!blueprt) return resResult(STATUS.COM_BATTLE_BLUEPRT_NOT_FOUND);
// 检查是否有已创建未结束的寻宝,预先占用一张藏宝图
let teams = await ComBattleTeamModel.getTeamByCapAndStatus(roleId, COM_TEAM_STATUS.FIGHTING);
if (teams && blueprt.count <= teams.length) return resResult(STATUS.COM_BATTLE_BLUEPRT_NOT_ENOUGH);
let roleStatus = [];
let roleIds = [];
roleIds.push(roleId);
let capStatus = new RoleStatus(roleId, roleName, true, false, headHid, sHid, topFiveCe, lv);
roleStatus.push(capStatus);
// 检查是否有正在匹配的符合要求的玩家
let teammates = await getTeamSearchByQuality(goodData.quality);
if (teammates) {
for (let teammate of teammates) {
let roleInfo = await RoleModel.findByRoleId(teammate.roleId);
if (!roleInfo || roleIds.indexOf(teammate.roleId) !== -1) continue;
let {roleId, roleName, headHid = 19, sHid = 19, topFiveCe, lv} = roleInfo;
if (topFiveCe < ceLimit) continue;
let isFrd = await getFrd(roleId, goodData.quality);
const st = new RoleStatus(roleId, roleName, false, isFrd, headHid, sHid, topFiveCe, lv);
roleStatus.push(st);
roleIds.push(roleInfo.roleId);
}
}
let { bossHpSum, bossHpArr } = getBossHpByBlueprtId(blueprtId);
// 创建队伍数据结构
let comTeam = new ComTeam(teamCode, pub, blueprtId, COM_TEAM_STATUS.DEFAULT, roleId, ceLimit, bossHpSum || 10000, goodData.quality, transBossHpArr(bossHpArr));
comTeam.roleStatus = roleStatus;
comTeam.roleIds = roleIds;
this.teamMap.set(teamCode, comTeam);
// TODO: 处理助战回滚
const team = await ComBattleTeamModel.createTeam(comTeam);
if (!team) return resResult(STATUS.COM_BATTLE_CREATE_ERR);
let channelService = this.app.get('channelService');
let channel = channelService.getChannel(teamCode, true);
let users = channel.getMembers();
if (users.indexOf(roleId) === -1) {
channel.add(roleId, sid);
}
let uids = [];
uids.push({roleId, sid});
if (teammates) {
for (let teammate of teammates) {
let { roleId, sid } = teammate;
uids.push({uid: roleId, sid});
let users = channel.getMembers();
if (users.indexOf(roleId) === -1) {
channel.add(roleId, sid);
}
}
channelService.pushMessageByUids('onTeamJoin', {teamInfo: comTeam}, uids);
}
let thiz = this;
// 倒计时一定时间给队长匹配机器人
setTimeout(async () => {
let team = thiz.teamMap.get(teamCode);
if (team && team.roleIds && team.status === COM_TEAM_STATUS.DEFAULT && team.roleIds.length < 3) {
let { robotStArr, robotIdArr } = getRandComBtlRobots(topFiveCe, lv, 3 - team.roleIds.length);
team.roleIds = team.roleIds.concat(robotIdArr);
team.roleStatus = team.roleStatus.concat(robotStArr);
for (let st of robotStArr) {
await ComBattleTeamModel.addRole(teamCode, st);
}
channel.pushMessage('onTeamJoin', {teamInfo: team});
}
// TODO: 代码抽象
if (team && team.roleIds && team.roleIds.length === 3) {
let timer = setTimeout(async () => {
thiz.dismiss({teamCode}, session);
}, COM_BTL_CONST.CAP_START_TIME);
thiz.teamDisTimer.set(teamCode, timer);
}
}, COM_BTL_CONST.CAP_TIME);
if (team.roleIds && team.roleIds.length === 3) {
let timer = setTimeout(async () => {
thiz.dismiss({teamCode}, session);
}, COM_BTL_CONST.CAP_START_TIME);
thiz.teamDisTimer.set(teamCode, timer);
}
return resResult(STATUS.SUCCESS, { teamCode, roleStatus });
}
/**
* @description 匹配队伍
* @param {{qualityArr: [number]}} msg 要匹配的品质数组列表
* @param {BackendSession} session
* @returns
* @memberof ComBattleHandler
*/
async searchTeam(msg: {qualityArr: [number]}, session: BackendSession) {
let roleId = session.get('roleId');
let roleName = session.get('roleName');
let sid = session.get('sid');
const { qualityArr } = msg;
let { lv, headHid = 19, topFiveCe = 1000, sHid = 19 } = await RoleModel.findByRoleId(roleId);
for (let q of qualityArr) {
let setting = getComBtlSetByQuality(q);
if (lv < setting.assistanceLevel) {
return resResult(STATUS.COM_BATTLE_ASSIST_LV_NOT_ENOUGH);
}
}
const team = await ComBattleTeamModel.getOtherTeamByQualityAndSt(roleId, qualityArr, COM_TEAM_STATUS.DEFAULT, topFiveCe);
// TODO: 有匹配的队伍还需要重新 joinTeam 加入,有失败可能,体验不好,需优化
if (team && team.roleIds.length < 3 && team.status === COM_TEAM_STATUS.DEFAULT && team.roleIds.indexOf(roleId) === -1) {
return resResult(STATUS.SUCCESS, {teamCode: team.teamCode});
}
let teamCode = session.get('teamCode');
await setTeamSearchReq(roleId, sid, qualityArr);
let thiz = this;
// 倒计时匹配两个机器人
setTimeout(async () => {
let inQueue = await checkRoleInQueue(roleId, sid, qualityArr);
if (!inQueue) return;
await rmRoleFromQueue(roleId, sid, qualityArr);
let roleStatus = [];
let roleIds = [];
// 创建队伍
let blueprtId = getRandBlueprtId(qualityArr).pop();
let { quality } = getGoodById(blueprtId);
let { bossHpSum, bossHpArr } = getBossHpByBlueprtId(blueprtId);
let comTeam = new ComTeam(teamCode, false, blueprtId, COM_TEAM_STATUS.DEFAULT, 'robot', 0, bossHpSum || 10000, quality, transBossHpArr(bossHpArr));
let isFrd = await getFrd(roleId, quality);
// 将玩家加入队伍
let roleInfo = new RoleStatus(roleId, roleName, false, isFrd, headHid, sHid, topFiveCe, lv);
roleStatus.push(roleInfo);
roleIds.push(roleId);
// 创建并添加机器人
let { robotStArr, robotIdArr } = getRandComBtlRobots(topFiveCe, lv, 2);
roleStatus = roleStatus.concat(robotStArr);
roleIds = roleIds.concat(robotIdArr);
comTeam.roleStatus = roleStatus;
comTeam.roleIds = roleIds;
let channelService = thiz.app.get('channelService');
const team = await ComBattleTeamModel.createTeam(comTeam);
// if (!team) channelService.pushMessageByUids('onTeamJoin', {teamInfo: null}, [{uid: roleId, sid}]);
thiz.teamMap.set(teamCode, comTeam);
// 推送组队消息
channelService.pushMessageByUids('onTeamJoin', {teamInfo: comTeam}, [{uid: roleId, sid}]);
let channel = channelService.getChannel(teamCode, true);
let users = channel.getMembers();
if (users.indexOf(roleId) === -1) {
channel.add(roleId, sid);
}
// 机器人队伍 3 秒直接开战
setTimeout(async () => {
await ComBattleTeamModel.updateStatus(teamCode, COM_TEAM_STATUS.FIGHTING);
channelService.pushMessageByUids('onComBtlStart', {teamCode, roleStatus: comTeam.roleStatus}, [{uid: roleId, sid}]);
}, 3000);
}, COM_BTL_CONST.ASSIST_TIME);
return resResult(STATUS.SUCCESS);
}
/**
* @description 取消匹配
* @param {{}} msg
* @param {BackendSession} session
* @memberof ComBattleHandler
*/
async cancelSearch(msg: {}, session: BackendSession) {
let roleId = session.get('roleId');
let sid = session.get('sid');
await rmRoleFromQueue(roleId, sid, GOOD_QUALITY);
return resResult(STATUS.SUCCESS);
}
/**
* @description 当匹配 searchTeam 匹配到其它队伍时,需要调用此接口加入
* @param {{teamCode: string, isFrd: boolean}} msg 要加入的队伍编号,是否情谊助战
* @param {BackendSession} session
* @returns
* @memberof ComBattleHandler
*/
async joinTeam(msg: {teamCode: string, isFrd: boolean}, session: BackendSession) {
let roleId = session.get('roleId');
let roleName = session.get('roleName');
let sid = session.get('sid');
let { teamCode, isFrd } = msg;
let teamStatus = this.teamMap.get(teamCode);
if (!teamStatus || teamStatus.status !== COM_TEAM_STATUS.DEFAULT || teamStatus.roleIds.length === 3) return resResult(STATUS.COM_BATTLE_MEMBER_LIMIT);
if (teamStatus.roleIds.indexOf(roleId) !== -1) return resResult(STATUS.COM_BATTLE_DUP_ENTER);
let { lv = 1, headHid = 19, topFiveCe = 0, sHid = 19 } = await Role.findByRoleId(roleId);
let { quality } = getGoodById(teamStatus.blueprtId);
let { assistanceLevel, assistanceTime } = getComBtlSetByQuality(quality);
if (lv < COM_BTL_CONST.ENABLE_LV) {
return resResult(STATUS.COM_BATTLE_LV_NOT_ENOUGH);
} else if (lv < assistanceLevel) {
return resResult(STATUS.COM_BATTLE_ASSIST_LV_NOT_ENOUGH);
} else if (topFiveCe < teamStatus.ceLimit) {
return resResult(STATUS.COM_BATTLE_CE_LIMIT);
}
isFrd = await getFrd(roleId, quality);
// 加入队伍
let roleStatus = new RoleStatus(roleId, roleName, false, isFrd, headHid, sHid, topFiveCe, lv);
const team = await ComBattleTeamModel.addRole(teamCode, roleStatus);
if (!team || team.roleIds.length > 3) {
return resResult(STATUS.COM_BATTLE_JOIN_ERR);
}
// 推送队伍信息给所有玩家
let channelService = this.app.get('channelService');
let channel = channelService.getChannel(teamCode, false);
teamStatus.roleIds.push(roleId);
teamStatus.roleStatus.push(roleStatus);
let users = channel.getMembers();
if (users.indexOf(roleId) === -1) {
channel.add(roleId, sid);
}
channel.pushMessage('onTeamJoin', {teamInfo: teamStatus});
if (teamStatus.roleIds && teamStatus.roleIds.length === 3) {
let thiz = this;
let timer = setTimeout(async () => {
thiz.dismiss({teamCode}, session);
}, COM_BTL_CONST.CAP_START_TIME);
thiz.teamDisTimer.set(teamCode, timer);
}
return resResult(STATUS.SUCCESS, { teamInfo: teamStatus});
}
/**
* 获取队伍列表-deprecated
* @param msg
* @param session
*/
async getTeams(msg: { blueprtIds: Array<number> }, session: BackendSession) {
let roleId = session.get('roleId');
let { lv } = await Role.findByRoleId(roleId);
if (lv < COM_BTL_CONST.ENABLE_LV) return resResult(STATUS.COM_BATTLE_LV_NOT_ENOUGH);
const teams = await ComBattleTeamModel.getTeamByBlueprt(msg.blueprtIds, COM_TEAM_STATUS.DEFAULT, true);
if (!teams) return resResult(STATUS.COM_BATTLE_NO_VALID_TEAM);
return resResult(STATUS.SUCCESS, { teamInfos: teams});
}
/**
* @description 获取今日已助战次数
* @param {{}} msg
* @param {BackendSession} session
* @returns
* @memberof ComBattleHandler
*/
async getAssistCnt(msg: {}, session: BackendSession) {
let roleId = session.get('roleId');
let cntMap = await getAssistTimesByQuality(roleId);
let cnt = [];
for (let i = 0; i < 5; ++i) {
cnt[i] = cntMap.get(i + 1) || 0;
}
return resResult(STATUS.SUCCESS, {cnt});
}
/**
* @description 队伍准备-deprecate
* @param {{teamCode: string, heroes: Array<number>}} msg
* @param {BackendSession} session
* @returns
* @memberof ComBattleHandler
*/
async teammateReady(msg: {teamCode: string, heroes: Array<number>}, session: BackendSession) {
let roleId = session.get('roleId');
let { teamCode, heroes } = msg;
let teamStatus = this.teamMap.get(teamCode);
if (!teamStatus || !teamStatus.roleIds || teamStatus.roleIds.indexOf(roleId) === -1) return resResult(STATUS.COM_BATTLE_TEAM_INVALID);
let team = await ComBattleTeamModel.updateHeroes(teamCode, roleId, heroes);
if (!team) return resResult(STATUS.COM_BATTLE_UPDATE_HEROES_ERR);
teamStatus.roleStatus.forEach(st => {
if (st && st.roleId === roleId) {
st.heroes = heroes;
}
});
let channelService = this.app.get('channelService');
let channel = channelService.getChannel(teamCode, false);
channel.pushMessage('onTeammateReady', {teamCode, roleId, heroes});
return resResult(STATUS.SUCCESS);
}
/**
* @description 出兵时记录玩家阵容
* @param {{teamCode: string, heroes: Array<number>}} msg 队伍编号;阵容
* @param {BackendSession} session
* @returns
* @memberof ComBattleHandler
*/
async setupHeroes(msg: {teamCode: string, heroes: Array<number>, battleCode: string}, session: BackendSession) {
let roleId = session.get('roleId');
let { teamCode, heroes, battleCode = 'default' } = msg;
if (!heroes || heroes.length === 0) return resResult(STATUS.COM_BATTLE_HEROES_ERR);
let teamStatus = this.teamMap.get(teamCode);
if (!teamStatus || !teamStatus.roleIds || teamStatus.roleIds.indexOf(roleId) === -1) return resResult(STATUS.COM_BATTLE_TEAM_INVALID);
let team = await ComBattleTeamModel.setupBattleInfo(teamCode, roleId, heroes, battleCode);
if (!team) return resResult(STATUS.COM_BATTLE_UPDATE_HEROES_ERR);
teamStatus.roleStatus.forEach(st => {
if (st && st.roleId === roleId) {
st.heroes = heroes;
st.battleCode = battleCode;
}
});
let channelService = this.app.get('channelService');
let channel = channelService.getChannel(teamCode, false);
channel.pushMessage('onTeammateReady', {teamCode, roleId, heroes});
return resResult(STATUS.SUCCESS);
}
/**
* @description 从队伍中移除玩家
* @param {{teamCode: string, roleIdToRm: string}} msg 队伍编号;要移除的玩家 Id
* @param {BackendSession} session
* @returns
* @memberof ComBattleHandler
*/
async rmTeammate(msg: {teamCode: string, roleIdToRm: string}, session: BackendSession) {
let roleId = session.get('roleId');
let { teamCode, roleIdToRm } = msg;
let teamStatus = this.teamMap.get(teamCode);
if (!teamStatus || !teamStatus.roleIds || teamStatus.roleIds.indexOf(roleId) === -1) return resResult(STATUS.COM_BATTLE_TEAM_INVALID);
if (roleId === teamStatus.capId && roleId === roleIdToRm) return resResult(STATUS.COM_BATTLE_RM_SELF); // 队长移除自己视为解散,提示确认
// if (roleId !== teamStatus.capId && roleId !== roleIdToRm) return resResult(STATUS.COM_BATTLE_CAN_NOT_RM);
if (roleId !== teamStatus.capId) return resResult(STATUS.COM_BATTLE_CAP_ONLY); // 只有队长可以移除玩家
// 移除操作
let team = await ComBattleTeamModel.removeRole(teamCode, roleIdToRm);
if (!team) return resResult(STATUS.COM_BATTLE_RM_TEAMMATE_ERR);
let roleIdx = teamStatus.roleIds.indexOf(roleIdToRm);
teamStatus.roleIds.splice(roleIdx, 1);
teamStatus.roleStatus.some((elem, idx) => {
if (elem.roleId === roleIdToRm) {
teamStatus.roleStatus.splice(idx, 1);
}
});
// 推送移除消息
let channelService = this.app.get('channelService');
let channel = channelService.getChannel(teamCode, false);
let users = channel.getMembers();
if (users.indexOf(roleIdToRm) !== -1) {
channel.removeMember(roleIdToRm);
}
channel.pushMessage('onLeaveTeam', {teamCode, roleId: roleIdToRm});
clearComBtlTimer(teamCode, this.teamDisTimer); // 移除队员停止解散计时
let thiz = this;
setTimeout(async () => {
let team = thiz.teamMap.get(teamCode);
if (team && team.roleIds && team.status === COM_TEAM_STATUS.DEFAULT && team.roleIds.length < 3) {
let roleSt: RoleStatus;
for (let st of team.roleStatus) {
if (st.roleId === roleId) {
roleSt = st;
}
}
if (!roleSt) return;
let { topFiveCe, lv } = roleSt;
let { robotStArr, robotIdArr } = getRandComBtlRobots(topFiveCe, lv, 3 - team.roleIds.length);
team.roleIds = team.roleIds.concat(robotIdArr);
team.roleStatus = team.roleStatus.concat(robotStArr);
for (let st of robotStArr) {
await ComBattleTeamModel.addRole(teamCode, st);
}
channel.pushMessage('onTeamJoin', {teamInfo: team});
}
// TODO: 代码抽象
if (team && team.roleIds && team.roleIds.length === 3) {
let timer = setTimeout(async () => {
thiz.dismiss({teamCode}, session);
}, COM_BTL_CONST.CAP_START_TIME);
thiz.teamDisTimer.set(teamCode, timer);
}
}, COM_BTL_CONST.ASSIST_TIME);
return resResult(STATUS.SUCCESS);
}
/**
* @description 队长解散队伍
* @param {{teamCode: string}} msg 要解散的队伍编号
* @param {BackendSession} session
* @returns
* @memberof ComBattleHandler
*/
async dismiss(msg: {teamCode: string}, session: BackendSession) {
let roleId = session.get('roleId');
let { teamCode } = msg;
let teamStatus = this.teamMap.get(teamCode);
if (!teamStatus || !teamStatus.roleIds || teamStatus.roleIds.indexOf(roleId) === -1) return resResult(STATUS.COM_BATTLE_TEAM_INVALID);
if (roleId !== teamStatus.capId) return resResult(STATUS.COM_BATTLE_CAP_ONLY);
let team = await ComBattleTeamModel.removeTeam(teamCode);
if (!team) return resResult(STATUS.COM_BATTLE_DISSMISS_ERR);
let rmSt = this.teamMap.delete(teamCode);
if (!rmSt) return resResult(STATUS.COM_BATTLE_DISSMISS_ERR);
let channelService = this.app.get('channelService');
let channel = channelService.getChannel(teamCode, false);
channel.pushMessage('onTeamDismiss', {teamCode});
channel.destroy();
clearComBtlTimer(teamCode, this.teamDisTimer); // 队伍解散停止解散计时
return resResult(STATUS.SUCCESS);
}
/**
* @description 开始战斗,队长操作或机器人队伍操作
* @param {{teamCode: string}} msg 队伍编号
* @param {BackendSession} session
* @returns
* @memberof ComBattleHandler
*/
async startBattle(msg: {teamCode: string}, session: BackendSession) {
let roleId = session.get('roleId');
let { teamCode } = msg;
let teamStatus = this.teamMap.get(teamCode);
if (!teamStatus || !teamStatus.roleIds || teamStatus.roleIds.indexOf(roleId) === -1) return resResult(STATUS.COM_BATTLE_TEAM_INVALID);
if (teamStatus.capId !== roleId && teamStatus.capId !== 'robot') return resResult(STATUS.COM_BATTLE_CAP_ONLY);
if (teamStatus.status !== COM_TEAM_STATUS.DEFAULT) return resResult(STATUS.COM_BATTLE_ALREADY_START);
teamStatus.status = COM_TEAM_STATUS.FIGHTING;
let team = await ComBattleTeamModel.updateStatus(teamCode, COM_TEAM_STATUS.FIGHTING);
if (!team) return resResult(STATUS.COM_BATTLE_START_ERR);
clearComBtlTimer(teamCode, this.teamDisTimer); // 战斗开始停止解散计时
let channelService = this.app.get('channelService');
let channel = channelService.getChannel(teamCode, false);
channel.pushMessage('onComBtlStart', {teamCode, roleStatus: teamStatus.roleStatus});
// 每场倒计时结算
let thiz = this;
setTimeout(async () => {
let teamStatus = thiz.teamMap.get(teamCode);
if (teamStatus && teamStatus.status === COM_TEAM_STATUS.FIGHTING) {
let channelService = thiz.app.get('channelService');
let channel = channelService.getChannel(teamCode, false);
let team = await ComBattleTeamModel.syncTeamData({teamCode, status: COM_TEAM_STATUS.LOOSE, roleStatus: teamStatus.roleStatus, bossHpArr: teamStatus.bossHpArr});
if (!team) return resResult(STATUS.COM_BATTLE_RESULT_ERR);
channel.pushMessage('onTeamComplete', {teamCode, result: false});
thiz.teamMap.delete(teamCode);
}
}, COM_BTL_CONST.BTL_TIME_LMT);
return resResult(STATUS.SUCCESS);
}
/**
* @description 战场中的状态同步,战斗结果判定
* @param {{teamCode: string, bossHurts: Array<{dataId: number, hurtHp: number}>, killed: Array<number>, curRnd: number}} msg 队伍编号boss 承伤;武将阵亡;当前回合
* @param {BackendSession} session
* @returns
* @memberof ComBattleHandler
*/
async action(msg: {teamCode: string, bossHurts: Array<{dataId: number, hurtHp: number}>, killed: Array<number>, curRnd: number}, session: BackendSession) {
let roleId = session.get('roleId');
let { teamCode, killed, bossHurts, curRnd } = msg;
let teamStatus = this.teamMap.get(teamCode);
if (!teamStatus || !teamStatus.roleIds || teamStatus.roleIds.indexOf(roleId) === -1) return resResult(STATUS.COM_BATTLE_TEAM_INVALID);
if (teamStatus.status !== COM_TEAM_STATUS.FIGHTING) return resResult(STATUS.COM_BATTLE_NOT_START);
for (let st of teamStatus.roleStatus) {
if (st.roleId === roleId && (!st.heroes || st.heroes.length === 0)) {
return resResult(STATUS.COM_BATTLE_HEROES_ERR);
}
}
// 重置总血量,计算真实伤害
let totalHurtHp = 0;
teamStatus.bossHpArr.forEach(boss => {
for (let bh of bossHurts) {
if (boss.dataId === bh.dataId && bh.hurtHp < 0) {
let deltaHp = Math.abs(bh.hurtHp);
if (boss.curHp >= deltaHp) {
totalHurtHp += deltaHp;
boss.curHp -= deltaHp;
} else if (boss.curHp > 0) {
totalHurtHp += boss.curHp;
boss.curHp = 0;
}
}
}
});
// 更新玩家武将阵亡情况,计算玩家总伤害,计算机器人造成的伤害
teamStatus.roleStatus.forEach(roleSt => {
if (roleSt.roleId === roleId) {
if (killed && killed.length) {
killed.forEach(killedHid => {
if (roleSt.killed.indexOf(killedHid) === -1 && roleSt.heroes.indexOf(killedHid) !== -1) {
roleSt.killed.push(killedHid);
}
});
}
roleSt.totalDmg += totalHurtHp;
} else if (curRnd > teamStatus.curRnd && curRnd <= COM_BTL_CONST.ROBOT_RND_LMT && roleSt.isRobot) {
// 机器人的伤害为boss 血量的一定比例,平均到一定回合数内,再平均到每个敌军,上下浮动一定比例
let eachHurtHp = getRandValue(teamStatus.bossHp / COM_BTL_CONST.ROBOT_RND_LMT * COM_BTL_CONST.ROBOT_HURT_RATIO / 5, COM_BTL_CONST.ROBOT_HURT_CH_RATIO, 0);
let robotTotalHurt = 0;
teamStatus.bossHpArr.forEach(boss => {
if (boss.curHp >= eachHurtHp) {
robotTotalHurt += eachHurtHp;
boss.curHp -= eachHurtHp;
} else if (boss.curHp > 0) { // 丢弃溢出的伤害
robotTotalHurt += boss.curHp;
boss.curHp = 0;
}
});
teamStatus.bossCurHp -= robotTotalHurt;
roleSt.totalDmg += robotTotalHurt;
// 输出回合一到机器人武将集体阵亡
if (curRnd === COM_BTL_CONST.ROBOT_RND_LMT) {
roleSt.killed === roleSt.heroes;
}
}
});
teamStatus.curRnd = curRnd;
teamStatus.bossCurHp -= totalHurtHp;
if (teamStatus.bossCurHp < 0) teamStatus.bossCurHp = 0;
// 推送本次行动情况
let channelService = this.app.get('channelService');
let channel = channelService.getChannel(teamCode, false);
const roleStatus = teamStatus.roleStatus.map(st => {return {roleId: st.roleId, totalDmg: st.totalDmg, killed: st.killed}});
channel.pushMessage('onTeammateAct', {teamCode, bossCurHp: teamStatus.bossCurHp, bossHpArr: teamStatus.bossHpArr, roleStatus});
// 判断战斗是否结束
let battleSt = checkComBattleResult(teamStatus);
teamStatus.status = battleSt;
if (battleSt === COM_TEAM_STATUS.WIN || battleSt === COM_TEAM_STATUS.LOOSE) {
let result = battleSt === COM_TEAM_STATUS.WIN;
if (result) {
teamStatus.bossHpArr.forEach(bs => {
bs.curHp = 0;
});
for (let st of teamStatus.roleStatus) {
st.fixReward = await getRealReward(teamStatus.blueprtId, st);
};
}
let team = await ComBattleTeamModel.syncTeamData({teamCode, status: battleSt, roleStatus: teamStatus.roleStatus, bossHpArr: teamStatus.bossHpArr});
if (!team) return resResult(STATUS.COM_BATTLE_RESULT_ERR);
// 战斗胜利队长扣减藏宝图
if (result && teamStatus.capId != 'robot') {
let res = await ItemModel.decreaseItems(teamStatus.capId, [{id: teamStatus.blueprtId, count: 1}]);
if (res.hasError) return resResult(STATUS.COM_BATTLE_BLUEPRT_NOT_ENOUGH);
}
channel.pushMessage('onTeamComplete', {teamCode, result});
this.teamMap.delete(teamCode);
}
return resResult(STATUS.SUCCESS);
}
/**
* 客户端给服务器的战斗结束通知-deprecated
* @param msg
* @param session
*/
async battleEnd(msg: {teamCode: string, isSuccess: boolean}, session: BackendSession) {
let roleId = session.get('roleId');
let { teamCode, isSuccess } = msg;
let teamStatus = this.teamMap.get(teamCode);
if (!teamStatus || !teamStatus.roleIds || teamStatus.roleIds.indexOf(roleId) === -1) return resResult(STATUS.COM_BATTLE_TEAM_INVALID);
let channelService = this.app.get('channelService');
let channel = channelService.getChannel(teamCode, false);
if (isSuccess && teamStatus.bossCurHp <= 0) {
let team = await ComBattleTeamModel.updateResult(teamCode, roleId, isSuccess);
if (!team) return resResult(STATUS.COM_BATTLE_RESULT_ERR);
channel.pushMessage('onTeamComplete', {teamCode, result: isSuccess});
} else if (!isSuccess) {
let team = await ComBattleTeamModel.updateResult(teamCode, roleId, isSuccess);
if (!team) return resResult(STATUS.COM_BATTLE_RESULT_ERR);
if (team.status === COM_TEAM_STATUS.LOOSE) {
channel.pushMessage('onTeamComplete', {teamCode, result: isSuccess});
} else {
channel.pushMessage('onTeammateAct', {teamCode, bossCurHp: teamStatus.bossCurHp, roleStatus: {roleId, battleStatus: 2}});
}
}
return resResult(STATUS.SUCCESS, { bossCurHp: teamStatus.bossCurHp });
}
/**
* @description 寻宝结算
* @param {{teamCode: string}} msg 寻宝队伍编号
* @param {BackendSession} session
* @returns 掉落物品和玩家升级信息
* @memberof ComBattleHandler
*/
async comBattleEnd(msg: {teamCode: string}, session: BackendSession) {
let roleId = session.get('roleId');
let roleName = session.get('roleName');
let sid = session.get('sid');
let { teamCode } = msg;
let team = await ComBattleTeamModel.getTeamByCode(teamCode);
if (!team || team.status !== COM_TEAM_STATUS.WIN) return resResult(STATUS.COM_BATTLE_REWARD_ERR);
let { roleStatus, blueprtId, status, bossHpArr } = team;
let roleSt: RoleStatus = null;
roleStatus.forEach(st => {
if (st && st.roleId === roleId) {
roleSt = st;
}
});
if (roleSt.gotReward) return resResult(STATUS.COM_BATTLE_REWARDED);
let warInfo = getWarById(getWarIdByBlueprtId(blueprtId));
if (!warInfo) return resResult(STATUS.BATTLE_MISS_INFO);
if(!warInfo.hasOwnProperty('cost')) {
warInfo['cost'] = 0;
}
const now = Date.now(); // 当前时间戳
let apJson = await setAp(now, roleId, -1 * warInfo.cost); // 扣除体力
if(!apJson) {
return resResult(STATUS.BATTLE_ACTION_POINT_LACK);
}
await ComBattleTeamModel.updateRewardSt(teamCode, roleId, true);
const goods = await handleFixedReward(roleId, roleName, sid, roleSt.fixReward, 1);
let actordata = await roleLevelup(roleId, warInfo.kingExp, this.app, session);// 主公升级经验
return resResult(STATUS.SUCCESS, { goods, ...actordata, teamInfo: {status, teamCode, roleStatus, bossHpArr} });
}
async getComBtlStatus(msg: {teamCode: string}, session: BackendSession) {
let { teamCode } = msg;
let roleStatus, status, bossHpArr;
let memTeam = this.teamMap.get(teamCode);
if (memTeam) {
({ roleStatus, status, bossHpArr } = memTeam);
} else {
({ roleStatus, status, bossHpArr } = await ComBattleTeamModel.getTeamByCode(teamCode));
}
return resResult(STATUS.SUCCESS, { teamInfo: {status, teamCode, roleStatus, bossHpArr} });
}
/**
* @description 获取自己一段时间内的寻宝记录
* @param {{}} msg
* @param {BackendSession} session
* @returns
* @memberof ComBattleHandler
*/
async getTeamRec(msg: {}, session: BackendSession) {
let roleId = session.get('roleId');
let teams = await ComBattleTeamModel.getTeamByRoleAndTime(roleId, null, new Date(new Date().setHours(0, 0, 0, 0) - 2 * 24 * 60 * 60 * 1000));
if (!teams) return resResult(STATUS.COM_BATTLE_NO_RECENT_REC);
return resResult(STATUS.SUCCESS, {teamInfos: teams});
}
/**
* @description 获取藏宝图数量
* @param {{ids: Array<number>}} msg 藏宝图Id数组可选参数
* @param {BackendSession} session
* @returns
* @memberof ComBattleHandler
*/
async getBlueprtCount(msg: {ids: Array<number>}, session: BackendSession) {
let roleId = session.get('roleId');
let { ids } = msg;
let blueprts;
if (ids && ids.length) {
blueprts = await ItemModel.findbyRoleAndIds(roleId, ids);
} else {
blueprts = await ItemModel.findByRoleAndType(roleId, CONSUME_TYPE.BLUEPRT);
}
return resResult(STATUS.SUCCESS, { blueprts });
}
/**
* @description 藏宝图合成
* @param {{original: Array<{id: number, count: number}>}} msg
* @param {BackendSession} session
* @returns
* @memberof ComBattleHandler
*/
async composeBlueprt(msg: {original: Array<{id: number, count: number}>}, session: BackendSession) {
const roleId = session.get('roleId');
const roleName = session.get('roleName');
const sid = session.get('sid');
const { original } = msg;
// 原材料检查
let originalQuality: number, originalSum: number = 0;
for(let {id, count} of original) {
const goodInfo = getGoodById(id);
if(!originalQuality) originalQuality = goodInfo.quality;
if(originalQuality != goodInfo.quality) {
return resResult(STATUS.COM_BLUEPRT_QUALITY_ERROR);
}
if(goodInfo.itid == IT_TYPE.BLUEPRT) {
originalSum += count;
}
}
const dicCompose = getBlueprtComposeByQuality(originalQuality);
if(!dicCompose) {
return resResult(STATUS.COM_BLUEPRT_QUALITY_CANNOT_COMPOSE);
}
if(originalSum != dicCompose.blueprtNum) {
return resResult(STATUS.COM_BLUEPRT_COUNT_ERROR);
}
// 添加寻宝币
original.push({
id: CURRENCY_BY_TYPE.get(CURRENCY_TYPE.TREASURE_POINT),
count: dicCompose.coinNum
});
// 消耗藏宝图和寻宝币
const rec = await ItemModel.decreaseItems(roleId, original);
if(rec.hasError) {
return resResult(STATUS.BATTLE_CONSUMES_NOT_ENOUGH);
}
const targetList = getBluePrtByQuality(dicCompose.targetQuality);
const target = getRandomByLen(targetList);
const reward = [{gid: target, count: 1}];
const goods = await addItems(roleId, roleName, sid, reward);
return resResult(STATUS.SUCCESS, { goods, costGold: 0 });
}
}