- 将 CardType.Special 拆分为 SpecialUpgrade 和 SpecialRefresh - 新增特殊卡使用逻辑:升级功能卡可随机升级场上英雄,刷新功能卡可筛选卡池 - 添加 drawCardsByRule 函数支持按类型、英雄类型和等级抽取卡牌 - 在 MissionCardComp 中处理特殊卡使用事件并更新UI
245 lines
9.0 KiB
TypeScript
245 lines
9.0 KiB
TypeScript
import * as exp from "constants"
|
||
import { HeroInfo, HType } from "./heroSet"
|
||
|
||
/** 卡牌大类定义 */
|
||
export enum CardType {
|
||
Hero = 1,
|
||
Skill = 2,
|
||
SpecialUpgrade = 3,
|
||
SpecialRefresh = 4,
|
||
}
|
||
|
||
/** 卡池等级定义 */
|
||
export enum CardKind {
|
||
LV1 = 1,
|
||
LV2 = 2,
|
||
LV3 = 3,
|
||
LV4 = 4,
|
||
LV5 = 5,
|
||
LV6 = 6,
|
||
}
|
||
|
||
/** 通用卡牌配置 */
|
||
export interface CardConfig {
|
||
uuid: number
|
||
type: CardType
|
||
cost: number
|
||
weight: number
|
||
lv: CardKind
|
||
hero_lv?: number
|
||
}
|
||
export const CardsUpSet: Record<number, number> = {
|
||
1: 50,
|
||
2: 100,
|
||
3: 150,
|
||
4: 200,
|
||
5: 250,
|
||
}
|
||
/**初始coin数 */
|
||
export const CardInitCoins = 4
|
||
/** 卡池升级每波减免金额 */
|
||
export const CARD_POOL_UPGRADE_DISCOUNT_PER_WAVE = 10
|
||
/** 卡池默认初始等级 */
|
||
export const CARD_POOL_INIT_LEVEL = CardKind.LV1
|
||
/** 卡池等级上限 */
|
||
export const CARD_POOL_MAX_LEVEL = CardKind.LV6
|
||
/** 英雄最高等级限制 */
|
||
export const CARD_HERO_MAX_LEVEL = 3
|
||
/** 基础卡池(英雄、技能、功能) */
|
||
export const CardPoolList: CardConfig[] = [
|
||
{ uuid: 5001, type: CardType.Hero, cost: 3, weight: 25, lv: 1, hero_lv: 1 },
|
||
{ uuid: 5101, type: CardType.Hero, cost: 3, weight: 25, lv: 1, hero_lv: 1 },
|
||
{ uuid: 5201, type: CardType.Hero, cost: 3, weight: 25, lv: 1, hero_lv: 1 },
|
||
{ uuid: 5301, type: CardType.Hero, cost: 3, weight: 25, lv: 1, hero_lv: 1 },
|
||
|
||
|
||
{ uuid: 5003, type: CardType.Hero, cost: 3, weight: 25, lv: 2, hero_lv: 1 },
|
||
{ uuid: 5012, type: CardType.Hero, cost: 3, weight: 25, lv: 2, hero_lv: 1 },
|
||
{ uuid: 5302, type: CardType.Hero, cost: 3, weight: 25, lv: 2, hero_lv: 1 },
|
||
|
||
{ uuid: 5001, type: CardType.Hero, cost: 3, weight: 25, lv: 3, hero_lv: 2 },
|
||
{ uuid: 5101, type: CardType.Hero, cost: 3, weight: 25, lv: 3, hero_lv: 2 },
|
||
{ uuid: 5201, type: CardType.Hero, cost: 3, weight: 25, lv: 3, hero_lv: 2 },
|
||
{ uuid: 5301, type: CardType.Hero, cost: 3, weight: 25, lv: 3, hero_lv: 2 },
|
||
|
||
{ uuid: 5002, type: CardType.Hero, cost: 3, weight: 25, lv: 3, hero_lv: 1 },
|
||
{ uuid: 5013, type: CardType.Hero, cost: 3, weight: 25, lv: 3, hero_lv: 1 },
|
||
{ uuid: 5202, type: CardType.Hero, cost: 3, weight: 25, lv: 3, hero_lv: 1 },
|
||
|
||
{ uuid: 5003, type: CardType.Hero, cost: 3, weight: 25, lv: 4, hero_lv: 2 },
|
||
{ uuid: 5012, type: CardType.Hero, cost: 3, weight: 25, lv: 4, hero_lv: 2 },
|
||
{ uuid: 5302, type: CardType.Hero, cost: 3, weight: 25, lv: 4, hero_lv: 2 },
|
||
|
||
{ uuid: 5004, type: CardType.Hero, cost: 3, weight: 25, lv: 4, hero_lv: 1 },
|
||
{ uuid: 5104, type: CardType.Hero, cost: 3, weight: 25, lv: 4, hero_lv: 1 },
|
||
{ uuid: 5303, type: CardType.Hero, cost: 3, weight: 25, lv: 4, hero_lv: 1 },
|
||
|
||
{ uuid: 5001, type: CardType.Hero, cost: 3, weight: 25, lv: 5, hero_lv: 3 },
|
||
{ uuid: 5101, type: CardType.Hero, cost: 3, weight: 25, lv: 5, hero_lv: 3 },
|
||
{ uuid: 5201, type: CardType.Hero, cost: 3, weight: 25, lv: 5, hero_lv: 3 },
|
||
{ uuid: 5301, type: CardType.Hero, cost: 3, weight: 25, lv: 5, hero_lv: 3 },
|
||
|
||
{ uuid: 5002, type: CardType.Hero, cost: 3, weight: 25, lv: 5, hero_lv: 2 },
|
||
{ uuid: 5013, type: CardType.Hero, cost: 3, weight: 25, lv: 5, hero_lv: 2 },
|
||
{ uuid: 5202, type: CardType.Hero, cost: 3, weight: 25, lv: 5, hero_lv: 2 },
|
||
|
||
{ uuid: 5105, type: CardType.Hero, cost: 3, weight: 25, lv: 5, hero_lv: 1 },
|
||
|
||
{ uuid: 5003, type: CardType.Hero, cost: 3, weight: 25, lv: 6, hero_lv: 3 },
|
||
{ uuid: 5012, type: CardType.Hero, cost: 3, weight: 25, lv: 6, hero_lv: 3 },
|
||
{ uuid: 5302, type: CardType.Hero, cost: 3, weight: 25, lv: 6, hero_lv: 3 },
|
||
|
||
{ uuid: 5304, type: CardType.Hero, cost: 3, weight: 25, lv: 6, hero_lv: 1 },
|
||
|
||
{ uuid: 7001, type: CardType.SpecialUpgrade, cost: 6, weight: 16, lv: 1 },
|
||
{ uuid: 7002, type: CardType.SpecialUpgrade, cost: 6, weight: 14, lv: 2 },
|
||
{ uuid: 7101, type: CardType.SpecialRefresh, cost: 4, weight: 14, lv: 1 },
|
||
{ uuid: 7102, type: CardType.SpecialRefresh, cost: 4, weight: 14, lv: 1 },
|
||
{ uuid: 7103, type: CardType.SpecialRefresh, cost: 5, weight: 12, lv: 2 },
|
||
]
|
||
|
||
|
||
export enum SpecialRefreshHeroType {
|
||
Any = 0,
|
||
Melee = 1,
|
||
Ranged = 2,
|
||
}
|
||
|
||
/** 升级功能卡完整配置 */
|
||
export interface SpecialUpgradeCardConfig extends CardConfig {
|
||
name: string
|
||
info: string
|
||
currentLv: number
|
||
targetLv: number
|
||
}
|
||
|
||
/** 刷新功能卡完整配置 */
|
||
export interface SpecialRefreshCardConfig extends CardConfig {
|
||
name: string
|
||
info: string
|
||
refreshLv: number
|
||
refreshHeroType: SpecialRefreshHeroType
|
||
}
|
||
|
||
/** 功能卡定义表 */
|
||
|
||
|
||
|
||
export const SpecialUpgradeCardList: Record<number, SpecialUpgradeCardConfig> = {
|
||
7001: { uuid: 7001,type: CardType.SpecialUpgrade,cost: 6,weight: 16,lv: CardKind.LV1,name:"战术晋升",info: "升级场上随机1个1级英雄到2级",
|
||
currentLv: 1, targetLv: 2,
|
||
},
|
||
7002: { uuid: 7002,type: CardType.SpecialUpgrade,cost: 6,weight: 14,lv: CardKind.LV2,name:"进阶战术",info: "升级场上随机1个2级英雄到3级",
|
||
currentLv: 2, targetLv: 3,
|
||
},
|
||
}
|
||
|
||
export const SpecialRefreshCardList: Record<number, SpecialRefreshCardConfig> = {
|
||
7101: { uuid: 7101,type: CardType.SpecialRefresh,cost: 4,weight: 14,lv: CardKind.LV1,name:"近战征召",info: "刷新卡池,都是近战英雄",
|
||
refreshLv: 0, refreshHeroType: SpecialRefreshHeroType.Melee,
|
||
},
|
||
7102: { uuid: 7102,type: CardType.SpecialRefresh,cost: 4,weight: 14,lv: CardKind.LV1,name:"远程征召",info: "刷新卡池,都是远程英雄",
|
||
refreshLv: 0, refreshHeroType: SpecialRefreshHeroType.Ranged,
|
||
},
|
||
7103: { uuid: 7103,type: CardType.SpecialRefresh,cost: 5,weight: 12,lv: CardKind.LV2,name:"精英筛选",info: "刷新卡池,都是3级卡池等级英雄",
|
||
refreshLv: 3, refreshHeroType: SpecialRefreshHeroType.Any,
|
||
},
|
||
}
|
||
|
||
|
||
|
||
/** 规范等级到合法区间 [LV1, LV6] */
|
||
const clampCardLv = (lv: number): CardKind => {
|
||
const value = Math.floor(lv)
|
||
if (value < CARD_POOL_INIT_LEVEL) return CARD_POOL_INIT_LEVEL
|
||
if (value > CARD_POOL_MAX_LEVEL) return CARD_POOL_MAX_LEVEL
|
||
return value as CardKind
|
||
}
|
||
|
||
/** 单次按权重抽取一张卡 */
|
||
const weightedPick = (cards: CardConfig[]): CardConfig | null => {
|
||
if (cards.length === 0) return null
|
||
const totalWeight = cards.reduce((total, card) => total + card.weight, 0)
|
||
let random = Math.random() * totalWeight
|
||
for (const card of cards) {
|
||
random -= card.weight
|
||
if (random <= 0) return card
|
||
}
|
||
return cards[cards.length - 1]
|
||
}
|
||
|
||
/** 连续抽取 count 张卡,允许重复 */
|
||
const pickCards = (cards: CardConfig[], count: number): CardConfig[] => {
|
||
if (cards.length === 0 || count <= 0) return []
|
||
const selected: CardConfig[] = []
|
||
while (selected.length < count) {
|
||
const pick = weightedPick(cards)
|
||
if (!pick) break
|
||
selected.push(pick)
|
||
}
|
||
return selected
|
||
}
|
||
|
||
/** 获取指定等级可出现的基础卡池 */
|
||
export const getCardPoolByLv = (lv: number, onlyCurrentLv: boolean = false): CardConfig[] => {
|
||
const cardLv = clampCardLv(lv)
|
||
if (onlyCurrentLv) {
|
||
return CardPoolList.filter(card => card.lv === cardLv)
|
||
}
|
||
return CardPoolList.filter(card => card.lv <= cardLv)
|
||
}
|
||
|
||
const normalizeTypeFilter = (type: CardType | CardType[]): Set<CardType> => {
|
||
const list = Array.isArray(type) ? type : [type]
|
||
return new Set<CardType>(list)
|
||
}
|
||
|
||
/** 常规发牌:前 2 英雄 + 后 2 其他;支持按类型和等级模式过滤 */
|
||
export const getCardsByLv = (
|
||
lv: number,
|
||
type?: CardType | CardType[],
|
||
onlyCurrentLv: boolean = false
|
||
): CardConfig[] => {
|
||
const pool = getCardPoolByLv(lv, onlyCurrentLv)
|
||
if (type !== undefined) {
|
||
const typeSet = normalizeTypeFilter(type)
|
||
const filteredPool = pool.filter(card => typeSet.has(card.type))
|
||
return pickCards(filteredPool, 4)
|
||
}
|
||
const heroPool = pool.filter(card => card.type === CardType.Hero)
|
||
const otherPool = pool.filter(card => card.type !== CardType.Hero)
|
||
const heroes = pickCards(heroPool, 2)
|
||
const others = pickCards(otherPool, 2)
|
||
return [...heroes, ...others]
|
||
}
|
||
|
||
export const drawCardsByRule = (
|
||
lv: number,
|
||
options: {
|
||
count?: number
|
||
onlyCurrentLv?: boolean
|
||
type?: CardType | CardType[]
|
||
heroType?: HType
|
||
heroLv?: number
|
||
} = {}
|
||
): CardConfig[] => {
|
||
const count = Math.max(0, Math.floor(options.count ?? 4))
|
||
const onlyCurrentLv = options.onlyCurrentLv ?? false
|
||
let pool = getCardPoolByLv(lv, onlyCurrentLv)
|
||
if (options.type !== undefined) {
|
||
const typeSet = normalizeTypeFilter(options.type)
|
||
pool = pool.filter(card => typeSet.has(card.type))
|
||
}
|
||
if (options.heroType !== undefined || options.heroLv !== undefined) {
|
||
pool = pool.filter(card => {
|
||
if (card.type !== CardType.Hero) return false
|
||
const hero = HeroInfo[card.uuid]
|
||
if (!hero) return false
|
||
if (options.heroType !== undefined && hero.type !== options.heroType) return false
|
||
if (options.heroLv !== undefined && card.hero_lv !== options.heroLv) return false
|
||
return true
|
||
})
|
||
}
|
||
return pickCards(pool, count)
|
||
}
|