Files
ZYZ/game-server/app/servers/comBattle/handler/comBattleHandler.ts
2026-03-13 01:38:40 +00:00

833 lines
39 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.
import { ComBattleInvitation, MemComBtlTeam } from '@domain/battleField/ComBattleTeamField';
import { difference, pick } from 'underscore';
/*
* @Author: 梁桐川
* @Date: 2020-11-30 15:05:48
* @Last Modified by: 梁桐川
* @Last Modified time: 2021-08-27 17:47:56
*/
import { IT_TYPE, CURRENCY_BY_TYPE, CURRENCY_TYPE, COM_TEAM_STATUS, COM_BTL_CONST, CONSUME_TYPE, MSG_SOURCE, ROLE_SELECT, TASK_TYPE, KING_EXP_RATIO_TYPE, ITEM_CHANGE_REASON, getChannelType, CHANNEL_PREFIX, DEBUG_MAGIC_WORD, PUSH_ROUTE, POPULATE_TYPE } from '../../../consts';
import Role, { RoleModel } from '@db/Role';
import { STATUS } from '@consts/statusCode';
import { Application, BackendSession } from 'pinus';
import { resResult, getRandSingleEelm, cal } from '@pubUtils/util';
import { RoleStatus, ComBattleTeamModel, ComBattleTeamType, BossHp, ComRoleStatusHero } from '@db/ComBattleTeam';
import { ItemModel, ItemType } from '@db/Item';
import { addItems, handleCost } from '../../../services/role/rewardService';
import { checkRoleInQueue, getServerName, redisClient, rmCreatedTeamFromRedis, rmRoleFromQueue, setTeamSearchReq } from '../../../services/redisService';
import { getRandBlueprtId, getFrd, updateRobotHurtByTime, comBtlLvInvalid, clearRobotHurtTimer, setDismissTimer, dismissTeam, handleComBtlProgress, getComBattleFriendAdd, teammateInBlackList, blueprtIdValid, hasEnoughBlueprt, addRoleToTeam, addRoleStToTeam, addValidSearchingRoles, validToJoin, addRobotsToTeam, addRobotsLater, teamIsFullToStart, oneTeamNotInBlack, getAllAssistCnt, checkHasMyTeam, checkTeamStatusAndSend, getComBtlLvByPlayerLv, addToSearchingTeams, getCapFrd, getCapExtraCnt, startTeam } from '../../../services/battle/comBattleService';
import { setAp } from '../../../services/actionPointService';
import { roleLevelup } from '../../../services/normalBattleService';
import { getSimpleRoleInfo } from '../../../services/roleService';
import { pushComBtlTeamMsg, pushFriendTeamInviteMsg, pushNormalItemMsg, pushTeamInviteMsg } from '../../../services/chatService';
import { EXTERIOR, INFO_WINDOW } from '@pubUtils/dicParam';
import { getZeroPointD, getTimeFunD, getSeconds, nowSeconds } from '@pubUtils/timeUtil';
import { FriendParams } from '@domain/roleField/friend';
import { checkTask, checkTaskInComBattleStart } from '../../../services/task/taskService';
import { gameData, getWarByBlueprtId } from '@pubUtils/data';
import { HeroModel } from '@db/Hero';
import { addUserToTeamChannel, delTeamChannel, removeFromTeamChannel, sendMessageToTeam, sendMessageToUsersWithSuc, sendMessageToUserWithSuc } from '../../../services/pushService';
import { getFriendRelationType, getRecommendType } from '../../../services/friendService';
import { FriendRelationModel } from '@db/FriendRelation';
import { isHeroHidden } from '../../../services/dataService';
import { addComTeam, clearComBtlTimer,deleteComBattle,getComTeamByCode } from '../../../services/memoryCache/comBattleData';
import { clearComBattleRoute } from '@pubUtils/dispatcher';
export default function(app: Application) {
return new ComBattleHandler(app);
}
export class ComBattleHandler {
constructor(private app: Application) {
}
/**
* @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 sid = session.get('sid');
let teamCode = session.get('teamCode');
const { blueprtId, pub, ceLimit } = msg;
// console.log('createTeam msg: ', msg);
// 检查藏宝图Id是否合法
if (!blueprtIdValid(blueprtId)) return resResult(STATUS.COM_BATTLE_BLUEPRT_INVALID);
const enoughBlueprt = await hasEnoughBlueprt(roleId, sid, blueprtId);
if (!enoughBlueprt) return resResult(STATUS.COM_BATTLE_BLUEPRT_NOT_ENOUGH);
const roleInfo = await RoleModel.findByRoleId(roleId, null, true);
const { lv, topLineupCe } = roleInfo;
if (lv < COM_BTL_CONST.ENABLE_LV) return resResult(STATUS.COM_BATTLE_LV_NOT_ENOUGH);
if(ceLimit && ceLimit > topLineupCe * (1 + COM_BTL_CONST.ROBOT_CE_RATIO)) {
return resResult(STATUS.COM_BATTLE_CREATE_CE_LIMIT)
}
// 创建队伍数据结构
let comTeam = new MemComBtlTeam(teamCode, pub, blueprtId, roleId, ceLimit, sid);
let isFrd = await getCapFrd(roleId);
addRoleToTeam(comTeam, roleInfo, sid, true, isFrd);
addUserToTeamChannel(teamCode, true, roleId, sid);
// 将正在匹配的符合要求的玩家加入队伍,并推送入队消息
if(pub == true) await addValidSearchingRoles(comTeam);
// 队伍数据持久化
const team = await ComBattleTeamModel.createTeam(comTeam);
if (!team) {
delTeamChannel(teamCode);
return resResult(STATUS.COM_BATTLE_CREATE_ERR);
}
addComTeam(teamCode, comTeam)
// 倒计时一定时间给队长匹配机器人
if (pub === true) {
await addRobotsLater(comTeam, roleInfo);
}
setDismissTimer(comTeam, roleId);
return resResult(STATUS.SUCCESS, { teamCode, roleStatus: comTeam.roleStatus });
}
/**
* @description 匹配队伍
* @param {{ lv: number }} msg 要匹配藏宝图品阶
* @param {BackendSession} session
* @returns
* @memberof ComBattleHandler
*/
async searchTeam(msg: { lv: number[], magicWord: string }, session: BackendSession) {
let roleId = session.get('roleId');
let sid = session.get('sid');
const { lv: lvs = [], magicWord } = msg;
const roleInfo = await RoleModel.findByRoleId(roleId, null, true);
const { lv: playerLv } = roleInfo;
let { topLineupCe = 1000 } = roleInfo;
if(await checkHasMyTeam(roleId) && magicWord != DEBUG_MAGIC_WORD) {
return resResult(STATUS.COM_BATTLE_IS_RUNNING);
}
if (comBtlLvInvalid(playerLv, lvs)) {
return resResult(STATUS.COM_BATTLE_ASSIST_LV_NOT_ENOUGH);
}
const teams = await ComBattleTeamModel.getOtherTeamByLvAndSt(roleId, lvs, COM_TEAM_STATUS.DEFAULT, topLineupCe);
const team: ComBattleTeamType = await oneTeamNotInBlack(teams, roleId);
if (team && team.roleIds.length < 3 && team.status === COM_TEAM_STATUS.DEFAULT && team.roleIds.indexOf(roleId) === -1 && team.blacklist && team.blacklist.indexOf(roleId) === -1) {
return resResult(STATUS.SUCCESS, {teamCode: team.teamCode});
}
let teamCode = session.get('teamCode');
let hasAdd = await addToSearchingTeams(roleId, sid, lvs);
if(hasAdd) return(STATUS.SUCCESS);
await setTeamSearchReq(roleId, sid, lvs);
let thiz = this;
// 倒计时匹配两个机器人
setTimeout(async () => {
let inQueue = await checkRoleInQueue(roleId, sid, lvs);
if (!inQueue) return;
await rmRoleFromQueue(roleId, sid, lvs);
// 创建队伍
let blueprtId = getRandBlueprtId(lvs).pop();
let comTeam = new MemComBtlTeam(teamCode, false, blueprtId, 'robot', 0, '')
let isFrd = await getFrd(roleId);
// 将玩家加入队伍
addRoleToTeam(comTeam, roleInfo, sid, false, isFrd);
addUserToTeamChannel(teamCode, true, roleId, sid);
// 创建并添加机器人
await addRobotsToTeam(comTeam, roleId, topLineupCe, playerLv, 2);
await ComBattleTeamModel.createTeam(comTeam);
addComTeam(teamCode, comTeam);
// 机器人队伍 3 秒直接开战
setTimeout(async () => {
thiz.startBattle({teamCode}, session);
}, 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);
let teamCode = session.get('teamCode');
if(teamCode) clearComBattleRoute(redisClient(), teamCode);
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 sid = session.get('sid');
let { teamCode, isFrd } = msg;
let teamStatus = getComTeamByCode(teamCode);
if (!teamStatus) return resResult(STATUS.COM_BATTLE_TEAM_INVALID);
if(teamStatus.status !== COM_TEAM_STATUS.DEFAULT) return resResult(STATUS.COM_BATTLE_TEAM_NOT_DEFAULT);
if (teamIsFullToStart(teamStatus)) return resResult(STATUS.COM_BATTLE_MEMBER_LIMIT);
if (teamStatus.roleIds.indexOf(roleId) !== -1) return resResult(STATUS.COM_BATTLE_DUP_ENTER);
if (teamStatus.blacklist.indexOf(roleId) != -1) return resResult(STATUS.COM_BATTLE_BE_KICKED);
let role = await Role.findByRoleId(roleId, null, true);
if (role.lv < COM_BTL_CONST.ENABLE_LV) return resResult(STATUS.COM_BATTLE_LV_NOT_ENOUGH);
if (comBtlLvInvalid(role.lv, [teamStatus.lv])) return resResult(STATUS.COM_BATTLE_ASSIST_LV_NOT_ENOUGH);
if (role.topLineupCe < teamStatus.ceLimit) return resResult(STATUS.COM_BATTLE_CE_LIMIT);
if (!isFrd) {
isFrd = await getFrd(roleId);
}
// 加入队伍
if (!validToJoin(teamStatus, roleId)) return resResult(STATUS.COM_BATTLE_TEAM_INVALID);
let roleStatus = new RoleStatus(role, sid, false, isFrd);
const team = await ComBattleTeamModel.addRole(teamCode, roleStatus);
if (!team) {
return resResult(STATUS.COM_BATTLE_JOIN_ERR);
}
addRoleStToTeam(teamStatus, roleStatus);
// 推送队伍信息给所有玩家
addUserToTeamChannel(teamCode, false, roleId, sid);
sendMessageToTeam(teamCode, PUSH_ROUTE.TEAM_JOIN, { teamInfo: teamStatus });
setDismissTimer(teamStatus, roleId);
return resResult(STATUS.SUCCESS, { teamInfo: teamStatus});
}
/**
* @description 设置是否情谊助战
* @param {{teamCode: string, isFrd: boolean}} msg 队伍编号情谊助战要设置的值true 为情谊助战
* @param {BackendSession} session
* @returns
* @memberof ComBattleHandler
*/
async setFrdAssistance(msg: {teamCode: string, isFrd: boolean}, session: BackendSession) {
let roleId = session.get('roleId');
let { isFrd, teamCode } = msg;
const isFrdPre = isFrd;
let teamStatus = getComTeamByCode(teamCode);
if (!teamStatus || teamStatus.status !== COM_TEAM_STATUS.DEFAULT) return resResult(STATUS.COM_BATTLE_TEAM_INVALID);
if (teamStatus.capId === roleId) return resResult(STATUS.COM_BATTLE_SET_FRD_ERR);
if (!isFrd) {
isFrd = await getFrd(roleId);
}
if (isFrd !== isFrdPre) {
return resResult(STATUS.COM_BATTLE_ASSIST_NOT_ENOUGH);
}
teamStatus.roleStatus.forEach(async st => {
if(st.roleId == roleId) {
st.isFrd = isFrd;
await ComBattleTeamModel.updateRoleStFrd(teamCode, roleId, isFrd);
}
});
return resResult(STATUS.SUCCESS, { teamCode, isFrd });
}
// /**
// * ! 获取队伍列表-deprecated
// * @param msg
// * @param session
// */
// async getTeams(msg: { blueprtIds: 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});
// }
// /**
// * ! deprecate
// * @description 队伍准备
// * @param {{teamCode: string, heroes: number[]}} msg
// * @param {BackendSession} session
// * @returns
// * @memberof ComBattleHandler
// */
// async teammateReady(msg: {teamCode: string, heroes: number[]}, session: BackendSession) {
// let roleId = session.get('roleId');
// let { teamCode, heroes: hids } = msg;
// let teamStatus = this.teamMap.get(teamCode);
// if (!teamStatus || !teamStatus.roleIds || teamStatus.roleIds.indexOf(roleId) === -1) return resResult(STATUS.COM_BATTLE_TEAM_INVALID);
// const heroDBs = await HeroModel.findByHidRange(hids, roleId);
// const heroes = heroDBs.map(hero => {
// return new ComRoleStatusHero(hero);
// });
// 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;
// }
// });
// sendMessageToTeam(teamCode, PUSH_ROUTE.TEAMMATE_READY, {teamCode, roleId, heroes});
// return resResult(STATUS.SUCCESS);
// }
/**
* @description 出兵时记录玩家阵容
* @param {{teamCode: string, heroes: number[]}} msg 队伍编号;阵容
* @param {BackendSession} session
* @returns
* @memberof ComBattleHandler
*/
async setupHeroes(msg: {teamCode: string, heroes: number[], battleCode: string}, session: BackendSession) {
let roleId = session.get('roleId');
let { teamCode, heroes: hids, battleCode = 'default' } = msg;
if (!hids || hids.length === 0) return resResult(STATUS.COM_BATTLE_HEROES_ERR);
if(isHeroHidden(...hids)) return resResult(STATUS.HERO_IS_HIDDEN);
let teamStatus = getComTeamByCode(teamCode);
if (!teamStatus || !teamStatus.roleIds || teamStatus.roleIds.indexOf(roleId) === -1) return resResult(STATUS.COM_BATTLE_TEAM_INVALID);
const heroDBs = await HeroModel.findByHidRange(hids, roleId);
const heroes = heroDBs.map(hero => {
return new ComRoleStatusHero(hero);
});
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;
}
});
sendMessageToTeam(teamCode, PUSH_ROUTE.TEAMMATE_READY, {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 = getComTeamByCode(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);
teamStatus.roleStatus.some((elem, idx) => {
if (elem.roleId === roleIdToRm) {
teamStatus.roleStatus.splice(idx, 1);
}
});
teamStatus.roleIds = teamStatus.roleStatus.map(cur => cur.roleId);
if(roleId === teamStatus.capId) { // 队长移除队友,并把他加入黑名单
teamStatus.blacklist.push(roleIdToRm);
}
// 先推送离队消息,再将玩家从房间中移除
sendMessageToTeam(teamCode, PUSH_ROUTE.LEAVE_TEAM, {teamCode, roleId: roleIdToRm});
removeFromTeamChannel(teamCode, roleIdToRm);
clearComBtlTimer(teamCode); // 移除队员停止解散计时
let thiz = this;
setTimeout(async () => {
let curTeamStatus = getComTeamByCode(teamCode);
if (validToJoin(curTeamStatus)) {
let roleSt: RoleStatus;
for (let st of curTeamStatus.roleStatus) {
if (st.isCap) {
roleSt = st;
}
}
if (!roleSt) return;
let { roleId, topLineupCe, lv } = roleSt;
await addRobotsToTeam(curTeamStatus, roleId, topLineupCe, lv, 3 - curTeamStatus.roleIds.length);
}
}, 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 = getComTeamByCode(teamCode);
if(!teamStatus) return resResult(STATUS.SUCCESS);
let result = await dismissTeam(teamStatus, roleId);
return result;
}
/**
* @description 开始战斗,队长操作或机器人队伍操作
* @param {{teamCode: string}} msg 队伍编号
* @param {BackendSession} session
* @returns
* @memberof ComBattleHandler
*/
async startBattle(msg: {teamCode: string}, session: BackendSession) {
let roleId = session.get('roleId');
let roleName = session.get('roleName');
let sid = session.get('sid');
let { teamCode } = msg;
let teamStatus = getComTeamByCode(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);
startTeam(teamStatus);
let team = await ComBattleTeamModel.updateStatusByCode(teamCode, teamStatus.status, teamStatus.startTime, teamStatus.endTime, teamStatus.hasTimeExtraReward);
if (!team) return resResult(STATUS.COM_BATTLE_START_ERR);
rmCreatedTeamFromRedis(teamCode, teamStatus.lv);
clearComBtlTimer(teamCode); // 战斗开始停止解散计时
await getComBattleFriendAdd(teamStatus.roleStatus);
sendMessageToTeam(teamCode, PUSH_ROUTE.COMBATTLE_START, {teamCode, roleStatus: teamStatus.roleStatus});
// 每场倒计时结算
let thiz = this;
setTimeout(async () => {
let teamStatus = getComTeamByCode(teamCode);
if (teamStatus && teamStatus.status === COM_TEAM_STATUS.FIGHTING) {
clearRobotHurtTimer(teamStatus);
let team = await ComBattleTeamModel.syncTeamData({teamCode, status: COM_TEAM_STATUS.LOOSE, roleStatus: teamStatus.roleStatus, bossHpArr: teamStatus.bossHpArr}, true);
if (!team) return resResult(STATUS.COM_BATTLE_RESULT_ERR);
teamStatus.timeout = true;
sendMessageToTeam(teamCode, PUSH_ROUTE.TEAM_COMPLETE, {teamCode, result: false, timeout: true});
deleteComBattle(teamCode);
clearComBattleRoute(redisClient(), teamCode)
}
}, COM_BTL_CONST.BTL_TIME_LMT);
teamStatus.roleStatus.forEach((st, idx) => {
if (st.isRobot === true) {
updateRobotHurtByTime(teamStatus, st, COM_BTL_CONST.ROBOT_BASE_TIME_INTERVAL + idx);
}
});
await checkTaskInComBattleStart(teamStatus.roleStatus, teamStatus.capId, teamStatus.blueprtId);
return resResult(STATUS.SUCCESS);
}
/**
* @description 战场中的状态同步,战斗结果判定
* @param {{teamCode: string, bossHurts: Array<{dataId: number, hurtHp: number}>, killed: number[], curRnd: number}} msg 队伍编号boss 承伤;武将阵亡;当前回合
* @param {BackendSession} session
* @returns
* @memberof ComBattleHandler
*/
async action(msg: {teamCode: string, bossHurts: Array<{hid: number, dataId: number, hurtHp: number}>, killed: number[], curRnd: number, timegap: number, roundTime: number }, session: BackendSession) {
let roleId = session.get('roleId');
let sid = session.get('sid');
let { teamCode, killed, bossHurts, curRnd, timegap = 0, roundTime = 0 } = msg;
let teamStatus = getComTeamByCode(teamCode);
if (!teamStatus || !teamStatus.roleIds || teamStatus.roleIds.indexOf(roleId) === -1) {
checkTeamStatusAndSend(teamCode, roleId, sid);
return resResult(STATUS.SUCCESS);
}
if (teamStatus.status !== COM_TEAM_STATUS.FIGHTING) {
checkTeamStatusAndSend(teamCode, roleId, sid);
return resResult(STATUS.SUCCESS);
}
for (let st of teamStatus.roleStatus) {
if (st.roleId === roleId && (!st.heroes || st.heroes.length === 0)) {
return resResult(STATUS.SUCCESS);
}
}
// 重置总血量,计算真实伤害
const roleSt = teamStatus.findMemberByRoleId(roleId);
if(!roleSt) return resResult(STATUS.SUCCESS);
if(!roleSt.startActionTime || roleSt.startActionTime == 0) { // 第一次调用设置初始
roleSt.startActionTime = nowSeconds();
}
if ((roundTime > 0 && roundTime < 500) || (timegap - (nowSeconds() - roleSt.startActionTime) > 5)) { // 前后端误差超过5秒拦截
return resResult(STATUS.SUCCESS, {
isError: true,
timegap: nowSeconds() - roleSt.startActionTime
});
}
let actBossHurts: {dataId: number, hurtHp: number}[] = [];
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) {
actBossHurts.push({dataId: boss.dataId, hurtHp: deltaHp});
totalHurtHp = cal.add(totalHurtHp, deltaHp);
boss.curHp = cal.sub(boss.curHp, deltaHp);
} else if (boss.curHp > 0) {
actBossHurts.push({dataId: boss.dataId, hurtHp: boss.curHp});
totalHurtHp = cal.add(totalHurtHp, boss.curHp);
boss.curHp = 0;
}
if(bh.hid) {
roleSt.addHeroDamage(bh.hid, deltaHp);
}
}
}
});
// 更新玩家武将阵亡情况,计算玩家总伤害
roleSt.totalDmg = cal.add(roleSt.totalDmg, totalHurtHp);
if (killed && killed.length) {
roleSt.killed = Array.from(new Set([...roleSt.killed, ...killed]));
}
teamStatus.curRnd = curRnd;
teamStatus.bossCurHp = cal.sub(teamStatus.bossCurHp, totalHurtHp);
if (teamStatus.bossCurHp < 0) teamStatus.bossCurHp = 0;
// 推送本次行动情况
const roleStatus = teamStatus.roleStatus.map(st => {return {roleId: st.roleId, totalDmg: st.totalDmg, killed: st.killed}});
sendMessageToTeam(teamCode, PUSH_ROUTE.TEAMMATE_ACT, { teamCode, bossCurHp: teamStatus.bossCurHp, bossHpArr: teamStatus.bossHpArr, roleStatus, actRoleId: roleId, actBossHurts });
const result = await handleComBtlProgress(teamStatus);
if (result && result.code !== 0) return result;
return resResult(STATUS.SUCCESS, {
isError: false,
timegap: nowSeconds() - roleSt.startActionTime
});
}
// /**
// * ! 客户端给服务器的战斗结束通知-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);
// if (isSuccess && teamStatus.bossCurHp <= 0) {
// let team = await ComBattleTeamModel.updateResult(teamCode, roleId, isSuccess);
// if (!team) return resResult(STATUS.COM_BATTLE_RESULT_ERR);
// sendMessageToTeam(teamCode, PUSH_ROUTE.TEAM_COMPLETE, {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) {
// sendMessageToTeam(teamCode, PUSH_ROUTE.TEAM_COMPLETE, {teamCode, result: isSuccess});
// } else {
// sendMessageToTeam(teamCode, PUSH_ROUTE.TEAMMATE_ACT, {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 ip = session.get('ip');
let serverId = session.get('serverId');
let { teamCode } = msg;
let team = await ComBattleTeamModel.getTeamByCode(teamCode);
clearRobotHurtTimer(team);
if (!team || team.status !== COM_TEAM_STATUS.WIN) return resResult(STATUS.COM_BATTLE_REWARD_ERR);
let { roleStatus, blueprtId, status, bossHpArr } = team;
let roleSt = roleStatus.find(st => st && st.roleId === roleId);
if(!roleSt) return resResult(STATUS.COM_BATTLE_REWARD_ERR);
await ComBattleTeamModel.updateRewardSt(teamCode, roleId, true);
const goods = await addItems(roleId, roleName, sid, roleSt.rewards, ITEM_CHANGE_REASON.COM_BATTLE_END);
return resResult(STATUS.SUCCESS, { battleGoods: goods, teamInfo: {status, teamCode, roleStatus, bossHpArr} });
}
async retreat(msg: {teamCode: string}, session: BackendSession) {
let roleId = session.get('roleId');
let sid = session.get('sid');
let { teamCode } = msg;
let teamStatus = getComTeamByCode(teamCode);
if (!teamStatus || !teamStatus.roleIds || teamStatus.roleIds.indexOf(roleId) === -1) {
checkTeamStatusAndSend(teamCode, roleId, sid);
return resResult(STATUS.SUCCESS);
}
if(teamStatus.roleStatus.length > 1) {
return resResult(STATUS.COM_BATTLE_RETREAT_ERR)
}
clearRobotHurtTimer(teamStatus);
let team = await ComBattleTeamModel.syncTeamData({ teamCode, status: COM_TEAM_STATUS.LOOSE, roleStatus: teamStatus.roleStatus, bossHpArr: teamStatus.bossHpArr, endTime: Date.now() }, false, true);
if (!team) return resResult(STATUS.COM_BATTLE_RESULT_ERR);
sendMessageToTeam(teamCode, PUSH_ROUTE.TEAM_COMPLETE, { teamCode, result: false });
deleteComBattle(teamCode);
clearComBattleRoute(redisClient(), teamCode);
return resResult(STATUS.SUCCESS, { teamInfo: pick(team, ['status', 'teamCode', 'roleStatus', 'bossHpArr']) });
}
async getComBtlStatus(msg: {teamCode: string}, session: BackendSession) {
let { teamCode } = msg;
let roleStatus: RoleStatus[], status: number, bossHpArr: BossHp[], timeout: boolean, endTime = 0;
let memTeam = getComTeamByCode(teamCode);
if (memTeam) {
({ roleStatus, status, bossHpArr, timeout, endTime } = memTeam);
} else {
let dbTeam = await ComBattleTeamModel.getTeamByCode(teamCode);
if (!dbTeam) return resResult(STATUS.COM_BATTLE_TEAM_INVALID);
({ roleStatus, status, bossHpArr, timeout, endTime } = dbTeam);
clearComBattleRoute(redisClient(), teamCode);
}
return resResult(STATUS.SUCCESS, { teamInfo: {status, teamCode, roleStatus, bossHpArr, timeout, endTime} });
}
/**
* @description 获取自己一段时间内的寻宝记录
* @param {{}} msg
* @param {BackendSession} session
* @returns
* @memberof ComBattleHandler
*/
async getTeamRec(msg: {}, session: BackendSession) {
let roleId = session.get('roleId');
let timef = getTimeFunD();
let teams = await ComBattleTeamModel.getTeamByRoleAndTime(roleId, null, <Date>timef.getBeforeDayWithHour(2));
if (!teams) return resResult(STATUS.COM_BATTLE_NO_RECENT_REC);
return resResult(STATUS.SUCCESS, {teamInfos: teams});
}
/**
* @description 获取藏宝图数量
* @param {{ids: number[]}} msg 藏宝图Id数组可选参数
* @param {BackendSession} session
* @returns
* @memberof ComBattleHandler
*/
async getBlueprtCount(msg: {ids: number[]}, session: BackendSession) {
let roleId = session.get('roleId');
let { ids } = msg;
let blueprts: ItemType[];
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 {{}} msg
* @param {BackendSession} session
* @returns
* @memberof ComBattleHandler
*/
async getAssistCnt(msg: {}, session: BackendSession) {
let roleId = session.get('roleId');
let cnt = await getAllAssistCnt(roleId);
return resResult(STATUS.SUCCESS, {cnt});
}
/**
* @description 获取寻宝可用次数,包含藏宝图数量和助战次数,分别用于创建和加入队伍
* @param {{}} msg 无参数
* @param {BackendSession} session
* @returns
* @memberof ComBattleHandler
*/
async getComBtlCnt(msg: {}, session: BackendSession) {
let roleId = session.get('roleId');
let cnt = await getAllAssistCnt(roleId);
const blueprts = await ItemModel.findByRoleAndType(roleId, CONSUME_TYPE.BLUEPRT);
let capExtraCnt = await getCapExtraCnt(roleId);
return resResult(STATUS.SUCCESS, { blueprts, assistCnt: cnt, capExtraCnt });
}
async sendTeamMsg(msg: { teamCode: string, type: number, content: string, targetRoleId: string, targetMsgCode: string }, session: BackendSession) {
let roleId = session.get('roleId');
let sid = session.get('sid');
let roleName = session.get('roleName');
let serverId = session.get('serverId');
const { teamCode, type, content, targetRoleId, targetMsgCode } = msg;
const result = await pushComBtlTeamMsg(teamCode, roleId, roleName, type, MSG_SOURCE.TEAM_ROLE, content, targetRoleId, targetMsgCode);
if (!result) {
return resResult(STATUS.WRONG_PARMS);
}
// 任务
await checkTask(serverId, roleId, sid, TASK_TYPE.CHAT, { chatType: getChannelType(CHANNEL_PREFIX.TEAM) });
return resResult(STATUS.SUCCESS);
}
/**
* @description 一键邀请,自动在世界频道发送消息
* @param {{ teamCode: string }} msg
* @param {BackendSession} session
* @memberof ComBattleHandler
*/
async autoInvite(msg: { teamCode: string }, session: BackendSession) {
let roleId = session.get('roleId');
let roleName = session.get('roleName');
let guildCode = session.get('guildCode');
if (!guildCode) return resResult(STATUS.COM_BATTLE_INVITE_GUILD_ERR);
const { teamCode } = msg;
let teamStatus = getComTeamByCode(teamCode);
if(!teamStatus) return resResult(STATUS.WRONG_PARMS);
await pushTeamInviteMsg(roleId, roleName, guildCode, teamCode, teamStatus.blueprtId, teamStatus.lv, teamStatus.ceLimit);
await ComBattleTeamModel.invite(teamCode, guildCode);
return resResult(STATUS.SUCCESS);
}
/**
* @description 邀请队友
* @param {{ teamCode: string, targetRoleId: string }} msg
* @param {BackendSession} session
* @memberof ComBattleHandler
*/
async inviteTeammate(msg: { teamCode: string, targetRoleId: string }, session: BackendSession) {
let roleId = session.get('roleId');
let roleName = session.get('roleName');
let guildCode = session.get('guildCode');
const { teamCode, targetRoleId } = msg;
let teamStatus = getComTeamByCode(teamCode);
if(!teamStatus) return resResult(STATUS.WRONG_PARMS);
let role = await RoleModel.findByRoleId(targetRoleId, 'lv');
if(comBtlLvInvalid(role.lv, [teamStatus.lv])) {
return resResult(STATUS.COM_BATTLE_INVITE_LV_NOT_ENOUGH);
}
if (role.topLineupCe < teamStatus.ceLimit) {
return resResult(STATUS.COM_BATTLE_CE_LIMIT);
}
await ComBattleTeamModel.invite(teamCode, targetRoleId);
let relation = await getFriendRelationType(roleId, targetRoleId);
const msgData = await pushFriendTeamInviteMsg(roleId, roleName, teamCode, teamStatus.blueprtId, targetRoleId, relation);
if (!msgData) return resResult(STATUS.WRONG_PARMS);
const roleInfo = await getSimpleRoleInfo(targetRoleId);
let index = teamStatus.blacklist.indexOf(targetRoleId);
if(index != -1) {
teamStatus.blacklist.splice(index, 1);
}
return resResult(STATUS.SUCCESS, {...msgData, roleInfo});
}
/**
* @description 最近组队过的队友列表
* @param {} msg
* @param {BackendSession} session
*/
async getRecentTeammates(msg: { }, session: BackendSession) {
let roleId = session.get('roleId');
const teams = await ComBattleTeamModel.getTeamByRoleAndTime(roleId, null, getZeroPointD());
let roleIdList = new Array<string>();
for(let { roleIds } of teams) {
for(let r of roleIds) {
if(r != roleId) roleIdList.push(r);
}
}
const roles = await RoleModel.findByRoleIds(roleIdList, ROLE_SELECT.SHOW_SIMPLE, true);
let result = new Array<FriendParams>();
for(let role of roles) {
if(role.quitTime == role.loginTime) {
let r = new FriendParams(role);
result.push(r);
}
}
return resResult(STATUS.SUCCESS, { list: result });
}
async getTeamInvitation(msg: { }, session: BackendSession) {
let roleId = session.get('roleId');
let guildCode = session.get('guildCode');
let role = await RoleModel.findByRoleId(roleId, 'lv topLineupCe');
const assistCnt = await getAllAssistCnt(roleId);
let { minLv, maxLv } = getComBtlLvByPlayerLv(role.lv);
let refreshTime = nowSeconds() - INFO_WINDOW.TEAM_INFORMATION_TIME;
const invitations = await ComBattleTeamModel.findInvitations(roleId, guildCode, minLv, maxLv, role.topLineupCe, refreshTime, INFO_WINDOW.TEAM_VIEW);
let roleIds = invitations.map(cur => cur.capId);
let roles = await RoleModel.findByRoleIds(roleIds);
let myFriendRelation = await FriendRelationModel.findFriendByRole(roleId, POPULATE_TYPE.NOT);
const teams: ComBattleInvitation[] = [];
for(let invitation of invitations) {
let leader = roles.find(role => role.roleId == invitation.capId);
if(leader) {
let leaderParam = new FriendParams(leader);
let type = getRecommendType(myFriendRelation, roleId, leader.roleId);
leaderParam.setType(type);
let serverName = await getServerName(leader.serverId);
leaderParam.setServerName(leader.serverId, serverName);
teams.push(new ComBattleInvitation(invitation, leaderParam));
}
}
return resResult(STATUS.SUCCESS, { teams, assistCnt });
}
// ! 测试接口
/**
* 修改玩家的等级-方便测试组队
* 寻宝创建队伍 - 会先调用这个接口
* @param {{ targetLv: number }} msg
* @param {BackendSession} session
* @return {*}
* @memberof ComBattleHandler
*/
async debugSetRoleLv(msg: { magicWord: string, targetLv: number }, session: BackendSession) {
const roleId = session.get('roleId');
const { targetLv, magicWord } = msg;
if (magicWord !== DEBUG_MAGIC_WORD) {
return resResult(STATUS.TOKEN_ERR);
}
let role = await RoleModel.updateRoleInfo(roleId, { lv: targetLv });
return resResult(STATUS.SUCCESS, { lv: role.lv, roleId });
}
}