340 lines
9.9 KiB
TypeScript
340 lines
9.9 KiB
TypeScript
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<number, Card[]>, 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<number, Card[]> = new Map()
|
|
let cardIdSet: Set<number> = 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<number, EffectCardCfg> = 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 }, oldpos: ${oldpos}`)
|
|
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: oldpos,
|
|
robot: 1
|
|
}
|
|
|
|
},
|
|
randomHero() {
|
|
let heroMap: Map<number, HeroCfg> = global.$cfg.get(BaseConst.HERO)
|
|
let heroArr = [...heroMap.values()]
|
|
let hero: HeroCfg = heroArr.randomOne()
|
|
return { heroId: hero.id }
|
|
}
|
|
}
|
|
|
|
export default assistantUtil
|