diff --git a/assets/script/game/map/CardComp.ts b/assets/script/game/map/CardComp.ts index 3702e455..6662958f 100644 --- a/assets/script/game/map/CardComp.ts +++ b/assets/script/game/map/CardComp.ts @@ -8,6 +8,7 @@ import { HeroInfo } from "../common/config/heroSet"; import { SkillSet } from "../common/config/SkillSet"; import { GameEvent } from "../common/config/GameEvent"; import { oops } from "db://oops-framework/core/Oops"; +import { smc } from "../common/SingletonModuleComp"; @@ -161,6 +162,19 @@ export class CardComp extends CCComp { useCard(): CardConfig | null { if (!this.cardData || this.isUsing) return null; + const cardCost = Math.max(0, Math.floor(this.cardData.cost ?? 0)); + const currentCoin = this.getMissionCoin(); + if (currentCoin < cardCost) { + oops.gui.toast(`金币不足,召唤需要${cardCost}`); + this.playReboundAnim(); + mLogger.log(this.debugMode, "CardComp", "use card coin not enough", { + uuid: this.cardData.uuid, + type: this.cardData.type, + cardCost, + currentCoin + }); + return null; + } if (this.cardData.type === CardType.Hero) { const guard = { cancel: false, @@ -174,11 +188,18 @@ export class CardComp extends CCComp { return null; } } + this.setMissionCoin(currentCoin - cardCost); + oops.message.dispatchEvent(GameEvent.CoinAdd, { + syncOnly: true, + delta: -cardCost + }); this.isUsing = true; const used = this.cardData; mLogger.log(this.debugMode, "CardComp", "use card", { uuid: used.uuid, - type: used.type + type: used.type, + cost: cardCost, + leftCoin: this.getMissionCoin() }); this.playUseDisappearAnim(() => { this.cardUseComp?.onCardUsed(used); @@ -481,6 +502,17 @@ export class CardComp extends CCComp { [...clips].forEach(clip => anim.removeClip(clip, true)); } + private getMissionCoin(): number { + const missionData = smc?.vmdata?.mission_data; + return Math.max(0, Math.floor(missionData?.coin ?? 0)); + } + + private setMissionCoin(value: number) { + const missionData = smc?.vmdata?.mission_data; + if (!missionData) return; + missionData.coin = Math.max(0, Math.floor(value)); + } + /** 视图对象通过 ecs.Entity.remove(ModuleViewComp) 删除组件是触发组件处理自定义释放逻辑 */ reset() { this.node.destroy(); diff --git a/assets/script/game/map/MissionCardComp.ts b/assets/script/game/map/MissionCardComp.ts index 001d6d65..1d36ba34 100644 --- a/assets/script/game/map/MissionCardComp.ts +++ b/assets/script/game/map/MissionCardComp.ts @@ -22,6 +22,8 @@ export class MissionCardComp extends CCComp { private readonly buttonNormalScale: number = 1; private readonly buttonPressScale: number = 0.94; private readonly buttonClickScale: number = 1.06; + @property({ tooltip: "每次刷新卡牌消耗金币" }) + refreshCost: number = 1; /** 四个插卡槽位(固定顺序分发:1~4) */ @property(Node) cards_node:Node = null! @@ -106,7 +108,7 @@ export class MissionCardComp extends CCComp { } this.resetButtonScale(this.cards_chou); this.resetButtonScale(this.cards_up); - this.updatePoolLvUI(); + this.updateCoinAndCostUI(); this.updateHeroNumUI(false, false); this.node.active = true; const cards = this.buildDrawCards(); @@ -161,14 +163,14 @@ export class MissionCardComp extends CCComp { } private onCoinAdd(args:any){ if (args?.syncOnly) { - this.updatePoolLvUI(); + this.updateCoinAndCostUI(); this.playCoinChangeAnim((args?.delta ?? 0) > 0); return; } const v = typeof args === 'number' ? args : (args?.delta ?? args?.value ?? 0); if (v === 0) return; this.setMissionCoin(this.getMissionCoin() + v); - this.updatePoolLvUI(); + this.updateCoinAndCostUI(); this.playCoinChangeAnim(v > 0); } @@ -260,8 +262,24 @@ export class MissionCardComp extends CCComp { /** 抽卡按钮:每次固定抽4张,然后顺序分发给4个单卡脚本 */ private onClickDraw() { + const cost = this.getRefreshCost(); + const currentCoin = this.getMissionCoin(); + if (currentCoin < cost) { + oops.gui.toast(`金币不足,刷新需要${cost}`); + this.updateCoinAndCostUI(); + mLogger.log(this.debugMode, "MissionCardComp", "draw coin not enough", { + currentCoin, + cost + }); + return; + } + this.setMissionCoin(currentCoin - cost); + this.playCoinChangeAnim(false); + this.updateCoinAndCostUI(); mLogger.log(this.debugMode, "MissionCardComp", "click draw", { - poolLv: this.poolLv + poolLv: this.poolLv, + cost, + leftCoin: this.getMissionCoin() }); this.layoutCardSlots(); const cards = this.buildDrawCards(); @@ -278,7 +296,7 @@ export class MissionCardComp extends CCComp { const currentCoin = this.getMissionCoin(); if (currentCoin < cost) { oops.gui.toast(`金币不足,升级需要${cost}`); - this.updatePoolLvUI(); + this.updateCoinAndCostUI(); mLogger.log(this.debugMode, "MissionCardComp", "pool upgrade coin not enough", { poolLv: this.poolLv, currentCoin, @@ -289,7 +307,7 @@ export class MissionCardComp extends CCComp { this.setMissionCoin(currentCoin - cost); this.poolLv += 1; this.playCoinChangeAnim(false); - this.updatePoolLvUI(); + this.updateCoinAndCostUI(); mLogger.log(this.debugMode, "MissionCardComp", "pool level up", { poolLv: this.poolLv, cost, @@ -423,6 +441,10 @@ export class MissionCardComp extends CCComp { const currentCoin = this.getMissionCoin(); return currentCoin >= this.getUpgradeCost(this.poolLv); } + + private canDrawCards() { + return this.getMissionCoin() >= this.getRefreshCost(); + } /** 更新升级按钮上的等级文案,反馈当前卡池层级 */ private updatePoolLvUI() { if (!this.cards_up) return; @@ -449,6 +471,24 @@ export class MissionCardComp extends CCComp { }); } + private updateDrawCostUI() { + if (!this.cards_chou) return; + const nobg = this.cards_chou.getChildByName("nobg"); + if (nobg) { + nobg.active = !this.canDrawCards(); + } + const coinNode = this.cards_chou.getChildByName("coin"); + const numLabel = coinNode?.getChildByName("num")?.getComponent(Label); + if (numLabel) { + numLabel.string = `${this.getRefreshCost()}`; + } + } + + private updateCoinAndCostUI() { + this.updatePoolLvUI(); + this.updateDrawCostUI(); + } + private playCoinChangeAnim(isIncrease: boolean) { if (!this.coins_node || !this.coins_node.isValid) return; const target = this.coins_node.getChildByName("num") || this.coins_node; @@ -466,6 +506,10 @@ export class MissionCardComp extends CCComp { return CardsUpSet[lv] ?? 0; } + private getRefreshCost(): number { + return Math.max(0, Math.floor(this.refreshCost)); + } + private ensureHeroInfoPanel(eid: number, model: HeroAttrsComp) { if (!this.hero_info_node || !this.hero_info_prefab) return; this.hero_info_node.active = true;