import { useEffect } from "react"; import { useShellStore } from "../app/shellStore"; import { dispatchDungeonEncounterSignal, registerDungeonEncounterEffectHandler, } from "./dungeonEncounterRuntime"; import { LOOT_CATALOG, rollBossLoot } from "./lootCatalog"; import { updatePartyRuntimePosition } from "./partyRuntimeRegistry"; import { usePartyStore } from "./partyStore"; import { useCombatStore } from "./combatStore"; import { useGameStore } from "./store"; import type { DungeonEncounterEffectEnvelope } from "./dungeonEncounterTypes"; import { publishOnlinePartyTeleport } from "./onlineSessionRuntime"; import { dungeonDefinitionById } from "./dungeonRegistry"; import { removeMobPosition } from "./mobRuntimeRegistry"; import { dungeonSimulationNow } from "./dungeonSimulationStore"; function grantEncounterLoot(lootTableId: string, now: number): boolean { const table = LOOT_CATALOG.bosses.find((candidate) => candidate.lootTableId === lootTableId); if (!table) return false; const combat = useCombatStore.getState(); const drops = rollBossLoot(table.bossKey, combat.level, { now }); if (!drops.length) return true; const inventory = [...combat.inventory, ...drops]; useCombatStore.setState({ inventory }); useShellStore.getState().saveActiveInventory(inventory); return true; } /** Applies platform effects emitted by the renderer-neutral encounter reducer. */ export function DungeonEncounterEffectBridge() { useEffect(() => registerDungeonEncounterEffectHandler((envelope) => { applyDungeonEncounterEffect(envelope, dungeonSimulationNow()); }), []); return null; } export function applyDungeonEncounterEffect( { dungeonId, effect }: DungeonEncounterEffectEnvelope, now = dungeonSimulationNow(), ): void { if (effect.kind === "signal") { dispatchDungeonEncounterSignal(effect.signalId, now); return; } if (effect.kind === "party-teleport") { const game = useGameStore.getState(); game.relocatePlayer({ footPosition: effect.destination, yaw: game.cameraYaw }, true); for (const member of usePartyStore.getState().members) { updatePartyRuntimePosition(member.id, ...effect.destination); } publishOnlinePartyTeleport(effect.destination, effect.actionId, now); return; } if (effect.kind === "despawn-group") { const group = dungeonDefinitionById(dungeonId)?.encounterSpawnGroups?.find( (candidate) => candidate.id === effect.spawnGroupId, ); if (!group) return; const combat = useCombatStore.getState(); for (const spawn of group.spawns) { combat.removeMob(spawn.id); removeMobPosition(spawn.id); } return; } if (effect.kind === "loot-grant" && !grantEncounterLoot(effect.lootTableId, now)) { useShellStore.getState().setNotice(`Loot table ${effect.lootTableId} is not packaged for this encounter.`); } }