feat: 添加段位和闯关奖励领取系统
1. 新增REWARD_CLAIMED游戏事件用于通知奖励领取完成 2. 新建RewardSet配置文件,定义段位和闯关奖励数据结构与具体配置 3. 在SingletonModuleComp中新增奖励领取相关逻辑: - 新增奖励领取状态存档字段 - 实现可领取奖励查询、奖励领取、通关标记等方法 - 新增统一的奖励发放工具方法
This commit is contained in:
@@ -10,6 +10,8 @@ import { mLogger } from "./Logger";
|
||||
import { gameDataSync } from "./GameDataSync";
|
||||
import { HERO_UPGRADE_NEED_FRAGMENTS } from "./config/GameSet";
|
||||
import { TalentSet, TALENT_LEVEL_MAX, getTalentLevelExp, getTalentUpgradeCost, isTalentTierUnlocked } from "./config/TalentSet";
|
||||
import { ScoreRankList, ScoreTier, getRankByScore } from "./config/ScoreRankSet";
|
||||
import { RANK_REWARDS, STAGE_REWARDS, RewardItem, pickRandomHeroUuid } from "./config/RewardSet";
|
||||
|
||||
/**
|
||||
* 用远程数据覆盖本地数据(统一方法)
|
||||
@@ -52,6 +54,15 @@ export interface GameDate {
|
||||
stage: number,
|
||||
section: number,
|
||||
},
|
||||
/** 奖励领取状态:段位/闯关首达奖励的已领取标记(玩家点击领取) */
|
||||
reward_claimed?: {
|
||||
/** 已领取的段位(ScoreTier 值) */
|
||||
rank: string[],
|
||||
/** 已领取的大关号 */
|
||||
stage: number[],
|
||||
},
|
||||
/** 已通关大关的显式标记(覆盖存档停留场景,如第 10 关通关后进度停留 1-10-10) */
|
||||
passed_stages?: number[],
|
||||
}
|
||||
export interface CloudData {
|
||||
openid: string;
|
||||
@@ -157,6 +168,13 @@ export class SingletonModuleComp extends ecs.Comp {
|
||||
stage: 1,
|
||||
section: 1,
|
||||
},
|
||||
/** 奖励领取状态(玩家点击领取,跨局保留) */
|
||||
reward_claimed: {
|
||||
rank: [],
|
||||
stage: [],
|
||||
},
|
||||
/** 已通关大关的显式标记 */
|
||||
passed_stages: [],
|
||||
}
|
||||
|
||||
vmdata: any = {
|
||||
@@ -370,6 +388,129 @@ export class SingletonModuleComp extends ecs.Comp {
|
||||
}
|
||||
oops.message.dispatchEvent(GameEvent.STAGE_PROGRESS_UPDATE);
|
||||
}
|
||||
|
||||
// ==================== 奖励领取(段位 / 闯关) ====================
|
||||
|
||||
/** 查询当前已达、未领取的段位列表(升序;跨档时可连领多份) */
|
||||
public getClaimableRankRewards(): ScoreTier[] {
|
||||
const current = getRankByScore(this.data.score ?? 0);
|
||||
const curIdx = ScoreRankList.findIndex(r => r.tier === current.tier);
|
||||
const claimed = this.data.reward_claimed?.rank ?? [];
|
||||
const result: ScoreTier[] = [];
|
||||
// 段位只涨不跌:当前段位即历史最高,低位段位全部视为已达
|
||||
for (let i = 0; i <= curIdx; i++) {
|
||||
const tier = ScoreRankList[i].tier;
|
||||
if (!claimed.includes(tier)) {
|
||||
result.push(tier);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/** 查询已通关、未领取的大关号列表(升序) */
|
||||
public getClaimableStageRewards(): number[] {
|
||||
const claimed = this.data.reward_claimed?.stage ?? [];
|
||||
const result: number[] = [];
|
||||
for (const stage of Object.keys(STAGE_REWARDS).map(Number)) {
|
||||
if (!claimed.includes(stage) && this.isStagePassed(stage)) {
|
||||
result.push(stage);
|
||||
}
|
||||
}
|
||||
return result.sort((a, b) => a - b);
|
||||
}
|
||||
|
||||
/** 是否存在待领取奖励(UI 红点总开关) */
|
||||
public hasUnclaimedRewards(): boolean {
|
||||
return this.getClaimableRankRewards().length > 0
|
||||
|| this.getClaimableStageRewards().length > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 领取段位奖励(玩家点击触发)
|
||||
* @param tier 目标段位
|
||||
* @returns 实际发放的奖励列表;段位未达/已领取/配置缺失时返回 null
|
||||
*/
|
||||
public claimRankReward(tier: ScoreTier): RewardItem[] | null {
|
||||
if (!this.getClaimableRankRewards().includes(tier)) return null;
|
||||
const rewards = RANK_REWARDS[tier];
|
||||
if (!rewards || rewards.length === 0) return null;
|
||||
|
||||
this.grantRewardItems(rewards);
|
||||
if (!this.data.reward_claimed) this.data.reward_claimed = { rank: [], stage: [] };
|
||||
this.data.reward_claimed.rank.push(tier);
|
||||
gameDataSync.markDataDirty();
|
||||
oops.message.dispatchEvent(GameEvent.REWARD_CLAIMED);
|
||||
return rewards;
|
||||
}
|
||||
|
||||
/**
|
||||
* 领取闯关奖励(玩家点击触发)
|
||||
* @param stage 目标大关号(1~10)
|
||||
* @returns 实际发放的奖励列表;未通关/已领取/配置缺失时返回 null
|
||||
*/
|
||||
public claimStageReward(stage: number): RewardItem[] | null {
|
||||
if (!this.getClaimableStageRewards().includes(stage)) return null;
|
||||
const rewards = STAGE_REWARDS[stage];
|
||||
if (!rewards || rewards.length === 0) return null;
|
||||
|
||||
this.grantRewardItems(rewards);
|
||||
if (!this.data.reward_claimed) this.data.reward_claimed = { rank: [], stage: [] };
|
||||
this.data.reward_claimed.stage.push(stage);
|
||||
gameDataSync.markDataDirty();
|
||||
oops.message.dispatchEvent(GameEvent.REWARD_CLAIMED);
|
||||
return rewards;
|
||||
}
|
||||
|
||||
/**
|
||||
* 标记大关已通关(通关点调用,覆盖存档停留场景)
|
||||
* Why: 第 10 关通关后存档停留 1-10-10,无法从 stage_progress 推导已通状态,
|
||||
* 需在通关时显式写入。
|
||||
* @param stage 大关号
|
||||
*/
|
||||
public markStagePassed(stage: number): void {
|
||||
if (!this.data.passed_stages) this.data.passed_stages = [];
|
||||
if (!this.data.passed_stages.includes(stage)) {
|
||||
this.data.passed_stages.push(stage);
|
||||
gameDataSync.markDataDirty();
|
||||
}
|
||||
}
|
||||
|
||||
/** 判定大关是否已通关:显式标记优先,存档推进兜底(已进入后续关即已通关) */
|
||||
private isStagePassed(stage: number): boolean {
|
||||
if ((this.data.passed_stages ?? []).includes(stage)) return true;
|
||||
return (this.data.stage_progress?.stage ?? 1) > stage;
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一发放奖励条目(复用现有货币/成长入口,自动落 data 持久层并标脏)
|
||||
* @param items 奖励条目列表
|
||||
*/
|
||||
private grantRewardItems(items: RewardItem[]): void {
|
||||
for (const item of items) {
|
||||
switch (item.type) {
|
||||
case 'gold':
|
||||
if (item.value > 0) this.updateGold(item.value);
|
||||
break;
|
||||
case 'silver':
|
||||
if (item.value > 0) this.updateSilver(item.value);
|
||||
break;
|
||||
case 'diamond':
|
||||
if (item.value > 0) this.updateDiamond(item.value);
|
||||
break;
|
||||
case 'talent_exp':
|
||||
if (item.value > 0) this.addTalentExp(item.value);
|
||||
break;
|
||||
case 'fragment': {
|
||||
const uuid = item.heroUuid ?? pickRandomHeroUuid();
|
||||
if (item.value > 0 && uuid > 0) {
|
||||
this.addHeroFragments(uuid, item.value);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getGameDate() {
|
||||
let data: GameDate = {
|
||||
...this.data,
|
||||
|
||||
Reference in New Issue
Block a user