Release Healer Man 0.1.46
This commit is contained in:
1 parent
f82daf1c13
commit
9ff574ac0b
73 files changed
+33486
-174
No files matched your search
@@ -0,0 +1,143 @@
|
||||
import { dispatchDungeonWorldObjectInteraction } from "./dungeonWorldInteraction";
|
||||
import { requireDungeonDefinition } from "./dungeonRegistry";
|
||||
import { useDungeonRouteStore } from "./dungeonRouteStore";
|
||||
import {
|
||||
dungeonRouteDefinition,
|
||||
dungeonRouteLeg,
|
||||
} from "./dungeonRoutes";
|
||||
import { useDungeonSimulationStore } from "./dungeonSimulationStore";
|
||||
import type { DungeonRouteDefinitionV1, DungeonRouteLeg } from "./dungeonSimulationTypes";
|
||||
import type { Vector3Tuple } from "./dungeonTypes";
|
||||
|
||||
export interface ActiveDungeonRouteTarget {
|
||||
readonly route: DungeonRouteDefinitionV1;
|
||||
readonly leg: DungeonRouteLeg;
|
||||
readonly checkpointIndex: number;
|
||||
readonly target: Vector3Tuple;
|
||||
readonly remaining: readonly Vector3Tuple[];
|
||||
}
|
||||
|
||||
let activeDungeonId: string | null = null;
|
||||
let activeObjectiveId: string | null = null;
|
||||
let checkpointIndex = 0;
|
||||
const completedActions = new Set<string>();
|
||||
|
||||
function distance(left: Vector3Tuple, right: Vector3Tuple): number {
|
||||
return Math.hypot(right[0] - left[0], right[1] - left[1], right[2] - left[2]);
|
||||
}
|
||||
|
||||
export function resetDungeonRouteRuntime(): void {
|
||||
activeDungeonId = null;
|
||||
activeObjectiveId = null;
|
||||
checkpointIndex = 0;
|
||||
completedActions.clear();
|
||||
}
|
||||
|
||||
export function routeForActiveDungeon(dungeonId: string): DungeonRouteDefinitionV1 | null {
|
||||
const route = dungeonRouteDefinition(dungeonId);
|
||||
if (!route) return null;
|
||||
const simulation = useDungeonSimulationStore.getState();
|
||||
if (simulation.sessionMode === "spectate-live") return route;
|
||||
return useDungeonRouteStore.getState().isApproved(route) ? route : null;
|
||||
}
|
||||
|
||||
function executeReachedActions(
|
||||
dungeonId: string,
|
||||
leg: DungeonRouteLeg,
|
||||
reachedIndex: number,
|
||||
actorId: string | undefined,
|
||||
now: number,
|
||||
): void {
|
||||
const definition = requireDungeonDefinition(dungeonId);
|
||||
for (const action of leg.actions) {
|
||||
if (action.checkpointIndex > reachedIndex || completedActions.has(action.id)) continue;
|
||||
const object = definition.serverGameObjects.find((candidate) => candidate.id === action.objectId);
|
||||
if (!object?.interaction) {
|
||||
useDungeonSimulationStore.getState().addFinding({
|
||||
id: `invalid-action:${leg.id}:${action.id}`,
|
||||
atMs: useDungeonSimulationStore.getState().elapsedMs,
|
||||
severity: "critical",
|
||||
code: "invalid-required-interaction",
|
||||
message: `Route action ${action.id} references unavailable object ${action.objectId}.`,
|
||||
objectiveId: leg.objectiveId,
|
||||
checkpointIndex: action.checkpointIndex,
|
||||
});
|
||||
completedActions.add(action.id);
|
||||
continue;
|
||||
}
|
||||
dispatchDungeonWorldObjectInteraction(object, actorId, now);
|
||||
if (useDungeonSimulationStore.getState().sessionMode === "spectate-live") {
|
||||
useDungeonSimulationStore.getState().addFinding({
|
||||
id: `route-action:${leg.id}:${action.id}`,
|
||||
atMs: useDungeonSimulationStore.getState().elapsedMs,
|
||||
severity: "info",
|
||||
code: "route-action",
|
||||
message: `Performed required route action ${action.id}.`,
|
||||
objectiveId: leg.objectiveId,
|
||||
checkpointIndex: action.checkpointIndex,
|
||||
actionId: action.id,
|
||||
});
|
||||
}
|
||||
completedActions.add(action.id);
|
||||
}
|
||||
}
|
||||
|
||||
function advanceNavigationOnlyObjective(route: DungeonRouteDefinitionV1, leg: DungeonRouteLeg): void {
|
||||
const simulation = useDungeonSimulationStore.getState();
|
||||
if (simulation.sessionMode !== "spectate-live" || simulation.mode !== "navigation-only") return;
|
||||
const index = route.legs.findIndex((candidate) => candidate.id === leg.id);
|
||||
const next = route.legs[index + 1] ?? null;
|
||||
simulation.setRouteProgress(next?.objectiveId ?? null, 0);
|
||||
activeObjectiveId = next?.objectiveId ?? null;
|
||||
checkpointIndex = 0;
|
||||
}
|
||||
|
||||
export function activeDungeonRouteTarget(
|
||||
dungeonId: string,
|
||||
objectiveId: string | null,
|
||||
position: Vector3Tuple,
|
||||
actorId: string | undefined,
|
||||
now: number,
|
||||
): ActiveDungeonRouteTarget | null {
|
||||
const route = routeForActiveDungeon(dungeonId);
|
||||
const simulation = useDungeonSimulationStore.getState();
|
||||
const routedObjectiveId = simulation.sessionMode === "spectate-live" && simulation.mode === "navigation-only"
|
||||
? simulation.objectiveId
|
||||
: objectiveId;
|
||||
const leg = dungeonRouteLeg(route, routedObjectiveId);
|
||||
if (!route || !leg || !leg.checkpoints.length) return null;
|
||||
if (activeDungeonId !== dungeonId || activeObjectiveId !== leg.objectiveId) {
|
||||
activeDungeonId = dungeonId;
|
||||
activeObjectiveId = leg.objectiveId;
|
||||
checkpointIndex = 0;
|
||||
}
|
||||
while (
|
||||
checkpointIndex < leg.checkpoints.length
|
||||
&& distance(position, leg.checkpoints[checkpointIndex]) <= 1.25
|
||||
) {
|
||||
executeReachedActions(dungeonId, leg, checkpointIndex, actorId, now);
|
||||
checkpointIndex += 1;
|
||||
}
|
||||
if (checkpointIndex >= leg.checkpoints.length) {
|
||||
advanceNavigationOnlyObjective(route, leg);
|
||||
return null;
|
||||
}
|
||||
if (simulation.sessionMode === "spectate-live") {
|
||||
simulation.setRouteProgress(leg.objectiveId, checkpointIndex);
|
||||
}
|
||||
return {
|
||||
route,
|
||||
leg,
|
||||
checkpointIndex,
|
||||
target: leg.checkpoints[checkpointIndex],
|
||||
remaining: leg.checkpoints.slice(checkpointIndex),
|
||||
};
|
||||
}
|
||||
|
||||
export function activeDungeonRouteProgress(): {
|
||||
readonly dungeonId: string | null;
|
||||
readonly objectiveId: string | null;
|
||||
readonly checkpointIndex: number;
|
||||
} {
|
||||
return { dungeonId: activeDungeonId, objectiveId: activeObjectiveId, checkpointIndex };
|
||||
}
|
||||
Reference in new issue
Block a user