card_svr/src/robot/Robot.ts

258 lines
6.6 KiB
TypeScript

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)
}
}
}