diff --git a/game-server/app/servers/battle/handler/comBattleHandler.ts b/game-server/app/servers/battle/handler/comBattleHandler.ts index 59d0e84c5..84a02cda4 100644 --- a/game-server/app/servers/battle/handler/comBattleHandler.ts +++ b/game-server/app/servers/battle/handler/comBattleHandler.ts @@ -1,25 +1,158 @@ -import { STATUS } from './../../../consts/statusCode'; +import { IT_TYPE } from '../../../consts/consts'; +import { getGoodById } 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 } from 'pinus'; import { resResult } from '../../../pubUtils/util'; +import { RoleStatus } from './../../../db/ComBattleTeam'; 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; +} export class ComBattleHandler { constructor(private app: Application) { } private bossHp: number = 10000; + private teamMap: Map = new Map(); - async startBattle(msg: {}, session: BackendSession) { - const battleId = Math.random().toString(36).slice(-8); + async createTeam(msg: {blueprtId: number, heroes: [ number ], pub: boolean, ceLimit: number}, session: BackendSession) { + let roleId = session.get('roleId'); + 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 { consumeGoods, lv, headHid, topFiveCe } = await RoleModel.findByRoleId(roleId); + if (lv < COM_TEAM_ENABLE_LV) return resResult(STATUS.COM_BATTLE_LV_NOT_ENOUGH); + let blueprt = consumeGoods.find(good => good.id === blueprtId && good.count >= 1); + if (!blueprt) return resResult(STATUS.COM_BATTLE_BLUEPRT_NOT_FOUND); + // 检查是否有已创建未结束的寻宝,预先占用一张藏宝图 + let teams = await ComBattleTeamModel.findTeamByCapAndStatus(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.capId = roleId; + comTeam.pub = pub; + comTeam.teamCode = teamCode; + comTeam.roleIds = [roleId]; + comTeam.status = COM_TEAM_STATUS.DEFAULT; + comTeam.ceLimit = ceLimit; + + let roleStatus = new RoleStatus(); + roleStatus.heroes = heroes; + roleStatus.isCap = true; + roleStatus.headHid = headHid; + roleStatus.topFiveCe = topFiveCe; + roleStatus.roleId = roleId; + 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 }); + } + + 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('role in startBattle: ', roleId, roleName, battleId); + console.log('role in joinTeam: ', roleId, roleName, msg, this.app.rpc); + console.log('teamMap:' + JSON.stringify(this.teamMap)); + let { teamCode, isFrd } = msg; + let teamStatus = this.teamMap.get(teamCode); + if (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); + // TODO:助战等级限制,等表 + let { lv, headHid, topFiveCe } = await Role.findByRoleId(roleId); + if (lv < COM_TEAM_ENABLE_LV) { + return resResult(STATUS.COM_BATTLE_LV_NOT_ENOUGH); + } else if (topFiveCe < teamStatus.ceLimit) { + return resResult(STATUS.COM_BATTLE_CE_LIMIT); + } + + let roleStatus = new RoleStatus(); + roleStatus.heroes = []; + roleStatus.isCap = false; + roleStatus.headHid = headHid; + roleStatus.topFiveCe = topFiveCe; + roleStatus.roleId = roleId; + roleStatus.isFrd = isFrd; + 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(battleId, true); + let channel = channelService.getChannel(teamCode, false); + let users = channel.getMembers(); + if (users.indexOf(roleId) === -1) { + channel.add(roleId, sid); + } + channel.pushMessage('onTeamJoin', {teamCode, roleInfo: {roleId, headHid, topFiveCe}}); + 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 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); @@ -33,7 +166,7 @@ export class ComBattleHandler { sid: tsid }]); - return resResult(STATUS.SUCCESS, { users, battleId }); + return resResult(STATUS.SUCCESS, { users, teamCode }); } /** diff --git a/game-server/app/util/routeUtil.ts b/game-server/app/util/routeUtil.ts index 8aaff6868..0cf05ea75 100644 --- a/game-server/app/util/routeUtil.ts +++ b/game-server/app/util/routeUtil.ts @@ -22,7 +22,23 @@ export function battle(session: Session, msg: any, app: Application, cb: (err: E return; } - let res = dispatch(session.get('roleId'), battleServers); + let rid = session.get('roleId'); + + if (msg.args && msg.args.length > 0) { + for (let arg of msg.args) { + if (!arg.route) continue; + if (arg.route === 'battle.comBattleHandler.createTeam') { + rid = Math.random().toString(36).slice(-8); + session.set('teamCode', rid); + } else if (arg.route.indexOf('battle.comBattleHandler') !== -1) { + if (arg.body.teamCode) { + rid = arg.body.teamCode; + } + } + } + } + + let res = dispatch(rid, battleServers); cb(null, res.id); } diff --git a/shared/consts/consts.ts b/shared/consts/consts.ts index d3bc4499a..ccb7b7708 100644 --- a/shared/consts/consts.ts +++ b/shared/consts/consts.ts @@ -25,6 +25,10 @@ export const BATTLE_REWARD_TYPE = { RANDOM_REWARD: 3 }; +export const IT_TYPE = { + BLUEPRT: 28 +} + export const GOOD_TYPE = { EQUIP: 1, CONSUMES: 2, @@ -220,4 +224,31 @@ export const GOLD_COST_RATIO = { export const EXPRESSION = { "CE": "1*hp+2*atk+2*matk+2*def+2*mdef+2*agi+2*luk+1*hit+1*cri+1*flee+1*antCri+1.75*damageIncrease+1.75*damageDecrease+3.5*defIngnore+3.5*bloodSuck" -} \ No newline at end of file +} + +// 寻宝(共斗)相关 +export const COM_TEAM_STATUS = { + DEFAULT: 0, + FIGHTING: 1, + WIN: 2, + LOOSE: 3 +} + +// 功能开启等级 +export const COM_TEAM_ENABLE_LV = 1; +// 助战掉落占队长掉落的比例 +export const COM_ASSIST_DROP_RATE = 0.5; +// 藏宝图伪随机所需体力 +export const COM_BLUEPRT_DROP_PER_AP = 10; +// 每局时长限制,秒 +export const COM_BATTLE_TIME_LMT = 10 * 60; +// 机器人生成时间,秒 +export const COM_BATTLE_ROBOT_TIME_LMT = 1; +// 每个机器人消耗 boss 血量百分比 +export const COM_BATTLE_ROBOT_HURT_RATE = 0.4; +// 每个机器人消耗 boss 血量百分比浮动范围 +export const COM_BATTLE_ROBOT_HURT_RAND_RATE = 0.05; +// 每日情谊点上限 +export const COM_BATTLE_FRDCNT_MAX = 100; +// 情谊点掉落数量 +export const COM_BATTLE_FRDCNT_DROP = 10; \ No newline at end of file diff --git a/shared/consts/statusCode.ts b/shared/consts/statusCode.ts index 95f468cf8..5c259d4ec 100644 --- a/shared/consts/statusCode.ts +++ b/shared/consts/statusCode.ts @@ -69,8 +69,18 @@ export const STATUS = { TOWER_TASK_MISSING: { code: 20517, simStr: '未找到该任务' }, TOWER_HANG_UP_NOT_START: { code: 20518, simStr: '挂机尚未开启' }, TOWER_REF_CNT_NOT_ENOUGH: { code: 20518, simStr: '派遣次数不足' }, - // 共斗 20600 - 20699 + // 寻宝(共斗) 20600 - 20699 COM_BATTLE_DUP_ENTER: { code: 20601, simStr: '不能重复加入' }, + COM_BATTLE_BLUEPRT_NOT_FOUND: { code: 20602, simStr: '藏宝图不足' }, + COM_BATTLE_BLUEPRT_INVALID: { code: 20603, simStr: '需使用藏宝图才能开启' }, + COM_BATTLE_BLUEPRT_NOT_ENOUGH: { code: 20604, simStr: '藏宝图不足,还有未结束的寻宝' }, + COM_BATTLE_CREATE_ERR: { code: 20605, simStr: '创建队伍失败' }, + COM_BATTLE_LV_NOT_ENOUGH: { code: 20606, simStr: '主公等级不够' }, + COM_BATTLE_MEMBER_LIMIT: { code: 20607, simStr: '队伍人数已满' }, + COM_BATTLE_CE_LIMIT: { code: 20608, simStr: '战力不足' }, + COM_BATTLE_JOIN_ERR: { code: 20609, simStr: '加入队伍失败' }, + COM_BATTLE_NO_VALID_TEAM: { code: 20610, simStr: '没有合适的队伍' }, + // 秘境 20700 - 20799 DUNGEON_REFRESH_TIMES_LACK: { code: 20701, simStr: '购买次数不足' }, DUNGEON_TIMES_LACK: { code: 20701, simStr: '挑战次数不足' }, diff --git a/shared/db/ComBattleTeam.ts b/shared/db/ComBattleTeam.ts index e5bfb8033..5f7329f71 100644 --- a/shared/db/ComBattleTeam.ts +++ b/shared/db/ComBattleTeam.ts @@ -1,7 +1,7 @@ import BaseModel from './BaseModel'; import { index, getModelForClass, prop } from '@typegoose/typegoose'; -class RoleStatus { +export class RoleStatus { @prop({ required: true }) roleId: string; @prop({ required: true }) @@ -15,8 +15,20 @@ class RoleStatus { @prop({ required: false, default: '' }) battleCode: string; // 玩家所用阵容 - @prop({ required: false }) + @prop({ required: false, type: Number, default: [] }) heroes: Array; + // 阵亡武将 + @prop({ required: false, default: [] }) + killed: Array; + // 是否情谊助阵 + @prop({ required: false, default: false }) + isFrd: boolean; + // 头像 + @prop({ required: true, default: 1 }) + headHid: number; + // 前五战力 + @prop({ required: true, default: 0 }) + topFiveCe: number; } @index({ teamCode: 1 }) @@ -28,7 +40,7 @@ export default class ComBattleTeam extends BaseModel { @prop({ required: true }) teamCode: string; - @prop({ required: true, default: [] }) + @prop({ required: true, type: String, default: [] }) roleIds: Array // 队伍是否开放加入 @@ -43,12 +55,36 @@ export default class ComBattleTeam extends BaseModel { @prop({ required: true, default: 0 }) status: number; - @prop({ required: true, default: [] }) + @prop({ required: true, type: RoleStatus, default: [] }) roleStatus: Array; // 队长 roleId @prop({ required: true }) capId: string; + + // 战力限制 + @prop({ required: true, default: 0 }) + ceLimit: number; + + public static async createTeam(teamData: {teamCode: string, roleIds: Array, pub: boolean, blueprtId: number, status: number, roleStatus: Array, capId: string}, lean = true) { + const team = await ComBattleTeamModel.findOneAndUpdate({ teamCode: teamData.teamCode }, {$set :{...teamData}}, {upsert: true, new: true}).lean(lean); + return team; + } + + public static async addRole(teamCode: string, roleStatus: RoleStatus, lean = true) { + const team = await ComBattleTeamModel.findOneAndUpdate({ teamCode: teamCode }, {$push: {roleIds: roleStatus.roleId, roleStatus}}, {upsert: true, new: true}).lean(lean); + return team; + } + + public static async findTeamByCapAndStatus(roleId: string, status: number, lean = true) { + const teams = await ComBattleTeamModel.find({capId: roleId, status}).lean(lean); + return teams; + } + + public static async getTeamByBlueprt(blueprtIds: Array, status: number, pub = true, limit = 50, lean = true) { + const teams = await ComBattleTeamModel.find({blueprtId: {$in: blueprtIds}, status, pub}).limit(limit).lean(lean); + return teams; + } } export const ComBattleTeamModel = getModelForClass(ComBattleTeam); \ No newline at end of file diff --git a/shared/db/Role.ts b/shared/db/Role.ts index 827da363f..1e6b709ab 100644 --- a/shared/db/Role.ts +++ b/shared/db/Role.ts @@ -39,6 +39,8 @@ export default class Role extends BaseModel { blocked: boolean; // 是否屏蔽 @prop({ required: true }) code: string; // 邀请码 + @prop({ required: true, default: 1 }) + headHid: number; // 头像所用武将 Id @prop({ required: true, default: 0 }) exp: number; // 经验值