diff --git a/src/cfg/RoomOptions.ts b/src/cfg/RoomOptions.ts index 8cfaad4..0250e84 100644 --- a/src/cfg/RoomOptions.ts +++ b/src/cfg/RoomOptions.ts @@ -5,18 +5,34 @@ import { GameEnv } from './GameEnv' export class RoomOptions { /** * 当前游戏能否吃牌 - * @param {boolean} advMode * @return {boolean} + * @param opt */ - public canEat(advMode: boolean) { + public canEat(opt: {advMode: boolean}) { let result = false - if (advMode && new GameEnv().canEatAdv) { + if (opt.advMode && new GameEnv().canEatAdv) { result = true - } else if (!advMode && new GameEnv().canEatBase) { + } else if (!opt.advMode && new GameEnv().canEatBase) { result = true } return result } + /** + * 一个回合能不能吃多次 + * //TODO: 根据配表判断 + * @param opt + */ + public multipleEat(opt?: any) { + return true + } + + /** + * 当前轮时间到了后, 是否自动出牌 + * @param opt + */ + public autoDiscard(opt?: any) { + return true + } } diff --git a/src/global.d.ts b/src/global.d.ts index ad20bcf..b9d2e93 100644 --- a/src/global.d.ts +++ b/src/global.d.ts @@ -238,8 +238,7 @@ declare module 'colyseus' { updatePetStat(datas: PetInfo[], fromplayer?: string): void; /** - * 给room.mainClock设定任务 - * mainClock任何时候只有一个可执行的任务 + * 添加一个计时器 * @param millisecond * @param handler * @param name @@ -247,15 +246,20 @@ declare module 'colyseus' { beginSchedule(millisecond: number, handler: Function, name: string): void; /** - * 取消当前room.mainClock的任务 - * mainClock任何时候只有一个可执行的任务 - * 返回当前剩余的毫秒数 - * @param name + * 取消某个计时器 */ stopSchedule(name: string): number; + /** + * 暂停某个计时器 + */ + pauseSchedule(name: string): number; + /** + * 恢复某个计时器 + */ + resumeSchedule(name: string): number; /** - * 给room.mainClock增加n秒 + * 给某个计时器增加n秒 * @param name * @param millisecond * @param reason diff --git a/src/robot/Robot.ts b/src/robot/Robot.ts index e78f249..63dfad4 100644 --- a/src/robot/Robot.ts +++ b/src/robot/Robot.ts @@ -80,8 +80,9 @@ export class Robot { // self.players = state.players; }) // 也可以监听state下某个特定值的变更, 比如下面是监听 当前轮的clientid - this.room.state.listen('currentTurn', (currentValue: string) => { - self.myTurn = currentValue === this.sessionId + this.room.state.listen('playerTurn', (currentValue: string) => { + let pid = currentValue.split(':')[0] + self.myTurn = pid === this.sessionId if (self.myTurn) { self.discard() } @@ -163,7 +164,7 @@ export class Robot { @wait('maxDiscardTime') private async discard() { let targetCard - let canEat = new RoomOptions().canEat(this.room.state.advMode) + let canEat = new RoomOptions().canEat({advMode: this.room.state.advMode}) if (this.room.state.cards.size == 1 && canEat) { targetCard = [...this.room.state.cards.values()][0] } diff --git a/src/robot/RobotClient.ts b/src/robot/RobotClient.ts index 46b4e79..2a2059c 100644 --- a/src/robot/RobotClient.ts +++ b/src/robot/RobotClient.ts @@ -45,7 +45,7 @@ export class RobotClient implements Client { addListeners() { this.listenerState = this.svrstate.listen('gameState', this.gameSateUpdate.bind(this)) - this.listenerTurn = this.svrstate.listen('currentTurn', this.gameTurnUpdate.bind(this)) + this.listenerTurn = this.svrstate.listen('playerTurn', this.gameTurnUpdate.bind(this)) } close(code?: number, data?: string): void { @@ -114,7 +114,8 @@ export class RobotClient implements Client { private gameTurnUpdate(currentValue: string, previousValue: string) { let self = this - self.myTurn = currentValue === self.sessionId + let pid = currentValue.split(':')[0] + self.myTurn = pid === self.sessionId if (!this.active) { return } @@ -140,7 +141,7 @@ export class RobotClient implements Client { @wait('maxDiscardTime') private async discard() { let targetCard - let canEat = new RoomOptions().canEat(this.svrstate.advMode) + let canEat = new RoomOptions().canEat({advMode: this.svrstate.advMode}) if (this.svrstate.cards.size == 1 && canEat) { targetCard = [...this.svrstate.cards.values()][0] } diff --git a/src/rooms/GeneralRoom.ts b/src/rooms/GeneralRoom.ts index 3343bdb..ed4dd59 100644 --- a/src/rooms/GeneralRoom.ts +++ b/src/rooms/GeneralRoom.ts @@ -163,7 +163,7 @@ export class GeneralRoom extends Room { this.dispatcher.dispatch(new OnJoinCommand(), data) } - //TODO: 掉线逻辑 + // 掉线逻辑 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) @@ -193,11 +193,19 @@ export class GeneralRoom extends Room { } onDispose() { + for (let [, clock] of this.gameClock) { + clock.clear() + } this.gameClock.clear() this.assistMap.clear() this.dispatcher.stop() } + /** + * 获取指定player的client实例, 如果玩家已掉线, 则获取该玩家的assist client + * @param {string | Player} player + * @return {Client} + */ getClient(player: string | Player): Client { let result: Client let sessionId @@ -216,13 +224,16 @@ export class GeneralRoom extends Room { return result } + /** + * 加入当前房间的client数量 + * @return {number} + */ clientCount(): number { return this.clients.length } /** - * 给room.gameClock设定任务 - * gameClock任何时候只有一个可执行的任务 + * 添加一个计时器 * @param millisecond * @param handler * @param name @@ -242,30 +253,60 @@ export class GeneralRoom extends Room { } /** - * 取消当前room.gameClock的任务 - * gameClock任何时候只有一个可执行的任务 + * 取消某个计时器 */ stopSchedule(name: string): number { debugRoom(`manual stop schedule: ${ name }`) if (!this.gameClock.has(name)) { return -1 - } else { - let clock = this.gameClock.get(name) - if (!clock.active) { - this.gameClock.delete(name) - return -1 - } else { - let time = clock.elapsedTime - clock.clear() - this.gameClock.delete(name) - return time - } - } + let clock = this.gameClock.get(name) + if (!clock.active) { + this.gameClock.delete(name) + return -1 + } + let time = clock.elapsedTime + clock.clear() + this.gameClock.delete(name) + return time } /** - * 给room的gameClock增加n秒 + * 暂停某个计时器, 返回这个机器器的剩余时间 + * @param {string} name + * @return {number} + */ + pauseSchedule(name: string) { + if (!this.gameClock.has(name)) { + return -1 + } + let clock = this.gameClock.get(name) + if (!clock.active) { + return -1 + } + clock.pause() + return clock.time - clock.elapsedTime + } + + /** + * 恢复某个计时器, 返回这个机器器的剩余时间 + * @param {string} name + * @return {number} + */ + resumeSchedule(name: string) { + if (!this.gameClock.has(name)) { + return -1 + } + let clock = this.gameClock.get(name) + if (!clock.active) { + return -1 + } + clock.resume() + return clock.time - clock.elapsedTime + } + + /** + * 给某个计时器增加n秒 * @param name * @param millisecond * @param reason @@ -303,6 +344,10 @@ export class GeneralRoom extends Room { await createRobot(data) } + /** + * 跟指定玩家添加一个assist client, 用于玩家掉线后接管 + * @param {string} sessionId + */ addAssistClient(sessionId: string) { if (!this.assistMap.has(sessionId)) { let client = new RobotClient(sessionId, this.state, this['onMessageHandlers']) @@ -313,7 +358,9 @@ export class GeneralRoom extends Room { getAssistClient(sessionId: string): RobotClient { return this.assistMap.get(sessionId) } - + /** + * 根据指定的座次号获取玩家信息 + */ getPlayerByIdx(idx: number) { for (let [, player] of this.state.players) { if (player.idx == idx) { diff --git a/src/rooms/commands/DiscardCommand.ts b/src/rooms/commands/DiscardCommand.ts index 86e7869..e2e925b 100644 --- a/src/rooms/commands/DiscardCommand.ts +++ b/src/rooms/commands/DiscardCommand.ts @@ -58,7 +58,7 @@ export class DiscardCommand extends Command { */ resetAllState() { this.state.restartCount = 0; - this.state.updateGameTurn( undefined); + this.state.updateGameTurn( undefined, 0); this.state.subTurn = undefined; this.state.round = 0; this.state.cardQueue.length = 0; diff --git a/src/rooms/commands/NextTurnCommand.ts b/src/rooms/commands/NextTurnCommand.ts index 83f0ccf..7c23868 100644 --- a/src/rooms/commands/NextTurnCommand.ts +++ b/src/rooms/commands/NextTurnCommand.ts @@ -35,7 +35,7 @@ export class NextTurnCommand extends Command { } this.state.updateGameTurn((this.state.currentTurn) ? sessionIds[(sessionIds.indexOf(this.state.currentTurn) + 1) % sessionIds.length] - : sessionIds[0]); + : sessionIds[0], 0); let player = this.state.players.get(this.state.currentTurn); player.cardQueue.clear(); if (!player) { diff --git a/src/rooms/commands/SelectPetCommand.ts b/src/rooms/commands/SelectPetCommand.ts index 3813e1c..cf801d6 100644 --- a/src/rooms/commands/SelectPetCommand.ts +++ b/src/rooms/commands/SelectPetCommand.ts @@ -4,6 +4,10 @@ import { Client } from 'colyseus' import { TurnEndCommand } from './TurnEndCommand' import { GameEnv } from '../../cfg/GameEnv' import gameUtil from '../../utils/game.util' +import { RoomOptions } from '../../cfg/RoomOptions' +import assistantUtil from '../../utils/assistant.util' +import { GameStateConst } from '../../constants/GameStateConst' +import { debugRoom } from '../../common/Debug' /** * 选择随从或者法术 @@ -94,7 +98,12 @@ export class SelectPetCommand extends Command 1) { + this.state.updateGameState(GameStateConst.STATE_BEGIN_DRAW) + this.state.updateGameTurn(player.id, this.state.eatCount + 1) + debugRoom(`more eatcount for player ${player.id}, ${this.state.eatCount}`) + } else { + return [new TurnEndCommand()] + } } } diff --git a/src/rooms/schema/CardGameState.ts b/src/rooms/schema/CardGameState.ts index 210dec7..f34e94d 100644 --- a/src/rooms/schema/CardGameState.ts +++ b/src/rooms/schema/CardGameState.ts @@ -21,6 +21,19 @@ export class CardGameState extends Schema { @type("string") currentTurn: string; + /** + * 用于替换currentTurn的字段, + * 格式: playerId:eatCount + * @type {string} + */ + @type("string") + playerTurn: string; + /** + * currentTurn当中当前玩家吃牌次数 + * @type {number} + */ + @type("number") + eatCount: number; /** * 用于吃牌时的计轮, 只有在gameState==3的时候才需要判断 */ @@ -76,10 +89,14 @@ export class CardGameState extends Schema { this.$listeners?.gameState?.invoke(val, preVal); } - updateGameTurn(val: string) { + updateGameTurn(val: string, eatCount: number) { let preVal = this.currentTurn; this.currentTurn = val; + this.eatCount = eatCount; this.$listeners?.currentTurn?.invoke(val, preVal); + let prePlayerTurn = this.playerTurn + this.playerTurn = `${this.currentTurn}:${this.eatCount}` + this.$listeners?.playerTurn?.invoke(this.playerTurn, prePlayerTurn); } get advMode() { diff --git a/src/utils/assistant.util.ts b/src/utils/assistant.util.ts index 1a22bc1..4354439 100644 --- a/src/utils/assistant.util.ts +++ b/src/utils/assistant.util.ts @@ -1,5 +1,4 @@ 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' @@ -12,11 +11,22 @@ import { CardType } from '../cfg/enums/CardType' import { GameEnv } from '../cfg/GameEnv' import { error, robotLog } from '../common/Debug' import { PlayerStateConst } from '../constants/PlayerStateConst' +import { Pet } from '../rooms/schema/Pet' + +function pushMapVal(map: Map, key: number, value: Card) { + if (map.has(key)) { + let arr = map.get(key) + arr.push(value) + map.set(key, arr) + } else { + map.set(key, [value]) + } +} let assistantUtil = { /** - * 检查是否可以吃牌 + * 检查是否可以吃牌或出连牌 * @param cardArr 待检查的卡组 * @param card 目标牌 */ @@ -28,23 +38,11 @@ let assistantUtil = { if (!(c.type == CardType.general || c.type == CardType.variable_unit)) { 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]) - } + pushMapVal(pointMap, c.number, c) cardIdSet.add(c.number) } if (card && (card.type == CardType.general || card.type == CardType.variable_unit)) { - if (pointMap.has(card.number)) { - let arr = pointMap.get(card.number) - arr.push(card) - pointMap.set(card.number, arr) - } else { - pointMap.set(card.number, [card]) - } + pushMapVal(pointMap, card.number, card) cardIdSet.add(card.number) } let fetched = false @@ -119,7 +117,7 @@ let assistantUtil = { } return result } else { - return arrUtil.randomGet(cardArr, 1) + return [cardArr.randomOne()] } }, /** @@ -133,7 +131,7 @@ let assistantUtil = { enemys.push(player) } } - return arrUtil.randomOne(enemys) + return enemys.randomOne() }, /** @@ -150,9 +148,9 @@ let assistantUtil = { if (pet.ap > 0 && pet.state == 1) pets.push(pet) } - let result + let result: Pet if (pets.length > 0) { - result = arrUtil.randomOne(pets) + result = pets.randomOne() } return result ? result.pos : 0 }, @@ -264,8 +262,8 @@ let assistantUtil = { randomHero() { let heroMap: Map = global.$cfg.get(BaseConst.HERO) let heroArr = [...heroMap.values()] - let hero = arrUtil.randomGet(heroArr, 1) - return { heroId: hero[0].id } + let hero: HeroCfg = heroArr.randomOne() + return { heroId: hero.id } } }