import { AttrCards, AttrInfo } from "./AttrSet"; import { talConf, ItalConf } from "./TalSet"; import { SkillSet, CanSelectSkills, SkillConfig } from "./SkillSet"; import { HeroInfo, CanSelectHeros, heroInfo } from "./heroSet"; /** * 卡牌类型枚举 */ export enum CardType { Skill = 1, // 技能 Talent = 2, // 天赋 Attr = 3, // 属性 Hero = 4 // 英雄(伙伴) } /** * 统一卡牌信息接口 (用于UI显示和逻辑处理) */ export interface ICardInfo { uuid: number; type: CardType; name: string; desc: string; icon: string; weight: number; // 抽取权重 tag?: string; // 标签 (如 "special" 表示特殊属性) payload: any; // 原始配置数据 } /** * 等级池配置项 */ export interface IPoolWeight { type: CardType; weight: number; tag?: string; // 如果指定,只从该类型中包含此tag的卡牌中抽取 } /** * 1-20 级卡牌池配置表 * 定义每个等级可能出现的卡牌类型及其权重 */ export const LevelPoolConfigs: Record = { 1: [{ type: CardType.Skill, weight: 100 }], 2: [{ type: CardType.Attr, weight: 100 }], // 常规属性 3: [{ type: CardType.Talent, weight: 50 }, { type: CardType.Attr, weight: 50, tag: "special" }], // 天赋或特殊属性 4: [{ type: CardType.Attr, weight: 100 }], 5: [{ type: CardType.Talent, weight: 100 }], 6: [{ type: CardType.Hero, weight: 100 }], // 伙伴节点 7: [{ type: CardType.Attr, weight: 80 }, { type: CardType.Skill, weight: 20 }], 8: [{ type: CardType.Attr, weight: 80 }, { type: CardType.Skill, weight: 20 }], 9: [{ type: CardType.Attr, weight: 50, tag: "special" }, { type: CardType.Talent, weight: 50 }], 10: [{ type: CardType.Talent, weight: 100 }], 11: [{ type: CardType.Attr, weight: 70 }, { type: CardType.Skill, weight: 30 }], 12: [{ type: CardType.Attr, weight: 70 }, { type: CardType.Skill, weight: 30 }], 13: [{ type: CardType.Attr, weight: 100 }], 14: [{ type: CardType.Attr, weight: 50, tag: "special" }, { type: CardType.Talent, weight: 50 }], 15: [{ type: CardType.Talent, weight: 100 }], 16: [{ type: CardType.Attr, weight: 60 }, { type: CardType.Skill, weight: 40 }], 17: [{ type: CardType.Attr, weight: 60 }, { type: CardType.Skill, weight: 40 }], 18: [{ type: CardType.Attr, weight: 50, tag: "special" }, { type: CardType.Talent, weight: 50 }], 19: [{ type: CardType.Attr, weight: 100 }], 20: [{ type: CardType.Talent, weight: 100 }], }; // ========== 卡牌池缓存 ========== let _cachedPools: Map = new Map(); /** * 初始化并获取指定类型的完整卡牌池 */ function getFullPool(type: CardType): ICardInfo[] { if (_cachedPools.has(type)) { return _cachedPools.get(type)!; } const pool: ICardInfo[] = []; switch (type) { case CardType.Attr: // 转换属性配置 Object.values(AttrCards).forEach(cfg => { pool.push({ uuid: cfg.uuid, type: CardType.Attr, name: cfg.desc.split(" ")[0] || "属性强化", // 简单处理名称 desc: cfg.desc, icon: cfg.icon, weight: 100, // 属性默认权重 100 tag: cfg.isSpecial ? "special" : undefined, payload: cfg }); }); break; case CardType.Talent: // 转换天赋配置 Object.values(talConf).forEach(cfg => { pool.push({ uuid: cfg.uuid, type: CardType.Talent, name: cfg.name, desc: cfg.desc, icon: cfg.icon, weight: 50, // 天赋默认权重 50 payload: cfg }); }); break; case CardType.Skill: // 转换技能配置 (仅包含 CanSelectSkills) CanSelectSkills.forEach(uuid => { const cfg = SkillSet[uuid]; if (cfg) { pool.push({ uuid: cfg.uuid, type: CardType.Skill, name: cfg.name, desc: cfg.info, icon: cfg.icon, weight: 80, // 技能默认权重 80 payload: cfg }); } }); break; case CardType.Hero: // 转换英雄配置 (仅包含 CanSelectHeros) CanSelectHeros.forEach(uuid => { const cfg = HeroInfo[uuid]; if (cfg) { pool.push({ uuid: cfg.uuid, type: CardType.Hero, name: cfg.name, desc: cfg.info, icon: cfg.path, // 使用 path 作为图标引用 weight: 1000, // 英雄权重极高(如果池子里有的话) payload: cfg }); } }); break; } _cachedPools.set(type, pool); return pool; } /** * 根据等级获取随机卡牌选项 * @param level 当前等级 * @param count 选项数量 (默认3个) * @param excludeUuids 排除的卡牌UUID列表 (用于去重或排除已拥有) */ export function getCardOptions(level: number, count: number = 3, excludeUuids: number[] = []): ICardInfo[] { // 1. 获取该等级的池配置,如果没有配置,默认给属性 const poolConfigs = LevelPoolConfigs[level] || [{ type: CardType.Attr, weight: 100 }]; const result: ICardInfo[] = []; const excludeSet = new Set(excludeUuids); // 循环抽取 count 次 for (let i = 0; i < count; i++) { // 2.1 随机决定本次抽取的类型池 const selectedPoolConfig = weightedRandomPool(poolConfigs); if (!selectedPoolConfig) continue; // 2.2 获取该类型的所有卡牌 let candidates = getFullPool(selectedPoolConfig.type); // 2.3 过滤 (Tag过滤 + 排除列表 + 已选中过滤) candidates = candidates.filter(card => { // Tag 匹配 if (selectedPoolConfig.tag && card.tag !== selectedPoolConfig.tag) return false; // 排除列表 if (excludeSet.has(card.uuid)) return false; // 当前轮次已选中去重 if (result.find(r => r.uuid === card.uuid)) return false; return true; }); // 2.4 如果该池子空了 (比如技能都学完了),尝试从属性池兜底 if (candidates.length === 0) { candidates = getFullPool(CardType.Attr).filter(c => !result.find(r => r.uuid === c.uuid)); } if (candidates.length > 0) { // 2.5 按卡牌权重随机抽取一张 const card = weightedRandomCard(candidates); if (card) { result.push(card); } } } // 3. 最终结果洗牌 (避免顺序固定) shuffleArray(result); return result; } // ========== 工具函数 ========== /** * 权重随机选择池配置 */ function weightedRandomPool(configs: IPoolWeight[]): IPoolWeight | null { if (!configs || configs.length === 0) return null; const totalWeight = configs.reduce((sum, item) => sum + item.weight, 0); let randomVal = Math.random() * totalWeight; for (const config of configs) { randomVal -= config.weight; if (randomVal <= 0) { return config; } } return configs[configs.length - 1]; } /** * 权重随机选择卡牌 */ function weightedRandomCard(cards: ICardInfo[]): ICardInfo | null { if (!cards || cards.length === 0) return null; const totalWeight = cards.reduce((sum, item) => sum + item.weight, 0); let randomVal = Math.random() * totalWeight; for (const card of cards) { randomVal -= card.weight; if (randomVal <= 0) { return card; } } return cards[cards.length - 1]; } /** * 数组洗牌 (Fisher-Yates) */ function shuffleArray(array: any[]) { for (let i = array.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [array[i], array[j]] = [array[j], array[i]]; } }