diff --git a/assets/script/game/common/config/ICardSet.ts b/assets/script/game/common/config/ICardSet.ts new file mode 100644 index 00000000..df6d5a73 --- /dev/null +++ b/assets/script/game/common/config/ICardSet.ts @@ -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; // 关联的技能 UUID(buff 技能) + 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); +} diff --git a/assets/script/game/map/ItemListComp.ts b/assets/script/game/map/ItemListComp.ts index 73fd3087..364915f1 100644 --- a/assets/script/game/map/ItemListComp.ts +++ b/assets/script/game/map/ItemListComp.ts @@ -1,23 +1,25 @@ /** * @file ItemListComp.ts - * @description 装备商店单个装备项组件(UI 视图层 + 购买逻辑) + * @description 商店列表项组件(UI 视图层 + 购买逻辑) * * 职责: - * 1. 渲染单个装备卡的显示信息(名称、等级、属性词条、图标)。 - * 2. 处理购买点击 → 扣费 → 派发 UseEquipCard 事件触发装备生效。 + * 1. 渲染单个商品/装备卡的显示信息(名称、等级、属性词条、图标)。 + * 2. 处理购买点击 → 扣费 → 根据卡牌类型派发对应事件触发购买效果。 * - * 装备使用机制: - * 与技能卡使用流程一致——购买后派发 GameEvent.UseEquipCard, - * 由 MissEquipComp 接收并创建 EquipBoxComp 实体, - * EquipBoxComp 按 Field 类型被动驻场,属性加成由 FieldSkillHelper 全局聚合。 + * 支持类型: + * - 装备卡(trigger_type=Field)→ 派发 UseEquipCard,由 MissEquipComp 处理。 + * - 商品/药品卡(kind=Potion)→ 派发 UseItemCard,由 MissSkillsComp 处理(一次性 buff)。 + * + * 设计说明: + * 本组件同时服务于装备商店和商品商店,通过 cardData 的 trigger_type / kind 自动判断类型。 */ import { mLogger } from "../common/Logger"; import { _decorator, Node, Sprite, Label, NodeEventType } from "cc"; import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS"; import { CCComp } from "../../../../extensions/oops-plugin-framework/assets/module/common/CCComp"; -import { CardConfig } from "../common/config/CardSet"; +import { CardConfig, CardTriggerType, CKind } from "../common/config/CardSet"; import { EquipPoolList } from "../common/config/EquipSet"; -import { FieldSkillSet } from "../common/config/SkillSet"; +import { FieldSkillSet, SkillSet } from "../common/config/SkillSet"; import { oops } from "db://oops-framework/core/Oops"; import { GameEvent } from "../common/config/GameEvent"; import { smc } from "../common/SingletonModuleComp"; @@ -26,10 +28,10 @@ import { MissionEconomy } from "./MissionEconomy"; const { ccclass, property } = _decorator; /** - * ItemListComp —— 装备商店单个装备项 + * ItemListComp —— 商店列表项(装备/商品通用) * - * 由 MissionCardComp.populateEquipments() 实例化。 - * 以图标 + 名称 + 属性词条 + 购买按钮的形式呈现。 + * 由 MissionCardComp.populateEquipments() / populateShopItems() 实例化。 + * 以图标 + 名称 + 描述/属性词条 + 购买按钮的形式呈现。 */ @ccclass('ItemListComp') @ecs.register('ItemListComp', false) @@ -38,7 +40,7 @@ export class ItemListComp extends CCComp { // ======================== 编辑器绑定节点 ======================== - /** 装备图标节点 */ + /** 商品图标节点 */ @property({ type: Node }) private icon_node: Node = null; @@ -46,17 +48,17 @@ export class ItemListComp extends CCComp { @property({ type: Node }) private bg_node: Node = null; - /** 装备名称 */ + /** 商品名称 */ @property(Label) private name_label: Label = null; - /** 属性词条 1 */ + /** 描述/属性词条 1 */ @property(Label) private fied1: Label = null; - /** 属性词条 2 */ + /** 描述/属性词条 2 */ @property(Label) private fied2: Label = null; - /** 属性词条 3 */ + /** 描述/属性词条 3 */ @property(Label) private fied3: Label = null; @@ -70,7 +72,7 @@ export class ItemListComp extends CCComp { // ======================== 运行时状态 ======================== - /** 当前装备的卡牌配置 */ + /** 当前商品的卡牌配置 */ private cardData: CardConfig | null = null; /** 是否已购买 */ private isPurchased: boolean = false; @@ -91,9 +93,9 @@ export class ItemListComp extends CCComp { // ======================== 数据初始化 ======================== /** - * 初始化装备卡数据并渲染 UI + * 初始化商品卡数据并渲染 UI * - * @param data 装备卡配置(必须为 trigger_type=Field 的装备卡) + * @param data 商品/装备卡配置 */ applyCardData(data: CardConfig): void { if (!data) return; @@ -107,11 +109,17 @@ export class ItemListComp extends CCComp { updateUI() { if (!this.cardData) return; - const cardConfig = EquipPoolList.find(c => c.uuid === this.cardData!.uuid); + const isEquip = this.cardData.trigger_type === CardTriggerType.Field; + const isPotion = this.cardData.kind === CKind.Potion; - // 名称 + // 名称:装备从 EquipPoolList 查找,商品直接用 cardData.name if (this.name_label) { - this.name_label.string = cardConfig?.name || ""; + if (isEquip) { + const equipConfig = EquipPoolList.find(c => c.uuid === this.cardData!.uuid); + this.name_label.string = equipConfig?.name || this.cardData.name || ""; + } else { + this.name_label.string = this.cardData.name || ""; + } } // 等级标签(★ 表示卡牌等级) @@ -120,25 +128,63 @@ export class ItemListComp extends CCComp { this.level_label.string = lv >= 2 ? "★".repeat(lv - 1) : ""; } - // 属性词条(最多显示 3 条,对应 fied1/fied2/fied3) + // 描述/属性词条(最多显示 3 条) const fieldLabels = [this.fied1, this.fied2, this.fied3]; - const fields = this.cardData.field || []; - for (let i = 0; i < fieldLabels.length; i++) { - if (!fieldLabels[i]) continue; - if (i < fields.length) { - const fieldConfig = FieldSkillSet[fields[i]]; - fieldLabels[i].string = fieldConfig?.info || ""; - fieldLabels[i].node.active = true; - } else { - fieldLabels[i].string = ""; - fieldLabels[i].node.active = false; + if (isEquip) { + // 装备:显示 field 词条 + const fields = this.cardData.field || []; + for (let i = 0; i < fieldLabels.length; i++) { + if (!fieldLabels[i]) continue; + if (i < fields.length) { + const fieldConfig = FieldSkillSet[fields[i]]; + fieldLabels[i].string = fieldConfig?.info || ""; + fieldLabels[i].node.active = true; + } else { + fieldLabels[i].string = ""; + fieldLabels[i].node.active = false; + } + } + } else if (isPotion) { + // 商品:显示技能描述 + info + const skillConfig = this.cardData.skill ? SkillSet[this.cardData.skill] : null; + const skillInfo = skillConfig?.info || ""; + const cardInfo = this.cardData.info || ""; + + if (fieldLabels[0]) { + fieldLabels[0].string = cardInfo; + fieldLabels[0].node.active = !!cardInfo; + } + if (fieldLabels[1]) { + fieldLabels[1].string = skillInfo; + fieldLabels[1].node.active = !!skillInfo && skillInfo !== cardInfo; + } + if (fieldLabels[2]) { + fieldLabels[2].string = ""; + fieldLabels[2].node.active = false; + } + } else { + // 其他类型:显示 info + for (let i = 0; i < fieldLabels.length; i++) { + if (!fieldLabels[i]) continue; + fieldLabels[i].string = i === 0 ? (this.cardData.info || "") : ""; + fieldLabels[i].node.active = i === 0 && !!this.cardData.info; } } - // 图标(取第一个 field 词条的图标) - if (this.icon_node && fields.length > 0) { - const iconId = FieldSkillSet[fields[0]]?.icon || ""; - this.updateIcon(this.icon_node, iconId); + // 图标:装备取第一个 field 词条图标,商品取技能图标 + if (this.icon_node) { + let iconId = ""; + if (isEquip) { + const fields = this.cardData.field || []; + if (fields.length > 0) { + iconId = FieldSkillSet[fields[0]]?.icon || ""; + } + } else if (isPotion && this.cardData.skill) { + iconId = SkillSet[this.cardData.skill]?.icon || ""; + } + if (iconId) { + this.updateIcon(this.icon_node, iconId); + } } // 购买按钮费用显示 @@ -168,12 +214,10 @@ export class ItemListComp extends CCComp { /** * 购买点击处理: * 1. 扣除金币(失败则提示并中止)。 - * 2. 派发 UseSkillCard 事件,触发与技能卡相同的生效流程。 + * 2. 根据卡牌类型派发对应事件: + * - 装备卡(trigger_type=Field)→ UseEquipCard → MissEquipComp + * - 商品/药品卡(kind=Potion)→ UseItemCard → MissSkillsComp(一次性 buff 技能) * 3. 标记已购买,隐藏购买按钮。 - * - * 装备生效链路: - * UseSkillCard → MissSkillsComp.addSkill() → SBox ECS 实体 → SkillBoxComp(Field 类型) - * → FieldSkillHelper.getFieldSkillTotalValue() 全局聚合属性加成 */ private onBuyClick() { if (!this.cardData || this.isPurchased) return; @@ -192,19 +236,39 @@ export class ItemListComp extends CCComp { return; } - // 派发 UseEquipCard,装备生效流程由 MissEquipComp 接收处理 - oops.message.dispatchEvent(GameEvent.UseEquipCard, this.cardData); + // 根据类型派发对应事件 + const isEquip = this.cardData.trigger_type === CardTriggerType.Field; + const isPotion = this.cardData.kind === CKind.Potion; + + if (isEquip) { + // 装备:被动驻场,由 MissEquipComp 处理 + oops.message.dispatchEvent(GameEvent.UseEquipCard, this.cardData); + mLogger.log(this.debugMode, "ItemListComp", "equipment purchased", { + uuid: this.cardData.uuid, + cost + }); + } else if (isPotion) { + // 商品/药品:一次性 buff 技能,由 MissSkillsComp 处理 + oops.message.dispatchEvent(GameEvent.UseItemCard, this.cardData); + mLogger.log(this.debugMode, "ItemListComp", "item purchased", { + uuid: this.cardData.uuid, + skill: this.cardData.skill, + cost + }); + } else { + // 默认走技能卡流程 + oops.message.dispatchEvent(GameEvent.UseSkillCard, this.cardData); + mLogger.log(this.debugMode, "ItemListComp", "card purchased", { + uuid: this.cardData.uuid, + cost + }); + } // 标记已购买 this.isPurchased = true; if (this.buy_node) { this.buy_node.active = false; } - - mLogger.log(this.debugMode, "ItemListComp", "equipment purchased", { - uuid: this.cardData.uuid, - cost - }); } /** 标记为已购买状态(用于跨波次保持购买记录) */ diff --git a/assets/script/game/map/MissionCardComp.ts b/assets/script/game/map/MissionCardComp.ts index c9a78328..6c4d5bbc 100644 --- a/assets/script/game/map/MissionCardComp.ts +++ b/assets/script/game/map/MissionCardComp.ts @@ -42,6 +42,7 @@ import { GameEvent } from "../common/config/GameEvent"; import { CardConfig, CardPoolList, CardType, drawCardsByRule, SpecialRefreshCardList, SpecialRefreshHeroType, SpecialUpgradeCardList } from "../common/config/CardSet"; import { drawSkillCards } from "../common/config/SCardSet"; import { EquipPoolList } from "../common/config/EquipSet"; +import { ItemCardList, drawItemCards } from "../common/config/ICardSet"; import { CardComp } from "./CardComp"; import { SCardComp } from "./SCardComp"; import { EquipListComp } from "./EquipListComp"; @@ -53,6 +54,7 @@ import { HeroViewComp } from "../hero/HeroViewComp"; import { FacSet, FightSet } from "../common/config/GameSet"; import { MissionEconomy } from "./MissionEconomy"; import { UIID } from "../common/config/GameUIConfig"; +import { ItemListComp } from "./ItemListComp"; const { ccclass, property } = _decorator; @@ -175,6 +177,8 @@ export class MissionCardComp extends CCComp { private skillCardComps: SCardComp[] = []; /** 已购买装备的 UUID 集合(跨波次保持,防止重复购买) */ private purchasedEquipUuids: Set = new Set(); + /** 已购买商品的 UUID 集合(跨波次保持,防止重复购买) */ + private purchasedItemUuids: Set = new Set(); /** 是否已缓存卡牌面板基准缩放 */ private hasCachedCardsBaseScale: boolean = false; /** 卡牌面板基准缩放(从场景读取) */ @@ -236,6 +240,12 @@ export class MissionCardComp extends CCComp { if (this.closeSkills && this.closeSkills.isValid) { this.closeSkills.off(NodeEventType.TOUCH_END, this.onCloseSkillsClick, this); } + if (this.showShop && this.showShop.isValid) { + this.showShop.off(NodeEventType.TOUCH_END, this.onShowShopClick, this); + } + if (this.closeShop && this.closeShop.isValid) { + this.closeShop.off(NodeEventType.TOUCH_END, this.onCloseShopClick, this); + } this.unbindEvents(); } @@ -282,6 +292,10 @@ export class MissionCardComp extends CCComp { this.purchasedEquipUuids.clear(); this.populateEquipments(); + // 重置商品购买记录并填充商品商店 + this.purchasedItemUuids.clear(); + this.populateShopItems(); + // 首次进入准备阶段自动抽取一次技能卡,后续刷新只能通过技能刷新按钮触发 this.initSkillCardsOnce(); @@ -292,6 +306,7 @@ export class MissionCardComp extends CCComp { onMissionEnd() { this.clearAllCards(); this.clearEquipments(); + this.clearShopItems(); if (this.node && this.node.isValid) { this.node.active = false; } @@ -337,6 +352,8 @@ export class MissionCardComp extends CCComp { oops.message.on(GameEvent.UseSkillCard, this.onUseSkillCard, this); // 监听装备购买事件,追踪已购记录 oops.message.on(GameEvent.UseEquipCard, this.onUseEquipCard, this); + // 监听商品购买事件,追踪已购记录 + oops.message.on(GameEvent.UseItemCard, this.onUseItemCard, this); oops.message.on(GameEvent.UseSpecialCard, this.onUseSpecialCard, this); oops.message.on(GameEvent.ShowSmallTip, this.onShowSmallTip, this); oops.message.on(GameEvent.CardUsed, this.onCardUsed, this); @@ -361,6 +378,11 @@ export class MissionCardComp extends CCComp { /** 关闭技能卡池按钮 */ this.closeSkills?.on(NodeEventType.TOUCH_END, this.onCloseSkillsClick, this); + /** 商店显示/隐藏切换按钮 */ + this.showShop?.on(NodeEventType.TOUCH_END, this.onShowShopClick, this); + /** 关闭商店按钮 */ + this.closeShop?.on(NodeEventType.TOUCH_END, this.onCloseShopClick, this); + /** 技能卡刷新按钮 */ this.skill_refresh?.on(NodeEventType.TOUCH_START, this.onSkillDrawTouchStart, this); this.skill_refresh?.on(NodeEventType.TOUCH_END, this.onSkillDrawTouchEnd, this); @@ -512,6 +534,70 @@ export class MissionCardComp extends CCComp { this.skill_card_node.active = false; } + // ======================== 商店面板 ======================== + + /** + * 商店显隐切换按钮回调: + * 切换 shopPanNode 的 active 状态。 + */ + private onShowShopClick() { + if (!this.shopPanNode || !this.shopPanNode.isValid) return; + oops.audio.playEffect("music/button"); + this.shopPanNode.active = !this.shopPanNode.active; + } + + /** 关闭商店按钮回调 */ + private onCloseShopClick() { + if (!this.shopPanNode || !this.shopPanNode.isValid) return; + oops.audio.playEffect("music/button"); + this.shopPanNode.active = false; + } + + /** + * 填充商品列表: + * 从 ICardSet 的 ItemCardList 获取所有商品卡, + * 实例化 itemPrefab 到 shopBoxNode, + * 每个商品项由 ItemListComp 渲染并处理购买。 + * + * 商品为一次性 buff 技能(Instant 触发,t_times=1), + * 购买后立即生效,由 MissSkillsComp 统一处理技能逻辑。 + */ + private populateShopItems() { + if (!this.shopBoxNode || !this.itemPrefab) return; + + // 清空旧列表 + this.shopBoxNode.removeAllChildren(); + + // 从商品卡池获取所有商品 + for (const item of ItemCardList) { + const node = instantiate(this.itemPrefab); + this.shopBoxNode.addChild(node); + const comp = node.getComponent(ItemListComp) || node.addComponent(ItemListComp); + comp.applyCardData(item); + + // 已购买的商品标记为已购 + if (this.purchasedItemUuids.has(item.uuid)) { + comp.setPurchased(); + } + } + + // 默认显示商店面板 + if (this.shopPanNode) { + this.shopPanNode.active = true; + } + + mLogger.log(this.debugMode, "MissionCardComp", "populate shop items", { + count: ItemCardList.length + }); + } + + /** 清空商品列表 */ + private clearShopItems() { + if (this.shopBoxNode && this.shopBoxNode.isValid) { + this.shopBoxNode.removeAllChildren(); + } + } + private dispatchCardsToSkillSlots(cards: CardConfig[]) { if (!this.skillCardComps) return; for (let i = 0; i < this.skillCardComps.length; i++) { @@ -548,6 +634,14 @@ export class MissionCardComp extends CCComp { } } + /** 商品购买事件回调:记录已购 UUID,防止重复购买 */ + private onUseItemCard(event: string, args: any) { + const usedCard = args as CardConfig; + if (usedCard) { + this.purchasedItemUuids.add(usedCard.uuid); + } + } + /** 解除按钮监听,避免节点销毁后回调泄漏 */ private unbindEvents() { oops.message.off(GameEvent.CoinAdd, this.onCoinAdd, this); @@ -557,6 +651,7 @@ export class MissionCardComp extends CCComp { oops.message.off(GameEvent.UseHeroCard, this.onUseHeroCard, this); oops.message.off(GameEvent.UseSkillCard, this.onUseSkillCard, this); oops.message.off(GameEvent.UseEquipCard, this.onUseEquipCard, this); + oops.message.off(GameEvent.UseItemCard, this.onUseItemCard, this); oops.message.off(GameEvent.UseSpecialCard, this.onUseSpecialCard, this); oops.message.off(GameEvent.ShowSmallTip, this.onShowSmallTip, this); oops.message.off(GameEvent.CardUsed, this.onCardUsed, this); @@ -587,6 +682,12 @@ export class MissionCardComp extends CCComp { this.skill_ad_refresh.off(NodeEventType.TOUCH_END, this.onSkillAdDrawTouchEnd, this); this.skill_ad_refresh.off(NodeEventType.TOUCH_CANCEL, this.onSkillAdDrawTouchCancel, this); } + if (this.showShop && this.showShop.isValid) { + this.showShop.off(NodeEventType.TOUCH_END, this.onShowShopClick, this); + } + if (this.closeShop && this.closeShop.isValid) { + this.closeShop.off(NodeEventType.TOUCH_END, this.onCloseShopClick, this); + } } /** @@ -1467,6 +1568,7 @@ export class MissionCardComp extends CCComp { this.cardComps = [] as any; this.skillCardComps = [] as any; this.purchasedEquipUuids.clear(); + this.purchasedItemUuids.clear(); if (this.node && this.node.isValid) { this.node.destroy();