v0.5: 深空信标系统 + 编年史历史 BUG 修复
新功能:深空信标(Deep Space Beacon) - 每日挑战:UTC 日期种子确定性生成,5 种类型 × 3 档难度 - 本地排行榜 Top 20,奖牌图标 + 难度色点 + 今日高亮 - 进度追踪独立 localStorage,不污染 GameState - 倒计时 + 领取奖励发放到游戏状态 BUG 修复:编年史历史条目显示原始 tide 键名 - 新增 regenerateLoreFromEntry(),显示时重新生成 lore - 修复 v0.4 之前条目 lore 中 tide_ruins 等原始键名 UI:第 7 标签页「信标」+ 统计面板「信标最高分」行 版本号 v0.4 → v0.5 详见 docs/10-深空信标系统-v0.5.md
This commit is contained in:
@@ -59,6 +59,13 @@ import {
|
||||
migrateChronicleFields,
|
||||
withPerks,
|
||||
} from "@/lib/game/chronicle";
|
||||
import {
|
||||
generateDailyChallenge,
|
||||
loadDailyProgress,
|
||||
addBeaconProgress,
|
||||
type BeaconDailyChallenge,
|
||||
type BeaconDailyProgress,
|
||||
} from "@/lib/game/beacon";
|
||||
|
||||
interface GameActions {
|
||||
// 生命周期
|
||||
@@ -107,6 +114,9 @@ interface GameActions {
|
||||
toggleTheme: () => void;
|
||||
toggleSound: () => void;
|
||||
|
||||
// 深空信标奖励发放(v0.5)
|
||||
grantBeaconReward: (insights: number, contact: number) => void;
|
||||
|
||||
// 派生
|
||||
canPrestige: () => boolean;
|
||||
}
|
||||
@@ -135,6 +145,29 @@ function syncStats(state: Partial<GameState>) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 深空信标进度追踪(v0.5)。
|
||||
* 在游戏关键动作(脉冲/解码/探险/BOSS/洞见)后调用,按今日挑战类型增量更新进度。
|
||||
* 进度独立存储于 localStorage(echo-nexus-beacon-prog-v1),不污染 GameState。
|
||||
* @returns 若刚完成则返回 true(供 UI 触发通知)
|
||||
*/
|
||||
function trackBeacon(
|
||||
type: "pulse" | "decode" | "expedition" | "boss" | "insight",
|
||||
delta: number
|
||||
): boolean {
|
||||
if (typeof window === "undefined") return false;
|
||||
try {
|
||||
const challenge: BeaconDailyChallenge = generateDailyChallenge();
|
||||
if (challenge.type !== type) return false;
|
||||
const current: BeaconDailyProgress = loadDailyProgress();
|
||||
if (current.completedAt !== null) return false; // 已完成不再累加
|
||||
const { justCompleted } = addBeaconProgress(current, challenge, delta);
|
||||
return justCompleted;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/** 检查并解锁叙事碎片 */
|
||||
function checkFragments(state: GameState): string[] {
|
||||
const unlocked: string[] = [];
|
||||
@@ -367,6 +400,8 @@ export const useGameStore = create<Store>()(
|
||||
_combo: combo,
|
||||
_lastPulse: now,
|
||||
});
|
||||
// 深空信标:脉冲任务进度 +1
|
||||
trackBeacon("pulse", 1);
|
||||
return { gain, combo };
|
||||
},
|
||||
|
||||
@@ -414,6 +449,9 @@ export const useGameStore = create<Store>()(
|
||||
totalDecoded: newTotal,
|
||||
fragments: tentative.fragments,
|
||||
});
|
||||
// 深空信标:解码 +1,洞见累计
|
||||
trackBeacon("decode", 1);
|
||||
trackBeacon("insight", rewards.insights);
|
||||
return { ok: true, finished: true, failReason: unlocked.join(",") || undefined };
|
||||
}
|
||||
// 点击成功但未完成:检测当前局面是否仍可解
|
||||
@@ -490,6 +528,9 @@ export const useGameStore = create<Store>()(
|
||||
fragments: tentative.fragments,
|
||||
_lastAutoDecode: now,
|
||||
});
|
||||
// 深空信标:自动解码也算进度
|
||||
trackBeacon("decode", 1);
|
||||
trackBeacon("insight", rewards.insights);
|
||||
},
|
||||
|
||||
buyTech: (techId) => {
|
||||
@@ -590,6 +631,14 @@ export const useGameStore = create<Store>()(
|
||||
expeditionLog: newLog,
|
||||
bossKills,
|
||||
});
|
||||
// 深空信标:探险完成(胜负都计)+ 洞见累计 + BOSS 击破
|
||||
if (result.ended) {
|
||||
trackBeacon("expedition", 1);
|
||||
if (result.endReason === "victory" && exp.nodes[exp.currentNode]?.type === "boss") {
|
||||
trackBeacon("boss", 1);
|
||||
}
|
||||
}
|
||||
if (result.insights) trackBeacon("insight", result.insights);
|
||||
return result;
|
||||
},
|
||||
|
||||
@@ -723,6 +772,15 @@ export const useGameStore = create<Store>()(
|
||||
|
||||
toggleTheme: () => set({ theme: get().theme === "dark" ? "light" : "dark" }),
|
||||
toggleSound: () => set({ soundOn: !get().soundOn }),
|
||||
|
||||
// 深空信标:发放每日挑战奖励(v0.5)
|
||||
grantBeaconReward: (insights, contact) => {
|
||||
const s = get();
|
||||
set({
|
||||
insights: s.insights + Math.round(insights),
|
||||
contact: Math.min(100, s.contact + contact),
|
||||
});
|
||||
},
|
||||
}),
|
||||
{
|
||||
name: "echo-nexus-save-v1",
|
||||
|
||||
Reference in New Issue
Block a user