From 3e499de1bcded1373df3d94f8aad2e29d3402d86 Mon Sep 17 00:00:00 2001 From: liangtongchuan Date: Fri, 27 Nov 2020 23:27:35 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AF=BB=E5=AE=9D=E5=8A=A9=E6=88=98=E5=8C=B9?= =?UTF-8?q?=E9=85=8D=E7=AE=80=E5=8D=95=E6=9C=BA=E5=99=A8=E4=BA=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../battle/handler/comBattleHandler.ts | 78 +++++++++++++++---- game-server/app/services/battleService.ts | 28 ++++++- game-server/app/services/comBattleService.ts | 18 +++++ game-server/app/util/routeUtil.ts | 2 +- shared/consts/consts.ts | 22 +++++- shared/db/ComBattleTeam.ts | 11 +-- shared/pubUtils/gamedata.ts | 8 +- shared/pubUtils/util.ts | 15 ++++ 8 files changed, 159 insertions(+), 23 deletions(-) create mode 100644 game-server/app/services/comBattleService.ts diff --git a/game-server/app/servers/battle/handler/comBattleHandler.ts b/game-server/app/servers/battle/handler/comBattleHandler.ts index 9cc95a617..c335dcb67 100644 --- a/game-server/app/servers/battle/handler/comBattleHandler.ts +++ b/game-server/app/servers/battle/handler/comBattleHandler.ts @@ -1,3 +1,4 @@ +import { COM_BATTLE_ROBOT_CE_RATIO, COM_BATTLE_ROBOT_ID_NAME, COM_BATTLE_ASSIST_TIME } from './../../../consts/consts'; 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'; @@ -5,11 +6,13 @@ 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 { resResult, getRandomByLen, calculateNum, getRandValue } from '../../../pubUtils/util'; import { RoleStatus } from '../../../db/ComBattleTeam'; import { ItemModel } from '../../../db/Item'; import { handleReward } from '../../../services/rewardService'; import { getTeamSearchByQuality, setTeamSearchReq } from '../../../services/redisService'; +import { getRandRobot } from '../../../services/battleService'; +import { getRandBlueprtId } from '../../../services/comBattleService'; export default function(app: Application) { return new ComBattleHandler(app); @@ -84,16 +87,18 @@ export class ComBattleHandler { console.log('teammates: ', teammates); if (teammates) { for (let teammate of teammates) { + // TODO: 要判断战力 let roleInfo = await RoleModel.findByRoleId(teammate.roleId); if (!roleInfo) continue; let {roleId, roleName, headHid = 19, sHid = 19, topFiveCe, lv} = roleInfo; // TODO: 没处理情谊助战 - roleStatus.push(new RoleStatus(roleId, roleName, false, false, headHid, sHid, topFiveCe, lv)); + const st = new RoleStatus(roleId, roleName, false, false, headHid, sHid, topFiveCe, lv); + roleStatus.push(st); roleIds.push(roleInfo.roleId); } } // 创建队伍数据结构 - let comTeam = new ComTeam(teamCode, pub, blueprtId, 0, roleId, ceLimit, getBossHpByBlueprtId(blueprtId) || 10000, goodData.quality); + let comTeam = new ComTeam(teamCode, pub, blueprtId, COM_TEAM_STATUS.DEFAULT, roleId, ceLimit, getBossHpByBlueprtId(blueprtId) || 10000, goodData.quality); comTeam.roleStatus = roleStatus; comTeam.roleIds = roleIds; @@ -127,14 +132,46 @@ export class ComBattleHandler { async searchTeam(msg: {qualityArr: [number]}, session: BackendSession) { let roleId = session.get('roleId'); + let roleName = session.get('roleName'); let sid = session.get('sid'); + let teamCode = session.get('teamCode'); const { qualityArr } = msg; - let { lv, headHid = 19, topFiveCe, sHid = 19 } = await RoleModel.findByRoleId(roleId); + let { lv, headHid = 19, topFiveCe = 1000, sHid = 19 } = await RoleModel.findByRoleId(roleId); await setTeamSearchReq(roleId, sid, qualityArr); - setTimeout(() => { - - }, 10000); + let thiz = this; + setTimeout(async () => { + let roleStatus = []; + let roleIds = [] + let robotHeroes = getRandRobot(2); + let roleInfo = new RoleStatus(roleId, roleName, false, false, headHid, sHid, topFiveCe, lv); + roleStatus.push(roleInfo); + roleIds.push(roleId); + let blueprtId = (await getRandBlueprtId(qualityArr)).pop(); + let { quality } = getGoodById(blueprtId); + let comTeam = new ComTeam(teamCode, false, blueprtId, COM_TEAM_STATUS.DEFAULT, 'robot', 0, getBossHpByBlueprtId(blueprtId) || 10000, quality); + for (let robot of robotHeroes) { + const robotCe = getRandValue(topFiveCe, COM_BATTLE_ROBOT_CE_RATIO, 0); + const robotLv = getRandValue(lv, COM_BATTLE_ROBOT_CE_RATIO, 0); + const imgHid = robot[Math.floor(Math.random() * robot.length)]; + const { robotRoleId, robotRoleName } = COM_BATTLE_ROBOT_ID_NAME[Math.floor(Math.random() * COM_BATTLE_ROBOT_ID_NAME.length)]; + let robotStatus = new RoleStatus(robotRoleId, robotRoleName, false, false, imgHid, imgHid, robotCe, robotLv, robot, true); + roleStatus.push(robotStatus); + roleIds.push(robotRoleId); + } + comTeam.roleStatus = roleStatus; + comTeam.roleIds = roleIds; + let channelService = thiz.app.get('channelService'); + const team = await ComBattleTeamModel.createTeam(comTeam); + // if (!team) channelService.pushMessageByUids('onTeamJoin', {teamInfo: null}, [{uid: roleId, sid}]); + thiz.teamMap.set(teamCode, comTeam); + channelService.pushMessageByUids('onTeamJoin', {teamInfo: comTeam}, [{uid: roleId, sid}]); + let channel = channelService.getChannel(teamCode, true); + let users = channel.getMembers(); + if (users.indexOf(roleId) === -1) { + channel.add(roleId, sid); + } + }, COM_BATTLE_ASSIST_TIME); return resResult(STATUS.SUCCESS); } @@ -215,7 +252,27 @@ export class ComBattleHandler { 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 setupHeroes(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; } }); @@ -284,11 +341,6 @@ export class ComBattleHandler { 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'); diff --git a/game-server/app/services/battleService.ts b/game-server/app/services/battleService.ts index 4cec3b752..32b6b8a05 100644 --- a/game-server/app/services/battleService.ts +++ b/game-server/app/services/battleService.ts @@ -5,7 +5,7 @@ import { HANG_UP_CONSTS, TOWER_TASK_CONST, REDIS_KEY } from './../consts/consts' import { BattleRecordModel } from './../db/BattleRecord'; import { TowerRecordModel } from './../db/TowerRecord'; import { RoleModel } from './../db/Role'; -import { getHeroInfoById, getJobInfoById, getTowerDataByLv, getTaskById, getGamedata } from "../pubUtils/gamedata" +import { getHeroInfoById, getJobInfoById, getTowerDataByLv, getTaskById, getGamedata, getRandExpedition, getWarById, getWarJsons } from "../pubUtils/gamedata" import { decodeArrayStr, shouldRefresh, resResult, decodeStr, cal, getRandomWithWeight, getRefTime, decodeStrSingle, genCode } from '../pubUtils/util'; import { handleFixedReward } from './rewardService'; import { STATUS } from '../consts/statusCode'; @@ -347,4 +347,30 @@ export async function getTasksReward(roleId: string, curTime: Date) { } } return goods +} + +/** + * 获取随机机器人数据 + * @param cnt 机器人数量 + * @param withAttr 是否返回属性,false: 仅返回阵容 + */ +export function getRandRobot(cnt = 1, withAttr = false) { + let setInfo = getRandExpedition(cnt); + if (!setInfo || setInfo.length !== cnt) return null; + + let robots = []; + for (let info of setInfo) { + if (!info || !info.warId) continue; + const warInfo = getWarJsons(info.warId).json; + if (!warInfo || !warInfo.length) continue; + + let heroes = []; + for(let hero of warInfo) { + if (hero && hero.relation === 2 && hero.actorId) { + heroes.push(hero.actorId); + } + } + robots.push(heroes); + } + return robots; } \ No newline at end of file diff --git a/game-server/app/services/comBattleService.ts b/game-server/app/services/comBattleService.ts new file mode 100644 index 000000000..342102122 --- /dev/null +++ b/game-server/app/services/comBattleService.ts @@ -0,0 +1,18 @@ +import { getBluePrtByQuality } from "../pubUtils/gamedata"; +import { getRandEelm } from "../pubUtils/util"; + +/** + * 在给定的品质列表中随机返回一定数量的藏宝图Id + * @param qualityArr 品质数组,在所有给定品质的藏宝图中筛选1 + * @param cnt 返回藏宝图数量 + */ +export async function getRandBlueprtId(qualityArr: Array, cnt = 1) { + if (!qualityArr || !qualityArr.length) return null; + let blueprtIdArr = []; + for (let q of qualityArr) { + blueprtIdArr = blueprtIdArr.concat(getBluePrtByQuality(q)); + } + if (blueprtIdArr.length === 0) return null; + const res = getRandEelm(blueprtIdArr, cnt); + return res; +} \ No newline at end of file diff --git a/game-server/app/util/routeUtil.ts b/game-server/app/util/routeUtil.ts index 0cf05ea75..54fad3081 100644 --- a/game-server/app/util/routeUtil.ts +++ b/game-server/app/util/routeUtil.ts @@ -27,7 +27,7 @@ export function battle(session: Session, msg: any, app: Application, cb: (err: E if (msg.args && msg.args.length > 0) { for (let arg of msg.args) { if (!arg.route) continue; - if (arg.route === 'battle.comBattleHandler.createTeam') { + if (['battle.comBattleHandler.createTeam', 'battle.comBattleHandler.searchTeam'].indexOf(arg.route) !== -1) { rid = Math.random().toString(36).slice(-8); session.set('teamCode', rid); } else if (arg.route.indexOf('battle.comBattleHandler') !== -1) { diff --git a/shared/consts/consts.ts b/shared/consts/consts.ts index ac56742a1..3c328e39e 100644 --- a/shared/consts/consts.ts +++ b/shared/consts/consts.ts @@ -280,7 +280,7 @@ export const COM_BLUEPRT_DROP_PER_AP = 10; // 每局时长限制,秒 export const COM_BATTLE_TIME_LMT = 10 * 60; // 机器人生成时间,秒 -export const COM_BATTLE_ROBOT_TIME_LMT = 1; +// export const COM_BATTLE_ROBOT_TIME_LMT = 1; // 每个机器人消耗 boss 血量百分比 export const COM_BATTLE_ROBOT_HURT_RATE = 0.4; // 每个机器人消耗 boss 血量百分比浮动范围 @@ -289,6 +289,24 @@ export const COM_BATTLE_ROBOT_HURT_RAND_RATE = 0.05; export const COM_BATTLE_FRDCNT_MAX = 150; // 情谊点掉落数量 export const COM_BATTLE_FRDCNT_DROP = 10; +// 机器人战力上下浮动百分比 +export const COM_BATTLE_ROBOT_CE_RATIO = 0.2; +// 助战匹配机器人的等待时长 +export const COM_BATTLE_ASSIST_TIME = 60 * 1000; +// 队长匹配机器人的等待时长 +export const COM_BATTLE_CAP_TIME = 60 * 1000; +// 人齐后队长开始时长倒计时 +export const COM_BATTLE_CAP_START_TIME = 60 * 1000; + +// 机器人名字随机 +export const COM_BATTLE_ROBOT_ID_NAME = [ + {robotRoleId: 'cd9h0iy8', robotRoleName: '徐埋农'}, + {robotRoleId: 'rtdgr4oz', robotRoleName: '简普瞳'}, + {robotRoleId: 'rv96unin', robotRoleName: '邛瑛'}, + {robotRoleId: 'b33u625l', robotRoleName: '嵇晁伊'}, + {robotRoleId: 'l6wopj9p', robotRoleName: '颜校'}, + {robotRoleId: '6wdqcumj', robotRoleName: '吉辉娇'} +]; export const REDIS_KEY = { USER_INFO: "userInfo", // 玩家缓存信息 @@ -303,4 +321,4 @@ export const FUNC_OPT_TYPE = { export const FUNCS_ID = { EVENT: 1 -} \ No newline at end of file +} diff --git a/shared/db/ComBattleTeam.ts b/shared/db/ComBattleTeam.ts index b533c2e6b..2f954ffb6 100644 --- a/shared/db/ComBattleTeam.ts +++ b/shared/db/ComBattleTeam.ts @@ -34,14 +34,14 @@ export class RoleStatus { // 前五战力 @prop({ required: true, default: 0 }) topFiveCe: number; - // 是否准备 - @prop({ required: true, default: false }) - isReady: boolean; // 主公等级 @prop({ required: true, default: 1 }) lv: number; + // 是否机器人 + @prop({ required: true, default: false }) + isRobot: boolean; - constructor(roleId: string, roleName: string, isCap: boolean, isFrd: boolean, headHid: number, sHid: number, topFiveCe: number, lv: number) { + constructor(roleId: string, roleName: string, isCap: boolean, isFrd: boolean, headHid: number, sHid: number, topFiveCe: number, lv: number, heroes = [], isRobot = false) { this.roleId = roleId; this.roleName = roleName; this.isCap = isCap; @@ -51,8 +51,9 @@ export class RoleStatus { this.sHid = sHid; this.topFiveCe = topFiveCe; this.lv = lv; - this.heroes = []; + this.heroes = heroes; this.killed = []; + this.isRobot = isRobot; } } diff --git a/shared/pubUtils/gamedata.ts b/shared/pubUtils/gamedata.ts index eef54b921..3f7e874a3 100644 --- a/shared/pubUtils/gamedata.ts +++ b/shared/pubUtils/gamedata.ts @@ -1,7 +1,7 @@ import fs = require('fs'); import path = require('path'); import { ABI_TYPE } from '../consts/abilityConst'; -import { decodeIdCntArrayStr } from './util'; +import { decodeIdCntArrayStr, getRandEelm } from './util'; import { IT_TYPE } from '../consts/consts'; let gamedata = {}; @@ -346,6 +346,12 @@ export function getExpeditionById(id: number) { return expeditionInfo.get(id); } +export function getRandExpedition(cnt = 1) { + const file = 'dic_expedition'; + const data = gamedata['jsons'][file] || []; + return getRandEelm(data, cnt); +} + export function getComBtlSetByQuality(quality: number) { return comBtlInfo.get(quality); } diff --git a/shared/pubUtils/util.ts b/shared/pubUtils/util.ts index b5e0657b4..9f1257f7d 100644 --- a/shared/pubUtils/util.ts +++ b/shared/pubUtils/util.ts @@ -242,6 +242,11 @@ export function getRefTime(now = new Date(), hour: number, day = 0) { return new Date(today + day * 24 * 60 * 60 * 1000); } +/** + * 从一个数组中随机返回不重复的 cnt 个元素数组 + * @param source 原数组 + * @param cnt 返回随机元素个数 + */ export function getRandEelm(source: Array = [], cnt = 1): Array { if (cnt > source.length) return []; if (cnt === source.length) return source; @@ -256,6 +261,16 @@ export function getRandEelm(source: Array = [], cnt = 1): Array { return source.filter((_item, idx) => idxs.has(idx)); } +/** + * 在给定数值的浮动范围中随机一个值 + * @param base 基础数值 + * @param ratio 随机范围:base 值上下浮动 ratio(小于 1 的整数) + * @param decimal 返回值保留的小数位数 + */ +export function getRandValue(base: number, ratio: number, decimal = 2): number { + return parseFloat((base * (1 - ratio + Math.random() * ratio * 2)).toFixed(decimal)); +} + export function resResult(status: {code: number, simStr: string}, data = null, customMsg = '') { const { code, simStr } = status; if (code !== STATUS.SUCCESS.code) {