import { Command } from '@colyseus/command' import { CardGameState } from '../schema/CardGameState' import gameUtil from '../../utils/game.util' import { Client } from 'colyseus' import { GameStateConst } from '../../constants/GameStateConst' import { GameEnv } from '../../cfg/GameEnv' import { debugRoom, error } from '../../common/Debug' import { TurnEndCommand } from './TurnEndCommand' import { Card } from '../schema/Card' import { Wait } from './Wait' import { StateTypeEnum } from '../enums/StateTypeEnum' import { RULE_CANEAT, RULE_SINGLEEAT } from '../../cfg/RoomOptions' import { ClockNameConst } from '../../constants/ClockNameConst' import { stopDrawCardClock } from '../../utils/clock.util' import { CardType } from '../../cfg/enums/CardType' /** * 出牌 * target: 如果是吃牌, 则带上此字段 * type: 0, 正常的抽牌 * type: 1, 到时间后, 自动的抽牌 */ export class DiscardCommand extends Command { // validate({ client, cards } = this.payload) { // const player = this.state.players.get(client.sessionId); // return player !== undefined && gameUtil.checkCardsExists(player.cards, cards); // } async execute({ client, cards, target, dtype , nums} = this.payload) { const player = this.state.players.get(client.sessionId) if (!player) { this.room.send(client, 'discard_card_s2c', { errcode: 1, errmsg: 'player不存在' }) return } let tmpCards = [] for (let id of cards) { if (player.cards.has(id + '')) { if (!player.cards.get(id + '').number) { error(`${ player.id } 的手牌 ${ id } 数据有问题`) continue } tmpCards.push(player.cards.get(id + '').clone()) } else { error(`${ player.id } 出的牌 ${ id } 在手牌中不存在`) this.room.send(client, 'discard_card_s2c', { errcode: 2, errmsg: `要出的牌 ${ id } 在手牌中不存在` }) return } } if (this.state.currentTurn != client.sessionId) { this.room.send(client, 'discard_card_s2c', { errcode: 3, errmsg: '不是当前轮' }) return } if (player.robot && !!nums) { debugRoom(`change card numbers`) let i = 0 for (let card of tmpCards) { if (card.type == CardType.double_effect || card.type == CardType.double_point) { card.type = CardType.general card.effect = gameUtil.randomEffect(this.state.advMode) } card.number = nums[i ++] } } let targetCard if (target) { if (!this.state.rules.get(RULE_CANEAT)) { this.room.send(client, 'discard_card_s2c', { errcode: 7, errmsg: '当前游戏不允许吃牌' }) return } if (this.state.cards.size > 1 || this.state.cards.size == 0) { this.room.send(client, 'discard_card_s2c', { errcode: 6, errmsg: '不符合吃牌规则' }) return } if (!this.state.cards.has(target + '')) { this.room.send(client, 'discard_card_s2c', { errcode: 5, errmsg: '找不到要吃的牌' }) return } targetCard = this.state.cards.values().next().value.clone() let targetPlayer = this.state.players.get(targetCard.owner) targetPlayer?.cardQueue.clear() tmpCards.push(targetCard) if (!gameUtil.checkDiscard(tmpCards, new GameEnv().otherEatCount)) { this.room.send(client, 'discard_card_s2c', { errcode: 4, errmsg: '出牌不符合规则' }) return } for (let [key, val] of this.state.cards) { this.state.cards.delete(key) } } else { if (!gameUtil.checkDiscard(tmpCards, new GameEnv().selfEatCount)) { this.room.send(client, 'discard_card_s2c', { errcode: 4, errmsg: '出牌不符合规则' }) return } } //停止出牌计时, 并更新player.extraTime; stopDrawCardClock(this.room, player) for (let card of tmpCards) { player.cardQueue.push(card) gameUtil.deleteCardFromPlayer(player, card.id) } // 如果当前出的牌只有一张, 且是法术牌或者随从牌, 则替换state.cards中的牌 if (tmpCards.length == 1 && (tmpCards[0].type == CardType.general || tmpCards[0].type == CardType.variable_unit)) { for (let [key, val] of this.state.cards) { this.state.cards.delete(key) } let card = tmpCards[0] this.state.cards.set(card.id + '', card) } /** * 这说明是当前轮正常出牌, * 如果出一张牌的话, 进入胡牌轮 * 否则直接进入选随从轮 */ this.room.send(client, 'discard_card_s2c', { errcode: 0, cards: cards, type: dtype }) const singleEat = !!this.state.rules.get(RULE_SINGLEEAT) if (cards.length === 1 && !(singleEat && tmpCards.length == 1 && (tmpCards[0].type == CardType.general || tmpCards[0].type == CardType.variable_unit))) { let cardArr: Card[] = [...this.state.cards.values()] let time = this.room.battleMan.onCardDiscarded(player, cardArr[0]) await this.delay(time) // 20210219 修改: 出单张牌后直接进入下个玩家的出牌时间 // if (cardArr[0].type == CardType.general || cardArr[0].type == CardType.variable_unit) { // return [new NextSubCommand()]; // } else { // return [new Wait().setPayload(new GameEnv().emptyRoundTime), new TurnEndCommand()]; // } return [new Wait().setPayload(new GameEnv().emptyRoundTime), new TurnEndCommand()] } else { let cardArr: Card[] = [...this.state.cards.values()] let self = this let cardMsg: any = { player: player.id, errcode: 0, errmsg: '' } if (targetCard) { cardMsg.target = targetCard.owner } this.room.broadcast('eat_card_s2c', cardMsg, { except: client }) cardMsg.cards = cards this.room.send(client, 'eat_card_s2c', cardMsg) let delay = this.room.battleMan.onCardLinkOver(player, cardArr) player.statData.inc(StateTypeEnum.EATCOUNT, 1) await this.delay(delay) let time = new GameEnv().playerActTime * 1000 + player.extraTime this.state.updateGameState(GameStateConst.STATE_PICK_PET) // 开启选随从计时, 计时结束后结束当前轮 let timeOverSelectPet = function () { player.extraTime = 0 debugRoom('选随从或者法术时间到, 自动出牌, 自动进入下一轮') self.room.dispatcher.dispatch(new TurnEndCommand()) } this.room.beginSchedule(time, timeOverSelectPet, ClockNameConst.SELECT_PET) } } }