Files
ZYZ/game-server/app/servers/battle/handler/comBattleHandler.ts
T
2020-11-26 11:26:10 +08:00

473 lines
20 KiB
TypeScript

import { IT_TYPE, GOLD_COST_RATIO, CURRENCY_BY_TYPE, CURRENCY_TYPE } from '../../../consts/consts';
import { getGoodById, getBossHpByBlueprtId, getComBtlSetByQuality, getBlueprtComposeByQuality, getBluePrtByQuality } from '../../../pubUtils/gamedata';
import { COM_TEAM_STATUS, COM_TEAM_ENABLE_LV } from '../../../consts/consts';
import { ComBattleTeamModel } from '../../../db/ComBattleTeam';
import Role, { RoleModel } from '../../../db/Role';
import { STATUS } from '../../../consts/statusCode';
import { Application, BackendSession, BlackListFunction } from 'pinus';
import { resResult, getRandomByLen, calculateNum } from '../../../pubUtils/util';
import { RoleStatus } from '../../../db/ComBattleTeam';
import { ItemModel } from '../../../db/Item';
import { handleReward } from '../../../services/rewardService';
export default function(app: Application) {
return new ComBattleHandler(app);
}
class ComTeam {
// 队伍唯一编号
teamCode: string;
// 玩家列表
roleIds: Array<string>
// 队伍是否开放加入
pub: boolean;
// 对应藏宝图 Id
blueprtId: number;
// 战斗状态 0:未开始,1:已开始,2:胜利,3:失败
status: number;
// 玩家状态
roleStatus: Array<RoleStatus>;
// 队长 roleId
capId: string;
// 战力限制
ceLimit: number;
// boss 血量
bossHp: number;
// 品质
quality: number;
}
export class ComBattleHandler {
constructor(private app: Application) {
}
private teamMap: Map<string, ComTeam> = new Map();
async createTeam(msg: {blueprtId: number, heroes: [ number ], pub: boolean, ceLimit: number}, session: BackendSession) {
let roleId = session.get('roleId');
let roleName = session.get('roleName');
let sid = session.get('sid');
let teamCode = session.get('teamCode');
const { blueprtId, heroes, pub, ceLimit } = msg;
console.log('createTeam msg: ', msg);
// 检查藏宝图Id是否合法
let goodData = getGoodById(blueprtId);
if (!goodData || goodData.itid !== IT_TYPE.BLUEPRT) return resResult(STATUS.COM_BATTLE_BLUEPRT_INVALID);
// 检查藏宝图是否足够
let { lv, headHid, topFiveCe, sHid } = await RoleModel.findByRoleId(roleId);
if (lv < COM_TEAM_ENABLE_LV) return resResult(STATUS.COM_BATTLE_LV_NOT_ENOUGH);
let blueprt = await ItemModel.findbyRoleAndGidAndCount(roleId, blueprtId, 1);
if (!blueprt) return resResult(STATUS.COM_BATTLE_BLUEPRT_NOT_FOUND);
// 检查是否有已创建未结束的寻宝,预先占用一张藏宝图
let teams = await ComBattleTeamModel.getTeamByCapAndStatus(roleId, COM_TEAM_STATUS.FIGHTING);
if (teams && blueprt.count <= teams.length) return resResult(STATUS.COM_BATTLE_BLUEPRT_NOT_ENOUGH);
// TODO: 检查武将是否拥有
// 创建队伍数据结构
let comTeam = new ComTeam();
comTeam.blueprtId = blueprtId;
comTeam.quality = goodData.quality;
comTeam.capId = roleId;
comTeam.pub = pub;
comTeam.teamCode = teamCode;
comTeam.roleIds = [roleId];
comTeam.status = COM_TEAM_STATUS.DEFAULT;
comTeam.ceLimit = ceLimit;
comTeam.bossHp = getBossHpByBlueprtId(blueprtId) || 10000;
let roleStatus = new RoleStatus();
roleStatus.heroes = heroes;
roleStatus.isCap = true;
roleStatus.headHid = headHid || 19;
roleStatus.topFiveCe = topFiveCe;
roleStatus.roleId = roleId;
roleStatus.isReady = true;
roleStatus.totalDmg = 0;
roleStatus.roleName = roleName;
roleStatus.lv = lv;
roleStatus.sHid = sHid || 19;
comTeam.roleStatus = [roleStatus];
this.teamMap.set(teamCode, comTeam);
const team = await ComBattleTeamModel.createTeam(comTeam);
if (!team) return resResult(STATUS.COM_BATTLE_CREATE_ERR);
let channelService = this.app.get('channelService');
let channel = channelService.getChannel(teamCode, true);
let users = channel.getMembers();
if (users.indexOf(roleId) === -1) {
channel.add(roleId, sid);
}
return resResult(STATUS.SUCCESS, { teamCode, roleStatus });
}
async joinTeam(msg: {teamCode: string, isFrd: boolean}, session: BackendSession) {
let roleId = session.get('roleId');
let roleName = session.get('roleName');
let sid = session.get('sid');
console.log('teamMap:' + JSON.stringify(this.teamMap));
let { teamCode, isFrd } = msg;
let teamStatus = this.teamMap.get(teamCode);
if (!teamStatus || teamStatus.status !== 0 || teamStatus.roleIds.length === 3) return resResult(STATUS.COM_BATTLE_MEMBER_LIMIT);
if (teamStatus.roleIds.indexOf(roleId) !== -1) return resResult(STATUS.COM_BATTLE_DUP_ENTER);
let { lv, headHid, topFiveCe, sHid } = await Role.findByRoleId(roleId);
let { quality } = getGoodById(teamStatus.blueprtId);
let { assistanceLevel, assistanceTime } = getComBtlSetByQuality(quality);
if (lv < COM_TEAM_ENABLE_LV) {
return resResult(STATUS.COM_BATTLE_LV_NOT_ENOUGH);
} else if (lv < assistanceLevel) {
return resResult(STATUS.COM_BATTLE_ASSIST_LV_NOT_ENOUGH);
} else if (topFiveCe < teamStatus.ceLimit) {
return resResult(STATUS.COM_BATTLE_CE_LIMIT);
}
let teams = await ComBattleTeamModel.getTeamByRoleAndTime(roleId, teamStatus.quality, new Date(new Date().setHours(0, 0, 0, 0)));
if (teams.length >= assistanceTime) resResult(STATUS.COM_BATTLE_ASSIST_NOT_ENOUGH);
let roleStatus = new RoleStatus();
roleStatus.heroes = [];
roleStatus.isCap = false;
roleStatus.headHid = headHid || 19; // 默认给赵云
roleStatus.topFiveCe = topFiveCe || 0;
roleStatus.roleId = roleId;
roleStatus.roleName = roleName;
roleStatus.isFrd = isFrd;
roleStatus.isReady = false;
roleStatus.totalDmg = 0;
roleStatus.lv = lv;
roleStatus.sHid = sHid || 19;
const team = await ComBattleTeamModel.addRole(teamCode, roleStatus);
if (!team) {
return resResult(STATUS.COM_BATTLE_CREATE_ERR);
}
let channelService = this.app.get('channelService');
let channel = channelService.getChannel(teamCode, false);
let users = channel.getMembers();
if (users.indexOf(roleId) === -1) {
channel.add(roleId, sid);
}
channel.pushMessage('onTeamJoin', {teamCode, roleInfo: roleStatus});
teamStatus.roleIds.push(roleId);
teamStatus.roleStatus.push(roleStatus);
return resResult(STATUS.SUCCESS, { teamInfo: {
teamCode, roleStatus: teamStatus.roleStatus, capId: teamStatus.capId, ceLimit: teamStatus.ceLimit
}});
}
async getTeams(msg: { blueprtIds: Array<number> }, session: BackendSession) {
let roleId = session.get('roleId');
let { lv } = await Role.findByRoleId(roleId);
if (lv < COM_TEAM_ENABLE_LV) return resResult(STATUS.COM_BATTLE_LV_NOT_ENOUGH);
const teams = await ComBattleTeamModel.getTeamByBlueprt(msg.blueprtIds, COM_TEAM_STATUS.DEFAULT, true);
if (!teams) return resResult(STATUS.COM_BATTLE_NO_VALID_TEAM);
return resResult(STATUS.SUCCESS, { teamInfos: teams});
}
async getAssistCnt(msg: {}, session: BackendSession) {
let roleId = session.get('roleId');
let teams = await ComBattleTeamModel.getTeamByRoleAndTime(roleId, null, new Date(new Date().setHours(0, 0, 0, 0)));
let cnt = [0, 0, 0, 0, 0];
teams.forEach(team => {
if (team && team.quality) {
cnt[team.quality - 1] += 1;
}
});
return resResult(STATUS.SUCCESS, {cnt});
}
async teammateReady(msg: {teamCode: string, heroes: Array<number>}, session: BackendSession) {
let roleId = session.get('roleId');
let { teamCode, heroes } = msg;
let teamStatus = this.teamMap.get(teamCode);
if (!teamStatus || !teamStatus.roleIds || teamStatus.roleIds.indexOf(roleId) === -1) return resResult(STATUS.COM_BATTLE_TEAM_INVALID);
let team = await ComBattleTeamModel.updateHeroes(teamCode, roleId, heroes);
if (!team) return resResult(STATUS.COM_BATTLE_UPDATE_HEROES_ERR);
teamStatus.roleStatus.forEach(st => {
if (st && st.roleId === roleId) {
st.heroes = heroes;
st.isReady = true;
}
});
let channelService = this.app.get('channelService');
let channel = channelService.getChannel(teamCode, false);
channel.pushMessage('onTeammateReady', {teamCode, roleId, heroes});
return resResult(STATUS.SUCCESS);
}
async rmTeammate(msg: {teamCode: string, roleIdToRm: string}, session: BackendSession) {
let roleId = session.get('roleId');
let { teamCode, roleIdToRm } = msg;
let teamStatus = this.teamMap.get(teamCode);
if (!teamStatus || !teamStatus.roleIds || teamStatus.roleIds.indexOf(roleId) === -1) return resResult(STATUS.COM_BATTLE_TEAM_INVALID);
if (roleId === teamStatus.capId && roleId === roleIdToRm) return resResult(STATUS.COM_BATTLE_RM_SELF);
if (roleId !== teamStatus.capId && roleId !== roleIdToRm) return resResult(STATUS.COM_BATTLE_CAN_NOT_RM);
let team = await ComBattleTeamModel.removeRole(teamCode, roleIdToRm);
if (!team) return resResult(STATUS.COM_BATTLE_RM_TEAMMATE_ERR);
let roleIdx = teamStatus.roleIds.indexOf(roleIdToRm);
teamStatus.roleIds.splice(roleIdx, 1);
teamStatus.roleStatus.some((elem, idx) => {
if (elem.roleId === roleIdToRm) {
teamStatus.roleStatus.splice(idx, 1);
}
});
let channelService = this.app.get('channelService');
let channel = channelService.getChannel(teamCode, false);
let users = channel.getMembers();
if (users.indexOf(roleIdToRm) !== -1) {
channel.removeMember(roleIdToRm);
}
channel.pushMessage('onLeaveTeam', {teamCode, roleId: roleIdToRm});
return resResult(STATUS.SUCCESS);
}
async dismiss(msg: {teamCode: string}, session: BackendSession) {
let roleId = session.get('roleId');
let { teamCode } = msg;
let teamStatus = this.teamMap.get(teamCode);
if (!teamStatus || !teamStatus.roleIds || teamStatus.roleIds.indexOf(roleId) === -1) return resResult(STATUS.COM_BATTLE_TEAM_INVALID);
if (roleId !== teamStatus.capId) return resResult(STATUS.COM_BATTLE_CAP_ONLY);
let team = await ComBattleTeamModel.removeTeam(teamCode);
if (!team) return resResult(STATUS.COM_BATTLE_DISSMISS_ERR);
let rmSt = this.teamMap.delete(teamCode);
if (!rmSt) return resResult(STATUS.COM_BATTLE_DISSMISS_ERR);
let channelService = this.app.get('channelService');
let channel = channelService.getChannel(teamCode, false);
channel.pushMessage('onTeamDismiss', {teamCode});
channel.destroy();
return resResult(STATUS.SUCCESS);
}
async startBattle(msg: {teamCode: string}, session: BackendSession) {
let roleId = session.get('roleId');
let { teamCode } = msg;
let teamStatus = this.teamMap.get(teamCode);
if (!teamStatus || !teamStatus.roleIds || teamStatus.roleIds.indexOf(roleId) === -1) return resResult(STATUS.COM_BATTLE_TEAM_INVALID);
if (teamStatus.capId !== roleId) return resResult(STATUS.COM_BATTLE_CAP_ONLY);
if (teamStatus.status !== COM_TEAM_STATUS.DEFAULT) return resResult(STATUS.COM_BATTLE_ALREADY_START);
for (let roleSt of teamStatus.roleStatus) {
if (!roleSt.isReady) {
return resResult(STATUS.COM_BATTLE_TEAM_NO_READY);
}
}
teamStatus.status = COM_TEAM_STATUS.FIGHTING;
let channelService = this.app.get('channelService');
let channel = channelService.getChannel(teamCode, false);
channel.pushMessage('onComBtlStart', {teamCode, roleStatus: teamStatus.roleStatus});
return resResult(STATUS.SUCCESS);
}
async action(msg: {teamCode: string, heroes: Array<{hid: number, hurtHp: number}>, killed: Array<number>}, session: BackendSession) {
let roleId = session.get('roleId');
let { teamCode, heroes, killed } = msg;
let teamStatus = this.teamMap.get(teamCode);
if (!teamStatus || !teamStatus.roleIds || teamStatus.roleIds.indexOf(roleId) === -1) return resResult(STATUS.COM_BATTLE_TEAM_INVALID);
if (teamStatus.status !== COM_TEAM_STATUS.FIGHTING) return resResult(STATUS.COM_BATTLE_NOT_START);
let totalHurtHp = 0;
if (heroes && heroes.length) {
heroes.forEach(hero => {
if (hero.hurtHp > 0) {
totalHurtHp += hero.hurtHp;
}
});
}
let curRoleSt = null;
teamStatus.roleStatus.forEach(roleSt => {
if (roleSt.roleId === roleId) {
if (killed && killed.length) {
killed.forEach(killedHid => {
if (roleSt.killed.indexOf(killedHid) === -1) {
roleSt.killed.push(killedHid);
}
});
}
roleSt.totalDmg += totalHurtHp;
curRoleSt = roleSt;
teamStatus.bossHp -= totalHurtHp;
}
});
let channelService = this.app.get('channelService');
let channel = channelService.getChannel(teamCode, false);
channel.pushMessage('onTeammateAct', {teamCode, bossHp: teamStatus.bossHp, roleStatus: {roleId, totalDmg: curRoleSt.totalDmg, killed}});
return resResult(STATUS.SUCCESS);
}
async battleEnd(msg: {teamCode: string, isSuccess: boolean}, session: BackendSession) {
let roleId = session.get('roleId');
let { teamCode, isSuccess } = msg;
let teamStatus = this.teamMap.get(teamCode);
if (!teamStatus || !teamStatus.roleIds || teamStatus.roleIds.indexOf(roleId) === -1) return resResult(STATUS.COM_BATTLE_TEAM_INVALID);
let channelService = this.app.get('channelService');
let channel = channelService.getChannel(teamCode, false);
if (isSuccess && teamStatus.bossHp <= 0) {
let team = await ComBattleTeamModel.updateResult(teamCode, roleId, isSuccess);
if (!team) return resResult(STATUS.COM_BATTLE_RESULT_ERR);
// TODO: 根据策划结论考虑是否在推送中添加掉落
// TODO: 用户总伤害等的持久化
channel.pushMessage('onTeamComplete', {teamCode, result: isSuccess});
} else if (!isSuccess) {
let team = await ComBattleTeamModel.updateResult(teamCode, roleId, isSuccess);
if (!team) return resResult(STATUS.COM_BATTLE_RESULT_ERR);
if (team.status === COM_TEAM_STATUS.LOOSE) {
channel.pushMessage('onTeamComplete', {teamCode, result: isSuccess});
} else {
channel.pushMessage('onTeammateAct', {teamCode, bossHp: teamStatus.bossHp, roleStatus: {roleId, battleStatus: 2}});
}
}
return resResult(STATUS.SUCCESS, { bossHp: teamStatus.bossHp });
}
async getTeamRec(msg: {}, session: BackendSession) {
let roleId = session.get('roleId');
let teams = await ComBattleTeamModel.getTeamByRoleAndTime(roleId, null, new Date(new Date().setHours(0, 0, 0, 0) - 2 * 24 * 60 * 60 * 1000));
if (!teams) return resResult(STATUS.COM_BATTLE_NO_RECENT_REC);
return resResult(STATUS.SUCCESS, {teamInfos: teams});
}
// async startBattle(msg: {}, session: BackendSession) {
// let roleId = session.get('roleId');
// let roleName = session.get('roleName');
// let sid = session.get('sid');
// let teamCode = session.get('teamCode');
// console.log('role in startBattle: ', roleId, roleName, teamCode);
// let channelService = this.app.get('channelService');
// let channel = channelService.getChannel(teamCode, true);
// let users = channel.getMembers();
// if (users.indexOf(roleId) === -1) {
// channel.add(roleId, sid);
// }
// users = channel.getMembers();
// channel.pushMessage('onAdd', {users});
// let tsid = channel.getMember(roleId)['sid'];
// channelService.pushMessageByUids('bossHp', {data: 'datadata'}, [{
// uid: roleId,
// sid: tsid
// }]);
// return resResult(STATUS.SUCCESS, { users, teamCode });
// }
// /**
// * Send messages to users
// *
// * @param {Object} msg message from client
// * @param {Object} session
// *
// */
// async enterBattle(msg: {battleId: string , target: string}, session: BackendSession) {
// let roleId = session.get('roleId');
// let roleName = session.get('roleName');
// let sid = session.get('sid');
// console.log('role in enterBattle: ', roleId, roleName, msg, this.app.rpc);
// let channelService = this.app.get('channelService');
// let channel = channelService.getChannel(msg.battleId, false);
// let users = channel.getMembers();
// if (users.indexOf(roleId) === -1) {
// channel.add(roleId, sid);
// } else {
// return resResult(STATUS.COM_BATTLE_DUP_ENTER);
// }
// channel.pushMessage('onAddBattle', {users});
// return resResult(STATUS.SUCCESS, { users });
// }
// async hurtHp(msg: {battleId: string, bossHurt: number, actorHurt: [{ actorId: number, actorHurt: number}]}, session: BackendSession) {
// let roleId = session.get('roleId');
// let roleName = session.get('roleName');
// console.log('role in enterBattle: ', roleId, roleName, msg);
// let channelService = this.app.get('channelService');
// let channel = channelService.getChannel(msg.battleId, false);
// this.bossHp -= msg.bossHurt;
// if (this.bossHp < 0) {
// this.bossHp = 0;
// channel.pushMessage('bossHp', {data: 'boss 挂啦!!!!!'}, undefined);
// }
// channel.pushMessage('bossHp', {bossHp: this.bossHp}, undefined);
// return resResult(STATUS.SUCCESS, { bossHp: this.bossHp});
// }
async composeBlueprt(msg: {original: Array<{id: number, count: number}>}, session: BackendSession) {
const roleId = session.get('roleId');
const roleName = session.get('roleName');
const { original } = msg;
// 原材料检查
let originalQuality: number, originalSum: number = 0;
for(let {id, count} of original) {
const goodInfo = getGoodById(id);
if(!originalQuality) originalQuality = goodInfo.quality;
if(originalQuality != goodInfo.quality) {
return resResult(STATUS.COM_BLUEPRT_QUALITY_ERROR);
}
if(goodInfo.itid == IT_TYPE.BLUEPRT) {
originalSum += count;
}
}
const dicCompose = getBlueprtComposeByQuality(originalQuality);
if(!dicCompose) {
return resResult(STATUS.COM_BLUEPRT_QUALITY_CANNOT_COMPOSE);
}
if(originalSum != dicCompose.blueprtNum) {
return resResult(STATUS.COM_BLUEPRT_COUNT_ERROR);
}
// 检查元宝
const role = await RoleModel.findByRoleId(roleId);
const costGold = calculateNum(GOLD_COST_RATIO.BLUEPRT_COMPOSE_COST, {num: originalQuality}, 1000);
if(!role || role.gold < costGold) {
return resResult(STATUS.TOWER_GOLD_NOT_ENOUGH);
}
// 添加寻宝币
original.push({
id: CURRENCY_BY_TYPE.get(CURRENCY_TYPE.TREASURE_POINT),
count: dicCompose.coinNum
});
// 消耗藏宝图和寻宝币
const rec = await ItemModel.decreaseItems(roleId, original);
if(!rec) {
return resResult(STATUS.BATTLE_CONSUMES_NOT_ENOUGH);
}
// 消耗元宝
await RoleModel.costGold(roleId, costGold);
const targetList = getBluePrtByQuality(dicCompose.targetQuality);
const target = getRandomByLen(targetList);
const reward = [{gid: target, count: 1}];
const goods = await handleReward(roleId, roleName, reward);
return resResult(STATUS.SUCCESS, { ...goods, costGold });
}
}