import { touchCharacter } from "./accountRepository"; import { useShellStore } from "./shellStore"; import { registerGeneratedManastormStageAssets } from "../game/manastormAssetRegistry"; import { isGameMasterSession, resolvedBossAdminCatalog, } from "../game/manastormAdminConfig"; import { drawRandomGmReviewTarget, type GmReviewKind, type GmReviewTarget, } from "../game/gmContentReview"; import { useManastormAdminStore } from "../game/manastormAdminStore"; import { INSTALLED_MANASTORM_RUNTIME_CATALOG } from "../game/manastormInstalledCatalog"; import { installedManastormStageBinding } from "../game/manastormInstalledStages"; import { registerManastormStageBindingResolver } from "../game/manastormStagePopulation"; import { activateManastormStage, releaseActiveManastormStage } from "../game/manastormStageLoader"; import { manastormModeForCharacterLevel, setManastormCatalog } from "../game/manastorm"; import { createEmptyManastormProgress, manastormModeProgress } from "../game/manastormProgress"; import { manastormActiveSpellLoadoutModel } from "../game/manastormSpellLoadout"; import { useManastormStore } from "../game/manastormStore"; import { defaultPartyRoleForClass } from "../game/partyRoles"; import { useGameStore } from "../game/store"; import { activateDungeonSession } from "../game/dungeonSession"; import type { CharacterProfile } from "./types"; function activeGmCharacter(): CharacterProfile | null { const shell = useShellStore.getState(); if (!isGameMasterSession(shell.session) || !shell.selectedCharacterId) { useShellStore.setState({ notice: "Game Master access is required." }); return null; } const activeCharacter = touchCharacter(shell.session!.ownerId, shell.selectedCharacterId) ?? shell.characters.find((character) => character.id === shell.selectedCharacterId) ?? null; if (!activeCharacter) { useShellStore.setState({ notice: "Select a character before testing content." }); return null; } return activeCharacter; } function enterGmDungeonTest(target: Extract): boolean { const activeCharacter = activeGmCharacter(); if (!activeCharacter) return false; useManastormStore.getState().resetRun(); releaseActiveManastormStage(); if (!activateDungeonSession(target.dungeonId, undefined, { gmTestMode: true, gmReviewTarget: target, })) { useShellStore.setState({ notice: "That dungeon did not pass its offline runtime gate." }); return false; } useGameStore.getState().setCompanionOpen(false); useShellStore.setState({ phase: "game", activeCharacter, activeDungeonId: target.dungeonId, activeDungeonRole: defaultPartyRoleForClass(activeCharacter.classId), notice: "GM dungeon review", }); return true; } export function enterRandomGmReview(kind: GmReviewKind): boolean { const admin = useManastormAdminStore.getState(); if (admin.dirty || admin.saving) { useShellStore.setState({ notice: "Save or discard GM changes before testing another target." }); return false; } const previous = useGameStore.getState().activeGmReviewTarget; const target = drawRandomGmReviewTarget(kind, admin.config, previous); if (!target) { const label = kind === "dungeon" ? "dungeons" : kind === "boss" ? "bosses" : "Manastorm encounters"; useShellStore.setState({ notice: `All runnable ${label} have been marked Ready.` }); return false; } if (target.kind === "dungeon") return enterGmDungeonTest(target); return enterGmManastormTest(target.bossKey, target); } export function enterGmManastormTest(bossKey: string, reviewTarget: GmReviewTarget | null = null): boolean { const activeCharacter = activeGmCharacter(); if (!activeCharacter) return false; const adminConfig = useManastormAdminStore.getState().config; const entry = resolvedBossAdminCatalog(adminConfig).find((candidate) => candidate.key === bossKey); if (!entry || !entry.runnable || !entry.stage) { useShellStore.setState({ notice: entry?.validationIssues[0] ?? "That boss is not available for GM testing." }); return false; } registerGeneratedManastormStageAssets(); registerManastormStageBindingResolver(installedManastormStageBinding); const modeId = manastormModeForCharacterLevel(activeCharacter.level, INSTALLED_MANASTORM_RUNTIME_CATALOG); const { milestoneLevel: _milestoneLevel, ...stageWithoutMilestone } = entry.stage; const testStage = Object.freeze({ ...stageWithoutMilestone, modeIds: [modeId], stageKind: "standard" as const, unlockLevel: 1, chaoticLinkEnabled: adminConfig.global.chaoticLinkEnabled, }); const testCatalog = Object.freeze({ ...INSTALLED_MANASTORM_RUNTIME_CATALOG, stages: [testStage], fallbackPolicy: "none" as const, runtimeOptions: Object.freeze({ ...adminConfig.global }), }); setManastormCatalog(testCatalog); useManastormStore.getState().resetRun(); const progress = activeCharacter.manastormProgress ?? createEmptyManastormProgress(); const modeProgress = manastormModeProgress(progress, modeId); const spellLoadout = manastormActiveSpellLoadoutModel( activeCharacter.classId, activeCharacter.level, activeCharacter.talentRanks, ); let encounter; try { encounter = useManastormStore.getState().startRun({ partySize: 5, startingLevel: 1, unlockedThroughLevel: 1, modeId, activeSpellLoadout: { available: spellLoadout.options, selectedIds: progress.loadout, maxSelections: spellLoadout.maxSelections, provenance: spellLoadout.provenance, }, cacheMeter: modeProgress.cacheMeter, rewardCaches: modeProgress.rewardCaches, random: () => 0, }); } catch { useShellStore.setState({ notice: "The configured boss could not be prepared for testing." }); return false; } if (!activateManastormStage(encounter, undefined, false, true, reviewTarget).activated) { useManastormStore.getState().resetRun(); useShellStore.setState({ notice: "The configured dungeon or stage package is not loadable." }); return false; } useGameStore.getState().setCompanionOpen(false); useShellStore.setState({ phase: "game", activeCharacter, activeDungeonId: encounter.dungeonId, activeDungeonRole: defaultPartyRoleForClass(activeCharacter.classId), notice: `GM test: ${entry.name}`, }); return true; }