Files
healer-man/src/app/dungeonShellRuntime.ts
T
2026-09-26 17:51:56 -04:00

89 lines
3.8 KiB
TypeScript

import { dungeonById } from "../game/dungeonCatalog";
import { activateDungeonSession } from "../game/dungeonSession";
import { useGameStore } from "../game/store";
import {
classCanFillPartyRole,
defaultPartyRoleForClass,
PARTY_ROLE_LABELS,
type PartyRole,
} from "../game/partyRoles";
import { useShellStore } from "./shellStore";
import { registerDungeonShellRuntime, type DungeonEntrySettings } from "./dungeonShellRuntimeBridge";
import { touchCharacter } from "./accountRepository";
import { specializationById } from "../game/specializationCatalog";
import { dungeonContentIsUsable } from "../content/contentManager";
export function installDungeonShellRuntime(): void {
registerDungeonShellRuntime({ enterDungeon });
}
function enterDungeon(dungeonId: string, requestedRole?: PartyRole, settings?: DungeonEntrySettings): boolean {
const dungeon = dungeonById(dungeonId);
if (!dungeon || !dungeon.available) {
useShellStore.setState({ notice: "That dungeon is not available yet." });
return false;
}
if (!dungeonContentIsUsable(dungeonId)) {
useShellStore.setState({ notice: "Install this expedition from Downloads before entering." });
return false;
}
const { session, selectedCharacterId, characters } = useShellStore.getState();
if (!session || !selectedCharacterId) {
useShellStore.setState({ notice: "Select or create a character first." });
return false;
}
const activeCharacter = touchCharacter(session.ownerId, selectedCharacterId)
?? characters.find((character) => character.id === selectedCharacterId)
?? null;
if (!activeCharacter) {
useShellStore.setState({ notice: "That character is no longer available." });
return false;
}
const savedSpecialization = specializationById(activeCharacter.specializationId);
if (activeCharacter.categoryId !== "rom" && !savedSpecialization) {
useShellStore.setState({ phase: "class-hall", notice: "Choose a specialization before entering activities." });
return false;
}
const playerRole = savedSpecialization?.role ?? requestedRole ?? defaultPartyRoleForClass(activeCharacter.classId);
if (savedSpecialization && requestedRole && requestedRole !== savedSpecialization.role) {
useShellStore.setState({ notice: `${savedSpecialization.displayName} is locked to ${PARTY_ROLE_LABELS[savedSpecialization.role]}.` });
return false;
}
if (!classCanFillPartyRole(activeCharacter.classId, playerRole)) {
useShellStore.setState({
notice: `${activeCharacter.name}'s class cannot enter as ${PARTY_ROLE_LABELS[playerRole]}.`,
});
return false;
}
const checkpoint = activeCharacter.dungeonRunCheckpoint;
const resume = !settings?.freshRun && checkpoint?.dungeonId === dungeonId
&& checkpoint.run?.finishedAt == null
&& (settings?.difficultyId === undefined || checkpoint.difficultyId === settings.difficultyId)
&& (settings?.bossDifficulty === undefined || checkpoint.run?.bossDifficulty === settings.bossDifficulty)
? activeCharacter.dungeonRunCheckpoint
: null;
if (!activateDungeonSession(dungeonId, settings?.difficultyId ?? resume?.difficultyId, {
bossDifficulty: settings?.bossDifficulty ?? resume?.run?.bossDifficulty,
spawn: resume?.spawn,
encounterSnapshots: resume?.encounters,
runProgress: resume?.run,
legacyResume: Boolean(resume && resume.run?.bossDifficulty === undefined),
runId: settings?.runId,
})) {
useShellStore.setState({
notice: dungeon.availabilityReason ?? "That dungeon failed its latest validation gate.",
});
return false;
}
if (settings?.raceStartBlocked) useGameStore.setState({ raceStartBlocked: true });
useGameStore.getState().setCompanionOpen(false);
useShellStore.setState({
phase: "game",
activeCharacter,
activeDungeonId: dungeon.id,
activeDungeonRole: playerRole,
notice: "",
});
return true;
}