feat(shop): 新增商品/药品卡池与商店系统

1. 新增ICardSet.ts定义商品卡池配置,包含基础/高级恢复类、属性强化类道具
2. 为MissionCardComp添加商品商店逻辑,支持购买记录追踪与显隐切换
3. 重构ItemListComp为通用商店列表组件,适配装备与商品两种商店类型
This commit is contained in:
panFD
2026-07-22 21:42:00 +08:00
parent 90db23e7c9
commit afbb349c25
3 changed files with 352 additions and 50 deletions

View File

@@ -0,0 +1,136 @@
/**
* @file ICardSet.ts
* @description 商品/药品卡池独立配置
*
* 职责:
* 定义所有商品/药品卡的静态数据与技能卡池SCardSet和装备卡池EquipSet分离。
* 商品/药品为一次性消耗品,购买后立即触发一次 buff 效果(如治疗、护盾、属性强化等)。
*
* 设计:
* - 参考 SCardSet.ts 结构,但商品是"只触发一次的 buff 技能",而非"多次触发的攻击技能"。
* - trigger_type 统一为 Instant即时触发
* - t_times 固定为 1只触发一次
* - kind 为 CKind.Potion药水类
*
* 依赖:
* - CardSet —— CardConfig / CardType / CKind / CardLV / CardTriggerType
* - SkillSet —— SkillOverrides
*/
import { CardConfig, CardType, CardLV, CKind, CardTriggerType } from "./CardSet";
import { SkillOverrides } from "./SkillSet";
/** 商品/药品卡原始数据(平铺字段,构建后转为 CardConfig */
interface ItemCardRaw {
uuid: number;
skill: number; // 关联的技能 UUIDbuff 技能)
name: string;
info: string;
cost: number; // 购买价格
weight: number; // 抽取权重
overrides?: SkillOverrides; // 技能参数覆写(如自定义治疗量、护盾值等)
}
const ItemCardData: ItemCardRaw[] = [
// ==================== 基础恢复类 ====================
{ uuid: 9101, skill: 6302, name: "治疗药水", info: "恢复全体友方 300 点生命", cost: 3, weight: 20 },
{ uuid: 9102, skill: 6301, name: "护盾药水", info: "为全体友方添加护盾,可抵挡 3 次伤害", cost: 4, weight: 15 },
{ uuid: 9103, skill: 6303, name: "金币袋", info: "立即获得 5 金币", cost: 2, weight: 15, overrides: { gold: 5 } },
// ==================== 属性强化类(单次触发) ====================
{ uuid: 9111, skill: 6401, name: "攻击药剂", info: "全体友方攻击力提升 5 点", cost: 3, weight: 12 },
{ uuid: 9112, skill: 6402, name: "生命药剂", info: "全体友方最大生命值提升 20 点", cost: 3, weight: 12 },
{ uuid: 9113, skill: 6403, name: "暴击药剂", info: "全体友方暴击率提升 10%", cost: 3, weight: 12 },
{ uuid: 9114, skill: 6404, name: "暴伤药剂", info: "全体友方暴击伤害提升 20%", cost: 3, weight: 12 },
{ uuid: 9115, skill: 6405, name: "击晕药剂", info: "全体友方击晕概率提升 10%", cost: 3, weight: 12 },
{ uuid: 9116, skill: 6408, name: "穿刺药剂", info: "全体友方穿透概率提升 20%", cost: 3, weight: 12 },
{ uuid: 9117, skill: 6409, name: "风怒药剂", info: "全体友方风怒次数提升 1 次", cost: 3, weight: 12 },
// ==================== 高级恢复类 ====================
{ uuid: 9201, skill: 6302, name: "高级治疗药水", info: "恢复全体友方 600 点生命", cost: 6, weight: 8, overrides: { ap: 600 } },
{ uuid: 9202, skill: 6301, name: "高级护盾药水", info: "为全体友方添加护盾,可抵挡 6 次伤害", cost: 8, weight: 6, overrides: { ap: 6 } },
{ uuid: 9203, skill: 6303, name: "大金币袋", info: "立即获得 12 金币", cost: 5, weight: 6, overrides: { gold: 12 } },
// ==================== 高级属性强化类 ====================
{ uuid: 9211, skill: 6401, name: "高级攻击药剂", info: "全体友方攻击力提升 10 点", cost: 6, weight: 5, overrides: { ap: 10 } },
{ uuid: 9212, skill: 6402, name: "高级生命药剂", info: "全体友方最大生命值提升 40 点", cost: 6, weight: 5, overrides: { ap: 40 } },
{ uuid: 9213, skill: 6403, name: "高级暴击药剂", info: "全体友方暴击率提升 20%", cost: 6, weight: 5, overrides: { ap: 2 } },
{ uuid: 9214, skill: 6404, name: "高级暴伤药剂", info: "全体友方暴击伤害提升 40%", cost: 6, weight: 5, overrides: { ap: 2 } },
];
/**
* 商品/药品卡池(已构建为标准 CardConfig[])。
* 所有商品卡统一配置:
* - type: Skill复用技能卡体系由 MissSkillsComp 统一处理)
* - kind: Potion药水类用于区分
* - trigger_type: Instant即时触发只生效一次
* - t_times: 1只触发一次
* - is_inst: true即时起效
*/
export const ItemCardList: CardConfig[] = ItemCardData.map(data => ({
uuid: data.uuid,
skill: data.skill,
type: CardType.Skill,
cost: data.cost,
weight: data.weight,
pool_lv: CardLV.LV1,
kind: CKind.Potion,
card_lv: 1,
name: data.name,
info: data.info,
is_inst: true,
t_times: 1,
t_inv: 0,
keep_waves: 0,
overrides: data.overrides,
trigger_type: CardTriggerType.Instant,
}));
/**
* 按权重抽取一张商品卡(带权重随机)。
*/
function weightedPick(cards: CardConfig[]): CardConfig | null {
if (cards.length === 0) return null;
const totalWeight = cards.reduce((total, card) => total + (card.weight ?? 0), 0);
let random = Math.random() * totalWeight;
for (const card of cards) {
random -= (card.weight ?? 0);
if (random <= 0) return card;
}
return cards[cards.length - 1];
}
/**
* 按权重抽取 N 张商品卡unique 保证一次刷新内不重复,不足时允许重复补齐)。
* @param count 需要抽取的数量
*/
export function drawItemCards(count: number): CardConfig[] {
const safeCount = Math.max(0, Math.floor(count));
if (ItemCardList.length === 0 || safeCount <= 0) return [];
const picked: CardConfig[] = [];
let available = [...ItemCardList];
while (picked.length < safeCount) {
if (available.length === 0) break;
const pick = weightedPick(available);
if (!pick) break;
picked.push(pick);
available = available.filter(c => c.uuid !== pick.uuid);
}
// 不足时允许重复补齐
const filled = [...picked];
while (filled.length < safeCount) {
const fallback = weightedPick(ItemCardList);
if (!fallback) break;
filled.push(fallback);
}
return filled;
}
/**
* 按 UUID 查找商品卡配置
* @param uuid 商品卡 UUID
*/
export function findItemCardByUuid(uuid: number): CardConfig | undefined {
return ItemCardList.find(e => e.uuid === uuid);
}