642 lines
26 KiB
TypeScript
642 lines
26 KiB
TypeScript
import { MemComBtlTeam } from './../domain/battleField/ComBattleTeamField';
|
||
import { ItemModel } from './../db/Item';
|
||
import { ITEM_CHANGE_REASON, IT_TYPE, PUSH_ROUTE } from './../consts';
|
||
import { FriendRelationModel } from './../db/FriendRelation';
|
||
import { RoleModel, RoleType } from './../db/Role';
|
||
import { EquipPrintDropType, EquipPrintDropModel } from './../db/EquipPrintDrop';
|
||
import { STATUS } from './../consts/statusCode';
|
||
import { COM_TEAM_STATUS, FRIEND_DROP_TYPE, COM_BTL_CONST, FRIEND_DROP_MAX } from './../consts';
|
||
import { RoleStatus, ComBattleTeamModel, ComBattleTeamType } from './../db/ComBattleTeam';
|
||
import { getRandEelm, getRandValue, resResult, ratioReward, getRandValueByMinMax, getRandEelmWithWeight, getRobotInfo, getRandSingleEelm } from "../pubUtils/util";
|
||
import { getRandRobot } from "./battleService";
|
||
import { Channel, ChannelService, pinus } from 'pinus';
|
||
import { TREASURE, EXTERIOR } from '../pubUtils/dicParam';
|
||
import { getFriendLvAdd } from './friendService';
|
||
import { getRoleIds } from '../pubUtils/friendUtil';
|
||
import { getTeamSearchByLv, rmRoleFromQueue } from './redisService';
|
||
import { getRewardByBlueprtId, gameData, getBossHpByBlueprtId, getDicBlueprtById } from '../pubUtils/data';
|
||
import { getZeroPointD, nowSeconds } from '../pubUtils/timeUtil';
|
||
import { handleCost } from './role/rewardService';
|
||
import { addUserToTeamChannel, delTeamChannel, sendMessageToTeam, sendMessageToUsersWithSuc, sendMessageToUserWithSuc } from './pushService';
|
||
import { checkTaskInComBattleEnd } from './task/taskService';
|
||
|
||
/**
|
||
* 在给定的品质列表中随机返回一定数量的藏宝图Id
|
||
* @param lv 品质数组,在所有给定品质的藏宝图中筛选1
|
||
* @param cnt 返回藏宝图数量
|
||
*/
|
||
export function getRandBlueprtId(lvs: number[], cnt = 1) {
|
||
if (!lvs || !lvs.length) return null;
|
||
|
||
let blueprtIdArr: number[] = [];
|
||
for (let lv of lvs) {
|
||
blueprtIdArr = blueprtIdArr.concat(gameData.blueprtByLv.get(lv));
|
||
}
|
||
if (blueprtIdArr.length === 0) return null;
|
||
|
||
const res = getRandEelm(blueprtIdArr, cnt);
|
||
// console.log('******** getRandBlueprtId', blueprtIdArr, cnt, res)
|
||
return res;
|
||
}
|
||
|
||
export function getRandComBtlRobots(topLineupCe: number, ceLimit: number, lv: number, cnt: number) {
|
||
let robotHeroes = getRandRobot(cnt); // 随机几个阵容
|
||
let robotInfos: { robotRoleName: string, robotRoleId: string }[] = []; // 随机几个机器人信息
|
||
for (let i = 0; i < cnt; i++) {
|
||
robotInfos.push(getRobotInfo());
|
||
}
|
||
// 创建并添加机器人
|
||
let robotStArr: RoleStatus[] = [], robotIdArr: string[] = [];
|
||
if (robotHeroes && robotInfos && robotHeroes.length && robotInfos.length && robotInfos.length === robotHeroes.length) {
|
||
robotHeroes.forEach((robot, idx) => {
|
||
let robotCe = 0;
|
||
if (ceLimit && ceLimit > 0) {
|
||
robotCe = getRandValueByMinMax(ceLimit, (topLineupCe || 0) * (1 + COM_BTL_CONST.ROBOT_CE_RATIO), 0);
|
||
} else {
|
||
robotCe = getRandValue(topLineupCe || 0, COM_BTL_CONST.ROBOT_CE_RATIO, 0);
|
||
}
|
||
let robotLv = getRandValue(lv, COM_BTL_CONST.ROBOT_CE_RATIO, 0);
|
||
if(robotLv > gameData.maxPlayerLv.max) robotLv = gameData.maxPlayerLv.max;
|
||
// const imgHid = robot[Math.floor(Math.random() * robot.length)];
|
||
const { robotRoleId, robotRoleName } = robotInfos[idx];
|
||
let robotStatus = new RoleStatus(robotRoleId, robotRoleName, false, false, EXTERIOR.EXTERIOR_FACE, EXTERIOR.EXTERIOR_FACECASE, EXTERIOR.EXTERIOR_APPEARANCE, robotCe, robotLv, robot, true);
|
||
robotStArr.push(robotStatus);
|
||
robotIdArr.push(robotRoleId);
|
||
});
|
||
}
|
||
return {
|
||
robotStArr, robotIdArr
|
||
}
|
||
}
|
||
|
||
export function checkComBattleResult(teamStatus) {
|
||
if (teamStatus.bossCurHp === 0) {
|
||
return COM_TEAM_STATUS.WIN;
|
||
} else {
|
||
let allPlayerKilled = true;
|
||
let robotRestHurt = 0;
|
||
// 看看是否还有活人
|
||
teamStatus.roleStatus.forEach(st => {
|
||
// 设置了阵容,且阵容人数和阵亡人数一样,说明玩家战败
|
||
if (!st.isRobot && st.battleStatus != 2 && st.heroes && ((st.heroes.length > 0 && st.killed.length < st.heroes.length) || st.heroes.length === 0 )) {
|
||
allPlayerKilled = false
|
||
}
|
||
});
|
||
// 没有活人的话看看还有没有机器人没打完伤害
|
||
if (allPlayerKilled && teamStatus.curRnd < COM_BTL_CONST.ROBOT_RND_LMT) {
|
||
teamStatus.roleStatus.forEach(st => {
|
||
if (st.isRobot) {
|
||
const deltaRnd = COM_BTL_CONST.ROBOT_RND_LMT - teamStatus.curRnd;
|
||
let hurtHp = getRandValue(teamStatus.bossHp / COM_BTL_CONST.ROBOT_RND_LMT * COM_BTL_CONST.ROBOT_HURT_RATIO, COM_BTL_CONST.ROBOT_HURT_CH_RATIO, 0) * deltaRnd; // 1 个机器人对 boss 造成的总伤害
|
||
robotRestHurt += hurtHp;
|
||
}
|
||
})
|
||
}
|
||
if (allPlayerKilled) {
|
||
// 没有活人且机器人剩余伤害打不死 boss,战败
|
||
if (teamStatus.bossCurHp > robotRestHurt) {
|
||
return COM_TEAM_STATUS.LOOSE;
|
||
} else {
|
||
return COM_TEAM_STATUS.WIN;
|
||
}
|
||
}
|
||
}
|
||
return COM_TEAM_STATUS.FIGHTING;
|
||
}
|
||
|
||
/**
|
||
* ! deprecated
|
||
* @description 计算寻宝结算
|
||
* @export
|
||
* @param {string} roleId
|
||
* @param {string} battleCode
|
||
* @returns
|
||
*/
|
||
export async function checkComBattleDrop(roleId: string, battleCode: string) {
|
||
let team = await ComBattleTeamModel.getTeamByRoleAndBattleCode(roleId, battleCode);
|
||
if (team.status !== COM_TEAM_STATUS.WIN) return { status: -1, resResult: resResult(STATUS.COM_BATTLE_REWARD_ERR) };
|
||
let roleSt = null;
|
||
team.roleStatus.forEach(st => {
|
||
if (st.roleId === roleId) {
|
||
roleSt = st;
|
||
}
|
||
});
|
||
if (!roleSt || roleSt.gotReward) return { status: -1, resResult: resResult(STATUS.COM_BATTLE_REWARD_ERR) };
|
||
let { fixReward, teammateReward } = getRewardByBlueprtId(team.blueprtId);
|
||
if (!roleSt.isCap) {
|
||
if (roleSt.isFrd) {
|
||
fixReward = [];
|
||
} else {
|
||
fixReward = teammateReward;
|
||
}
|
||
}
|
||
await ComBattleTeamModel.updateRewardSt(team.teamCode, roleId, true);
|
||
return { status: 0, fixReward };
|
||
}
|
||
|
||
export function clearComBtlTimer(teamCode: string, timerMap: Map<string, NodeJS.Timer>) {
|
||
let timer = timerMap.get(teamCode);
|
||
if (timer) {
|
||
clearTimeout(timer);
|
||
}
|
||
}
|
||
|
||
export function setComBtlTimer(teamCode: string, timer: NodeJS.Timer, timerMap: Map<string, NodeJS.Timer>) {
|
||
let preTimer = timerMap.get(teamCode);
|
||
if (preTimer) {
|
||
clearTimeout(preTimer);
|
||
}
|
||
timerMap.set(teamCode, timer);
|
||
}
|
||
|
||
export async function getRealReward(blueprtId: number, roleSt: RoleStatus) {
|
||
let { fixReward, teammateReward } = getRewardByBlueprtId(blueprtId);
|
||
if (!roleSt.isCap) {
|
||
if (roleSt.isFrd) {
|
||
fixReward = []
|
||
} else {
|
||
fixReward = teammateReward;
|
||
}
|
||
}
|
||
return fixReward;
|
||
}
|
||
|
||
export async function getAllAssistCnt(roleId: string) {
|
||
let teams = await ComBattleTeamModel.getAssistTeamsByTime(roleId, getZeroPointD(), true);
|
||
return teams.length;
|
||
}
|
||
|
||
export async function getFrd(roleId: string) {
|
||
let isFrd = false;
|
||
let cnt = await getAllAssistCnt(roleId);
|
||
if (cnt >= TREASURE.TREASURE_ASSIST_TIME) isFrd = true;
|
||
return isFrd;
|
||
}
|
||
|
||
/**
|
||
* @description 更新队伍状态
|
||
* @export
|
||
* @param {number} preStatus 更新前状态,作为筛选条件
|
||
* @param {number} newStatus 要设置的新状态
|
||
*/
|
||
export async function updateTeamStatus(preStatus: number, newStatus: number) {
|
||
if (preStatus === newStatus) return;
|
||
await ComBattleTeamModel.updateStatusByStatus(preStatus, newStatus);
|
||
}
|
||
|
||
/**
|
||
* @description 计算机器人每次对 boss 造成的伤害
|
||
* @param {number} bossHp boss 总血量
|
||
*/
|
||
function robotEachHurt(bossHp: number, bossCnt: number) {
|
||
const robotTotalHurt = bossHp * COM_BTL_CONST.ROBOT_HURT_RATIO;
|
||
const robotAverageHurt = robotTotalHurt / COM_BTL_CONST.ROBOT_ACT_LMT / bossCnt;
|
||
return getRandValue(robotAverageHurt, COM_BTL_CONST.ROBOT_HURT_CH_RATIO, 0)
|
||
}
|
||
|
||
/**
|
||
* @description 更新机器人阵亡情况
|
||
* @param {number} bossHp
|
||
* @param {RoleStatus} roleSt
|
||
*/
|
||
function updateRobotKilled(bossHp: number, roleSt: RoleStatus) {
|
||
const robotTotalHurt = bossHp * COM_BTL_CONST.ROBOT_HURT_RATIO;
|
||
// 让阵亡人数和打出伤害的进度同步,比如有 5 个武将,每打出目标总伤害的 1 / 5 应该增加一个阵亡武将
|
||
const dmgProgress = Math.floor(roleSt.totalDmg / (robotTotalHurt / roleSt.heroes.length));
|
||
if (dmgProgress > roleSt.killed.length && dmgProgress <= roleSt.heroes.length) {
|
||
const newKilledCnt = dmgProgress - roleSt.killed.length;
|
||
const aliveHeroes = roleSt.heroes.filter(hero => {
|
||
return roleSt.killed.indexOf(hero.id) == -1;
|
||
}).map(cur => cur.id);
|
||
const newKilledHeroes = getRandEelm(aliveHeroes, newKilledCnt);
|
||
roleSt.killed = roleSt.killed.concat(newKilledHeroes);
|
||
}
|
||
}
|
||
|
||
export async function handleComBtlProgress(teamStatus: MemComBtlTeam, robotHurtTimer: Map<string, NodeJS.Timer>, teamMap: Map<string, MemComBtlTeam>) {
|
||
const { teamCode } = teamStatus;
|
||
// 判断战斗是否结束
|
||
let battleSt = checkComBattleResult(teamStatus);
|
||
teamStatus.status = battleSt;
|
||
if (battleSt === COM_TEAM_STATUS.WIN || battleSt === COM_TEAM_STATUS.LOOSE) {
|
||
let result = battleSt === COM_TEAM_STATUS.WIN;
|
||
if (result) {
|
||
teamStatus.bossHpArr.forEach(bs => {
|
||
bs.curHp = 0;
|
||
});
|
||
for (let st of teamStatus.roleStatus) {
|
||
st.fixReward = await getRealReward(teamStatus.blueprtId, st);
|
||
};
|
||
await checkTaskInComBattleEnd(teamStatus.roleStatus, teamStatus.capId);
|
||
}
|
||
let team = await ComBattleTeamModel.syncTeamData({ teamCode, status: battleSt, roleStatus: teamStatus.roleStatus, bossHpArr: teamStatus.bossHpArr, endTime: teamStatus.endTime });
|
||
if (!team) return resResult(STATUS.COM_BATTLE_RESULT_ERR);
|
||
|
||
// 战斗胜利队长扣减藏宝图
|
||
if (result && teamStatus.capId != 'robot') {
|
||
let res = await handleCost(teamStatus.capId, teamStatus.sid, [{ id: teamStatus.blueprtId, count: 1 }], ITEM_CHANGE_REASON.COM_BATTLE_USE_BLUEPRT);
|
||
if (res === false) return resResult(STATUS.COM_BATTLE_BLUEPRT_NOT_ENOUGH);
|
||
}
|
||
|
||
clearRobotHurtTimer(teamStatus, robotHurtTimer);
|
||
sendMessageToTeam(teamCode, PUSH_ROUTE.TEAM_COMPLETE, { teamCode, result });
|
||
|
||
teamMap.delete(teamCode);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @description 更新机器人对 boss 的伤害
|
||
* @export
|
||
* @param {*} teamStatus 要更新的队伍信息
|
||
* @param {RoleStatus} roleSt 要更新的玩家信息
|
||
*/
|
||
export function updateRobotHurt(teamStatus: MemComBtlTeam, roleSt: RoleStatus) {
|
||
// 机器人的伤害为:boss 血量的一定比例,平均到一定回合数内,再平均到每个敌军,上下浮动一定比例
|
||
let eachHurtHp = robotEachHurt(teamStatus.bossHp, teamStatus.bossHpArr.length);
|
||
let robotTotalHurt = 0;
|
||
let actBossHurts = [];
|
||
let hero = getRandSingleEelm(roleSt.heroes);
|
||
for (let boss of teamStatus.bossHpArr) {
|
||
if (boss.curHp === 0) continue;
|
||
if (boss.curHp >= eachHurtHp) {
|
||
actBossHurts.push({ dataId: boss.dataId, hurtHp: eachHurtHp });
|
||
robotTotalHurt += eachHurtHp;
|
||
boss.curHp -= eachHurtHp;
|
||
hero.addDamage(eachHurtHp);
|
||
} else if (boss.curHp > 0) { // 丢弃溢出的伤害
|
||
actBossHurts.push({ dataId: boss.dataId, hurtHp: boss.curHp });
|
||
robotTotalHurt += boss.curHp;
|
||
hero.addDamage(boss.curHp);
|
||
boss.curHp = 0;
|
||
}
|
||
break;
|
||
}
|
||
teamStatus.bossCurHp -= robotTotalHurt;
|
||
roleSt.totalDmg += robotTotalHurt;
|
||
updateRobotKilled(teamStatus.bossHp, roleSt);
|
||
sendMessageToTeam(teamStatus.teamCode, PUSH_ROUTE.TEAMMATE_ACT, { teamCode: teamStatus.teamCode, bossCurHp: teamStatus.bossCurHp, bossHpArr: teamStatus.bossHpArr, roleStatus: teamStatus.roleStatus, actRoleId: roleSt.roleId, actBossHurts });
|
||
}
|
||
|
||
/**
|
||
* @description 按一定时间间隔刷新机器人伤害
|
||
* @export
|
||
* @param {*} teamStatus
|
||
* @param {RoleStatus} roleSt
|
||
* @param {number} interval
|
||
* @param {Channel} channel
|
||
* @param {Map<string, NodeJS.Timer>} robotHurtTimer
|
||
*/
|
||
export function updateRobotHurtByTime(teamStatus: MemComBtlTeam, roleSt: RoleStatus, interval: number, robotHurtTimer: Map<string, NodeJS.Timer>, teamMap: Map<string, MemComBtlTeam>) {
|
||
const timerKey = `${teamStatus.teamCode}_${roleSt.roleId}`;
|
||
const robotTimer = setInterval(() => {
|
||
const robotTotalHurt = teamStatus.bossHp * COM_BTL_CONST.ROBOT_HURT_RATIO;
|
||
if (roleSt.totalDmg < robotTotalHurt && teamStatus.bossCurHp > 0 && teamMap.has(teamStatus.teamCode)) {
|
||
updateRobotHurt(teamStatus, roleSt);
|
||
handleComBtlProgress(teamStatus, robotHurtTimer, teamMap);
|
||
} else {
|
||
clearInterval(robotTimer);
|
||
}
|
||
}, interval * 1000);
|
||
if (!robotHurtTimer.has(timerKey)) {
|
||
robotHurtTimer.set(timerKey, robotTimer);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @description 清理机器人伤害的 timer
|
||
* @export
|
||
* @param {*} teamStatus 寻宝队伍状态
|
||
* @param {Map<string, NodeJS.Timer>} robotHurtTimer
|
||
*/
|
||
export function clearRobotHurtTimer(teamStatus, robotHurtTimer: Map<string, NodeJS.Timer>) {
|
||
teamStatus.roleStatus.forEach(st => {
|
||
const timerKey = `${teamStatus.teamCode}_${st.roleId}`;
|
||
if (st.isRobot === true && robotHurtTimer.has(timerKey)) {
|
||
clearInterval(robotHurtTimer.get(timerKey));
|
||
}
|
||
});
|
||
}
|
||
|
||
/**
|
||
* @description 检查寻宝等级是否合法
|
||
* @export
|
||
* @param {number} playerLv 玩家等级
|
||
* @param {number} blueprtLv 藏宝图等级
|
||
* @returns
|
||
*/
|
||
export function comBtlLvInvalid(playerLv: number, blueprtLvs: number[]) {
|
||
for(let blueprtLv of blueprtLvs) {
|
||
const range = gameData.comBtlLvRange.get(blueprtLv);
|
||
if (!range) return true;
|
||
let { min, max } = range;
|
||
if(playerLv < min || playerLv > max) return true;
|
||
}
|
||
return false
|
||
}
|
||
|
||
export function getComBtlLvByPlayerLv(playerLv: number) {
|
||
let lvs: number[] = [];
|
||
for(let [lv, {min, max}] of gameData.comBtlLvRange) {
|
||
if(playerLv >= min && playerLv <= max) lvs.push(lv);
|
||
}
|
||
let minLv = Math.min(...lvs);
|
||
let maxLv = Math.max(...lvs);
|
||
return { minLv, maxLv }
|
||
}
|
||
|
||
export async function dismissTeam(teamStatus: MemComBtlTeam, teamMap: Map<string, MemComBtlTeam>, roleId: string, teamDisTimer: Map<string, NodeJS.Timer>) {
|
||
const { teamCode } = teamStatus;
|
||
if (!teamStatus || !teamStatus.roleIds || teamStatus.roleIds.indexOf(roleId) === -1) return resResult(STATUS.COM_BATTLE_TEAM_INVALID);
|
||
if (teamStatus.status !== COM_TEAM_STATUS.DEFAULT) return resResult(STATUS.COM_BATTLE_DISSMISS_ERR);
|
||
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 = teamMap.delete(teamCode);
|
||
if (!rmSt) return resResult(STATUS.COM_BATTLE_DISSMISS_ERR);
|
||
|
||
sendMessageToTeam(teamCode, PUSH_ROUTE.TEAM_DISMISS, { teamCode });
|
||
delTeamChannel(teamCode);
|
||
clearComBtlTimer(teamCode, teamDisTimer); // 队伍解散停止解散计时
|
||
return resResult(STATUS.SUCCESS);
|
||
}
|
||
|
||
export function setDismissTimer(teamStatus: MemComBtlTeam, teamMap: Map<string, MemComBtlTeam>, roleId: string, teamDisTimer: Map<string, NodeJS.Timer>) {
|
||
if (teamIsFullToStart(teamStatus)) {
|
||
clearComBtlTimer(teamStatus.teamCode, teamDisTimer);
|
||
let timer = setTimeout(async () => {
|
||
await dismissTeam(teamStatus, teamMap, roleId, teamDisTimer);
|
||
}, COM_BTL_CONST.CAP_START_TIME);
|
||
teamDisTimer.set(teamStatus.teamCode, timer);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 按照好友关系,新增加成
|
||
*
|
||
* @param {RoleStatus[]} roleStatus 队伍内的所有队友
|
||
*/
|
||
export async function getComBattleFriendAdd(roleStatus: RoleStatus[]) {
|
||
let hasAdd: string[] = []; //roleIds
|
||
for (let myRoleStatus of roleStatus) {
|
||
for (let rs of roleStatus) {
|
||
if (myRoleStatus.roleId == rs.roleId) continue;
|
||
if (myRoleStatus.isRobot || rs.isRobot) continue;
|
||
|
||
let { roleIds } = getRoleIds([myRoleStatus.roleId, rs.roleId]);
|
||
if (hasAdd.includes(roleIds)) continue;
|
||
|
||
let add = await getFriendLvAdd(myRoleStatus.roleId, rs.roleId);
|
||
rs.addFrdRatio(add);
|
||
myRoleStatus.addFrdRatio(add);
|
||
|
||
hasAdd.push(roleIds);
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @description 检查玩家是否符合加入队伍的条件
|
||
* @param {Partial<RoleType>} roleInfo 要加入玩家的信息
|
||
* @param {string} roleId 要加入玩家的 id
|
||
* @param {string[]} roleIds 队伍中当前玩家列表
|
||
* @param {number} ceLimit
|
||
* @returns
|
||
*/
|
||
async function teammateValid(roleInfo: Partial<RoleType>, roleId: string, roleIds: string[], ceLimit: number) {
|
||
if (!roleInfo || roleIds.indexOf(roleId) !== -1) return false;
|
||
|
||
const isBlack = await teammateInBlackList(roleId, roleIds);
|
||
if (isBlack) return false;
|
||
|
||
let { topLineupCe } = roleInfo;
|
||
if (topLineupCe < ceLimit) return false;
|
||
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* @description 将用户信息转换成寻宝组队所需的 RoleStatus
|
||
* @export
|
||
* @param {string} roleId 要加入玩家的信息
|
||
* @param {string[]} roleIds 队伍中当前玩家列表
|
||
* @param {number} ceLimit
|
||
* @returns
|
||
*/
|
||
export async function getValidTeammateRoleSt(roleId: string, roleIds: string[], ceLimit: number) {
|
||
let roleInfo = await RoleModel.findByRoleId(roleId, null, true);
|
||
let { roleName, head = EXTERIOR.EXTERIOR_FACE, frame = EXTERIOR.EXTERIOR_FACECASE, spine = EXTERIOR.EXTERIOR_APPEARANCE, topLineupCe, lv: playerLv } = roleInfo;
|
||
|
||
const valid = await teammateValid(roleInfo, roleId, roleIds, ceLimit);
|
||
if (!valid) return null;
|
||
|
||
let isFrd = await getFrd(roleId);
|
||
const result = new RoleStatus(roleId, roleName, false, isFrd, head, frame, spine, topLineupCe, playerLv);
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* @description 检查队伍中是否有人互为黑名单
|
||
* @export
|
||
* @param {string} roleId 要加入队伍的玩家 id
|
||
* @param {string[]} roleIds 队伍中已有的玩家 id
|
||
* @returns
|
||
*/
|
||
export async function teammateInBlackList(roleId: string, roleIds: string[]) {
|
||
for (let teammateRoleId of roleIds) {
|
||
const isBlack = await FriendRelationModel.isInBlackList(roleId, teammateRoleId);
|
||
if (isBlack === true) return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
export function blueprtIdValid(id: number) {
|
||
return gameData.blueprt.has(id);
|
||
}
|
||
|
||
/**
|
||
* @description 检查是否有足够的藏宝图,未结束的战斗也占用一张藏宝图
|
||
* @export
|
||
* @param {string} roleId
|
||
* @param {number} blueprtId
|
||
* @returns
|
||
*/
|
||
export async function hasEnoughBlueprt(roleId: string, sid: string, blueprtId: number) {
|
||
let blueprt = await ItemModel.findbyRoleAndGidAndCount(roleId, blueprtId, 1);
|
||
if (!blueprt || blueprt.count <= 0) return false;
|
||
// 检查是否有已创建未结束的寻宝,预先占用一张藏宝图
|
||
// // 背包中占用的藏宝图不显示,所以这里就扣掉,结束再加回去
|
||
// let result = await handleCost(roleId, sid, [{ id: blueprtId, count: 1 }]);
|
||
// return result;
|
||
let teams = await ComBattleTeamModel.getBlueprtInUse(roleId, COM_TEAM_STATUS.FIGHTING, blueprtId);
|
||
console.log('hasEnoughBlueprt', blueprt.count, teams.length)
|
||
if (teams && blueprt.count <= teams.length) return false;
|
||
return true
|
||
}
|
||
|
||
/**
|
||
* @description 将玩家加入到队伍数据结构中,需将玩家信息做转化
|
||
* @export
|
||
* @param {MemComBtlTeam} comTeam 队伍数据结构
|
||
* @param {RoleType} roleInfo 原始玩家信息
|
||
* @param {boolean} isCap
|
||
* @param {boolean} isFrd
|
||
*/
|
||
export function addRoleToTeam(comTeam: MemComBtlTeam, roleInfo: RoleType, isCap: boolean, isFrd: boolean) {
|
||
const { roleId, roleName, head = EXTERIOR.EXTERIOR_FACE, frame = EXTERIOR.EXTERIOR_FACECASE, spine = EXTERIOR.EXTERIOR_APPEARANCE, lv } = roleInfo;
|
||
let { topLineupCe = 1000 } = roleInfo;
|
||
const roleSt = new RoleStatus(roleId, roleName, isCap, isFrd, head, frame, spine, topLineupCe, lv);
|
||
addRoleStToTeam(comTeam, roleSt);
|
||
}
|
||
|
||
/**
|
||
* @description 将玩家加入到队伍数据结构中
|
||
* @export
|
||
* @param {MemComBtlTeam} comTeam 队伍数据结构
|
||
* @param {RoleStatus} roleSt 要加入的玩家数据
|
||
*/
|
||
export function addRoleStToTeam(comTeam: MemComBtlTeam, roleSt: RoleStatus) {
|
||
const { roleStatus = [], roleIds = [] } = comTeam;
|
||
comTeam.roleStatus = [roleSt, ...roleStatus];
|
||
comTeam.roleIds = [roleSt.roleId, ...roleIds];
|
||
}
|
||
|
||
/**
|
||
* @description 将符合要求的用户匹配到队伍中
|
||
* @export
|
||
* @param {MemComBtlTeam} comTeam 队伍数据
|
||
* @param {string} sid 当前用户 sid
|
||
* @returns
|
||
*/
|
||
export async function addValidSearchingRoles(comTeam: MemComBtlTeam) {
|
||
const { lv } = getDicBlueprtById(comTeam.blueprtId);
|
||
let teammates = await getTeamSearchByLv(lv);
|
||
if (teammates && teammates.length) {
|
||
for (let teammate of teammates) {
|
||
const { roleId: teammateRoleId, sid } = teammate;
|
||
const st = await getValidTeammateRoleSt(teammateRoleId, comTeam.roleIds, comTeam.ceLimit);
|
||
if (!st) continue;
|
||
await rmRoleFromQueue(teammateRoleId, sid); // 匹配成功后删除redis中该用户的匹配记录
|
||
addRoleStToTeam(comTeam, st);
|
||
addUserToTeamChannel(comTeam.teamCode, false, teammateRoleId, sid);
|
||
}
|
||
sendMessageToUsersWithSuc(PUSH_ROUTE.TEAM_JOIN, { teamInfo: comTeam }, teammates.map(t => { return { uid: t.roleId, sid: t.sid } }));
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @description 判断队伍是否处于可加入状态
|
||
* @export
|
||
* @param {MemComBtlTeam} comTeam
|
||
* @param {string} [roleId=''] 要加入的玩家 id
|
||
* @returns
|
||
*/
|
||
export function validToJoin(comTeam: MemComBtlTeam, roleId = '') {
|
||
return comTeam && comTeam.roleIds && comTeam.status === COM_TEAM_STATUS.DEFAULT && comTeam.roleIds.length < 3 && comTeam.roleIds.indexOf(roleId) === -1;
|
||
}
|
||
|
||
/**
|
||
* @description 判断队伍是否处于可满员状态
|
||
* @export
|
||
* @param {MemComBtlTeam} comTeam
|
||
* @returns
|
||
*/
|
||
export function teamIsFullToStart(comTeam: MemComBtlTeam) {
|
||
return comTeam && comTeam.roleIds && comTeam.status === COM_TEAM_STATUS.DEFAULT && comTeam.roleIds.length === 3;
|
||
}
|
||
|
||
/**
|
||
* @description 添加指定数量的机器人到队伍
|
||
* @export
|
||
* @param {MemComBtlTeam} comTeam
|
||
* @param {number} roleCe 真实玩家战力,用来做机器人战力基准
|
||
* @param {number} roleLv 真实玩家等级,用来做机器人等级基准
|
||
* @param {number} [count=1]
|
||
*/
|
||
export async function addRobotsToTeam(comTeam: MemComBtlTeam, roleId: string, roleCe: number, roleLv: number, teamMap: Map<string, MemComBtlTeam>, teamDisTimer: Map<string, NodeJS.Timer>, count = 1) {
|
||
const { teamCode, roleStatus } = comTeam;
|
||
let hasCap = roleStatus.findIndex(cur => cur.isCap) != -1;
|
||
const { robotStArr, robotIdArr } = getRandComBtlRobots(roleCe, comTeam.ceLimit, roleLv, count);
|
||
for (let st of robotStArr) {
|
||
if(!hasCap) {
|
||
st.isCap = true;
|
||
hasCap = true;
|
||
}
|
||
addRoleStToTeam(comTeam, st);
|
||
await ComBattleTeamModel.addRole(teamCode, st);
|
||
}
|
||
sendMessageToTeam(teamCode, PUSH_ROUTE.TEAM_JOIN, { teamInfo: comTeam })
|
||
setDismissTimer(comTeam, teamMap, roleId, teamDisTimer);
|
||
}
|
||
|
||
/**
|
||
* @description 在不同的时间加入机器人
|
||
* @export
|
||
* @param {MemComBtlTeam} comTeam
|
||
* @param {RoleType} roleInfo
|
||
* @param {Map<string, MemComBtlTeam>} teamMap
|
||
* @param {Map<string, NodeJS.Timer>} teamDisTimer
|
||
*/
|
||
export async function addRobotsLater(comTeam: MemComBtlTeam, roleInfo: RoleType, teamMap: Map<string, MemComBtlTeam>, teamDisTimer: Map<string, NodeJS.Timer>) {
|
||
const teamStatus = comTeam;
|
||
const { teamCode } = teamStatus;
|
||
const { roleId, lv } = roleInfo;
|
||
let { topLineupCe = 1000 } = roleInfo;
|
||
|
||
if (validToJoin(teamStatus)) {
|
||
const robotCnt = 3 - teamStatus.roleIds.length;
|
||
for (let robotIdx = 0; robotIdx < robotCnt; robotIdx++) {
|
||
const joinTime = getRandValueByMinMax(COM_BTL_CONST.MIN_CAP_TIME, COM_BTL_CONST.MAX_CAP_TIME, 0);
|
||
setTimeout(async () => {
|
||
const curTeamStatus = teamMap.get(teamCode);
|
||
if (validToJoin(curTeamStatus)) {
|
||
await addRobotsToTeam(curTeamStatus, roleId, topLineupCe, lv, teamMap, teamDisTimer, 1);
|
||
}
|
||
}, joinTime);
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @description 从数组里找出第一个不在黑名单的队伍
|
||
* @export
|
||
* @param {ComBattleTeamType[]} teams 队伍数组
|
||
* @param {string} roleId 要加入的玩家 id
|
||
* @returns
|
||
*/
|
||
export async function oneTeamNotInBlack(teams: ComBattleTeamType[], roleId: string) {
|
||
for (let team of teams) {
|
||
let { roleIds } = team;
|
||
const inBlackList = await teammateInBlackList(roleId, roleIds);
|
||
if (!inBlackList) {
|
||
return team;
|
||
}
|
||
}
|
||
return null;
|
||
}
|
||
|
||
// export async function setComBtlOnUserLeave(roleId: string, teamCode: string) {
|
||
// let res = dispatch(teamCode, pinus.app.getServersByType('battle'), 'battle');
|
||
// await pinus.app.rpc.battle.comBattleRemote.leaveFromBattle.toServer(res.id, roleId, teamCode);
|
||
// }
|
||
|
||
export async function checkHasMyTeam(roleId: string) {
|
||
let battles = pinus.app.getServersByType('battle');
|
||
let hasMyTeam = false;
|
||
for(let server of battles) {
|
||
let checkResult = await pinus.app.rpc.battle.comBattleRemote.checkMyTeam.toServer(server.id, roleId);
|
||
if(checkResult) {
|
||
hasMyTeam = true; break;
|
||
}
|
||
}
|
||
return hasMyTeam;
|
||
}
|
||
|
||
export async function checkTeamStatusAndSend(teamCode: string, roleId: string, sid: string) {
|
||
let team = await ComBattleTeamModel.getTeamByCode(teamCode);
|
||
if(team && (team.status == 2|| team.status == 3)) {
|
||
await sendMessageToUserWithSuc(roleId, PUSH_ROUTE.TEAM_COMPLETE, { teamCode, result: team.status == 2? true: false, timeout: team.timeout }, sid);
|
||
}
|
||
} |