import { useFrame } from "@react-three/fiber"; import { useRef, useSyncExternalStore } from "react"; import type { Group } from "three"; import { BITE_SIZED_WAILING_CAVERNS_DUNGEON_ID } from "../game/dungeonContentSource"; import { dispatchDungeonEncounterSignal, dungeonEncounterSnapshot, subscribeDungeonEncounterSnapshots, } from "../game/dungeonEncounterRuntime"; import { useGameStore } from "../game/store"; import { useWailingEncounterStore, wailingDisciplePosition, type WailingEncounterPhase, } from "../game/wailingCavernsEncounter"; import { WorldNpcPrompt } from "./WorldNpcPrompt"; import { dungeonSimulationNow } from "../game/dungeonSimulationStore"; export function WailingNaralexEvent() { const activeDungeonId = useGameStore((state) => state.activeDungeonId); const gameMode = useGameStore((state) => state.gameMode); const sourcePhase = useWailingEncounterStore((state) => state.phase); const sourcePhaseStartedAt = useWailingEncounterStore((state) => state.phaseStartedAt); const biteEncounterId = `${BITE_SIZED_WAILING_CAVERNS_DUNGEON_ID}:naralex-escort`; useSyncExternalStore( subscribeDungeonEncounterSnapshots, () => dungeonEncounterSnapshot(biteEncounterId)?.revision ?? 0, () => 0, ); const biteSnapshot = dungeonEncounterSnapshot(biteEncounterId); const phase = activeDungeonId === BITE_SIZED_WAILING_CAVERNS_DUNGEON_ID ? biteSnapshot?.phase ?? "ready" : sourcePhase; const phaseStartedAt = activeDungeonId === BITE_SIZED_WAILING_CAVERNS_DUNGEON_ID ? biteSnapshot?.phaseStartedAt ?? 0 : sourcePhaseStartedAt; const isBiteSized = activeDungeonId === BITE_SIZED_WAILING_CAVERNS_DUNGEON_ID; const groupRef = useRef(null); useFrame(() => { if ( (activeDungeonId !== "wailing-caverns" && !isBiteSized) || gameMode !== "dungeon" ) return; const liveSnapshot = isBiteSized ? dungeonEncounterSnapshot(biteEncounterId) : null; const now = dungeonSimulationNow(); const position = wailingDisciplePosition( (liveSnapshot?.phase ?? useWailingEncounterStore.getState().phase) as Parameters[0], liveSnapshot?.phaseStartedAt ?? useWailingEncounterStore.getState().phaseStartedAt, now, ); groupRef.current?.position.set(...position); }); if ( (activeDungeonId !== "wailing-caverns" && !isBiteSized) || gameMode !== "dungeon" ) return null; const initialPosition = wailingDisciplePosition(phase as WailingEncounterPhase, phaseStartedAt); return (
Disciple of Naralex {phase === "locked" ? Defeat the four Fanglords : null} {phase === "ready" ? ( ) : null} {phase === "cleansing" ? Channeling Serpentine Cleansing… : null} {phase === "complete" ? {isBiteSized ? "Naralex has been rescued" : "Naralex has awakened"} : null}
); }