Release v0.1.7 2026-07-12
This commit is contained in:
+21
-9
@@ -8,7 +8,7 @@ import type { BossId } from "./game/types";
|
||||
import type { DifficultySlug } from "./game/progression/loot";
|
||||
import { useActionBindings } from "./game/useGameLoop";
|
||||
import { useAuthoritativeDualScreenSync, useForcedThorDisplays } from "./platform/useThorDualScreen";
|
||||
import { DUAL_SCREEN_LAUNCH_EVENT } from "./platform/dualScreenSync";
|
||||
import { DUAL_SCREEN_EXIT_EVENT, DUAL_SCREEN_LAUNCH_EVENT } from "./platform/dualScreenSync";
|
||||
|
||||
const TopScreen = lazy(() => import("./components/TopScreen").then((module) => ({ default: module.TopScreen })));
|
||||
const BottomScreen = lazy(() => import("./components/BottomScreen").then((module) => ({ default: module.BottomScreen })));
|
||||
@@ -33,6 +33,7 @@ export default function App() {
|
||||
const updateActiveHealerInventory = useFrontendStore((state) => state.updateActiveHealerInventory);
|
||||
const recordBossVictory = useFrontendStore((state) => state.recordBossVictory);
|
||||
const recordRoguelikeDefeat = useFrontendStore((state) => state.recordRoguelikeDefeat);
|
||||
const recordRogueTrialsEndlessDefeat = useFrontendStore((state) => state.recordRogueTrialsEndlessDefeat);
|
||||
const clearRecentRewards = useFrontendStore((state) => state.clearRecentRewards);
|
||||
const rewardedBossInstances = useRef(new Set<string>());
|
||||
const screenRef = useRef(screen);
|
||||
@@ -69,6 +70,11 @@ export default function App() {
|
||||
return () => window.removeEventListener(DUAL_SCREEN_LAUNCH_EVENT, onDualScreenLaunch);
|
||||
}, [launchGame]);
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener(DUAL_SCREEN_EXIT_EVENT, leaveGame);
|
||||
return () => window.removeEventListener(DUAL_SCREEN_EXIT_EVENT, leaveGame);
|
||||
}, [leaveGame]);
|
||||
|
||||
useActionBindings(screen === "game", leaveGame);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -79,8 +85,11 @@ export default function App() {
|
||||
useEffect(() => {
|
||||
return useGameStore.subscribe((state, previousState) => {
|
||||
const startedFreshEncounter = state.phase === "briefing" && previousState.phase !== "briefing"
|
||||
|| previousState.phase === "intermission" && state.phase === "combat";
|
||||
if (state.phase === "briefing" || previousState.phase === "intermission" && state.phase === "combat") {
|
||||
|| previousState.phase === "intermission" && state.phase === "combat"
|
||||
|| previousState.phase === "victory" && state.phase === "combat" && state.endlessMode;
|
||||
if (state.phase === "briefing"
|
||||
|| previousState.phase === "intermission" && state.phase === "combat"
|
||||
|| previousState.phase === "victory" && state.phase === "combat" && state.endlessMode) {
|
||||
rewardedBossInstances.current.clear();
|
||||
}
|
||||
if (startedFreshEncounter) clearRecentRewards();
|
||||
@@ -88,11 +97,14 @@ export default function App() {
|
||||
if (state.runMode === "roguelike" && state.phase === "defeat" && previousState.phase !== "defeat") {
|
||||
recordRoguelikeDefeat(state.round);
|
||||
}
|
||||
if (state.endlessMode && state.phase === "defeat" && previousState.phase !== "defeat") {
|
||||
recordRogueTrialsEndlessDefeat(state.endlessBossKills);
|
||||
}
|
||||
const bossCount = 1 + state.additionalBosses.length;
|
||||
if (state.boss.hp <= 0 && previousState.boss.hp > 0) {
|
||||
const primaryInstanceId = `boss-0-${state.boss.id}`;
|
||||
const primaryInstanceId = state.bossInstanceId;
|
||||
if (!rewardedBossInstances.current.has(primaryInstanceId)) {
|
||||
rewardedBossInstances.current.add(primaryInstanceId);
|
||||
if (!state.endlessMode) rewardedBossInstances.current.add(primaryInstanceId);
|
||||
const defeatedBefore = (state.round - 1) * bossCount;
|
||||
const rewardDifficulty = state.runMode !== "encounter" && defeatedBefore >= 5 ? "veteran" : state.difficultySlug;
|
||||
recordBossVictory(state.boss.id, rewardDifficulty);
|
||||
@@ -102,14 +114,14 @@ export default function App() {
|
||||
const entry = state.additionalBosses[index];
|
||||
const previous = previousState.additionalBosses[index];
|
||||
const justDefeated = entry.boss.hp <= 0 && (!previous || previous.instanceId !== entry.instanceId || previous.boss.hp > 0);
|
||||
if (!justDefeated || rewardedBossInstances.current.has(entry.instanceId)) continue;
|
||||
rewardedBossInstances.current.add(entry.instanceId);
|
||||
if (!justDefeated || !state.endlessMode && rewardedBossInstances.current.has(entry.instanceId)) continue;
|
||||
if (!state.endlessMode) rewardedBossInstances.current.add(entry.instanceId);
|
||||
const defeatedBefore = (state.round - 1) * bossCount + index + 1;
|
||||
const rewardDifficulty = state.runMode !== "encounter" && defeatedBefore >= 5 ? "veteran" : state.difficultySlug;
|
||||
recordBossVictory(entry.boss.id, rewardDifficulty);
|
||||
}
|
||||
});
|
||||
}, [clearRecentRewards, recordBossVictory, recordRoguelikeDefeat]);
|
||||
}, [clearRecentRewards, recordBossVictory, recordRoguelikeDefeat, recordRogueTrialsEndlessDefeat]);
|
||||
|
||||
return (
|
||||
<main className="app-shell">
|
||||
@@ -118,7 +130,7 @@ export default function App() {
|
||||
<p>Offline-first healer roguelike <i /> v{packageJson.version}</p>
|
||||
</header>
|
||||
{screen === "game"
|
||||
? <Suspense fallback={<GameLoadingScreen />}><DualDisplayFrame top={<TopScreen onExit={leaveGame} />} bottom={<BottomScreen />} /></Suspense>
|
||||
? <Suspense fallback={<GameLoadingScreen />}><DualDisplayFrame top={<TopScreen onExit={leaveGame} />} bottom={<BottomScreen onExit={leaveGame} />} /></Suspense>
|
||||
: <FrontEnd onLaunch={launchGame} />}
|
||||
</main>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user