Files
ZYZ/game-server/app/servers/battle/handler/comBattleHandler.ts
2020-11-30 18:12:23 +08:00

670 lines
31 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-11-30 18:08:49
*/
import { COM_BATTLE_ROBOT_CE_RATIO, COM_BATTLE_ROBOT_ID_NAME, COM_BATTLE_ASSIST_TIME, COM_BATTLE_ROBOT_ROUND_LMT, COM_BATTLE_ROBOT_HURT_RATIO, COM_BATTLE_ROBOT_HURT_CH_RATIO, COM_TEAM_STATUS } from './../../../consts/consts';
import { IT_TYPE, GOLD_COST_RATIO, CURRENCY_BY_TYPE, CURRENCY_TYPE } from '../../../consts/consts';
import { getGoodById, getBossHpByBlueprtId, getComBtlSetByQuality, getBlueprtComposeByQuality, getBluePrtByQuality } from '../../../pubUtils/gamedata';
import { COM_TEAM_ENABLE_LV } from '../../../consts/consts';
import { ComBattleTeamModel } from '../../../db/ComBattleTeam';
import Role, { RoleModel } from '../../../db/Role';
import { STATUS } from '../../../consts/statusCode';
import { Application, BackendSession } from 'pinus';
import { resResult, getRandomByLen, calculateNum, getRandValue } from '../../../pubUtils/util';
import { RoleStatus } from '../../../db/ComBattleTeam';
import { ItemModel } from '../../../db/Item';
import { handleReward } from '../../../services/rewardService';
import { getTeamSearchByQuality, setTeamSearchReq } from '../../../services/redisService';
import { getRandRobot, transBossHpArr } from '../../../services/battleService';
import { getRandBlueprtId } from '../../../services/comBattleService';
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<{dataId: number, hp: number, curHp: number}>;
// 品质
quality: number;
// 当前回合
curRnd: number;
constructor(teamCode: string, pub: boolean, blueprtId: number, status: number, capId: string, ceLimit: number, bossHp: number, quality: number, bossHpArr:Array<{dataId: number, hp: number, curHp: number}> ) {
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;
}
}
export class ComBattleHandler {
constructor(private app: Application) {
}
private teamMap: Map<string, ComTeam> = 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, sHid = 19 } = await RoleModel.findByRoleId(roleId);
if (lv < COM_TEAM_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);
console.log('teammates: ', teammates);
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;
// TODO: 没处理情谊助战
const st = new RoleStatus(roleId, roleName, false, false, 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();
for (let roleId of roleIds) {
if (users.indexOf(roleId) === -1) {
channel.add(roleId, sid);
}
}
if (teammates) {
let uids = [];
for (let teammate of teammates) {
let { roleId, sid } = teammate;
uids.push({uid: roleId, sid});
}
// TODO: 处理助战 timer
channelService.pushMessageByUids('onTeamJoin', {teamInfo: comTeam}, uids);
}
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);
const team = await ComBattleTeamModel.getOneTeamByQualityAndSt(qualityArr, COM_TEAM_STATUS.DEFAULT, topFiveCe);
// TODO: 有匹配的队伍还需要重新 joinTeam 加入,有失败可能,体验不好,需优化
if (team) {
return resResult(STATUS.SUCCESS, {teamCode: team.teamCode});
}
let teamCode = session.get('teamCode');
await setTeamSearchReq(roleId, sid, qualityArr);
let thiz = this;
// 倒计时匹配两个机器人
setTimeout(async () => {
let roleStatus = [];
let roleIds = []
let robotHeroes = getRandRobot(2); // 随机两个阵容
let roleInfo = new RoleStatus(roleId, roleName, false, false, headHid, sHid, topFiveCe, lv);
roleStatus.push(roleInfo);
roleIds.push(roleId);
let blueprtId = (await 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));
// 创建并添加机器人
for (let robot of robotHeroes) {
const robotCe = getRandValue(topFiveCe, COM_BATTLE_ROBOT_CE_RATIO, 0);
const robotLv = getRandValue(lv, COM_BATTLE_ROBOT_CE_RATIO, 0);
const imgHid = robot[Math.floor(Math.random() * robot.length)];
const { robotRoleId, robotRoleName } = COM_BATTLE_ROBOT_ID_NAME[Math.floor(Math.random() * COM_BATTLE_ROBOT_ID_NAME.length)];
let robotStatus = new RoleStatus(robotRoleId, robotRoleName, false, false, imgHid, imgHid, robotCe, robotLv, robot, true);
roleStatus.push(robotStatus);
roleIds.push(robotRoleId);
}
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);
}
}, COM_BATTLE_ASSIST_TIME);
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');
console.log('teamMap:' + JSON.stringify(this.teamMap));
let { teamCode, isFrd } = msg;
let teamStatus = this.teamMap.get(teamCode);
if (!teamStatus || teamStatus.status !== 0 || 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_TEAM_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);
}
let teams = await ComBattleTeamModel.getTeamByRoleAndTime(roleId, teamStatus.quality, new Date(new Date().setHours(0, 0, 0, 0)), true);
if (teams.length >= assistanceTime) resResult(STATUS.COM_BATTLE_ASSIST_NOT_ENOUGH);
// 加入队伍
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);
channel.pushMessage('onTeamJoin', {teamInfo: teamStatus});
let users = channel.getMembers();
if (users.indexOf(roleId) === -1) {
channel.add(roleId, sid);
}
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_TEAM_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 teams = await ComBattleTeamModel.getTeamByRoleAndTime(roleId, null, new Date(new Date().setHours(0, 0, 0, 0)), true);
let cnt = [0, 0, 0, 0, 0];
teams.forEach(team => {
if (team && team.quality) {
cnt[team.quality - 1] += 1;
}
});
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>}, 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, 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});
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();
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);
let channelService = this.app.get('channelService');
let channel = channelService.getChannel(teamCode, false);
channel.pushMessage('onComBtlStart', {teamCode, roleStatus: teamStatus.roleStatus});
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);
// 重置总血量,计算真实伤害
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 {
totalHurtHp += deltaHp;
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.killed.push(killedHid);
}
});
}
roleSt.totalDmg += totalHurtHp;
} else if (curRnd > teamStatus.curRnd && curRnd <= COM_BATTLE_ROBOT_ROUND_LMT && roleSt.isRobot) {
// 机器人的伤害为boss 血量的一定比例,平均到一定回合数内,再平均到每个敌军,上下浮动一定比例
let eachHurtHp = getRandValue(teamStatus.bossHp / COM_BATTLE_ROBOT_ROUND_LMT * COM_BATTLE_ROBOT_HURT_RATIO / 5, COM_BATTLE_ROBOT_HURT_CH_RATIO, 0);
let robotTotalHurt = 0;
teamStatus.bossHpArr.forEach(boss => {
if (boss.curHp >= eachHurtHp) {
robotTotalHurt += eachHurtHp;
boss.curHp -= eachHurtHp;
} else { // 丢弃溢出的伤害
robotTotalHurt += boss.curHp;
boss.curHp = 0;
}
});
teamStatus.bossCurHp -= robotTotalHurt;
roleSt.totalDmg += robotTotalHurt;
// 输出回合一到机器人武将集体阵亡
if (curRnd === COM_BATTLE_ROBOT_ROUND_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});
// 判断战斗是否结束
if (teamStatus.bossCurHp === 0) {
let team = await ComBattleTeamModel.syncTeamData({teamCode, status: COM_TEAM_STATUS.WIN, roleStatus: teamStatus.roleStatus});
if (!team) return resResult(STATUS.COM_BATTLE_RESULT_ERR);
channel.pushMessage('onTeamComplete', {teamCode, result: true});
} else {
let allPlayerKilled = true;
let robotRestHurt = 0;
// 看看是否还有活人
teamStatus.roleStatus.forEach(st => {
if (!st.isRobot && st.killed.length < st.heroes.length) {
allPlayerKilled = false
}
});
// 没有活人的话看看还有没有机器人没打完伤害
if (allPlayerKilled && teamStatus.curRnd < COM_BATTLE_ROBOT_ROUND_LMT) {
teamStatus.roleStatus.forEach(st => {
if (st.isRobot) {
const deltaRnd = COM_BATTLE_ROBOT_ROUND_LMT - teamStatus.curRnd;
let hurtHp = getRandValue(teamStatus.bossHp / COM_BATTLE_ROBOT_ROUND_LMT * COM_BATTLE_ROBOT_HURT_RATIO, COM_BATTLE_ROBOT_HURT_CH_RATIO, 0) * deltaRnd; // 1 个机器人对 boss 造成的总伤害
robotRestHurt += hurtHp;
}
})
}
if (allPlayerKilled) {
// 没有活人且机器人剩余伤害打不死 boss战败
if (teamStatus.bossCurHp > robotRestHurt) {
let team = await ComBattleTeamModel.syncTeamData({teamCode, status: COM_TEAM_STATUS.LOOSE, roleStatus: teamStatus.roleStatus});
if (!team) return resResult(STATUS.COM_BATTLE_RESULT_ERR);
channel.pushMessage('onTeamComplete', {teamCode, result: false});
} else {
let team = await ComBattleTeamModel.syncTeamData({teamCode, status: COM_TEAM_STATUS.WIN, roleStatus: teamStatus.roleStatus});
if (!team) return resResult(STATUS.COM_BATTLE_RESULT_ERR);
channel.pushMessage('onTeamComplete', {teamCode, result: true});
}
}
}
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);
// TODO: 根据策划结论考虑是否在推送中添加掉落
// TODO: 用户总伤害等的持久化
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 {{}} 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 {{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 { 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);
}
// 检查元宝
const role = await RoleModel.findByRoleId(roleId);
const costGold = calculateNum(GOLD_COST_RATIO.BLUEPRT_COMPOSE_COST, {num: originalQuality}, 1000);
if(!role || role.gold < costGold) {
return resResult(STATUS.TOWER_GOLD_NOT_ENOUGH);
}
// 添加寻宝币
original.push({
id: CURRENCY_BY_TYPE.get(CURRENCY_TYPE.TREASURE_POINT),
count: dicCompose.coinNum
});
// 消耗藏宝图和寻宝币
const rec = await ItemModel.decreaseItems(roleId, original);
if(!rec) {
return resResult(STATUS.BATTLE_CONSUMES_NOT_ENOUGH);
}
// 消耗元宝
await RoleModel.costGold(roleId, costGold);
const targetList = getBluePrtByQuality(dicCompose.targetQuality);
const target = getRandomByLen(targetList);
const reward = [{gid: target, count: 1}];
const goods = await handleReward(roleId, roleName, reward);
return resResult(STATUS.SUCCESS, { ...goods, costGold });
}
}