833 lines
39 KiB
TypeScript
833 lines
39 KiB
TypeScript
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 });
|
||
}
|
||
|
||
}
|
||
|