Files
healer-man/src/game/DungeonEncounterEffectBridge.tsx
T
2026-09-16 14:30:58 -04:00

71 lines
2.8 KiB
TypeScript

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.`);
}
}