345 lines
12 KiB
TypeScript
345 lines
12 KiB
TypeScript
import {Card} from "../rooms/schema/Card";
|
|
|
|
import {Player} from "../rooms/schema/Player";
|
|
import {BaseConst} from "../constants/BaseConst";
|
|
import {SystemCardCfg} from "../cfg/parsers/SystemCardCfg";
|
|
import {EffectCardCfg} from "../cfg/parsers/EffectCardCfg";
|
|
import {cardLog, error} from "../common/Debug";
|
|
import {Room} from "colyseus";
|
|
import {PlayerStateConst} from "../constants/PlayerStateConst";
|
|
import {GameEnv} from "../cfg/GameEnv";
|
|
import {CardGameState} from "../rooms/schema/CardGameState";
|
|
import {CardType} from "../cfg/enums/CardType";
|
|
import {EffectType} from "../cfg/enums/EffectType";
|
|
|
|
let gameUtil = {
|
|
/**
|
|
* 游戏开始时, 初始化卡组
|
|
*/
|
|
initCardQue(beginNum: number) {
|
|
let cards: Card[] = [];
|
|
let numCfgMap: Map<number, SystemCardCfg> = global.$cfg.get(BaseConst.SYSTEMCARD);
|
|
let effCfgMap: Map<number, EffectCardCfg> = global.$cfg.get(BaseConst.EFFECTCARD);
|
|
|
|
let countMap: Map<number, number> = new Map();
|
|
let localId = beginNum;
|
|
for (let [, cfg] of numCfgMap) {
|
|
for (let i = 0; i < cfg.count; i++) {
|
|
let [effid, effType] = this.getRandomEffect(cfg.weightArr, effCfgMap, countMap);
|
|
let type = cfg.type_id;
|
|
// 如果效果的type_id为11, 说明是自选随从卡, 则将card的type改为11
|
|
if (effType == EffectType.variable_unit) {
|
|
type = CardType.variable_unit;
|
|
}
|
|
let card = new Card(localId++, cfg.point, type, effid);
|
|
cards.push(card);
|
|
}
|
|
}
|
|
|
|
cards.randomSort();
|
|
return cards;
|
|
},
|
|
/**
|
|
* 随机生成一张指定效果的卡
|
|
* @param effectId
|
|
* @param preCardId
|
|
* @param options
|
|
*/
|
|
generateCardWithEffect(effectId: number, preCardId: number, options?: any): Card {
|
|
let numCfgMap: Map<number, SystemCardCfg> = global.$cfg.get(BaseConst.SYSTEMCARD);
|
|
const effectMap = global.$cfg.get(BaseConst.EFFECTCARD);
|
|
let cfgs = [];
|
|
const effectCfg = effectMap.get(effectId);
|
|
if (!effectCfg) {
|
|
return null;
|
|
}
|
|
if (effectCfg.type_id == EffectType.unit) {
|
|
let point = Math.random2(1, 11) | 0;
|
|
return new Card(preCardId + 1, point, CardType.variable_unit, effectId);
|
|
} else {
|
|
for (let [, cfg] of numCfgMap) {
|
|
if (cfg.weight.indexOf(effectId + '') >= 0) {
|
|
cfgs.push(cfg);
|
|
}
|
|
}
|
|
let cfg: SystemCardCfg = cfgs.randomOne();
|
|
return new Card(preCardId + 1, cfg.point, cfg.type_id, effectId);
|
|
}
|
|
|
|
},
|
|
/**
|
|
* 获取随机的随从
|
|
* @param player
|
|
*/
|
|
getRandomServant(player: Player) {
|
|
let total = 0;
|
|
let tmpArr: number[][] = [];
|
|
for (let [id, weight] of player.unitCfgs) {
|
|
total += weight;
|
|
tmpArr.push([parseInt(id), total]);
|
|
}
|
|
let num = Math.random() * total;
|
|
let result;
|
|
for (let data of tmpArr) {
|
|
if (data[1] >= num) {
|
|
result = data[0];
|
|
break;
|
|
}
|
|
}
|
|
return result;
|
|
},
|
|
/**
|
|
* 根据配表中的权重, 获取一个效果卡的id
|
|
* @param weightArr 配表中的权重列表
|
|
* @param effCfgMap 配表中的所有效果卡的配置
|
|
* @param countMap 当前已生成的效果卡数量
|
|
*/
|
|
getRandomEffect(weightArr: number[][], effCfgMap: Map<number, EffectCardCfg>, countMap: Map<number, number>): number[] {
|
|
let total = 0;
|
|
let tmpArr: number[][] = [];
|
|
for (let data of weightArr) {
|
|
total += data[1];
|
|
tmpArr.push([data[0], total]);
|
|
}
|
|
let num = Math.random() * total;
|
|
let effid;
|
|
let effType;
|
|
for (let data of tmpArr) {
|
|
if (data[1] >= num) {
|
|
let count = countMap.has(data[0]) ? countMap.get(data[0]) : 0;
|
|
if (count < effCfgMap.get(data[0]).count) {
|
|
effid = effCfgMap.get(data[0]).id;
|
|
effType = effCfgMap.get(data[0]).type_id;
|
|
countMap.set(effid, count + 1);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (!effid) {
|
|
for (let [id, count] of countMap) {
|
|
if (count < effCfgMap.get(id).count) {
|
|
effid = id;
|
|
effType = effCfgMap.get(effid).type_id;
|
|
countMap.set(effid, count + 1);
|
|
break
|
|
}
|
|
}
|
|
}
|
|
if (!effid) {
|
|
error('生成卡组时, 无法匹配效果卡, 请确认效果卡的最大数量是否等于点数卡总数')
|
|
}
|
|
return [effid, effType];
|
|
},
|
|
/**
|
|
* 检查目标数组中的卡id是否在存在
|
|
* @param cardMap
|
|
* @param cardIds
|
|
*/
|
|
checkCardsExists(cardMap: Map<string, Card>, cardIds: Array<string>) {
|
|
let result = true;
|
|
for (let id of cardIds) {
|
|
if (!cardMap.has(id + '')) {
|
|
result = false;
|
|
break;
|
|
}
|
|
}
|
|
return result;
|
|
},
|
|
/**
|
|
* 抽卡
|
|
* @param room
|
|
* @param cardArr
|
|
* @param player
|
|
* @param count
|
|
* @param fromplayer
|
|
* @param extData 指定卡的效果
|
|
*/
|
|
drawCard(room: Room, cardArr: Card[], player: Player, count: number, fromplayer?: Player, extData?: {}): Card[] {
|
|
let cards: Card[] = [];
|
|
for (let i = 0; i < count; i++) {
|
|
let card = cardArr.pop();
|
|
if (extData) {
|
|
// @ts-ignore
|
|
extData['effect'] && (card.effect = extData['effect']);
|
|
// @ts-ignore
|
|
extData['type'] && (card.type = extData['type']);
|
|
// @ts-ignore
|
|
extData['number'] && (card.number = extData['number']);
|
|
}
|
|
cards.push(card);
|
|
}
|
|
this.addCardToPlayer(room, player, cards, fromplayer);
|
|
return cards;
|
|
},
|
|
/**
|
|
* 随机移除n张手牌
|
|
* @param player
|
|
* @param count
|
|
*/
|
|
removeCard(player: Player, count: number): Card[] {
|
|
let cards: Card[] = [];
|
|
let cardArr: Card[] = [...player.cards.values()];
|
|
cards = cardArr.randomGet(count);
|
|
this.deleteCardFromPlayer(player, cards);
|
|
return cards;
|
|
},
|
|
/**
|
|
* 从玩家手牌中删除指定的卡
|
|
* @param player
|
|
* @param cards
|
|
*/
|
|
deleteCardFromPlayer(player: Player, cards: Card[] | string[] | number[] | number | string) {
|
|
let deleteOne = function (cardId: string) {
|
|
if (player.cards.has(cardId)) {
|
|
if (cardLog.enabled) {
|
|
let card = player.cards.get(cardId);
|
|
cardLog(`delete: ${player.id} ${card.id} ${card.effect} ${card.type} `)
|
|
}
|
|
player.cards.delete(cardId);
|
|
player.cardSet.delete(cardId);
|
|
}
|
|
}
|
|
if (typeof cards == 'number' || typeof cards == 'string') {
|
|
const cardId = cards + '';
|
|
deleteOne(cardId);
|
|
} else {
|
|
for (let card of cards) {
|
|
let cardId = '';
|
|
if (typeof card == 'string') {
|
|
cardId = card;
|
|
} else if (typeof card == 'number') {
|
|
cardId = card + '';
|
|
} else {
|
|
cardId = (card as Card).id + '';
|
|
}
|
|
deleteOne(cardId);
|
|
}
|
|
}
|
|
|
|
},
|
|
pushInPlayerCards(player: Player, cards: Card[]) {
|
|
const effectMap = global.$cfg.get(BaseConst.EFFECTCARD);
|
|
for (let card of cards) {
|
|
// 如果card的type == 11, 说明是自选随从卡, 则替换成玩家牌组中的卡
|
|
if (card.type == CardType.variable_unit && effectMap.get(card.effect).type_id == EffectType.variable_unit) {
|
|
card.effect = this.getRandomServant(player);
|
|
}
|
|
player.cards.set(card.id + '', card);
|
|
player.cardSet.add(card.id + '');
|
|
}
|
|
cardLog(`add: ${player.id} ${cards.map(o => [o.id, o.effect, o.type])}`)
|
|
},
|
|
/**
|
|
* 往玩家的卡组里添加卡
|
|
* @param room
|
|
* @param player
|
|
* @param cards
|
|
* @param fromplayer
|
|
*/
|
|
addCardToPlayer(room: Room, player: Player, cards: Card[], fromplayer?: Player) {
|
|
this.pushInPlayerCards(player, cards);
|
|
player.countTotal += cards.length;
|
|
let time = room.battleMan.onCardGetted(player, cards, fromplayer);
|
|
cardLog(`addCardToPlayer add time: ${time}`);
|
|
},
|
|
/**
|
|
* 更换相同数量的卡
|
|
* @param cardArr
|
|
* @param player
|
|
* @param targetCards
|
|
*/
|
|
changeCard(cardArr: Card[], player: Player, targetCards: Card[]): Card[] {
|
|
const effectMap = global.$cfg.get(BaseConst.EFFECTCARD);
|
|
let cards: Card[] = [];
|
|
let tmpCards: Card[] = [];
|
|
for (let card of targetCards) {
|
|
tmpCards.push(card.clone());
|
|
}
|
|
this.deleteCardFromPlayer(player, targetCards);
|
|
cardArr.randomInsert(tmpCards);
|
|
let count = targetCards.length;
|
|
for (let i = 0; i < count; i++) {
|
|
cards.push(cardArr.pop());
|
|
}
|
|
this.pushInPlayerCards(player, cards);
|
|
return cards;
|
|
},
|
|
/**
|
|
* 检查出牌是否符合规则
|
|
* @param cardsLst
|
|
* @param maxCount
|
|
*/
|
|
checkDiscard(cardsLst: Card[], maxCount: number) {
|
|
if (cardsLst.length == 0 || cardsLst.length == 2) {
|
|
return false
|
|
} else if (cardsLst.length == 1) {
|
|
return true;
|
|
}
|
|
let numSet: number[] = [];
|
|
cardsLst.forEach(function (value) {
|
|
if (value.type == CardType.general || value.type == CardType.variable_unit) {
|
|
numSet.push(value.number);
|
|
}
|
|
});
|
|
if (numSet.length === 1) {
|
|
return true;
|
|
}
|
|
if (numSet.length < maxCount) {
|
|
return false;
|
|
}
|
|
numSet.sort((a, b) => {
|
|
return a - b;
|
|
});
|
|
let preNum;
|
|
let sequence = true; //是否是顺序
|
|
let same = true; //是否是相同
|
|
for (let num of numSet) {
|
|
if (preNum) {
|
|
if (num !== (preNum + 1) && sequence) {
|
|
sequence = false;
|
|
}
|
|
if (num !== preNum && same) {
|
|
same = false;
|
|
}
|
|
if (!sequence && !same) {
|
|
return false;
|
|
}
|
|
}
|
|
preNum = num;
|
|
}
|
|
|
|
return true;
|
|
},
|
|
/**
|
|
* 结算时计算总的ap
|
|
* @param player
|
|
*/
|
|
calcTotalAp(player: Player) {
|
|
let result = 0;
|
|
if (!player) {
|
|
return result;
|
|
}
|
|
for (let [pid, pet] of player.pets) {
|
|
result += pet.ap;
|
|
}
|
|
return result;
|
|
},
|
|
|
|
checkGameEnd(state: CardGameState) {
|
|
let deadCount0 = 0;
|
|
let deadCount1 = 0;
|
|
for (let [, player] of state.players) {
|
|
if (player.team == 0 && player.state == PlayerStateConst.PLAYER_DEAD ) {
|
|
deadCount0 ++;
|
|
} else if (player.team == 1 && player.state == PlayerStateConst.PLAYER_DEAD ){
|
|
deadCount1 ++;
|
|
}
|
|
}
|
|
const roundNum = new GameEnv().duelRoundNum;
|
|
const totalRound = roundNum * new GameEnv().maxDuelNum;
|
|
return (deadCount0 == 2 || deadCount1 == 2) || (state.round >= totalRound - 1);
|
|
}
|
|
|
|
}
|
|
export default gameUtil;
|