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 // 队伍是否开放加入 pub: boolean; // 对应藏宝图 Id blueprtId: number; // 战斗状态 0:未开始,1:已开始,2:胜利,3:失败 status: number; // 玩家状态 roleStatus: Array; // 队长 roleId capId: string; // 战力限制 ceLimit: number; // boss 血量 bossHp: number; // 品质 quality: number; } export class ComBattleHandler { constructor(private app: Application) { } private teamMap: Map = 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 }, 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}, 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}, 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 }); } }