Files
healer-man/src/game/dungeonTypes.ts
T
2026-09-12 15:14:56 -04:00

299 lines
11 KiB
TypeScript

import type {
MobPackDefinition,
MobVector3,
PopulationDefinitionMap,
StaticMobSpawnDefinition,
} from "./mobPopulation";
import type { DungeonEncounterDefinition } from "./dungeonEncounterTypes";
import type { DungeonWorldObjectDefinition } from "./dungeonWorldObjects";
export type Vector3Tuple = MobVector3;
export type DungeonEnvironmentMode = "global-wmo" | "adt-hybrid" | "runewaker-ros";
export type DungeonExpansion = "classic" | "burning-crusade" | "wrath" | "runewaker";
export type DungeonAvailability = "available" | "blocked" | "disabled";
export type DungeonDifficulty = "normal" | "heroic";
export const DUNGEON_SOURCE_RECIPE_SCHEMA_VERSION = 1;
export const DUNGEON_DEFINITION_SCHEMA_VERSION = 1;
export const CREATURE_ASSET_SCHEMA_VERSION = 1;
export const DUNGEON_PACK_SCHEMA_VERSION = 1;
export interface DungeonDifficultyVariant {
readonly id: string;
readonly difficulty: DungeonDifficulty;
readonly mapDifficultyId?: number;
readonly spawnMask: number;
readonly levelRange: readonly [minimum: number, maximum: number];
}
export interface DungeonSourceRecipe {
readonly schemaVersion: typeof DUNGEON_SOURCE_RECIPE_SCHEMA_VERSION;
readonly slug: string;
readonly title: string;
readonly mapId: number;
readonly lfgDungeonIds: readonly number[];
readonly expansion: DungeonExpansion;
readonly clientBuild: "3.3.5a" | "3.3.5a-Ascension" | "3.3.5a-Epoch";
readonly mapDirectory: string;
readonly environmentMode: DungeonEnvironmentMode | "detect";
readonly difficultyVariants: readonly DungeonDifficultyVariant[];
readonly clientSource: {
readonly rootEnvironmentVariable: "WOW_CLIENT_ROOT" | "EPOCH_CLIENT_ROOT";
readonly relativeDefault: string;
};
readonly serverSource: {
readonly rootEnvironmentVariable: "WOW_SERVER_DATA";
readonly adapter: "normalized-json" | "trinity-sql";
readonly readOnly: true;
};
readonly extraction: {
readonly rootWmo?: string;
readonly doodadSets?: readonly string[];
readonly adtTiles?: readonly string[] | "all-present";
};
/** Reviewed WC fixture input; later recipes receive these records from server/display discovery. */
readonly creatures?: readonly DungeonCreatureSource[];
readonly review: {
readonly entrance: "required" | "approved";
readonly bossOrder: "required" | "approved";
readonly optionalEncounters: "required" | "approved";
readonly presentation: "required" | "approved";
readonly offMeshLinks: "required" | "approved";
};
readonly exceptions: readonly string[];
}
export interface DungeonCreatureEquipmentSource {
readonly name: string;
readonly attachmentId: number;
readonly modelPath: string;
readonly skinTextures?: readonly string[];
readonly displayInfoId?: number;
readonly displayModelIndex?: number;
}
export interface DungeonCreatureSource {
readonly slug: string;
readonly name: string;
readonly entry: number;
readonly displayId: number;
readonly displayScale: number;
readonly rigType: "m2" | "character-composite";
readonly modelPath: string;
readonly skinTextures?: readonly string[];
readonly bakedTexture?: string;
readonly hairTexture?: string;
readonly textureOverrides?: Readonly<Record<string, string>>;
readonly geosets?: readonly (readonly [number, number])[];
readonly equipment?: readonly DungeonCreatureEquipmentSource[];
readonly animationIds?: readonly number[] | "all-source-clips";
readonly spellcaster?: boolean;
readonly fallbackExceptions?: readonly string[];
}
export interface DungeonAssetChunk {
readonly id: string;
readonly fileName: string;
/** Root-relative public asset URL for generated/shared environment packages. */
readonly url?: string;
readonly checksum?: string;
readonly size?: number;
readonly triangleCount?: number;
}
export interface DungeonEnvironmentAssets {
readonly visual: readonly DungeonAssetChunk[];
readonly collision: readonly DungeonAssetChunk[];
readonly navigation?: DungeonAssetChunk;
readonly minimap?: string;
readonly editableSource?: string;
}
export interface DungeonTransform {
readonly position: Vector3Tuple;
readonly rotation: Vector3Tuple;
readonly scale: number;
readonly fromWow?: "three(x,y,z)=(-wow.x,wow.z,wow.y)";
readonly fromRunewaker?: string;
}
export interface WorldSpawn {
readonly footPosition: Vector3Tuple;
readonly yaw: number;
}
export interface DungeonEntrance extends WorldSpawn {
readonly name: string;
readonly forward: Vector3Tuple;
}
export interface DungeonBounds {
readonly min: Vector3Tuple;
readonly max: Vector3Tuple;
}
export interface DungeonAreaCheckpoint {
readonly id: string;
readonly name: string;
readonly center: Vector3Tuple;
readonly radius: number;
}
export interface DungeonBossObjective {
readonly id: string;
readonly name: string;
readonly position: Vector3Tuple;
readonly optional?: boolean;
/** Spawned by an encounter state machine rather than the static population. */
readonly eventOnly?: boolean;
}
export interface DungeonNavigationLink {
readonly id: string;
readonly start: Vector3Tuple;
readonly end: Vector3Tuple;
readonly bidirectional: boolean;
readonly authoredReason: string;
}
/** Reviewed package-space walking proxy; the rendered staircase is unchanged. */
export interface DungeonTraversalRamp {
readonly id: string;
readonly start: Vector3Tuple;
readonly end: Vector3Tuple;
readonly width: number;
readonly navigationBridge: {
readonly linkId: string;
readonly startPortal: readonly [Vector3Tuple, Vector3Tuple];
readonly endPortal: readonly [Vector3Tuple, Vector3Tuple];
};
}
export interface DungeonEncounterSpawnGroupDefinition {
readonly id: string;
readonly spawns: readonly StaticMobSpawnDefinition[];
}
export interface DungeonMapPresentation {
readonly width: number;
readonly height: number;
readonly padding: number;
readonly contours: readonly string[];
}
export interface DungeonMaterialRoles {
readonly cutoutPatterns: readonly string[];
readonly cutoutNames: readonly string[];
readonly blendPatterns: readonly string[];
readonly blendNames: readonly string[];
readonly additivePatterns: readonly string[];
readonly additiveNames: readonly string[];
}
export interface DungeonPresentation {
readonly location: string;
readonly theme: string;
readonly summary: string;
readonly loadingMessage: string;
readonly unchartedAreaName: string;
readonly background: string;
readonly fog: { readonly color: string; readonly near: number; readonly far: number };
readonly ambientLight: { readonly color: string; readonly intensity: number };
readonly hemisphereLight: {
readonly skyColor: string;
readonly groundColor: string;
readonly intensity: number;
};
readonly directionalLight: { readonly color: string; readonly intensity: number; readonly offset: Vector3Tuple };
readonly materials: DungeonMaterialRoles;
readonly map: DungeonMapPresentation;
}
export interface DungeonSourceProvenance {
readonly clientBuild: string;
readonly coordinateAlignment?: "player-anchor" | "source" | "source-transform";
readonly clientArchiveHashes: Readonly<Record<string, string>>;
readonly databaseAdapter: string;
readonly databaseRevision?: string;
readonly sourceSnapshot?: string;
/** Auditable source-to-package basis; global WMO and ADT clients use different mappings. */
readonly coordinateTransform: string;
}
export interface DungeonValidationStatus {
readonly status: "green" | "blocked" | "unvalidated";
/** Navigation-only review state; permits routing without overstating encounter validation. */
readonly navigation?: "green" | "blocked" | "unvalidated";
readonly report?: string;
readonly validatedAt?: string;
readonly blockers: readonly string[];
readonly warnings: readonly string[];
}
export interface DungeonDefinition {
readonly schemaVersion: typeof DUNGEON_DEFINITION_SCHEMA_VERSION;
readonly id: string;
readonly title: string;
readonly mapId: number;
readonly lfgDungeonIds: readonly number[];
readonly expansion: DungeonExpansion;
readonly environmentMode: DungeonEnvironmentMode;
readonly difficultyVariants: readonly DungeonDifficultyVariant[];
readonly defaultDifficultyId: string;
readonly availability: DungeonAvailability;
readonly availabilityReason?: string;
readonly presentation: DungeonPresentation;
readonly assets: DungeonEnvironmentAssets;
readonly transform: DungeonTransform;
readonly bounds: DungeonBounds;
readonly entrance: DungeonEntrance;
readonly areas: readonly DungeonAreaCheckpoint[];
readonly entities: PopulationDefinitionMap;
readonly staticSpawns: readonly StaticMobSpawnDefinition[];
readonly roamingPacks: readonly MobPackDefinition[];
readonly bosses: readonly DungeonBossObjective[];
readonly objectiveOrder: readonly DungeonBossObjective[];
readonly navigationLinks: readonly DungeonNavigationLink[];
readonly traversalRamps?: readonly DungeonTraversalRamp[];
/** Serializable dungeon-wide orchestration kept separate from render state. */
readonly encounters?: readonly DungeonEncounterDefinition[];
/** Declarative groups activated by encounter actions; renderer ownership stays outside the reducer. */
readonly encounterSpawnGroups?: readonly DungeonEncounterSpawnGroupDefinition[];
readonly serverGameObjects: readonly DungeonWorldObjectDefinition[];
readonly provenance: DungeonSourceProvenance;
readonly validation: DungeonValidationStatus;
}
export type SemanticAnimation = "stand" | "walk" | "run" | "attack" | "cast" | "hit" | "death";
export interface CreatureAssetDefinition {
readonly schemaVersion: typeof CREATURE_ASSET_SCHEMA_VERSION;
readonly id: string;
readonly displayId: number;
readonly compositeRecipeHash?: string;
readonly sourceM2: string;
readonly sourceTextures: readonly string[];
readonly rigType: "m2" | "character-composite";
readonly bounds: DungeonBounds;
readonly scale: number;
readonly groundOffset: number;
readonly facing: { readonly axis: "+x" | "+z"; readonly runtimeRotationY: number };
readonly materialRoles: Readonly<Record<string, "opaque" | "cutout" | "blend" | "additive">>;
readonly equipment: readonly unknown[];
readonly animations: Readonly<Partial<Record<SemanticAnimation, string>>>;
readonly fallbackExceptions: readonly string[];
readonly assetUrl: string;
readonly checksum: string;
readonly size: number;
}
export interface DungeonPackManifest {
readonly schemaVersion: typeof DUNGEON_PACK_SCHEMA_VERSION;
readonly dungeonId: string;
readonly definitionChecksum: string;
readonly generatedAt: string;
readonly assets: readonly DungeonAssetChunk[];
readonly creatureDependencies: readonly string[];
readonly reports: readonly string[];
}