增加机器人的作弊模式

This commit is contained in:
zhl 2021-03-05 18:18:16 +08:00
parent 2f4e95df53
commit 579a3dd318
13 changed files with 346 additions and 156 deletions

View File

@ -1,105 +1,111 @@
import {BaseCfg} from "./parsers/BaseCfg";
import {BaseConst} from "../constants/BaseConst";
import {singleton} from "../decorators/singleton.decorator";
import { BaseCfg } from './parsers/BaseCfg'
import { BaseConst } from '../constants/BaseConst'
import { singleton } from '../decorators/singleton.decorator'
@singleton
export class GameEnv {
// 初始手牌数量
public initCardNum: number;
// 可更换的初始手牌上限
public cardChangeNum : number;
// 更换初始手牌时限
public cardChangeTime: number;
// 每回合发牌数量
public roundDrawNum: number;
// 每满几论决斗一次
public duelRoundNum: number;
// 第几次决斗后游戏结束
public maxDuelNum: number;
// 玩家手牌数量上限
public maxCardNum: number;
// 出牌公共时限
public maxDiscardTime: number;
// 吃牌公共时限
public maxEatTime: number;
// 操作公共时限
public playerActTime: number;
// 玩家灵活时限
public maxExtTime: number;
// 每回合增加玩家灵活时限数值
public roundExtTime: number;
// 玩家随从上限
public maxPlayerPetCount: number;
// 结算显示时间
public resultShowTime: number;
// 基本奖励分
public baseAddScore: number;
// 额外奖励分
public extraAddScore: number;
// 游戏结果显示时间, 也是游戏重开等待时间
public gameResultTime: number;
// 匹配等待时间, 时间结束后, 填充机器人;
public waitingPlayerTime: number;
// 匹配等待时, 每进入一个玩家, 等待时间延长n秒
public waitingPlayerOnePlus: number;
// 英雄选择时间
public pickHeroTime: number;
// 机器人操作最小时间
public robotActTimeMin: number;
// 机器人操作最大时间
public robotActTimeMax: number;
// 队友死亡后,补牌数量
public teamDeadAddNum: number;
// 胡牌张数(自摸)
public selfEatCount: number;
// 胡牌张数(吃牌)
public otherEatCount: number;
// 轮空轮的间隔时间
public emptyRoundTime: number;
// 玩家初始卡牌数
public playerInitNums: number[] = [];
// 初级场能否吃牌
public canEatBase: boolean;
// 进阶场能否吃牌
public canEatAdv: boolean;
// 随从继承战力的比率
public petInheritRate: number;
// 初始手牌数量
public initCardNum: number
// 可更换的初始手牌上限
public cardChangeNum: number
// 更换初始手牌时限
public cardChangeTime: number
// 每回合发牌数量
public roundDrawNum: number
// 每满几论决斗一次
public duelRoundNum: number
// 第几次决斗后游戏结束
public maxDuelNum: number
// 玩家手牌数量上限
public maxCardNum: number
// 出牌公共时限
public maxDiscardTime: number
// 吃牌公共时限
public maxEatTime: number
// 操作公共时限
public playerActTime: number
// 玩家灵活时限
public maxExtTime: number
// 每回合增加玩家灵活时限数值
public roundExtTime: number
// 玩家随从上限
public maxPlayerPetCount: number
// 结算显示时间
public resultShowTime: number
// 基本奖励分
public baseAddScore: number
// 额外奖励分
public extraAddScore: number
// 游戏结果显示时间, 也是游戏重开等待时间
public gameResultTime: number
// 匹配等待时间, 时间结束后, 填充机器人;
public waitingPlayerTime: number
// 匹配等待时, 每进入一个玩家, 等待时间延长n秒
public waitingPlayerOnePlus: number
// 英雄选择时间
public pickHeroTime: number
// 机器人操作最小时间
public robotActTimeMin: number
// 机器人操作最大时间
public robotActTimeMax: number
// 队友死亡后,补牌数量
public teamDeadAddNum: number
// 胡牌张数(自摸)
public selfEatCount: number
// 胡牌张数(吃牌)
public otherEatCount: number
// 轮空轮的间隔时间
public emptyRoundTime: number
// 玩家初始卡牌数
public playerInitNums: number[] = []
// 初级场能否吃牌
public canEatBase: boolean
// 进阶场能否吃牌
public canEatAdv: boolean
// 随从继承战力的比率
public petInheritRate: number
// 低级机器人的胜率值
public robotLvlLow: number
// 高级机器人的胜率值
public robotLvlHigh: number
public init(data: Map<number, BaseCfg>) {
this.initCardNum = data.get(BaseConst.INIT_CARD_NUM).value;
this.cardChangeNum = data.get(BaseConst.CARD_CHANGE_NUM).value;
this.cardChangeTime = data.get(BaseConst.CARD_CHANGE_TIME).value;
this.roundDrawNum = data.get(BaseConst.ROUND_DRAW_NUM).value;
this.duelRoundNum = data.get(BaseConst.DUEL_ROUND_NUM).value;
this.maxDuelNum = data.get(BaseConst.MAX_DUEL_NUM).value;
this.maxCardNum = data.get(BaseConst.MAX_CARD_NUM).value;
this.maxDiscardTime = data.get(BaseConst.MAX_DISCARD_TIME).value;
this.maxEatTime = data.get(BaseConst.MAX_EAT_TIME).value;
this.playerActTime = data.get(BaseConst.PLAYER_ACT_TIME).value;
this.maxExtTime = data.get(BaseConst.MAX_EXT_TIME).value;
this.roundExtTime = data.get(BaseConst.ROUND_EXT_TIME).value;
this.maxPlayerPetCount = data.get(BaseConst.MAX_PLAYER_PET_COUNT).value;
this.resultShowTime = data.get(BaseConst.ROUND_SHOW_TIME).value;
this.baseAddScore = data.get(BaseConst.BASE_ADD_SCORE).value;
this.extraAddScore = data.get(BaseConst.EXTRA_ADD_SCORE).value;
this.gameResultTime = data.get(BaseConst.GAME_RESULT_TIME).value;
this.waitingPlayerTime = data.get(BaseConst.WAITING_PLAYER_TIME).value;
this.waitingPlayerOnePlus = data.get(BaseConst.WAITING_PLAYER_ONEPLUS).value;
this.pickHeroTime = data.get(BaseConst.PICK_HERO_TIME).value;
this.robotActTimeMin = data.get(BaseConst.ROBOT_ACTTIME_MIN).value;
this.robotActTimeMax = data.get(BaseConst.ROBOT_ACTTIME_MAX).value;
this.teamDeadAddNum = data.get(BaseConst.TEAM_DEAD_ADDNUM).value;
this.selfEatCount = data.get(BaseConst.SELF_EAT_COUNT).value;
this.otherEatCount = data.get(BaseConst.OTHER_EAT_COUNT).value;
this.emptyRoundTime = data.get(BaseConst.EMPTY_ROUND_TIME).value;
this.playerInitNums = [
data.get(BaseConst.PLAYER1_INIT_NUM).value,
data.get(BaseConst.PLAYER2_INIT_NUM).value,
data.get(BaseConst.PLAYER3_INIT_NUM).value,
data.get(BaseConst.PLAYER4_INIT_NUM).value,
]
this.canEatBase = !!data.get(BaseConst.CAN_EAT_BASE).value;
this.canEatAdv = !!data.get(BaseConst.CAN_EAT_ADV).value;
this.petInheritRate = data.get(BaseConst.PET_INHERIT_RATE).value / 100;
}
public init(data: Map<number, BaseCfg>) {
this.initCardNum = data.get(BaseConst.INIT_CARD_NUM).value
this.cardChangeNum = data.get(BaseConst.CARD_CHANGE_NUM).value
this.cardChangeTime = data.get(BaseConst.CARD_CHANGE_TIME).value
this.roundDrawNum = data.get(BaseConst.ROUND_DRAW_NUM).value
this.duelRoundNum = data.get(BaseConst.DUEL_ROUND_NUM).value
this.maxDuelNum = data.get(BaseConst.MAX_DUEL_NUM).value
this.maxCardNum = data.get(BaseConst.MAX_CARD_NUM).value
this.maxDiscardTime = data.get(BaseConst.MAX_DISCARD_TIME).value
this.maxEatTime = data.get(BaseConst.MAX_EAT_TIME).value
this.playerActTime = data.get(BaseConst.PLAYER_ACT_TIME).value
this.maxExtTime = data.get(BaseConst.MAX_EXT_TIME).value
this.roundExtTime = data.get(BaseConst.ROUND_EXT_TIME).value
this.maxPlayerPetCount = data.get(BaseConst.MAX_PLAYER_PET_COUNT).value
this.resultShowTime = data.get(BaseConst.ROUND_SHOW_TIME).value
this.baseAddScore = data.get(BaseConst.BASE_ADD_SCORE).value
this.extraAddScore = data.get(BaseConst.EXTRA_ADD_SCORE).value
this.gameResultTime = data.get(BaseConst.GAME_RESULT_TIME).value
this.waitingPlayerTime = data.get(BaseConst.WAITING_PLAYER_TIME).value
this.waitingPlayerOnePlus = data.get(BaseConst.WAITING_PLAYER_ONEPLUS).value
this.pickHeroTime = data.get(BaseConst.PICK_HERO_TIME).value
this.robotActTimeMin = data.get(BaseConst.ROBOT_ACTTIME_MIN).value
this.robotActTimeMax = data.get(BaseConst.ROBOT_ACTTIME_MAX).value
this.teamDeadAddNum = data.get(BaseConst.TEAM_DEAD_ADDNUM).value
this.selfEatCount = data.get(BaseConst.SELF_EAT_COUNT).value
this.otherEatCount = data.get(BaseConst.OTHER_EAT_COUNT).value
this.emptyRoundTime = data.get(BaseConst.EMPTY_ROUND_TIME).value
this.playerInitNums = [
data.get(BaseConst.PLAYER1_INIT_NUM).value,
data.get(BaseConst.PLAYER2_INIT_NUM).value,
data.get(BaseConst.PLAYER3_INIT_NUM).value,
data.get(BaseConst.PLAYER4_INIT_NUM).value
]
this.canEatBase = !!data.get(BaseConst.CAN_EAT_BASE).value
this.canEatAdv = !!data.get(BaseConst.CAN_EAT_ADV).value
this.petInheritRate = data.get(BaseConst.PET_INHERIT_RATE).value / 100
this.robotLvlLow = data.get(BaseConst.ROBOT_LVL_LOW).value
this.robotLvlHigh = data.get(BaseConst.ROBOT_LVL_HIGHT).value
}
}

