import { Card } from '../rooms/schema/Card' import { EffectCardCfg } from '../cfg/parsers/EffectCardCfg' import { BaseConst } from '../constants/BaseConst' import { SkillTargetType } from '../rooms/logic/skill/SkillConst' import CfgMan from '../rooms/logic/CfgMan' import { CardGameState } from '../rooms/schema/CardGameState' import { Player } from '../rooms/schema/Player' import { HeroCfg } from '../cfg/parsers/HeroCfg' import { EffectType } from '../cfg/enums/EffectType' 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' import { getRandom } from './number.util' 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 目标牌 */ 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 = new Map() let cardIdSet: Set = new Set() for (let c of cardArr) { if (!(c.type == CardType.general || c.type == CardType.variable_unit)) { continue } pushMapVal(pointMap, c.number, c) cardIdSet.add(c.number) } if (card && (card.type == CardType.general || card.type == CardType.variable_unit)) { pushMapVal(pointMap, card.number, card) cardIdSet.add(card.number) } let fetched = false let result: Card[] = [] // 优先出对子 for (let [point, arr] of pointMap) { if (card) { if (point == card.number && arr.length >= maxCount) { fetched = true result = arr break } } else { if (arr.length >= maxCount) { fetched = true result = arr break } } } if (fetched) { return {cards: result} } let cardIds = [...cardIdSet] cardIds.sort((a, b) => a - b) let tmp = [] for (let i = 0, length = cardIds.length; i < length; i++) { let cur = cardIds[i] i == 0 && tmp.push(cur) if (i > 0) { if (cur != tmp[tmp.length - 1] + 1) { tmp.length = 0 } tmp.push(cur) } if (card) { if (tmp.indexOf(card.number) >= 0 && tmp.length >= maxCount) { break } } else { if (tmp.length >= maxCount) { break } } } if (tmp.length >= maxCount) { let subTmp = [] for (let i = tmp[0] - 1; i > 0; i--) { if (cardIdSet.has(i)) { subTmp.push(i) } else { break } } for (let i = tmp[tmp.length]; i < cardIdSet.size; i++) { if (cardIdSet.has(i)) { subTmp.push(i) } else { break } } tmp = tmp.concat(subTmp) for (let point of tmp) { if (card && point === card.number) { result.push(card) } else { result.push(pointMap.get(point)[0]) } } return {cards: result} } else { if (cardArr.length > maxCount && rate > 0) { let random = getRandom(0, 100) robotLog(`check cheat ^_^ random: ${random}, rate: ${rate}`) if (random <= rate) { let max = Math.min(maxCount+2, 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()]} } }, /** * 随机获取敌对玩家 * @private */ getEnemyPlayer(dstPlayer: Player, state: CardGameState): Player { let enemys = [] for (let [, player] of state.players) { if (player.team !== dstPlayer.team) { enemys.push(player) } } return enemys.randomOne() }, /** * 随机获取可用的随从 * @param player * @private */ getRandomPet(player: Player): number { if (player.state === PlayerStateConst.PLAYER_DEAD) { return -1 } let pets = [] for (let [, pet] of player.pets) { if (pet.ap > 0 && pet.state == 1) pets.push(pet) } let result: Pet if (pets.length > 0) { result = pets.randomOne() } return result ? result.pos : 0 }, /** * 选择一个法术或者一个随从 * @private */ async selectPet(dstPlayer: Player, state: CardGameState) { let cards = [...dstPlayer.cardQueue.values()] let result: Card let effectMap: Map = global.$cfg.get(BaseConst.EFFECTCARD) let spellCards: Card[] = [] let petCards: Card[] = [] // 优先取随从 let petCount = 0 for (let [, pet] of dstPlayer.pets) { if (pet.state == 1 && !pet.isHero) petCount++ } let noMorePet = petCount >= new GameEnv().maxPlayerPetCount let noPet = Math.random2(0, 100) > 70 for (let card of cards) { if (card.type == CardType.variable_unit) { if (dstPlayer.unitCfgs.has(card.effect + '')) { petCards.push(card) } } else if (card.type == CardType.general) { spellCards.push(card) } } if (!noMorePet && !noPet && petCards.length > 0) { result = petCards.randomOne() } if (!result && spellCards.length > 0) { result = spellCards.randomOne() } let oldpos = -1 if (!result && petCards.length > 0) { result = petCards.randomOne() if (noMorePet) { oldpos = 1 } } if (!result) { error(`无法选择随从或法术, 随从数: ${ petCount }, 法术牌数量: ${ spellCards.length }`) return null } let targetType: SkillTargetType = CfgMan.getTargetByCard(result.effect) robotLog(`select_pet ${ dstPlayer.id }: ${ result.effect } 类型: ${ effectMap.get(result.effect).type_id == EffectType.skill ? '法术' : '随从' }, targetType: ${ targetType }`) let targetPlayer let targetPos switch (targetType) { case SkillTargetType.ENEMY_PLAYER: targetPlayer = this.getEnemyPlayer(dstPlayer, state) break case SkillTargetType.ENEMY_PET: for (let [, player] of state.players) { if (player.team !== dstPlayer.team) { let pos = this.getRandomPet(player) if (pos > -1) { targetPlayer = player targetPos = pos break } } } break case SkillTargetType.FRIEND_PET: for (let [, player] of state.players) { if (player.team == dstPlayer.team) { let pos = this.getRandomPet(player) if (pos > -1) { targetPlayer = player targetPos = pos break } } } break case SkillTargetType.SELF_PET: let pos = this.getRandomPet(dstPlayer) if (pos > -1) { targetPlayer = dstPlayer targetPos = pos break } break } //TODO: 增加效果卡 let effCards: number[] = [] for (let [, card] of dstPlayer.cards) { if (card.type == CardType.double_effect || card.type == CardType.double_point) { effCards.push(card.id) } } return { card: result.id, player: targetPlayer?.id, pos: targetPos, effCards, oldpos } }, randomHero() { let heroMap: Map = global.$cfg.get(BaseConst.HERO) let heroArr = [...heroMap.values()] let hero: HeroCfg = heroArr.randomOne() return { heroId: hero.id } } } export default assistantUtil