import { Client, Room } from 'colyseus.js' import { error, robotLog as log, robotLog as debug } from '../common/Debug' import { GameStateConst } from '../constants/GameStateConst' import { Player } from '../rooms/schema/Player' import assistantUtil from '../utils/assistant.util' import { delay, wait } from '../decorators/cfg' import { RoomOptions } from '../cfg/RoomOptions' import { RULE_CANEAT } from '../constants/GameRuleConst' export class Robot { host: string roomId: string room: Room sessionId: string client: Client myTurn: boolean = false player: Player constructor(host: string, roomId: string) { this.host = host this.roomId = roomId this.client = new Client(host) } async connect() { try { this.room = await this.client.joinById(this.roomId, { rank: 1, accountid: 'robot' }) this.addListeners() this.sessionId = this.room.sessionId this.setReady() return this.room.sessionId } catch (err) { error(`error join room ${ this.host }, ${ this.roomId }`) } } 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) => { switch (type) { case 'draw_card_s2c': // if (data.player == self.sessionId) { // self.cards = self.cards.concat(data.cards); // } break case 'player_ready_s2c': break case 'eat_card_s2c': if (data.errcode == 0 && data.player == self.sessionId) { debug(`eat_success: ${ self.sessionId }`) self.selectPet() } break } }) this.room.onLeave(function () { debug('LEFT ROOM', arguments) self.room.removeAllListeners() self.room.leave() }) /** * 监听房间状态的变更, state含有当前房间游戏的所有公共信息, 任何值的更改都会触发该方法 * */ this.room.onStateChange(function (state) { self.player = state.players.get(self.sessionId) // self.players = state.players; }) // 也可以监听state下某个特定值的变更, 比如下面是监听 当前轮的clientid this.room.state.listen('playerTurn', (currentValue: string) => { let pid = currentValue.split(':')[0] self.myTurn = pid === this.sessionId if (self.myTurn) { self.discard() } }) this.room.state.listen('subTurn', (currentValue: string, previousValue: string) => { // self.mySubTurn = currentValue === self.sessionId; // if (self.mySubTurn) { // setTimeout(self.giveup.bind(self), self.delay); // } }) // 监听游戏状态的改变 this.room.state.listen('gameState', (currentValue: number, previousValue: number) => { switch (currentValue) { case GameStateConst.DETERMINE_TURN: // console.log('比大小阶段'); //TODO: 随机分牌比大小阶段, 需要 break case GameStateConst.CHANGE_HERO: // console.log('英雄选择阶段'); self.selectHero() break case GameStateConst.STATE_CHANGE_CARD: // console.log('开局换卡阶段'); self.changeCard() break case GameStateConst.STATE_BEGIN_EAT: if (!self.myTurn) { self.eatOrGiveUp() } break case GameStateConst.STATE_ROUND_RESULT: console.log('结算轮') break } }) } private reply(messageType: string, message: any) { this.room.send(messageType, message) } // >>>>>>>>>>>>>>>>>> begin /** * 开局选择英雄 * @private */ @wait('pickHeroTime') private async selectHero() { let data = assistantUtil.randomHero() this.reply('select_hero_c2s', data) } /** * 开局准备 * @private */ @delay(2) private async setReady() { this.reply('play_ready_c2s', '') } /** * 开局换牌 * @private */ @wait('cardChangeTime') private async changeCard() { let cardIds: number[] = [] this.reply('change_card_c2s', { cards: cardIds }) } /** * 出牌 * @private */ @wait('maxDiscardTime') private async discard() { let targetCard let canEat = !!this.room.state.rules.get(RULE_CANEAT) if (this.room.state.cards.size == 1 && canEat) { targetCard = [...this.room.state.cards.values()][0] } let self = this let cardArr = [...self.player.cards.values()] let cards = assistantUtil.checkDiscard(cardArr, targetCard) if (!cards || cards.length == 0) { return } let cardIds: number[] = [] let hasEatCard = false for (let card of cards) { if (!targetCard || (targetCard && card.id !== targetCard.id)) { cardIds.push(card.id) } if (targetCard && card.id == targetCard.id) { hasEatCard = true } } log(`discard: ${ self.sessionId } ${ cardIds }`) let repData: any = { cards: cardIds } if (hasEatCard) { repData.target = targetCard.id } self.reply('discard_card_c2s', repData) } /** * 吃牌或者放弃 * @private */ @wait('maxEatTime') private async eatOrGiveUp() { let targetCard = [...this.room.state.cards.values()][0] let cardArr = [...this.player.cards.values()] let tmpCards = assistantUtil.checkDiscard(cardArr, targetCard) let next = this.giveup.bind(this) if (tmpCards.length > 1 && targetCard.type === 1) { let cardIds: number[] = [] for (let card of tmpCards) { if (card.id !== targetCard.id) { cardIds.push(card.id) } } next = this.eatCard.bind(this, cardIds, targetCard.id) } next.apply(this) } /** * 吃牌 * @param cardIds * @param target * @private */ private eatCard(cardIds: number[], target: number) { log(`eta_card: ${ this.sessionId } ${ cardIds } -> ${ target }`) this.reply('eat_card_c2s', { cards: cardIds, target }) } /** * 放弃吃牌 * @private */ private giveup() { this.reply('give_up_eat_c2s', {}) } /** * 选择一个法术或者一个随从 * @private */ @wait('playerActTime') private async selectPet() { let data = await assistantUtil.selectPet(this.player, this.room.state) if (data) { this.reply('select_pet_c2s', data) } } }