refactor: 将刷新石替换为银币作为卡牌刷新消耗
1. 重构全局配置,移除刷新石相关定义,新增银币刷新消耗常量 2. 新增局外持久货币银币的数据结构与管理逻辑 3. 重构卡牌刷新经济系统,统一使用银币进行刷新消耗 4. 更新UI显示与事件通知,适配银币系统变更 5. 调整清屏奖励逻辑,将刷新石奖励改为金币奖励
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -1628,7 +1628,7 @@
|
|||||||
"watchPath": "data.data.gold",
|
"watchPath": "data.data.gold",
|
||||||
"labelType": "cc.Label",
|
"labelType": "cc.Label",
|
||||||
"watchPathArr": [
|
"watchPathArr": [
|
||||||
"data.gold"
|
"data.silver"
|
||||||
],
|
],
|
||||||
"_id": ""
|
"_id": ""
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ export interface GameDate {
|
|||||||
mission?: number,
|
mission?: number,
|
||||||
diamond?: number,
|
diamond?: number,
|
||||||
gold?: number,
|
gold?: number,
|
||||||
|
/** 银币:局外持久货币,用于局内刷新英雄卡牌,仅通过日常任务等途径积攒 */
|
||||||
|
silver?: number,
|
||||||
task?: number,
|
task?: number,
|
||||||
noStop?: boolean,
|
noStop?: boolean,
|
||||||
showInfo?: boolean,
|
showInfo?: boolean,
|
||||||
@@ -110,6 +112,8 @@ export class SingletonModuleComp extends ecs.Comp {
|
|||||||
mission: 1,
|
mission: 1,
|
||||||
diamond: 100, //商店购买 及 双倍奖励资源
|
diamond: 100, //商店购买 及 双倍奖励资源
|
||||||
gold: 1000,
|
gold: 1000,
|
||||||
|
/** 银币:刷新英雄卡牌专用,每局不重置,仅日常积攒 */
|
||||||
|
silver: 0,
|
||||||
task: 0,
|
task: 0,
|
||||||
noStop: false,
|
noStop: false,
|
||||||
showInfo: true,
|
showInfo: true,
|
||||||
@@ -157,7 +161,6 @@ export class SingletonModuleComp extends ecs.Comp {
|
|||||||
level: 1,//关卡等级
|
level: 1,//关卡等级
|
||||||
max_mission: 4,//最大关卡
|
max_mission: 4,//最大关卡
|
||||||
coin: 0,
|
coin: 0,
|
||||||
refresh_stone: 0,//刷新石(刷新卡池时优先消耗,不足时消耗金币)
|
|
||||||
time: 15 * 60,//游戏时间
|
time: 15 * 60,//游戏时间
|
||||||
},
|
},
|
||||||
scores: {
|
scores: {
|
||||||
@@ -216,6 +219,7 @@ export class SingletonModuleComp extends ecs.Comp {
|
|||||||
|
|
||||||
gold: 0, // 金币数据(MVVM绑定字段,镜像 data.gold)
|
gold: 0, // 金币数据(MVVM绑定字段,镜像 data.gold)
|
||||||
diamond: 0, // 钻石数据(MVVM绑定字段,镜像 data.diamond)
|
diamond: 0, // 钻石数据(MVVM绑定字段,镜像 data.diamond)
|
||||||
|
silver: 0, // 银币数据(MVVM绑定字段,镜像 data.silver,刷新卡牌消耗)
|
||||||
switch_effect: true, // 音效开关(MVVM绑定字段)
|
switch_effect: true, // 音效开关(MVVM绑定字段)
|
||||||
switch_music: true, // 音乐开关(MVVM绑定字段)
|
switch_music: true, // 音乐开关(MVVM绑定字段)
|
||||||
};
|
};
|
||||||
@@ -324,6 +328,7 @@ export class SingletonModuleComp extends ecs.Comp {
|
|||||||
public syncCurrencyToView(): void {
|
public syncCurrencyToView(): void {
|
||||||
this.vmdata.gold = this.data.gold ?? 0;
|
this.vmdata.gold = this.data.gold ?? 0;
|
||||||
this.vmdata.diamond = this.data.diamond ?? 0;
|
this.vmdata.diamond = this.data.diamond ?? 0;
|
||||||
|
this.vmdata.silver = this.data.silver ?? 0;
|
||||||
}
|
}
|
||||||
getGameDate() {
|
getGameDate() {
|
||||||
let data: GameDate = {
|
let data: GameDate = {
|
||||||
@@ -363,6 +368,22 @@ export class SingletonModuleComp extends ecs.Comp {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 变更银币(正数获得 / 负数消耗),以 data 为权威源并镜像到 vmdata。
|
||||||
|
* Why: 银币为局外持久货币,仅用于刷新英雄卡牌,日常任务等途径积攒。
|
||||||
|
* @param silver 变动量
|
||||||
|
* @param is_sync 是否标记脏并触发云端/本地同步
|
||||||
|
*/
|
||||||
|
updateSilver(silver: number, is_sync: boolean = true) {
|
||||||
|
this.data.silver = Math.max(0, (this.data.silver ?? 0) + silver);
|
||||||
|
this.vmdata.silver = this.data.silver;
|
||||||
|
if (is_sync) {
|
||||||
|
gameDataSync.markDataDirty();
|
||||||
|
}
|
||||||
|
oops.message.dispatchEvent(GameEvent.SILVER_UPDATE)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
updateSwitchEffect(isOpen: boolean, is_sync: boolean = true) {
|
updateSwitchEffect(isOpen: boolean, is_sync: boolean = true) {
|
||||||
this.vmdata.switch_effect = isOpen;
|
this.vmdata.switch_effect = isOpen;
|
||||||
if (oops.audio) oops.audio.switchEffect = isOpen;
|
if (oops.audio) oops.audio.switchEffect = isOpen;
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ export enum GameEvent {
|
|||||||
UpdateMissionGet = "UpdateMissionGet",
|
UpdateMissionGet = "UpdateMissionGet",
|
||||||
GlobalAttrChange = "GlobalAttrChange",
|
GlobalAttrChange = "GlobalAttrChange",
|
||||||
CoinAdd = "CoinAdd",
|
CoinAdd = "CoinAdd",
|
||||||
RefreshStone = "RefreshStone", // 刷新石数量变更事件
|
SILVER_UPDATE = "SILVER_UPDATE", // 银币数量变更事件(刷新卡牌消耗)
|
||||||
ShowSmallTip = "ShowSmallTip",
|
ShowSmallTip = "ShowSmallTip",
|
||||||
CardPoolUpgrade = "CardPoolUpgrade",
|
CardPoolUpgrade = "CardPoolUpgrade",
|
||||||
TriggerSkill = "TriggerSkill", // 瞬间触发施法事件
|
TriggerSkill = "TriggerSkill", // 瞬间触发施法事件
|
||||||
|
|||||||
@@ -73,9 +73,8 @@ export enum FightSet {
|
|||||||
REFRESH_COST = 2,
|
REFRESH_COST = 2,
|
||||||
BASE_COST = 5,
|
BASE_COST = 5,
|
||||||
INIT_COIN = 7, // 初始金币数
|
INIT_COIN = 7, // 初始金币数
|
||||||
INIT_REFRESH_STONE = 3, // 初始刷新石数量
|
/** 单次刷新卡牌消耗的银币数量 */
|
||||||
/** 单次刷新消耗的刷新石数量 */
|
SILVER_REFRESH_COST = 1,
|
||||||
REFRESH_STONE_COST = 1,
|
|
||||||
/** 全局默认闪避率(百分点),heroSet 未配置时生效 */
|
/** 全局默认闪避率(百分点),heroSet 未配置时生效 */
|
||||||
DEFAULT_DODGE = 15,
|
DEFAULT_DODGE = 15,
|
||||||
/** 全局默认命中率(百分点),heroSet 未配置时生效 */
|
/** 全局默认命中率(百分点),heroSet 未配置时生效 */
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ const { ccclass, property } = _decorator;
|
|||||||
const FAST_CLEAR_COIN = 2;
|
const FAST_CLEAR_COIN = 2;
|
||||||
/** 清屏奖励:极速清场(< 50% 时长) */
|
/** 清屏奖励:极速清场(< 50% 时长) */
|
||||||
const ULTRA_CLEAR_COIN = 5;
|
const ULTRA_CLEAR_COIN = 5;
|
||||||
|
/** 清屏奖励:全员存活(allAlive)额外金币 */
|
||||||
|
const ALL_ALIVE_COIN = 3;
|
||||||
/** 连杀分级金币爆发(tier 0/1/2 对应 5/10/20 连杀) */
|
/** 连杀分级金币爆发(tier 0/1/2 对应 5/10/20 连杀) */
|
||||||
const COMBO_COIN = [2, 5, 10];
|
const COMBO_COIN = [2, 5, 10];
|
||||||
|
|
||||||
@@ -58,7 +60,7 @@ export class BattleBannerComp extends CCComp {
|
|||||||
private onWaveClear(event: string, data: { wave: number; clearTime: number; allAlive: boolean; fastClear: number }) {
|
private onWaveClear(event: string, data: { wave: number; clearTime: number; allAlive: boolean; fastClear: number }) {
|
||||||
if (data.allAlive) {
|
if (data.allAlive) {
|
||||||
this.playBanner("Perfect!", new Color(255, 80, 80), 1.2);
|
this.playBanner("Perfect!", new Color(255, 80, 80), 1.2);
|
||||||
MissionEconomy.addRefreshStone(1);
|
MissionEconomy.addCoin(ALL_ALIVE_COIN);
|
||||||
oops.audio.playEffect("music/flash");
|
oops.audio.playEffect("music/flash");
|
||||||
} else if (data.fastClear === 2) {
|
} else if (data.fastClear === 2) {
|
||||||
this.playBanner("极速清场!", new Color(255, 170, 0), 1.15);
|
this.playBanner("极速清场!", new Color(255, 170, 0), 1.15);
|
||||||
|
|||||||
@@ -81,8 +81,6 @@ export class MissionCardComp extends CCComp {
|
|||||||
private readonly buttonPressScale: number = 0.94;
|
private readonly buttonPressScale: number = 0.94;
|
||||||
/** 按钮弹起缩放(峰值) */
|
/** 按钮弹起缩放(峰值) */
|
||||||
private readonly buttonClickScale: number = 1.06;
|
private readonly buttonClickScale: number = 1.06;
|
||||||
/** 抽卡(刷新)费用 */
|
|
||||||
refreshCost: number = FightSet.REFRESH_COST;
|
|
||||||
/** 卡牌面板展开/收起动画时长(秒) */
|
/** 卡牌面板展开/收起动画时长(秒) */
|
||||||
cardsPanelMoveDuration: number = 0.2;
|
cardsPanelMoveDuration: number = 0.2;
|
||||||
|
|
||||||
@@ -170,7 +168,7 @@ export class MissionCardComp extends CCComp {
|
|||||||
/** 英雄数量显示节点(含 icon + num 子节点) */
|
/** 英雄数量显示节点(含 icon + num 子节点) */
|
||||||
@property(Node)
|
@property(Node)
|
||||||
hero_num_node: Node = null!
|
hero_num_node: Node = null!
|
||||||
/** 刷新石数量显示节点(含 icon + num 子节点) */
|
/** 银币数量显示节点(含 icon + num 子节点) */
|
||||||
@property(Node)
|
@property(Node)
|
||||||
refresh_stone_num_node: Node = null!
|
refresh_stone_num_node: Node = null!
|
||||||
|
|
||||||
@@ -330,6 +328,7 @@ export class MissionCardComp extends CCComp {
|
|||||||
this.resetButtonScale(this.cards_refresh);
|
this.resetButtonScale(this.cards_refresh);
|
||||||
this.resetPanelOpenCosts();
|
this.resetPanelOpenCosts();
|
||||||
this.updateCoinAndCostUI();
|
this.updateCoinAndCostUI();
|
||||||
|
this.updateSilverNumUI();
|
||||||
this.updateHeroNumUI(false, false);
|
this.updateHeroNumUI(false, false);
|
||||||
if (this.node && this.node.isValid) {
|
if (this.node && this.node.isValid) {
|
||||||
this.node.active = true;
|
this.node.active = true;
|
||||||
@@ -416,7 +415,7 @@ export class MissionCardComp extends CCComp {
|
|||||||
this.on("PhasePrepareStart", this.onPhasePrepareStart, this);
|
this.on("PhasePrepareStart", this.onPhasePrepareStart, this);
|
||||||
|
|
||||||
oops.message.on(GameEvent.CoinAdd, this.onCoinAdd, this);
|
oops.message.on(GameEvent.CoinAdd, this.onCoinAdd, this);
|
||||||
oops.message.on(GameEvent.RefreshStone, this.onRefreshStone, this);
|
oops.message.on(GameEvent.SILVER_UPDATE, this.onSilverUpdate, this);
|
||||||
oops.message.on(GameEvent.MasterCalled, this.onMasterCalled, this);
|
oops.message.on(GameEvent.MasterCalled, this.onMasterCalled, this);
|
||||||
oops.message.on(GameEvent.HeroDead, this.onHeroDead, this);
|
oops.message.on(GameEvent.HeroDead, this.onHeroDead, this);
|
||||||
oops.message.on(GameEvent.HeroSell, this.onHeroSell, this);
|
oops.message.on(GameEvent.HeroSell, this.onHeroSell, this);
|
||||||
@@ -477,13 +476,14 @@ export class MissionCardComp extends CCComp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 刷新石数量变更:刷新刷新按钮状态/费用显示,并播放数量变化动画 */
|
/** 银币数量变更:刷新银币数值显示 + 刷新按钮状态/费用显示,并播放数量变化动画 */
|
||||||
private onRefreshStone(event: string, args: any) {
|
private onSilverUpdate(event: string, args: any) {
|
||||||
const payload = args ?? event;
|
const payload = args ?? event;
|
||||||
const v = typeof payload === 'number' ? payload : (payload?.delta ?? payload?.value ?? 0);
|
const v = typeof payload === 'number' ? payload : (payload?.delta ?? payload?.value ?? 0);
|
||||||
|
this.updateSilverNumUI();
|
||||||
this.updateDrawCostUI();
|
this.updateDrawCostUI();
|
||||||
if (v !== 0) {
|
if (v !== 0) {
|
||||||
this.playRefreshStoneChangeAnim(v > 0);
|
this.playSilverChangeAnim(v > 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -506,9 +506,10 @@ export class MissionCardComp extends CCComp {
|
|||||||
* 挂在 showHeros / showEquips / showSkills / showShop 按钮节点(按钮下需预置 smalltip 子节点)
|
* 挂在 showHeros / showEquips / showSkills / showShop 按钮节点(按钮下需预置 smalltip 子节点)
|
||||||
* @param text 可选:覆盖气泡文字(默认读 prefab 中配置的文本)
|
* @param text 可选:覆盖气泡文字(默认读 prefab 中配置的文本)
|
||||||
*/
|
*/
|
||||||
public showSmallTip(type: "refresh_coin" | "buy_coin" | "hero_full" | "panel_hero_full" | "panel_equip_full" | "panel_skill_full" | "panel_shop_full", text?: string) {
|
public showSmallTip(type: "refresh_silver" | "refresh_coin" | "buy_coin" | "hero_full" | "panel_hero_full" | "panel_equip_full" | "panel_skill_full" | "panel_shop_full", text?: string) {
|
||||||
let targetNode: Node | null = null;
|
let targetNode: Node | null = null;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
case "refresh_silver":
|
||||||
case "refresh_coin":
|
case "refresh_coin":
|
||||||
targetNode = this.cards_refresh;
|
targetNode = this.cards_refresh;
|
||||||
break;
|
break;
|
||||||
@@ -673,7 +674,7 @@ export class MissionCardComp extends CCComp {
|
|||||||
/** 解除按钮监听,避免节点销毁后回调泄漏 */
|
/** 解除按钮监听,避免节点销毁后回调泄漏 */
|
||||||
private unbindEvents() {
|
private unbindEvents() {
|
||||||
oops.message.off(GameEvent.CoinAdd, this.onCoinAdd, this);
|
oops.message.off(GameEvent.CoinAdd, this.onCoinAdd, this);
|
||||||
oops.message.off(GameEvent.RefreshStone, this.onRefreshStone, this);
|
oops.message.off(GameEvent.SILVER_UPDATE, this.onSilverUpdate, this);
|
||||||
oops.message.off(GameEvent.MasterCalled, this.onMasterCalled, this);
|
oops.message.off(GameEvent.MasterCalled, this.onMasterCalled, this);
|
||||||
oops.message.off(GameEvent.HeroDead, this.onHeroDead, this);
|
oops.message.off(GameEvent.HeroDead, this.onHeroDead, this);
|
||||||
oops.message.off(GameEvent.HeroSell, this.onHeroSell, this);
|
oops.message.off(GameEvent.HeroSell, this.onHeroSell, this);
|
||||||
@@ -1447,10 +1448,9 @@ export class MissionCardComp extends CCComp {
|
|||||||
this.playButtonResetAnim(this.skill_refresh);
|
this.playButtonResetAnim(this.skill_refresh);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 装备刷新:扣费后重新抽取 3 张装备展示 */
|
/** 装备刷新:扣银币后重新抽取 3 张装备展示 */
|
||||||
private onClickEquipRefresh() {
|
private onClickEquipRefresh() {
|
||||||
const cost = MissionEconomy.getRefreshCost(this.refreshCost);
|
const success = MissionEconomy.executeRefresh();
|
||||||
const success = MissionEconomy.executeRefresh(this.refreshCost);
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
this.showSmallTip("refresh_coin");
|
this.showSmallTip("refresh_coin");
|
||||||
return;
|
return;
|
||||||
@@ -1458,10 +1458,9 @@ export class MissionCardComp extends CCComp {
|
|||||||
this.populateEquipments();
|
this.populateEquipments();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 药品刷新:扣费后重新抽取 3 张商品展示 */
|
/** 药品刷新:扣银币后重新抽取 3 张商品展示 */
|
||||||
private onClickShopRefresh() {
|
private onClickShopRefresh() {
|
||||||
const cost = MissionEconomy.getRefreshCost(this.refreshCost);
|
const success = MissionEconomy.executeRefresh();
|
||||||
const success = MissionEconomy.executeRefresh(this.refreshCost);
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
this.showSmallTip("refresh_coin");
|
this.showSmallTip("refresh_coin");
|
||||||
return;
|
return;
|
||||||
@@ -1469,9 +1468,9 @@ export class MissionCardComp extends CCComp {
|
|||||||
this.populateShopItems();
|
this.populateShopItems();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 技能刷新:扣费后重新抽取 3 张技能卡展示 */
|
/** 技能刷新:扣银币后重新抽取 3 张技能卡展示 */
|
||||||
private onClickSkillRefresh() {
|
private onClickSkillRefresh() {
|
||||||
const success = MissionEconomy.executeRefresh(this.refreshCost);
|
const success = MissionEconomy.executeRefresh();
|
||||||
if (!success) {
|
if (!success) {
|
||||||
this.showSmallTip("refresh_coin");
|
this.showSmallTip("refresh_coin");
|
||||||
return;
|
return;
|
||||||
@@ -1568,18 +1567,18 @@ export class MissionCardComp extends CCComp {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 刷新卡池按钮核心逻辑:
|
* 刷新卡池按钮核心逻辑:
|
||||||
* 1. 检查金币/刷新石是否足够 → 不够则 toast 提示。
|
* 1. 检查银币是否足够 → 不够则 toast 提示。
|
||||||
* 2. 扣除费用、播放金币动画。
|
* 2. 扣除银币费用。
|
||||||
* 3. 重新布局槽位 → 从卡池构建 3 张卡 → 分发到槽位(三选一展示)。
|
* 3. 重新布局槽位 → 从卡池构建 3 张卡 → 分发到槽位(三选一展示)。
|
||||||
*/
|
*/
|
||||||
private onClickDraw() {
|
private onClickDraw() {
|
||||||
const cost = MissionEconomy.getRefreshCost(this.refreshCost);
|
const cost = MissionEconomy.getSilverRefreshCost();
|
||||||
const success = MissionEconomy.executeRefresh(this.refreshCost);
|
const success = MissionEconomy.executeRefresh();
|
||||||
if (!success) {
|
if (!success) {
|
||||||
this.showSmallTip("refresh_coin");
|
this.showSmallTip("refresh_silver", "银币不足");
|
||||||
this.updateCoinAndCostUI();
|
this.updateCoinAndCostUI();
|
||||||
mLogger.log(this.debugMode, "MissionCardComp", "draw coin not enough", {
|
mLogger.log(this.debugMode, "MissionCardComp", "draw silver not enough", {
|
||||||
currentCoin: MissionEconomy.getCoin(),
|
currentSilver: MissionEconomy.getSilver(),
|
||||||
cost
|
cost
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
@@ -1587,7 +1586,7 @@ export class MissionCardComp extends CCComp {
|
|||||||
|
|
||||||
mLogger.log(this.debugMode, "MissionCardComp", "click refresh", {
|
mLogger.log(this.debugMode, "MissionCardComp", "click refresh", {
|
||||||
cost,
|
cost,
|
||||||
leftCoin: MissionEconomy.getCoin()
|
leftSilver: MissionEconomy.getSilver()
|
||||||
});
|
});
|
||||||
this.layoutCardSlots();
|
this.layoutCardSlots();
|
||||||
const cards = this.buildDrawCards();
|
const cards = this.buildDrawCards();
|
||||||
@@ -1626,8 +1625,10 @@ export class MissionCardComp extends CCComp {
|
|||||||
}
|
}
|
||||||
// 开局三选一期满后永久隐藏 showHeros(战前限定,不随阶段恢复)
|
// 开局三选一期满后永久隐藏 showHeros(战前限定,不随阶段恢复)
|
||||||
this.updateShowHerosVisibility();
|
this.updateShowHerosVisibility();
|
||||||
// 刷新所有刷新按钮的费用显示(含刷新石/金币切换与置灰状态)
|
// 刷新所有刷新按钮的费用显示(含银币置灰状态)
|
||||||
this.updateDrawCostUI();
|
this.updateDrawCostUI();
|
||||||
|
// 同步银币数量显示(阶段切换时确保数值最新)
|
||||||
|
this.updateSilverNumUI();
|
||||||
// 显示卡牌面板(默认进入准备阶段时展开,缩放放大到 1,点亮按钮 active 高亮)
|
// 显示卡牌面板(默认进入准备阶段时展开,缩放放大到 1,点亮按钮 active 高亮)
|
||||||
if (this.cardPanNode && this.cardPanNode.isValid) {
|
if (this.cardPanNode && this.cardPanNode.isValid) {
|
||||||
this.showCardsPanel();
|
this.showCardsPanel();
|
||||||
@@ -1851,17 +1852,17 @@ export class MissionCardComp extends CCComp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private canDrawCards() {
|
private canDrawCards() {
|
||||||
// 有刷新石时可直接刷新,否则校验金币是否足够
|
// 银币足够时才可刷新
|
||||||
return MissionEconomy.canRefresh(this.refreshCost);
|
return MissionEconomy.canRefresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
private updateDrawCostUI() {
|
private updateDrawCostUI() {
|
||||||
const stones = MissionEconomy.getRefreshStone();
|
const silver = MissionEconomy.getSilver();
|
||||||
const stoneCost = MissionEconomy.getRefreshStoneCost();
|
const silverCost = MissionEconomy.getSilverRefreshCost();
|
||||||
this.updateOneRefreshBtnUI(this.cards_refresh, stones, stoneCost);
|
this.updateOneRefreshBtnUI(this.cards_refresh, silver, silverCost);
|
||||||
this.updateOneRefreshBtnUI(this.equip_refresh, stones, stoneCost);
|
this.updateOneRefreshBtnUI(this.equip_refresh, silver, silverCost);
|
||||||
this.updateOneRefreshBtnUI(this.shop_refresh, stones, stoneCost);
|
this.updateOneRefreshBtnUI(this.shop_refresh, silver, silverCost);
|
||||||
this.updateOneRefreshBtnUI(this.skill_refresh, stones, stoneCost);
|
this.updateOneRefreshBtnUI(this.skill_refresh, silver, silverCost);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1871,50 +1872,42 @@ export class MissionCardComp extends CCComp {
|
|||||||
* - 背景 :按钮底图
|
* - 背景 :按钮底图
|
||||||
* - nobg :置灰遮罩,不可刷新时激活
|
* - nobg :置灰遮罩,不可刷新时激活
|
||||||
* - Node/ :费用容器,下含 Label + coin + stone
|
* - Node/ :费用容器,下含 Label + coin + stone
|
||||||
* - coin/ :金币费用(含 num 子节点 Label),刷新石=0 时显示
|
* - coin/ :金币费用(含 num 子节点 Label),银币机制下隐藏
|
||||||
* - stone/ :刷新石费用(含 num 子节点 Label),刷新石>0 时显示
|
* - stone/ :银币数量(含 num 子节点 Label),显示当前持有银币数
|
||||||
*
|
*
|
||||||
* @param btnNode 刷新按钮节点
|
* @param btnNode 刷新按钮节点
|
||||||
* @param stones 当前刷新石数量(外部统一读取,避免 4 次重复访问)
|
* @param silver 当前银币数量(外部统一读取,避免 4 次重复访问)
|
||||||
* @param stoneCost 单次刷新消耗的刷新石数量
|
* @param silverCost 单次刷新消耗的银币数量(仅用于判断是否置灰)
|
||||||
*/
|
*/
|
||||||
private updateOneRefreshBtnUI(btnNode: Node | null, stones: number, stoneCost: number) {
|
private updateOneRefreshBtnUI(btnNode: Node | null, silver: number, silverCost: number) {
|
||||||
if (!btnNode || !btnNode.isValid) return;
|
if (!btnNode || !btnNode.isValid) return;
|
||||||
|
|
||||||
// 刷新石足够一次消耗时走刷新石通道,否则走金币通道
|
// 银币足够一次消耗时走银币通道
|
||||||
const useStone = stones >= stoneCost;
|
const useSilver = silver >= silverCost;
|
||||||
|
|
||||||
// 置灰遮罩:有刷新石必定可刷新,否则按金币判断
|
// 置灰遮罩:银币不足时置灰
|
||||||
const nobg = btnNode.getChildByName("nobg");
|
const nobg = btnNode.getChildByName("nobg");
|
||||||
if (nobg) {
|
if (nobg) {
|
||||||
nobg.active = useStone ? false : !this.canDrawCards();
|
nobg.active = !useSilver;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 费用容器:按钮下的 Node 子节点(统一结构:背景 + Node[Label/coin/stone])
|
// 费用容器:按钮下的 Node 子节点(统一结构:背景 + Node[Label/coin/stone])
|
||||||
const container = btnNode.getChildByName("Node");
|
const container = btnNode.getChildByName("Node");
|
||||||
if (!container) return;
|
if (!container) return;
|
||||||
|
|
||||||
// 金币费用节点
|
// 金币费用节点:银币机制下隐藏,不再显示金币费用
|
||||||
const coinNode = container.getChildByName("coin");
|
const coinNode = container.getChildByName("coin");
|
||||||
if (coinNode) {
|
if (coinNode) {
|
||||||
coinNode.active = !useStone;
|
coinNode.active = false;
|
||||||
if (!useStone) {
|
|
||||||
const numLabel = coinNode.getChildByName("num")?.getComponent(Label);
|
|
||||||
if (numLabel) {
|
|
||||||
numLabel.string = `${MissionEconomy.getRefreshCost(this.refreshCost)}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 刷新石费用节点(显示单次刷新消耗数量)
|
// 银币费用节点(复用 stone 子节点结构,显示当前持有银币数量)
|
||||||
const stoneNode = container.getChildByName("stone");
|
const stoneNode = container.getChildByName("stone");
|
||||||
if (stoneNode) {
|
if (stoneNode) {
|
||||||
stoneNode.active = useStone;
|
stoneNode.active = true;
|
||||||
if (useStone) {
|
const numLabel = stoneNode.getChildByName("num")?.getComponent(Label);
|
||||||
const numLabel = stoneNode.getChildByName("num")?.getComponent(Label);
|
if (numLabel) {
|
||||||
if (numLabel) {
|
numLabel.string = `${silver}`;
|
||||||
numLabel.string = `${stoneCost}`;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1930,6 +1923,17 @@ export class MissionCardComp extends CCComp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 刷新银币数量显示(refresh_stone_num_node 下的 num Label),未绑定或节点失效时静默跳过 */
|
||||||
|
private updateSilverNumUI() {
|
||||||
|
if (!this.refresh_stone_num_node || !this.refresh_stone_num_node.isValid) return;
|
||||||
|
const numNode = this.refresh_stone_num_node.getChildByName("num");
|
||||||
|
if (!numNode || !numNode.isValid) return;
|
||||||
|
const label = numNode.getComponent(Label);
|
||||||
|
if (label) {
|
||||||
|
label.string = `${MissionEconomy.getSilver()}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private playCoinChangeAnim(isIncrease: boolean) {
|
private playCoinChangeAnim(isIncrease: boolean) {
|
||||||
if (!this.coins_node || !this.coins_node.isValid) return;
|
if (!this.coins_node || !this.coins_node.isValid) return;
|
||||||
const icon = this.coins_node.getChildByName("icon");
|
const icon = this.coins_node.getChildByName("icon");
|
||||||
@@ -1941,8 +1945,8 @@ export class MissionCardComp extends CCComp {
|
|||||||
this.playHeroNumNodePop(num, peak);
|
this.playHeroNumNodePop(num, peak);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 刷新石计数变化动画(与金币一致的 icon+num 弹跳) */
|
/** 银币计数变化动画(与金币一致的 icon+num 弹跳) */
|
||||||
private playRefreshStoneChangeAnim(isIncrease: boolean) {
|
private playSilverChangeAnim(isIncrease: boolean) {
|
||||||
if (!this.refresh_stone_num_node || !this.refresh_stone_num_node.isValid) return;
|
if (!this.refresh_stone_num_node || !this.refresh_stone_num_node.isValid) return;
|
||||||
const peak = isIncrease ? 1.2 : 1.2;
|
const peak = isIncrease ? 1.2 : 1.2;
|
||||||
const icon = this.refresh_stone_num_node.getChildByName("icon");
|
const icon = this.refresh_stone_num_node.getChildByName("icon");
|
||||||
|
|||||||
@@ -830,9 +830,7 @@ export class MissionComp extends CCComp {
|
|||||||
smc.resetScores();
|
smc.resetScores();
|
||||||
|
|
||||||
smc.vmdata.mission_data.coin = Math.max(0, Math.floor(FightSet.INIT_COIN));
|
smc.vmdata.mission_data.coin = Math.max(0, Math.floor(FightSet.INIT_COIN));
|
||||||
// 初始化刷新石数量,并派发事件通知 UI 刷新(MissionStart 早于 data_init,需手动通知)
|
// 银币为局外持久货币,每局不重置,仅通过日常积攒,无需初始化
|
||||||
smc.vmdata.mission_data.refresh_stone = Math.max(0, Math.floor(FightSet.INIT_REFRESH_STONE));
|
|
||||||
oops.message.dispatchEvent(GameEvent.RefreshStone, { delta: FightSet.INIT_REFRESH_STONE });
|
|
||||||
// 【评分系统 - 效率分】记录初始获得的金币收入
|
// 【评分系统 - 效率分】记录初始获得的金币收入
|
||||||
smc.vmdata.scores.gold_earned += smc.vmdata.mission_data.coin;
|
smc.vmdata.scores.gold_earned += smc.vmdata.mission_data.coin;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,68 +39,45 @@ export class MissionEconomy {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** 获取当前银币数量(局外持久货币,刷新卡牌消耗) */
|
||||||
* 计算卡牌刷新费用
|
static getSilver(): number {
|
||||||
* @param baseCost 基础费用,默认为1
|
return Math.max(0, Math.floor(smc.vmdata.silver ?? 0));
|
||||||
*/
|
|
||||||
static getRefreshCost(baseCost: number = 1): number {
|
|
||||||
return Math.floor(Math.max(0, baseCost));
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 获取当前刷新石数量 */
|
|
||||||
static getRefreshStone(): number {
|
|
||||||
return Math.max(0, Math.floor(smc.vmdata.mission_data.refresh_stone ?? 0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 增加刷新石
|
* 增加银币
|
||||||
* @param amount 增加数量,<=0 时忽略
|
* @param amount 增加数量,<=0 时忽略
|
||||||
*/
|
*/
|
||||||
static addRefreshStone(amount: number) {
|
static addSilver(amount: number) {
|
||||||
if (amount <= 0) return;
|
if (amount <= 0) return;
|
||||||
amount = Math.floor(amount);
|
smc.updateSilver(Math.floor(amount));
|
||||||
smc.vmdata.mission_data.refresh_stone = this.getRefreshStone() + amount;
|
|
||||||
|
|
||||||
// 发送 UI 更新事件(复用 RefreshStone 事件通知刷新按钮状态刷新)
|
|
||||||
oops.message.dispatchEvent(GameEvent.RefreshStone, { delta: amount });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 单次刷新消耗的刷新石数量 */
|
/** 单次刷新消耗的银币数量 */
|
||||||
static getRefreshStoneCost(): number {
|
static getSilverRefreshCost(): number {
|
||||||
return Math.max(1, Math.floor(FightSet.REFRESH_STONE_COST));
|
return Math.max(1, Math.floor(FightSet.SILVER_REFRESH_COST));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 判断当前是否可以执行一次刷新(刷新石足够或金币足够)
|
* 判断当前是否可以执行一次刷新(银币足够)
|
||||||
*/
|
*/
|
||||||
static canRefresh(baseCost: number = 1): boolean {
|
static canRefresh(): boolean {
|
||||||
if (this.getRefreshStone() >= this.getRefreshStoneCost()) return true;
|
return this.getSilver() >= this.getSilverRefreshCost();
|
||||||
return this.getCoin() >= this.getRefreshCost(baseCost);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 执行刷新卡牌:
|
* 执行刷新卡牌:
|
||||||
* 1. 刷新石足够时优先扣除 REFRESH_STONE_COST 颗刷新石(不消耗金币)。
|
* 银币足够时扣除 SILVER_REFRESH_COST 枚银币,否则刷新失败。
|
||||||
* 2. 刷新石不足时扣除金币(含刷新优惠折扣)。
|
* Why: 英雄卡牌只能银币刷新,不能金币刷新,银币为局外持久货币,靠日常积攒。
|
||||||
*/
|
*/
|
||||||
static executeRefresh(baseCost: number = 1): boolean {
|
static executeRefresh(): boolean {
|
||||||
// 优先消耗刷新石
|
const cost = this.getSilverRefreshCost();
|
||||||
const stoneCost = this.getRefreshStoneCost();
|
const silver = this.getSilver();
|
||||||
const stones = this.getRefreshStone();
|
if (silver < cost) return false;
|
||||||
if (stones >= stoneCost) {
|
|
||||||
smc.vmdata.mission_data.refresh_stone = stones - stoneCost;
|
|
||||||
smc.vmdata.scores.refresh_count++;
|
|
||||||
oops.message.dispatchEvent(GameEvent.RefreshStone, { delta: -stoneCost });
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 刷新石不足 → 扣除金币
|
smc.updateSilver(-cost);
|
||||||
const cost = this.getRefreshCost(baseCost);
|
smc.vmdata.scores.refresh_count++;
|
||||||
const success = this.spendCoin(cost);
|
return true;
|
||||||
if (success) {
|
|
||||||
smc.vmdata.scores.refresh_count++;
|
|
||||||
}
|
|
||||||
return success;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user