v0.8.1: 探险平衡 + 信标系统扩展(周挑战 + 信标链)
P1-a 探险 BOSS 胜率平衡 + 能量恢复(expedition.ts + config.ts + gameStore.ts + ExpeditionPanel.tsx): - combatWinRate: scale 8→4, floor 0.25→0.35(基础力10对BOSS胜率 25%→35-45%) - BOSS 难度 5-7→3-5(配合新公式基础胜率达 45-55%) - computeEnergyRegenInterval(state): 动态恢复间隔 - exp_2 解锁 -30%, exp_3 解锁 -20%, 探索力属性 -最高30% - 下限 12s(原固定 45s) - computeEnergyRegen 接受 intervalSec 参数 - gameStore tick 传入动态间隔 - config.ts: exp_2/exp_3 描述加'能量恢复 +30%/+20%' - ExpeditionPanel: 显示实际恢复速度 + '已加速'标记 P1-b 信标系统扩展(beacon.ts + BeaconPanel.tsx + gameStore.ts)[subagent 9-b]: - 周挑战: getWeekKey ISO 8601 + FNV-1a 种子确定性生成 - 难度强制 anomaly 60%/singular 40%, goal 日挑战×3-5倍 - 完整进度/领奖/排行榜推送(isWeekly标记) - 信标链: 4里程碑(3/7/14/30天) + grace续命机制(每链1次) - recordChainCompletion 核心断链/续命逻辑 - 奖励 50→680洞见递增 - BeaconPanel: 周挑战fuchsia主题 + 信标链amber→rose渐变里程碑节点 - gameStore: trackBeacon升级 + claimWeeklyBeacon/claimChainReward actions - VLM 8/10, lint零错误, 5场景bun测试全PASS
This commit is contained in:
+125
-14
@@ -39,6 +39,7 @@ import {
|
||||
computeExpeditionPower,
|
||||
computeExpeditionHp,
|
||||
computeEnergyRegen,
|
||||
computeEnergyRegenInterval,
|
||||
EXPEDITION_CONFIG,
|
||||
} from "@/lib/game/expedition";
|
||||
import { ACHIEVEMENTS, type Achievement } from "@/lib/game/achievements";
|
||||
@@ -61,10 +62,20 @@ import {
|
||||
} from "@/lib/game/chronicle";
|
||||
import {
|
||||
generateDailyChallenge,
|
||||
generateWeeklyChallenge,
|
||||
loadDailyProgress,
|
||||
loadWeeklyProgress,
|
||||
loadChainState,
|
||||
addBeaconProgress,
|
||||
addWeeklyProgress,
|
||||
recordChainCompletion,
|
||||
claimWeeklyReward,
|
||||
claimChainMilestone,
|
||||
getTodayKey,
|
||||
type BeaconDailyChallenge,
|
||||
type BeaconDailyProgress,
|
||||
type BeaconWeeklyChallenge,
|
||||
type BeaconWeeklyProgress,
|
||||
} from "@/lib/game/beacon";
|
||||
import { setPendingOfflineReport } from "@/lib/game/offlineReport";
|
||||
import {
|
||||
@@ -129,6 +140,19 @@ interface GameActions {
|
||||
// 深空信标奖励发放(v0.5)
|
||||
grantBeaconReward: (insights: number, contact: number) => void;
|
||||
|
||||
// 深空信标 · 周挑战领取 + 信标链里程碑领取(v0.8)
|
||||
claimWeeklyBeacon: () => {
|
||||
rewardInsight: number;
|
||||
rewardContact: number;
|
||||
score: number;
|
||||
};
|
||||
claimChainReward: (milestone: number) => {
|
||||
rewardInsight: number;
|
||||
rewardContact: number;
|
||||
label: string;
|
||||
ok: boolean;
|
||||
};
|
||||
|
||||
// 深空巡航奖励发放(v0.6 — 实时 Canvas 玩法)
|
||||
grantCruiseReward: (rewards: { crystals?: number; insights?: number; contact?: number }) => void;
|
||||
|
||||
@@ -165,25 +189,61 @@ function syncStats(state: Partial<GameState>) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 深空信标进度追踪(v0.5)。
|
||||
* 在游戏关键动作(脉冲/解码/探险/BOSS/洞见)后调用,按今日挑战类型增量更新进度。
|
||||
* 进度独立存储于 localStorage(echo-nexus-beacon-prog-v1),不污染 GameState。
|
||||
* @returns 若刚完成则返回 true(供 UI 触发通知)
|
||||
* 深空信标进度追踪(v0.5 → v0.8 扩展)。
|
||||
* 在游戏关键动作(脉冲/解码/探险/BOSS/洞见)后调用,同时更新:
|
||||
* 1. 日挑战进度(按今日挑战类型增量)
|
||||
* 2. 周挑战进度(按本周挑战类型增量)
|
||||
* 3. 信标链:日挑战刚完成时记录一次完成(含 grace 续命逻辑)
|
||||
* 进度独立存储于 localStorage,不污染 GameState。
|
||||
* @returns 三类状态变更供 UI 触发通知
|
||||
*/
|
||||
function trackBeacon(
|
||||
type: "pulse" | "decode" | "expedition" | "boss" | "insight",
|
||||
delta: number
|
||||
): boolean {
|
||||
if (typeof window === "undefined") return false;
|
||||
): {
|
||||
dailyJustCompleted: boolean;
|
||||
weeklyJustCompleted: boolean;
|
||||
newChainMilestones: number[];
|
||||
} {
|
||||
const result = {
|
||||
dailyJustCompleted: false,
|
||||
weeklyJustCompleted: false,
|
||||
newChainMilestones: [] as number[],
|
||||
};
|
||||
if (typeof window === "undefined") return result;
|
||||
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;
|
||||
if (challenge.type === type) {
|
||||
const current: BeaconDailyProgress = loadDailyProgress();
|
||||
if (current.completedAt === null) {
|
||||
const { justCompleted } = addBeaconProgress(current, challenge, delta);
|
||||
result.dailyJustCompleted = justCompleted;
|
||||
// 日挑战刚完成 → 更新信标链
|
||||
if (justCompleted) {
|
||||
const { newMilestones } = recordChainCompletion(getTodayKey());
|
||||
result.newChainMilestones = newMilestones;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---- 周挑战 ----
|
||||
const wChallenge: BeaconWeeklyChallenge = generateWeeklyChallenge();
|
||||
if (wChallenge.type === type) {
|
||||
const wCurrent: BeaconWeeklyProgress = loadWeeklyProgress();
|
||||
if (wCurrent.completedAt === null) {
|
||||
const { justCompleted } = addWeeklyProgress(
|
||||
wCurrent,
|
||||
wChallenge,
|
||||
delta
|
||||
);
|
||||
result.weeklyJustCompleted = justCompleted;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch {
|
||||
return false;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -403,11 +463,12 @@ export const useGameStore = create<Store>()(
|
||||
lastSpawn = now;
|
||||
}
|
||||
|
||||
// 能量恢复(探险系统)
|
||||
// 能量恢复(探险系统,v0.8.1 动态间隔)
|
||||
let energy = s.energy;
|
||||
let lastEnergyTick = s.lastEnergyTick;
|
||||
if (energy < s.energyMax) {
|
||||
const regen = computeEnergyRegen(lastEnergyTick, now, energy, s.energyMax);
|
||||
const intervalSec = computeEnergyRegenInterval(s);
|
||||
const regen = computeEnergyRegen(lastEnergyTick, now, energy, s.energyMax, intervalSec);
|
||||
energy = regen.energy;
|
||||
lastEnergyTick = regen.lastTick;
|
||||
} else {
|
||||
@@ -948,6 +1009,56 @@ export const useGameStore = create<Store>()(
|
||||
});
|
||||
},
|
||||
|
||||
// 深空信标:领取周挑战奖励(v0.8)
|
||||
claimWeeklyBeacon: () => {
|
||||
const challenge = generateWeeklyChallenge();
|
||||
const progress = loadWeeklyProgress();
|
||||
const res = claimWeeklyReward(challenge, progress);
|
||||
if (res.rewardInsight > 0 || res.rewardContact > 0) {
|
||||
const s = get();
|
||||
set({
|
||||
insights: s.insights + Math.round(res.rewardInsight),
|
||||
contact: Math.min(100, s.contact + res.rewardContact),
|
||||
});
|
||||
}
|
||||
return {
|
||||
rewardInsight: res.rewardInsight,
|
||||
rewardContact: res.rewardContact,
|
||||
score: res.score,
|
||||
};
|
||||
},
|
||||
|
||||
// 深空信标:领取信标链里程碑奖励(v0.8)
|
||||
claimChainReward: (milestone) => {
|
||||
// loadChainState 仅用于前置校验,真正的状态修改由 claimChainMilestone 完成
|
||||
const pre = loadChainState();
|
||||
if (
|
||||
pre.currentStreak < milestone ||
|
||||
pre.milestonesClaimed.includes(milestone)
|
||||
) {
|
||||
return {
|
||||
rewardInsight: 0,
|
||||
rewardContact: 0,
|
||||
label: "",
|
||||
ok: false,
|
||||
};
|
||||
}
|
||||
const res = claimChainMilestone(milestone);
|
||||
if (res.rewardInsight > 0 || res.rewardContact > 0) {
|
||||
const s = get();
|
||||
set({
|
||||
insights: s.insights + Math.round(res.rewardInsight),
|
||||
contact: Math.min(100, s.contact + res.rewardContact),
|
||||
});
|
||||
}
|
||||
return {
|
||||
rewardInsight: res.rewardInsight,
|
||||
rewardContact: res.rewardContact,
|
||||
label: res.label,
|
||||
ok: res.rewardInsight > 0 || res.rewardContact > 0,
|
||||
};
|
||||
},
|
||||
|
||||
// 深空巡航:发放实时玩法奖励(v0.6)
|
||||
grantCruiseReward: (rewards) => {
|
||||
const s = get();
|
||||
|
||||
Reference in New Issue
Block a user