diff --git a/pm2_dev.sh b/pm2_dev.sh index 27441e7..1941fda 100755 --- a/pm2_dev.sh +++ b/pm2_dev.sh @@ -1,2 +1,2 @@ -pm2 start npm --name "card" -- run "dev:jc" -pm2 start npm --name "robot" -- run "dev:robot" +pm2 start npm --name "card" --log-date-format "YYYY-MM-DD HH:MM:ss" -- run "dev:jc" +pm2 start npm --name "robot" --log-date-format "YYYY-MM-DD HH:MM:ss" -- run "dev:robot" diff --git a/src/common/Debug.ts b/src/common/Debug.ts index 1132649..7a4df6d 100644 --- a/src/common/Debug.ts +++ b/src/common/Debug.ts @@ -7,3 +7,5 @@ export const error = debug('jc:error'); export const msgLog = debug('jc:msg'); export const robotLog = debug('jc:robot'); + +export const assistLog = debug('jc:assist'); diff --git a/src/global.d.ts b/src/global.d.ts index 795ad78..ee8da43 100644 --- a/src/global.d.ts +++ b/src/global.d.ts @@ -8,6 +8,7 @@ import {RemovePetMsg} from "./message/RemovePetMsg"; import {Dispatcher} from "@colyseus/command"; import {Delayed} from "@gamestdio/timer/lib/Delayed"; import {Player} from "./rooms/schema/Player"; +import {RobotClient} from "./robot/RobotClient"; export {}; @@ -34,6 +35,11 @@ declare module "colyseus" { * @param player 玩家id或者玩家的对象 */ getClient(player: string | Player): Client; + + /** + * 获取当前room的client数量 + */ + clientCount(): number; // >>>>>>>>> Begin of extend send message <<<<<<<<<<<<< /** * 广播玩家加入房间 @@ -154,6 +160,8 @@ declare module "colyseus" { */ bMsgQueue(datas: IMsg[], options?: any): void; + send(client: Client, type: string, data?: any): void; + // >>>>>>>>> End of extend send message <<<<<<<<<<<<< @@ -241,6 +249,17 @@ declare module "colyseus" { */ addRobot(playerId?: string):void; + /** + * 添加一个辅助机器人 + * @param sessionId + */ + addAssistClient(sessionId: string): void; + /** + * 获取当前session的辅助机器人 + * @param sessionId + */ + getAssistClient(sessionId: string): RobotClient; + } } diff --git a/src/robot/Robot.ts b/src/robot/Robot.ts index 893dd8e..4b480b6 100644 --- a/src/robot/Robot.ts +++ b/src/robot/Robot.ts @@ -9,6 +9,8 @@ import {Player} from "../rooms/schema/Player"; import {EffectCardCfg} from "../cfg/parsers/EffectCardCfg"; import {SkillTargetType} from "../rooms/logic/skill/SkillConst"; import CfgMan from "../rooms/logic/CfgMan"; +import gameUtil from "../utils/game.util"; +import assistantUtil from "../utils/assistant.util"; export class Robot { host: string; @@ -37,6 +39,17 @@ export class Robot { } } + async reConnect(sessionId: string) { + try { + this.room = await this.client.reconnect(this.roomId, sessionId); + this.addListeners(); + this.sessionId = this.room.sessionId; + return this.room.sessionId; + } catch (err) { + error(`error reConnect room ${this.host}, ${this.roomId}, sessionId: ${sessionId}`); + } + } + addListeners() { let self = this; this.room.onMessage("*", (type, data) => { @@ -117,129 +130,6 @@ export class Robot { this.room.send(messageType, message); } - private checkTriple(cardArr: Card[], card?: Card): Card[] { - if (card) cardArr.push(card); - let pointMap: Map = new Map(); - let cardIdSet: Set = new Set(); - for (let c of cardArr) { - if (c.type !== 1) { - continue; - } - if (pointMap.has(c.number)) { - let arr = pointMap.get(c.number); - arr.push(c); - pointMap.set(c.number, arr); - } else { - pointMap.set(c.number, [c]); - } - cardIdSet.add(c.number); - } - let fetched = false; - let result:Card[] = []; - // 优先出对子 - for (let [point, arr] of pointMap) { - if (card) { - if (point == card.number && arr.length >= 3) { - fetched = true; - result = arr; - break; - } - } else { - if (arr.length >= 3) { - fetched = true; - result = arr; - break; - } - } - - } - if (fetched) { - return result; - } - - let cardIds = [...cardIdSet]; - cardIds.sort((a, b) => a - b); - let tmp = []; - for (let i = 0, length = cardIds.length; i < length; i++) { - let cur = cardIds[i]; - i == 0 && tmp.push(cur); - if (i > 0) { - if (cur != tmp[i - 1] + 1) { - tmp.length = 0; - } - tmp.push(cur); - } - if (card) { - if (tmp.indexOf(card.number) >= 0 && tmp.length >=3 ){ - break; - } - } else { - if (tmp.length >= 3) { - break; - } - } - } - - if (tmp.length >= 3) { - let subTmp = []; - for (let i = tmp[0] - 1; i > 0 ; i -- ) { - if (cardIdSet.has(i)) { - subTmp.push(i); - } else { - break; - } - } - for (let i = tmp[tmp.length]; i < cardIdSet.size; i ++) { - if (cardIdSet.has(i)) { - subTmp.push(i); - } else { - break; - } - } - tmp = tmp.concat(subTmp); - for (let point of tmp) { - if (card && point === card.number) { - result.push(card); - } else { - result.push(pointMap.get(point)[0]); - } - } - return result; - } else { - return arrUtil.randomGet(cardArr, 1); - } - } - /** - * 随机获取敌对玩家 - * @private - */ - private getEnemyPlayer(): Player { - let enemys = []; - for (let [,player] of this.room.state.players) { - if (player.team !== this.player.team) { - enemys.push(player); - } - } - return arrUtil.randomOne(enemys); - } - - /** - * 随机获取可用的随从 - * @param player - * @private - */ - private getRandomPet(player: Player): number { - let pets = []; - for (let [, pet] of player.pets) { - if (pet.ap > 0 && pet.state == 1) - pets.push(pet); - } - let result; - if (pets.length > 0) { - result = arrUtil.randomOne(pets); - } - return result ? result.pos : -1; - } // >>>>>>>>>>>>>>>>>> begin /** @@ -247,13 +137,9 @@ export class Robot { * @private */ private async selectHero() { - let heroMap: Map = global.$cfg.get(BaseConst.HERO); - let heroArr = [...heroMap.values()]; - let hero = arrUtil.randomGet(heroArr, 1); await this.delay(2); - this.reply('select_hero_c2s', { - heroId: hero[0].id - }); + let data = assistantUtil.randomHero(); + this.reply('select_hero_c2s', data); } /** @@ -284,7 +170,7 @@ export class Robot { await this.delay(3); let self = this; let cardArr = [...self.player.cards.values()]; - let cards = self.checkTriple(cardArr); + let cards = assistantUtil.checkTriple(cardArr); if (!cards) { return; } @@ -302,7 +188,7 @@ export class Robot { await this.delay(2); let targetCard = [...this.room.state.cards.values()][0]; let cardArr = [...this.player.cards.values()]; - let tmpCards = this.checkTriple(cardArr, targetCard); + let tmpCards = assistantUtil.checkTriple(cardArr, targetCard); let next = this.giveup.bind(this); if (tmpCards.length > 1) { let cardIds: number[] = []; @@ -345,66 +231,8 @@ export class Robot { * @private */ private async selectPet() { - await this.delay(5, 0.2); - let cards = [...this.room.state.cards.values()]; - let result; - let effectMap: Map = global.$cfg.get(BaseConst.EFFECTCARD); - for (let card of cards) { - let effect = effectMap.get(card.effect); - if (effect.type_id == 1) { - result = card; - break; - } - } - if (!result) { - result = arrUtil.randomGet(cards, 1)[0]; - } - let targetType: SkillTargetType = CfgMan.getTargetByCard(result.id); - let targetPlayer; - let targetPos; - switch (targetType) { - case SkillTargetType.ENEMY_PLAYER: - targetPlayer = this.getEnemyPlayer(); - break; - case SkillTargetType.ENEMY_PET: - for (let [,player] of this.room.state.players) { - if (player.team !== this.player.team) { - let pos = this.getRandomPet(player); - if (pos > - 1) { - targetPlayer = player; - targetPos = pos; - break; - } - } - } - break; - case SkillTargetType.FRIEND_PET: - for (let [,player] of this.room.state.players) { - if (player.team == this.player.team) { - let pos = this.getRandomPet(player); - if (pos > - 1) { - targetPlayer = player; - targetPos = pos; - break; - } - } - } - break; - case SkillTargetType.SELF_PET: - let pos = this.getRandomPet(this.player); - if (pos > - 1) { - targetPlayer = this.player; - targetPos = pos; - break; - } - break; - } - this.reply('select_pet_c2s', { - card: result.id, - player: targetPlayer?.id, - pos: targetPos, - effCards: [] - }) + let data = await assistantUtil.selectPet(this.player, this.room.state); + this.reply('select_pet_c2s', data); } diff --git a/src/robot/RobotClient.ts b/src/robot/RobotClient.ts index c20f5cf..d140e8e 100644 --- a/src/robot/RobotClient.ts +++ b/src/robot/RobotClient.ts @@ -1,19 +1,12 @@ import {Client, Room} from "colyseus"; import {ClientState, ISendOptions} from "colyseus/lib/transport/Transport"; import {EventEmitter} from 'events'; -import {robotLog as log} from '../common/Debug'; +import {assistLog as log} from '../common/Debug'; import {CardGameState} from "../rooms/schema/CardGameState"; -import Clock from "@gamestdio/timer"; import {GameStateConst} from "../constants/GameStateConst"; import {Card} from "../rooms/schema/Card"; -import {BaseConst} from "../constants/BaseConst"; -import arrUtil from "../utils/array.util"; -import {HeroCfg} from "../cfg/parsers/HeroCfg"; -import {EffectCardCfg} from "../cfg/parsers/EffectCardCfg"; -import CfgMan from '../rooms/logic/CfgMan'; -import {SkillTargetType} from "../rooms/logic/skill/SkillConst"; import {Player} from "../rooms/schema/Player"; -import gameUtil from "../utils/game.util"; +import assistantUtil from "../utils/assistant.util"; export class RobotClient implements Client { id: string; @@ -23,26 +16,19 @@ export class RobotClient implements Client { selfPlayer: Player; state: ClientState; svrstate: CardGameState; - room: Room; - clock: Clock; myTurn: boolean = false; cards: Map; onMessageHandlers: {[id: string]: (client: Client, message: any) => void} = {}; listenerState: any; listenerTurn: any; + active: boolean = false; - constructor(sessionId: string, state: CardGameState, clock: Clock, onMessageHandlers: {[id: string]: (client: Client, message: any) => void}) { + constructor(sessionId: string, state: CardGameState, onMessageHandlers: {[id: string]: (client: Client, message: any) => void}) { this.sessionId = sessionId; this.svrstate = state; this.selfPlayer = this.svrstate.players.get(sessionId); - this.clock = clock; this.ref = new EventEmitter(); this.onMessageHandlers = onMessageHandlers; - let self = this; - let time = Math.random() * 2500 | 0; - this.clock.setTimeout(function (){ - self.reply('play_ready_c2s', ''); - }, time); this.addListeners(); log(`new robot with session: ${sessionId}`); @@ -74,13 +60,15 @@ export class RobotClient implements Client { private gameSateUpdate(currentValue: number, previousValue: number) { let self = this; + if (!this.active) { + return; + } log(`server game state change: ${currentValue}, pre value: ${previousValue}`); switch (currentValue) { case GameStateConst.CHANGE_HERO: self.selectHero(); break; case GameStateConst.STATE_CHANGE_CARD: - self.cards = self.svrstate.players.get(self.sessionId).cards; self.changeCard(); break; case GameStateConst.STATE_BEGIN_EAT: @@ -94,8 +82,11 @@ export class RobotClient implements Client { } private gameTurnUpdate(currentValue: string, previousValue: string) { let self = this; - log(`server turn change: ${currentValue}, pre value: ${previousValue}`); self.myTurn = currentValue === self.sessionId; + if (!this.active) { + return; + } + log(`server turn change: ${currentValue}, pre value: ${previousValue}`); if (self.myTurn) { self.discard(); } @@ -104,6 +95,9 @@ export class RobotClient implements Client { public send(messageOrType: any, messageOrOptions?: any | ISendOptions, options?: ISendOptions) { log(`receive server msg: ${messageOrType}, ${messageOrOptions}`); let self = this; + if (!this.active) { + return; + } let data = messageOrOptions; switch (messageOrType) { case 'draw_card_s2c': @@ -127,99 +121,34 @@ export class RobotClient implements Client { (this.onMessageHandlers['*'] as any)(this, messageType, message); } } - - private checkTriple(cardArr: Card[], card?: Card): Card[] { - if (card) cardArr.push(card); - let cards = cardArr.filter(o => o.type == 1); - cards.sort((a, b) => a.number - b.number); - let result = []; - for (let i = 0, length = cards.length; i < length; i ++) { - let cur = cards[i]; - i == 0 && result.push(cur); - if (i > 0) { - let isSame = false; - if (result.length > 1) { - if (result[result.length - 1].number == result[result.length - 2].number) { - isSame = true; - } - } - if ((result[result.length - 1].number == cur.number) && (isSame || result.length == 1)) { - result.push(cur); - } else if ((result[result.length - 1].number + 1 == cur.number) && (!isSame || result.length == 1)) { - result.push(cur); - } else { - result.length = 0; - result.push(cur); - } - } - } - if (result.length < 3) { - return [cards[0]]; - } else { - return result; - } - } - /** - * 随机获取敌对玩家 - * @private - */ - private getEnemyPlayer(): Player { - let enemys = []; - for (let [,player] of this.svrstate.players) { - if (player.team !== this.selfPlayer.team) { - enemys.push(player); - } - } - return arrUtil.randomOne(enemys); - } - - /** - * 随机获取可用的随从 - * @param player - * @private - */ - private getRandomPet(player: Player): number { - let pets = []; - for (let [, pet] of player.pets) { - if (pet.ap > 0 && pet.state == 1) - pets.push(pet); - } - let result; - if (pets.length > 0) { - result = arrUtil.randomOne(pets); - } - return result ? result.pos : -1; - } // >>>>>>>>>>>>>>>>>> begin /** * 出牌 * @private */ - private discard() { + private async discard() { + await assistantUtil.delay(3); let self = this; - let next = function () { - let cardArr = [...self.cards.values()]; - // cardArr.sort((a, b) => a.number - b.number); - let cards = self.checkTriple(cardArr); - if (!cards) { - return; - } - let cardIds = cards.map(o => o.id); - self.reply('discard_card_c2s', { - cards: cardIds - }); + let cardArr = [...self.selfPlayer.cards.values()]; + let cards = assistantUtil.checkTriple(cardArr); + if (!cards) { + return; } - this.clock.setTimeout(next, 1500); + let cardIds = cards.map(o => o.id); + self.reply('discard_card_c2s', { + cards: cardIds + }); } /** * 吃牌或者放弃 * @private */ - private eatOrGiveUp() { + private async eatOrGiveUp() { + await assistantUtil.delay(2); let targetCard = [...this.svrstate.cards.values()][0]; - let cardArr = [...this.cards.values()]; - let tmpCards = this.checkTriple(cardArr, targetCard); + let cardArr = [...this.selfPlayer.cards.values()]; + let tmpCards = assistantUtil.checkTriple(cardArr, targetCard); let next = this.giveup.bind(this); if (tmpCards.length > 1) { let cardIds: number[] = []; @@ -230,8 +159,7 @@ export class RobotClient implements Client { } next = this.eatCard.bind(this, cardIds, targetCard.id); } - - this.clock.setTimeout(next, 1500); + next.apply(this); } /** @@ -256,17 +184,23 @@ export class RobotClient implements Client { this.reply('give_up_eat_c2s', {}); } + /** + * 开局装备 + * @private + */ + private async setReady() { + await assistantUtil.delay(2.5); + this.reply('play_ready_c2s', ''); + } + /** * 开局选择英雄 * @private */ - private selectHero() { - let heroMap: Map = global.$cfg.get(BaseConst.HERO); - let heroArr = [...heroMap.values()]; - let hero = arrUtil.randomGet(heroArr, 1); - this.reply('select_hero_c2s', { - heroId: hero[0].id - }); + private async selectHero() { + await assistantUtil.delay(2); + let data = assistantUtil.randomHero(); + this.reply('select_hero_c2s', data); } /** @@ -286,66 +220,9 @@ export class RobotClient implements Client { * 选择一个法术或者一个随从 * @private */ - private selectPet() { - let cards = [...this.svrstate.cards.values()]; - let result; - let effectMap: Map = global.$cfg.get(BaseConst.EFFECTCARD); - for (let card of cards) { - let effect = effectMap.get(card.effect); - if (effect.type_id == 1) { - result = card; - break; - } - } - if (!result) { - result = arrUtil.randomGet(cards, 1)[0]; - } - let targetType: SkillTargetType = CfgMan.getTargetByCard(result.id); - let targetPlayer; - let targetPos; - switch (targetType) { - case SkillTargetType.ENEMY_PLAYER: - targetPlayer = this.getEnemyPlayer(); - break; - case SkillTargetType.ENEMY_PET: - for (let [,player] of this.svrstate.players) { - if (player.team !== this.selfPlayer.team) { - let pos = this.getRandomPet(player); - if (pos > - 1) { - targetPlayer = player; - targetPos = pos; - break; - } - } - } - break; - case SkillTargetType.FRIEND_PET: - for (let [,player] of this.svrstate.players) { - if (player.team == this.selfPlayer.team) { - let pos = this.getRandomPet(player); - if (pos > - 1) { - targetPlayer = player; - targetPos = pos; - break; - } - } - } - break; - case SkillTargetType.SELF_PET: - let pos = this.getRandomPet(this.selfPlayer); - if (pos > - 1) { - targetPlayer = this.selfPlayer; - targetPos = pos; - break; - } - break; - } - this.reply('select_pet_c2s', { - card: result.id, - player: targetPlayer?.id, - pos: targetPos, - effCards: [] - }) + private async selectPet() { + let data = await assistantUtil.selectPet(this.selfPlayer, this.svrstate); + this.reply('select_pet_c2s', data) } } diff --git a/src/robot/RobotManage.ts b/src/robot/RobotManage.ts index 0198408..d92fcec 100644 --- a/src/robot/RobotManage.ts +++ b/src/robot/RobotManage.ts @@ -6,4 +6,9 @@ export class RobotManage { let robot = new Robot(host, room); let sessionId = await robot.connect(); } + + async reConnect({host, room, sessionId}: { host: string, room: string, sessionId: string }) { + let robot = new Robot(host, room); + await robot.reConnect(sessionId); + } } diff --git a/src/robot/main.controller.ts b/src/robot/main.controller.ts index bca5189..8f05fac 100644 --- a/src/robot/main.controller.ts +++ b/src/robot/main.controller.ts @@ -7,13 +7,20 @@ const router = express.Router(); router.get('/create', async (req, res, next) => { let query = req.query; - let {host, room } = query; + let {host, room, sessionId } = query; host = host as string; room = room as string; - debug(`receive create robot msg: ${host}, ${room}`); + let manage = singleton(RobotManage); try { - await manage.addOne({host, room}); + if (sessionId) { + sessionId = sessionId as string; + debug(`receive reconnect msg: ${host}, ${room}, ${sessionId}`); + await manage.reConnect({host, room, sessionId}) + } else { + debug(`receive create robot msg: ${host}, ${room}`); + await manage.addOne({host, room}); + } res.json({errcode: 0}); } catch (err) { res.json({errcode: 1}) diff --git a/src/rooms/GeneralRoom.ts b/src/rooms/GeneralRoom.ts index ca7dad4..3cd04d2 100644 --- a/src/rooms/GeneralRoom.ts +++ b/src/rooms/GeneralRoom.ts @@ -27,6 +27,9 @@ export class GeneralRoom extends Room { battleMan = new BattleHandler(); // 用于游戏过程中各种计时器, 使用该计时器的前提是, 只针对当前操作玩家 gameClock: Map = new Map(); + + assistMap: Map = new Map(); + async onAuth (client:Client, options: any, request: IncomingMessage) { console.log(options); // TODO: 验证用户信息 @@ -102,19 +105,24 @@ export class GeneralRoom extends Room { async onLeave (client: Client, consented: boolean) { if (this.state.gameState === GameStateConst.STATE_GAME_OVER || this.state.gameState === GameStateConst.STATE_WAIT_JOIN) { this.state.players.delete(client.sessionId); + this.assistMap.delete(client.sessionId); this.bUserLeft(client.sessionId); } else { this.state.players.get(client.sessionId).state = PlayerStateConst.PLAYER_OFFLINE; + let assistClient = this.getAssistClient(client.sessionId); + assistClient.active = true; try { if (consented) { throw new Error("consented leave"); + } else { + await this.allowReconnection(client, 60); + debugRoom(`${client.sessionId} 重连`); + assistClient.active = false; + this.state.players.get(client.sessionId).state = PlayerStateConst.PLAYER_NORMAL; } - await this.allowReconnection(client, 60); - this.state.players.get(client.sessionId).state = PlayerStateConst.PLAYER_NORMAL; - } catch (e) { - debugRoom(`player realy level :${client.sessionId}`); - this.state.players.delete(client.sessionId); + debugRoom(`player realy level :${client.sessionId}, try add robot`); + // this.state.players.delete(client.sessionId); } } } @@ -125,17 +133,26 @@ export class GeneralRoom extends Room { getClient(player: string | Player): Client { let result: Client; + let sessionId; if (typeof player == 'string') { + sessionId = player; result = this.clients.find(client => client.sessionId == player ); } else { + sessionId = player.id; result = this.clients.find(client => client.sessionId == player.id ); } if (!result) { - error(`无法获取id为: ${typeof player == 'string' ? player : player.id} 的客户端`) + error(`无法获取id为: ${typeof player == 'string' ? player : player.id} 的客户端`); + result = this.getAssistClient(sessionId); + debugRoom(`启用辅助机器人, 当前机器人状态: ${(result as RobotClient).active}`) } return result; } + clientCount(): number { + return this.clients.length; + } + /** * 给room.gameClock设定任务 * gameClock任何时候只有一个可执行的任务 @@ -213,7 +230,9 @@ export class GeneralRoom extends Room { let data = { host: 'ws://127.0.0.1:2567', room: this.roomId, + sessionId: playerId } + axios.get('http://127.0.0.1:2500/robot/create', { params: data }).then((res) => { @@ -247,4 +266,13 @@ export class GeneralRoom extends Room { // } // this._events.emit('join', client); } + + addAssistClient(sessionId: string) { + let client = new RobotClient(sessionId, this.state, this['onMessageHandlers']); + this.assistMap.set(sessionId, client); + } + + getAssistClient(sessionId: string): RobotClient { + return this.assistMap.get(sessionId); + } } diff --git a/src/rooms/MSender.ts b/src/rooms/MSender.ts index 53691f6..bff69f3 100644 --- a/src/rooms/MSender.ts +++ b/src/rooms/MSender.ts @@ -215,6 +215,17 @@ Object.defineProperties(Room.prototype, { value: function (client: Client, data?: any) { client && client.send("change_card_s2c", data); } + }, + + send: { + value: function (client: Client, type: string, data?: any) { + if (client) { + client.send(type, data); + } else { + let assistClient = this.getAssistClient(client.sessionId); + assistClient && assistClient.send(type, data); + } + } } }); diff --git a/src/rooms/commands/BeginGameCommand.ts b/src/rooms/commands/BeginGameCommand.ts index 2698a0e..a48673b 100644 --- a/src/rooms/commands/BeginGameCommand.ts +++ b/src/rooms/commands/BeginGameCommand.ts @@ -21,8 +21,8 @@ export class BeginGameCommand extends Command { let cardAll = card0.concat(card1); arrUtil.randomSort(cardAll); this.state.cardQueue = cardAll; - for (let client of this.room.clients) { - this.room.addCard(client.sessionId, singleton(GameEnv).initCardNum, 0); + for (let [id] of this.state.players) { + this.room.addCard(id, singleton(GameEnv).initCardNum, 0); } this.state.updateGameState(GameStateConst.STATE_CHANGE_CARD); // 超时后结束换卡, 进入下一轮 diff --git a/src/rooms/commands/DiscardCommand.ts b/src/rooms/commands/DiscardCommand.ts index 44c00da..4c765aa 100644 --- a/src/rooms/commands/DiscardCommand.ts +++ b/src/rooms/commands/DiscardCommand.ts @@ -24,15 +24,15 @@ export class DiscardCommand extends Command { await self.room.setPrivate(false); //开启匹配定时, 长时间没匹配到人的话, 添加机器人 let timeOutWaitingPlayer = function () { - let count = self.room.maxClients - self.room.clients.length; + let count = self.room.maxClients - self.room.clientCount(); if (count > 0) { for (let i = 0; i < count; i++) { self.room.addRobot(); diff --git a/src/rooms/commands/OnJoinCommand.ts b/src/rooms/commands/OnJoinCommand.ts index d602f12..f07412e 100644 --- a/src/rooms/commands/OnJoinCommand.ts +++ b/src/rooms/commands/OnJoinCommand.ts @@ -17,11 +17,12 @@ export class OnJoinCommand extends Command 0) { for (let i = 0; i < count; i++) { self.room.addRobot(); @@ -30,7 +31,7 @@ export class OnJoinCommand extends Command 1 && this.room.clients.length < this.room.maxClients) { + } else if (this.room.clientCount() > 1 && this.room.clientCount() < this.room.maxClients) { let moreTime = singleton(GameEnv).waitingPlayerOnePlus * 1000; self.room.addScheduleTime(moreTime, 'play_join', 'waiting_player') } diff --git a/src/rooms/commands/PrepareCommand.ts b/src/rooms/commands/PrepareCommand.ts index 89a597d..68dc935 100644 --- a/src/rooms/commands/PrepareCommand.ts +++ b/src/rooms/commands/PrepareCommand.ts @@ -12,7 +12,7 @@ export class PrepareCommand extends Command { this.state.updateGameState(GameStateConst.DETERMINE_TURN); let time = 3000; //TODO:: 每人发2张牌, 并比较大小, 确定先手 - for (let client of this.room.clients) { + for (let client of this.state.players) { // this.room.broadcast(); } diff --git a/src/utils/assistant.util.ts b/src/utils/assistant.util.ts new file mode 100644 index 0000000..cf6d530 --- /dev/null +++ b/src/utils/assistant.util.ts @@ -0,0 +1,222 @@ +import {Card} from "../rooms/schema/Card"; +import arrUtil from "./array.util"; +import {EffectCardCfg} from "../cfg/parsers/EffectCardCfg"; +import {BaseConst} from "../constants/BaseConst"; +import {SkillTargetType} from "../rooms/logic/skill/SkillConst"; +import CfgMan from "../rooms/logic/CfgMan"; +import {CardGameState} from "../rooms/schema/CardGameState"; +import {Player} from "../rooms/schema/Player"; +import {HeroCfg} from "../cfg/parsers/HeroCfg"; + +let assistantUtil = { + delay(max: number, min?: number) { + min = min || 0; + let milliseconds = (Math.random() * (max - min) + min) * 1000 | 0; + return new Promise(resolve => setTimeout(resolve, milliseconds)); + }, + /** + * 检查是否可以吃牌 + * @param cardArr 待检查的卡组 + * @param card 目标牌 + */ + checkTriple(cardArr: Card[], card?: Card): Card[] { + if (card) cardArr.push(card); + let pointMap: Map = new Map(); + let cardIdSet: Set = new Set(); + for (let c of cardArr) { + if (c.type !== 1) { + continue; + } + if (pointMap.has(c.number)) { + let arr = pointMap.get(c.number); + arr.push(c); + pointMap.set(c.number, arr); + } else { + pointMap.set(c.number, [c]); + } + cardIdSet.add(c.number); + } + let fetched = false; + let result: Card[] = []; + // 优先出对子 + for (let [point, arr] of pointMap) { + if (card) { + if (point == card.number && arr.length >= 3) { + fetched = true; + result = arr; + break; + } + } else { + if (arr.length >= 3) { + fetched = true; + result = arr; + break; + } + } + + } + if (fetched) { + return result; + } + + let cardIds = [...cardIdSet]; + cardIds.sort((a, b) => a - b); + let tmp = []; + for (let i = 0, length = cardIds.length; i < length; i++) { + let cur = cardIds[i]; + i == 0 && tmp.push(cur); + if (i > 0) { + if (cur != tmp[i - 1] + 1) { + tmp.length = 0; + } + tmp.push(cur); + } + if (card) { + if (tmp.indexOf(card.number) >= 0 && tmp.length >= 3) { + break; + } + } else { + if (tmp.length >= 3) { + break; + } + } + } + + if (tmp.length >= 3) { + let subTmp = []; + for (let i = tmp[0] - 1; i > 0; i--) { + if (cardIdSet.has(i)) { + subTmp.push(i); + } else { + break; + } + } + for (let i = tmp[tmp.length]; i < cardIdSet.size; i++) { + if (cardIdSet.has(i)) { + subTmp.push(i); + } else { + break; + } + } + tmp = tmp.concat(subTmp); + for (let point of tmp) { + if (card && point === card.number) { + result.push(card); + } else { + result.push(pointMap.get(point)[0]); + } + } + return result; + } else { + return arrUtil.randomGet(cardArr, 1); + } + }, + /** + * 随机获取敌对玩家 + * @private + */ + getEnemyPlayer(dstPlayer: Player, state: CardGameState): Player { + let enemys = []; + for (let [, player] of state.players) { + if (player.team !== dstPlayer.team) { + enemys.push(player); + } + } + return arrUtil.randomOne(enemys); + }, + + /** + * 随机获取可用的随从 + * @param player + * @private + */ + getRandomPet(player: Player): number { + let pets = []; + for (let [, pet] of player.pets) { + if (pet.ap > 0 && pet.state == 1) + pets.push(pet); + } + let result; + if (pets.length > 0) { + result = arrUtil.randomOne(pets); + } + return result ? result.pos : -1; + }, + /** + * 选择一个法术或者一个随从 + * @private + */ + async selectPet(dstPlayer: Player, state: CardGameState) { + await this.delay(5, 0.2); + let cards = [...state.cards.values()]; + let result; + let effectMap: Map = global.$cfg.get(BaseConst.EFFECTCARD); + for (let card of cards) { + let effect = effectMap.get(card.effect); + if (effect.type_id == 1) { + result = card; + break; + } + } + if (!result) { + result = arrUtil.randomGet(cards, 1)[0]; + } + let targetType: SkillTargetType = CfgMan.getTargetByCard(result.effect); + let targetPlayer; + let targetPos; + switch (targetType) { + case SkillTargetType.ENEMY_PLAYER: + targetPlayer = this.getEnemyPlayer(dstPlayer, state); + break; + case SkillTargetType.ENEMY_PET: + for (let [, player] of state.players) { + if (player.team !== dstPlayer.team) { + let pos = this.getRandomPet(player); + if (pos > -1) { + targetPlayer = player; + targetPos = pos; + break; + } + } + } + break; + case SkillTargetType.FRIEND_PET: + for (let [, player] of state.players) { + if (player.team == dstPlayer.team) { + let pos = this.getRandomPet(player); + if (pos > -1) { + targetPlayer = player; + targetPos = pos; + break; + } + } + } + break; + case SkillTargetType.SELF_PET: + let pos = this.getRandomPet(dstPlayer); + if (pos > -1) { + targetPlayer = dstPlayer; + targetPos = pos; + break; + } + break; + } + //TODO: 增加效果卡 + let effCards: number[] = []; + return { + card: result.id, + player: targetPlayer?.id, + pos: targetPos, + effCards + } + + }, + randomHero() { + let heroMap: Map = global.$cfg.get(BaseConst.HERO); + let heroArr = [...heroMap.values()]; + let hero = arrUtil.randomGet(heroArr, 1); + return {heroId: hero[0].id} + } +} + +export default assistantUtil; diff --git a/src/utils/game.util.ts b/src/utils/game.util.ts index fa11d11..94cf698 100644 --- a/src/utils/game.util.ts +++ b/src/utils/game.util.ts @@ -255,7 +255,8 @@ let gameUtil = { result += pet.ap; } return result; - } + }, + } export default gameUtil;