feat: 添加段位和闯关奖励领取系统

1. 新增REWARD_CLAIMED游戏事件用于通知奖励领取完成
2. 新建RewardSet配置文件,定义段位和闯关奖励数据结构与具体配置
3. 在SingletonModuleComp中新增奖励领取相关逻辑:
   - 新增奖励领取状态存档字段
   - 实现可领取奖励查询、奖励领取、通关标记等方法
   - 新增统一的奖励发放工具方法
This commit is contained in:
pan
2026-09-11 17:08:55 +08:00
parent 6afb8af05e
commit 88ac1337a4
3 changed files with 219 additions and 0 deletions

View File

@@ -102,6 +102,8 @@ export enum GameEvent {
TALENT_UPDATE = "TALENT_UPDATE",
/** 关卡进度变更(payload 为空,UI 重新读取 smc.vmdata.stage_progress) */
STAGE_PROGRESS_UPDATE = "STAGE_PROGRESS_UPDATE",
/** 奖励领取完成(payload 为空,UI 刷新待领取列表/红点) */
REWARD_CLAIMED = "REWARD_CLAIMED",
/** 小节开始(payload: { chapter, stage, section },MissionMonComp 据此生成怪物) */
SectionStart = "SectionStart",
/** 小节结束(payload: { chapter, stage, section },玩家点击"下一节"后推进) */

View File

@@ -0,0 +1,76 @@
/**
* @file RewardSet.ts
* @description 段位奖励 + 闯关奖励配置(纯数据,无逻辑)
*
* 定位差异化:
* - 段位奖励(RANK_REWARDS):稀有向——钻石 + 英雄碎片,荣誉回报
* - 闯关奖励(STAGE_REWARDS):养成向——金币 + 天赋经验,进程回报(精英关/Boss 关加成)
*
* 领取模式:玩家点击领取(SMC.claimRankReward / claimStageReward),
* 状态持久化于 smc.data.reward_claimed,不领不丢、跨局保留。
*/
import { HeroInfo } from "./heroSet";
import { FacSet } from "./GameSet";
import { ScoreTier } from "./ScoreRankSet";
/** 奖励资源类型 */
export type RewardType = 'gold' | 'silver' | 'diamond' | 'talent_exp' | 'fragment';
/** 单条奖励 */
export interface RewardItem {
/** 资源类型 */
type: RewardType;
/** 数量 */
value: number;
/** 英雄碎片专用:指定英雄 uuid,缺省随机抽取 */
heroUuid?: number;
}
/**
* 段位首达奖励(每档一份,跨档可补领)
* 阈值与段位定义见 ScoreRankSet.ScoreRankList
*/
export const RANK_REWARDS: Record<ScoreTier, RewardItem[]> = {
[ScoreTier.BRONZE]: [{ type: 'diamond', value: 10 }],
[ScoreTier.SILVER]: [{ type: 'diamond', value: 20 }, { type: 'fragment', value: 3 }],
[ScoreTier.GOLD]: [{ type: 'diamond', value: 30 }, { type: 'fragment', value: 5 }],
[ScoreTier.PLATINUM]: [{ type: 'diamond', value: 50 }, { type: 'fragment', value: 8 }],
[ScoreTier.DIAMOND]: [{ type: 'diamond', value: 80 }, { type: 'fragment', value: 10 }],
[ScoreTier.MASTER]: [{ type: 'diamond', value: 120 }, { type: 'fragment', value: 15 }],
[ScoreTier.LEGEND]: [{ type: 'diamond', value: 200 }, { type: 'fragment', value: 20 }],
};
/**
* 闯关奖励(每大关首通一份,共 10 份)
* 养成向:金币 + 天赋经验;第 5 关(精英)/第 10 关(Boss)额外附赠银币
*/
export const STAGE_REWARDS: Record<number, RewardItem[]> = {
1: [{ type: 'gold', value: 200 }, { type: 'talent_exp', value: 20 }],
2: [{ type: 'gold', value: 300 }, { type: 'talent_exp', value: 30 }],
3: [{ type: 'gold', value: 400 }, { type: 'talent_exp', value: 40 }],
4: [{ type: 'gold', value: 500 }, { type: 'talent_exp', value: 50 }],
5: [{ type: 'gold', value: 700 }, { type: 'talent_exp', value: 70 }, { type: 'silver', value: 10 }],
6: [{ type: 'gold', value: 600 }, { type: 'talent_exp', value: 60 }],
7: [{ type: 'gold', value: 700 }, { type: 'talent_exp', value: 70 }],
8: [{ type: 'gold', value: 800 }, { type: 'talent_exp', value: 80 }],
9: [{ type: 'gold', value: 900 }, { type: 'talent_exp', value: 90 }],
10: [{ type: 'gold', value: 1500 }, { type: 'talent_exp', value: 150 }, { type: 'silver', value: 20 }],
};
/**
* 从全英雄池随机抽取 1 个英雄 uuid(排除指定集合,池空时兜底返回 0)
* @param exclude 需排除的 uuid 集合(可空)
* @returns 随机英雄 uuid;英雄池为空返回 0
*/
export function pickRandomHeroUuid(exclude?: Set<number>): number {
const excludeSet = exclude ?? new Set<number>();
// 仅英雄池参与抽取(HeroInfo 同时含怪物条目,碎片属英雄局外成长)
const all = Object.keys(HeroInfo)
.map(k => Number(k))
.filter(u => u > 0 && HeroInfo[u]?.fac === FacSet.HERO);
const candidates = all.filter(u => !excludeSet.has(u));
const pool = candidates.length > 0 ? candidates : all;
if (pool.length === 0) return 0;
return pool[Math.floor(Math.random() * pool.length)];
}