/** * @file heroUpSet.ts * @description 英雄局外升级规则与判定逻辑(纯逻辑模块,无 UI / 无单例依赖) * * 职责: * 1. 封装 HERO_UPGRADE_NEED_FRAGMENTS 升级消耗表的查询口径(满级判定)。 * 2. 提供"是否可升级"的统一判定,供 smc.upgradeHero / HerosListComp / CardLiteComp 复用。 * * 关键设计: * - 不直接引用 smc 单例,由调用方传入成长数据(lv / fragments),保持纯函数可测试。 * - 升级表 key 为目标等级:need = HERO_UPGRADE_NEED_FRAGMENTS[lv + 1],查不到即满级。 */ import { HERO_UPGRADE_NEED_FRAGMENTS } from "./GameSet"; import { HeroInfo, HeroList } from "./heroSet"; /** 英雄升级状态快照 */ export interface HeroUpgradeState { /** 当前局外等级 */ lv: number; /** 下一级(满级时为当前等级) */ nextLv: number; /** 当前拥有碎片数 */ fragments: number; /** 升到下一级所需碎片数(满级为 0) */ needFragments: number; /** 是否已满级 */ isMaxLv: boolean; /** 是否满足升级条件(未满级且碎片充足) */ canUpgrade: boolean; } /** 英雄最高局外等级(升级表最大 key - 1) */ export const HERO_MAX_LV: number = Math.max(...Object.keys(HERO_UPGRADE_NEED_FRAGMENTS).map(Number)) - 1; /** * 查询从当前等级升到下一级所需的碎片数。 * @param lv 当前局外等级 * @returns 所需碎片数;已满级返回 undefined */ export function getHeroUpgradeNeedFragments(lv: number): number | undefined { return HERO_UPGRADE_NEED_FRAGMENTS[lv + 1]; } /** * 判断英雄当前等级是否已满级。 * @param lv 当前局外等级 */ export function isHeroMaxLv(lv: number): boolean { return getHeroUpgradeNeedFragments(lv) === undefined; } /** * 判断英雄是否满足升级条件(未满级且碎片充足)。 * @param lv 当前局外等级 * @param fragments 当前拥有碎片数 */ export function canHeroUpgrade(lv: number, fragments: number): boolean { const need = getHeroUpgradeNeedFragments(lv); return need !== undefined && fragments >= need; } /** * 汇总英雄升级状态快照(供 UI 一次性取用,避免重复查表)。 * @param lv 当前局外等级 * @param fragments 当前拥有碎片数 */ export function getHeroUpgradeState(lv: number, fragments: number): HeroUpgradeState { const need = getHeroUpgradeNeedFragments(lv); const isMax = need === undefined; return { lv, nextLv: isMax ? lv : lv + 1, fragments, needFragments: need ?? 0, isMaxLv: isMax, canUpgrade: !isMax && fragments >= (need as number), }; } /** * 图鉴展示排序:可升级优先 → 现有等级降序 → 品质降序。 * Why: 图鉴(HerosListComp)与英雄详情(HeroInfoComp)共用同一排序口径, * 保证图鉴中的卡片顺序与详情面板"前后切换"顺序一致。 * @param getGrowth 查询英雄成长数据(lv / fragments)的回调,通常由 smc.getHeroGrowth 注入 * @returns 排序后的英雄 uuid 数组(新数组,不修改 HeroList) */ export function getSortedHeroList(getGrowth: (uuid: number) => { lv: number; fragments: number }): number[] { return [...HeroList].sort((a, b) => { const ga = getGrowth(a); const gb = getGrowth(b); // 可升级的一批排在最左 const ca = canHeroUpgrade(ga.lv, ga.fragments) ? 0 : 1; const cb = canHeroUpgrade(gb.lv, gb.fragments) ? 0 : 1; if (ca !== cb) return ca - cb; // 同批内:现有等级降序优先 if (ga.lv !== gb.lv) return gb.lv - ga.lv; // 等级相同:品质降序(rarity 越大品质越高) return (HeroInfo[b]?.rarity ?? 1) - (HeroInfo[a]?.rarity ?? 1); }); }