View File

@ -62,6 +62,10 @@ export class BaseConst {
public static readonly CAN_EAT_ADV = 99040
// 随从继承比例
public static readonly PET_INHERIT_RATE = 99041
// 低级机器人的胜率值
public static readonly ROBOT_LVL_LOW = 99042
// 高级机器人的胜率值
public static readonly ROBOT_LVL_HIGHT = 99044
public static readonly COMPOUND = 'compound'
public static readonly EFFECTCARD = 'effectcard'

8
src/global.d.ts vendored
View File

@ -306,6 +306,14 @@ declare module 'colyseus' {
*/
getOppositePlayer(srcPlayer: string | Player): Player;
/**
*
* @param {string | Player} srcPlayer
* @param exPlayer
* @return {Player[]}
*/
getOtherTeamPlayers(srcPlayer: string, exPlayer?: string ): Player[];
/**
* index获取玩家
* @param {number} idx

View File

@ -14,6 +14,7 @@ export class Robot {
client: Client
myTurn: boolean = false
player: Player
cheatRate: number = 0
constructor(host: string, roomId: string) {
this.host = host
@ -64,6 +65,10 @@ export class Robot {
self.selectPet()
}
break
case 'update_change_rate':
log(`update cheat rate to: ${data.val}`)
self.cheatRate = data.val
break
}
})
@ -170,7 +175,8 @@ export class Robot {
}
let self = this
let cardArr = [...self.player.cards.values()]
let cards = assistantUtil.checkDiscard(cardArr, targetCard)
let result = assistantUtil.checkDiscard({cardArr, card: targetCard, rate: this.cheatRate})
let cards = result.cards;
if (!cards || cards.length == 0) {
return
}
@ -191,6 +197,9 @@ export class Robot {
if (hasEatCard) {
repData.target = targetCard.id
}
if (result.nums) {
repData.nums = result.nums
}
self.reply('discard_card_c2s', repData)
}
@ -202,7 +211,8 @@ export class Robot {
private async eatOrGiveUp() {
let targetCard = [...this.room.state.cards.values()][0]
let cardArr = [...this.player.cards.values()]
let tmpCards = assistantUtil.checkDiscard(cardArr, targetCard)
let result = assistantUtil.checkDiscard({cardArr, card: targetCard, rate: this.cheatRate})
let tmpCards = result.cards;
let next = this.giveup.bind(this)
if (tmpCards.length > 1 && targetCard.type === 1) {
let cardIds: number[] = []

View File

@ -31,6 +31,7 @@ export class RobotClient implements Client {
listenerState: any
listenerTurn: any
active: boolean = false
cheatRate: number = 0
constructor(sessionId: string, state: CardGameState, onMessageHandlers: { [id: string]: (client: Client, message: any) => void }) {
this.sessionId = sessionId
@ -86,6 +87,10 @@ export class RobotClient implements Client {
self.selectPet()
}
break
case 'update_change_rate':
log(`update cheat rate to: ${data.val}`)
self.cheatRate = data.val
break
}
}
@ -147,7 +152,8 @@ export class RobotClient implements Client {
}
let self = this
let cardArr = [...self.selfPlayer.cards.values()]
let cards = assistantUtil.checkDiscard(cardArr, targetCard)
let result = assistantUtil.checkDiscard({cardArr, card: targetCard, rate: this.cheatRate})
let cards = result.cards
if (!cards || cards.length == 0) {
return
}
@ -168,6 +174,9 @@ export class RobotClient implements Client {
if (hasEatCard) {
repData.target = targetCard.id
}
if (result.nums) {
repData.nums = result.nums
}
self.reply('discard_card_c2s', repData)
}
@ -179,7 +188,8 @@ export class RobotClient implements Client {
private async eatOrGiveUp() {
let targetCard = [...this.svrstate.cards.values()][0]
let cardArr = [...this.selfPlayer.cards.values()]
let tmpCards = assistantUtil.checkDiscard(cardArr, targetCard)
let result = assistantUtil.checkDiscard({cardArr, card: targetCard, rate: this.cheatRate})
let tmpCards = result.cards
let next = this.giveup.bind(this)
if (tmpCards.length > 1 && targetCard.type === 1) {
let cardIds: number[] = []

View File

@ -86,7 +86,8 @@ export class GeneralRoom extends Room {
client,
cards: message.cards,
target: message.target,
dtype: 0
dtype: 0,
nums: message.nums
})
})
this.onMessage('eat_card_c2s', (client, message) => {
@ -399,4 +400,16 @@ export class GeneralRoom extends Room {
let opposIdx = ((this.maxClients / 2 | 0) + idx) % this.maxClients
return this.getPlayerByIdx(opposIdx)
}
getOtherTeamPlayers(srcPlayer: string, exPlayer?: string): Player[] {
let team = this.state.players.get(srcPlayer).team
let results:Player[] = []
for (let [,player] of this.state.players) {
if (player.team !== team) {
if (exPlayer && player.id != exPlayer) {
results.push(player)
}
}
}
return results
}
}

View File

@ -4,6 +4,7 @@ import { GameStateConst } from '../../constants/GameStateConst'
import gameUtil from '../../utils/game.util'
import { GameEnv } from '../../cfg/GameEnv'
import { NextTurnCommand } from './NextTurnCommand'
import { debugRoom } from '../../common/Debug'
/**
*
@ -18,9 +19,49 @@ export class BeginGameCommand extends Command<CardGameState, {}> {
let card1 = gameUtil.initCardQue(card0.length + 1, this.state.advMode)
let cardAll = card0.concat(card1)
cardAll.randomSort()
//FixMe:: 移除
// let card0 = gameUtil.initSampleCards(1)
// this.state.cardQueue = card0;
// 如果是匹配模式, 挑战机器人作弊比率
if (this.state.mode == 1) {
let highRate = new GameEnv().robotLvlHigh / 100
let lowRate = new GameEnv().robotLvlLow / 100
for (let [, player] of this.state.players) {
if (!player.robot) {
continue
}
let client = this.room.getClient(player)
let oplayer = this.room.getOppositePlayer(player)
if (oplayer.robot) {
let eplayers = this.room.getOtherTeamPlayers(player.id, oplayer.id)
if (!eplayers || eplayers.length == 0) {
continue
}
for (let p of eplayers) {
if (!p.robot) {
oplayer = p
break
}
}
if (oplayer.robot) {
continue
}
}
let rate = 0
if (oplayer.winRate > highRate) {
rate = oplayer.winRate * 100 | 0
} else if (oplayer.winRate > lowRate) {
rate = oplayer.winRate / 2 * 100 | 0
}
debugRoom(`opposite play win rate: ${oplayer.winRate}, robot change rate: ${rate}`)
if (global.isProd) {
client.send('update_change_rate', { val: rate })
} else {
client.send('update_change_rate', { val: 100 })
}
let assistClient = this.room.getAssistClient(player.id)
assistClient.send('update_change_rate', { val: rate })
}
}
this.state.cardQueue = cardAll
let i = 0
for (let [id] of this.state.players) {

View File

@ -12,6 +12,7 @@ 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'
/**
*
@ -19,13 +20,13 @@ import { stopDrawCardClock } from '../../utils/clock.util'
* type: 0,
* type: 1, ,
*/
export class DiscardCommand extends Command<CardGameState, { client: Client, cards: [string], target?: string, dtype: number }> {
export class DiscardCommand extends Command<CardGameState, { client: Client, cards: [string], target?: string, dtype: number, nums?: [number] }> {
// 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 } = this.payload) {
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', {
@ -58,6 +59,17 @@ export class DiscardCommand extends Command<CardGameState, { client: Client, car
})
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)) {

View File

@ -1,11 +1,10 @@
import {Command} from "@colyseus/command";
import {CardGameState} from "../schema/CardGameState";
import {Player} from "../schema/Player";
import {Client} from "colyseus";
import {GameStateConst} from "../../constants/GameStateConst";
import {GameEnv} from "../../cfg/GameEnv";
import {BaseConst} from "../../constants/BaseConst";
import {getRandom} from "../../utils/number.util";
import { Command } from '@colyseus/command'
import { CardGameState } from '../schema/CardGameState'
import { Player } from '../schema/Player'
import { Client } from 'colyseus'
import { GameStateConst } from '../../constants/GameStateConst'
import { GameEnv } from '../../cfg/GameEnv'
import { BaseConst } from '../../constants/BaseConst'
import { getUserInfo, randomUserInfo } from '../../common/WebApi'
import { ClockNameConst } from '../../constants/ClockNameConst'
@ -18,23 +17,23 @@ export class OnJoinCommand extends Command<CardGameState, {
seat?: number,
score?: number
}> {
async execute({client, accountId, seat, score} = this.payload) {
let count = this.state.players.size;
async execute({ client, accountId, seat, score } = this.payload) {
let count = this.state.players.size
if (count >= this.room.maxClients) {
return;
return
}
// begin of set seat and team
let idx = count;
let seatSet = new Set([0,1,2,3])
let idx = count
let seatSet = new Set([0, 1, 2, 3])
let accounts: string[] = []
for (let [,p] of this.state.players) {
for (let [, p] of this.state.players) {
seatSet.delete(p.idx)
accounts.push(p.accountId)
}
if (seat != undefined) {
seat = +seat
if (seatSet.has(seat)) {
idx = seat;
idx = seat
} else {
idx = seatSet.values().next().value
}
@ -42,70 +41,73 @@ export class OnJoinCommand extends Command<CardGameState, {
idx = seatSet.values().next().value
}
let team
if (this.room.maxClients % 2 == 0 ) {
team = (idx == 1 || idx == 2) ? 1 : 0;
if (this.room.maxClients % 2 == 0) {
team = (idx == 1 || idx == 2) ? 1 : 0
} else {
team = idx
}
// end of set seat and team
let player = new Player(client.sessionId, idx, team);
this.state.players.set(client.sessionId, player);
let uinfo: {nickname: string, avatar: string, score: number, accountid: string, heros: number[]}
let player = new Player(client.sessionId, idx, team)
this.state.players.set(client.sessionId, player)
let uinfo: { nickname: string, avatar: string, score: number, accountid: string, heros: number[], rate?: number }
if (accountId && accountId != 'robot') {
uinfo = await getUserInfo(accountId, !!this.room.match)
player.heros = uinfo.heros.map(o => parseInt(o+''))
player.heros = uinfo.heros.map(o => parseInt(o + ''))
player.robot = false
player.winRate = uinfo.rate < 0 ? 0 : uinfo.rate
} else {
const fc = global.$cfg.get(BaseConst.FORMULA);
let low = (this.room.score * fc.get(70034).number / 100) | 0;
let high = (this.room.score * fc.get(70035).number / 100) | 0;
const fc = global.$cfg.get(BaseConst.FORMULA)
let low = (this.room.score * fc.get(70034).number / 100) | 0
let high = (this.room.score * fc.get(70035).number / 100) | 0
uinfo = await randomUserInfo(low, high, accounts)
player.robot = true
}
accountId = uinfo.accountid
player.accountId = accountId;
player.accountId = accountId
player.nickname = uinfo.nickname
player.avatar = uinfo.avatar
player.score = uinfo.score
this.room.addAssistClient(client.sessionId);
let self = this;
this.room.addAssistClient(client.sessionId)
let self = this
if (!this.room.match && !this.room.robotCount) {
if (this.state.players.size >= this.room.maxClients) {
this.room.lock().then(() => {
});
this.state.updateGameState(GameStateConst.STATE_WAIT_PREPARE);
})
this.state.updateGameState(GameStateConst.STATE_WAIT_PREPARE)
}
} else {
if (this.room.clientCount() == 1) {
// 正常的匹配逻辑进入的第一个玩家, 开启定时, 超过设定时间人没齐的话, 添加机器人
let timeOutWaitingPlayer = async function () {
let count = self.room.maxClients - self.room.clientCount();
let count = self.room.maxClients - self.room.clientCount()
if (count > 0) {
for (let i = 0; i < count; i++) {
await self.room.addRobot();
await self.room.addRobot()
}
}
}
let time = new GameEnv().waitingPlayerTime * 1000;
self.room.beginSchedule(time, timeOutWaitingPlayer, ClockNameConst.WAITING_PLAYER);
let time = new GameEnv().waitingPlayerTime * 1000
self.room.beginSchedule(time, timeOutWaitingPlayer, ClockNameConst.WAITING_PLAYER)
} else if (this.room.clientCount() > 1 && this.room.clientCount() < this.room.maxClients) {
let moreTime = new GameEnv().waitingPlayerOnePlus * 1000;
let moreTime = new GameEnv().waitingPlayerOnePlus * 1000
self.room.addScheduleTime(moreTime, 'play_join', ClockNameConst.WAITING_PLAYER)
}
if (this.state.players.size >= this.room.maxClients) {
this.room.stopSchedule(ClockNameConst.WAITING_PLAYER);
this.room.stopSchedule(ClockNameConst.WAITING_PLAYER)
this.room.lock().then(() => {
});
this.state.updateGameState(GameStateConst.STATE_WAIT_PREPARE);
})
this.state.updateGameState(GameStateConst.STATE_WAIT_PREPARE)
} else if (this.state.players.size < this.room.maxClients
&& this.state.players.size >= this.room.maxClients - this.room.robotCount) {
for (let i = 0; i < this.room.robotCount; i++) {
this.room.robotCount --;
await self.room.addRobot();
this.room.robotCount--
await self.room.addRobot()
}
}
}
this.room.bUserJoin(`${client.sessionId}`, {except: client});
this.room.bUserJoin(`${ client.sessionId }`, { except: client })
}
}

View File

@ -101,7 +101,7 @@ export class SelectPetCommand extends Command<CardGameState, {
let time = this.room.battleMan.useCard(data)
await this.delay(time)
const multipEat = !!this.state.rules.get(RULE_MULTIPLEEAT)
if (multipEat && assistantUtil.checkDiscard([...player.cards.values()]).length > 1) {
if (multipEat && assistantUtil.checkDiscard({cardArr: [...player.cards.values()]}).cards.length > 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}`)

View File

@ -108,8 +108,11 @@ export class Player extends Schema {
* pet值,
*/
petData: Map<number, number> = new Map();
heros: number[];
// 是否是机器人
robot: boolean;
// 十场胜率
winRate: number;
/**
* , , ()

View File

@ -12,6 +12,7 @@ import { GameEnv } from '../cfg/GameEnv'
import { error, robotLog } from '../common/Debug'
import { PlayerStateConst } from '../constants/PlayerStateConst'
import { Pet } from '../rooms/schema/Pet'
import { getRandom } from './number.util'
function pushMapVal(map: Map<number, Card[]>, key: number, value: Card) {
if (map.has(key)) {
@ -30,7 +31,7 @@ let assistantUtil = {
* @param cardArr
* @param card
*/
checkDiscard(cardArr: Card[], card?: Card): Card[] {
checkDiscard({cardArr, card, rate}: {cardArr: Card[], card?: Card, rate?: number}): {cards: Card[], nums?: number[]} {
let maxCount = card ? new GameEnv().otherEatCount : new GameEnv().selfEatCount
let pointMap: Map<number, Card[]> = new Map()
let cardIdSet: Set<number> = new Set()
@ -65,7 +66,7 @@ let assistantUtil = {
}
if (fetched) {
return result
return {cards: result}
}
let cardIds = [...cardIdSet]
@ -115,9 +116,76 @@ let assistantUtil = {
result.push(pointMap.get(point)[0])
}
}
return result
return {cards: result}
} else {
return [cardArr.randomOne()]
if (cardArr.length > maxCount && rate > 0) {
robotLog(`begin cheat ^_^`)
let random = getRandom(0, 100)
if (random <= rate) {
let max = Math.min(maxCount+1, cardArr.length + 1)
let randomCount = getRandom(maxCount, max)
let resultCards: Card[] = cardArr.randomGet(randomCount)
let sameVal = false
if (getRandom(0, 100) > 50) {
sameVal = true
}
let resultNums = []
if (card && (card.type == CardType.general || card.type == CardType.variable_unit)) {
if (sameVal) {
for (let _c of resultCards) {
resultNums.push(card.number)
}
} else {
resultNums.push(card.number)
for (let _c of resultCards) {
let nextU: number = Math.max.apply(this, resultNums) + 1
let nextD: number = Math.min.apply(this, resultNums) - 1
if (getRandom(0, 100) > 50 ) {
if (nextU <= 10) {
resultNums.push(nextU)
} else {
resultNums.push(nextD)
}
} else {
if (nextD > 0) {
resultNums.push(nextD)
} else {
resultNums.push(nextU)
}
}
}
}
resultCards.push(card)
} else {
if (sameVal) {
for (let i = 0; i < resultCards.length; i++) {
resultNums.push(resultCards[0].number)
}
} else {
resultNums.push(resultCards[0].number)
for (let i = 1; i < resultCards.length; i++) {
let nextU: number = Math.max.apply(this, resultNums) + 1
let nextD: number = Math.min.apply(this, resultNums) - 1
if (getRandom(0, 100) > 50 ) {
if (nextU <= 10) {
resultNums.push(nextU)
} else {
resultNums.push(nextD)
}
} else {
if (nextD > 0) {
resultNums.push(nextD)
} else {
resultNums.push(nextU)
}
}
}
}
return {cards: resultCards, nums: resultNums}
}
}
}
return {cards: [cardArr.randomOne()]}
}
},
/**

View File

@ -52,6 +52,19 @@ let gameUtil = {
debugRoom(cards)
return cards
},
randomEffect(advMode: boolean): number {
let effCfgMap: Map<number, EffectCardCfg> = global.$cfg.get(BaseConst.EFFECTCARD)
let results = []
for (let [,effCfg] of effCfgMap) {
if (effCfg.type_id !== 2) {
continue
}
if ((advMode && effCfg.intermediateaccess) || (!advMode && effCfg.primaryaccess)) {
results.push(effCfg.id)
}
}
return results.randomOne()
},
/**
*
* @param effectId