670 lines
31 KiB
TypeScript
670 lines
31 KiB
TypeScript
/*
|
||
* @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 });
|
||
}
|
||
}
|