forked from phenom/healer-man
Release Healer Man 0.1.40
This commit is contained in:
1 parent
ed0d2fea3d
commit
197a64117c
215 files changed
+5131
-181
No files matched your search
@@ -0,0 +1,64 @@
|
||||
import catalog from "./generated/wowDungeonMaps.generated.json";
|
||||
import type { DungeonDefinition, Vector3Tuple } from "./dungeonTypes";
|
||||
|
||||
export interface WowMapFloor {
|
||||
readonly level: number;
|
||||
readonly name: string;
|
||||
/** World MinX, MaxX, MinY, MaxY; X points north and Y points west. */
|
||||
readonly bounds: readonly [number, number, number, number];
|
||||
readonly image: string;
|
||||
readonly checksum: string;
|
||||
}
|
||||
export interface WowDungeonMap {
|
||||
readonly mapId: number;
|
||||
readonly coordinateTransform: string;
|
||||
readonly visualChecksum?: string;
|
||||
/** Three row-major affine rows converting package position to WoW XYZ. */
|
||||
readonly runtimeToWow: readonly number[];
|
||||
readonly floors: readonly WowMapFloor[];
|
||||
}
|
||||
const maps = catalog.dungeons as unknown as Readonly<Record<string, WowDungeonMap>>;
|
||||
|
||||
export function wowDungeonMapFor(dungeon: DungeonDefinition): WowDungeonMap | null {
|
||||
const map = maps[dungeon.id];
|
||||
// A replacement environment must be reimported, never silently misaligned.
|
||||
return map?.mapId === dungeon.mapId
|
||||
&& map.coordinateTransform === dungeon.provenance.coordinateTransform
|
||||
&& map.visualChecksum === dungeon.assets.visual[0]?.checksum ? map : null;
|
||||
}
|
||||
|
||||
export function wowMapWorldPosition(map: WowDungeonMap, position: Vector3Tuple): Vector3Tuple {
|
||||
return [0, 1, 2].map((row) => {
|
||||
const i = row * 4;
|
||||
return map.runtimeToWow[i] * position[0] + map.runtimeToWow[i + 1] * position[1]
|
||||
+ map.runtimeToWow[i + 2] * position[2] + map.runtimeToWow[i + 3];
|
||||
}) as unknown as Vector3Tuple;
|
||||
}
|
||||
|
||||
export function wowMapPoint(map: WowDungeonMap, floor: WowMapFloor, position: Vector3Tuple): readonly [number, number] {
|
||||
const [x, y] = wowMapWorldPosition(map, position);
|
||||
const [minX, maxX, minY, maxY] = floor.bounds;
|
||||
return [(maxY - y) / (maxY - minY) * 1002, (maxX - x) / (maxX - minX) * 668];
|
||||
}
|
||||
|
||||
export function wowMapContains(map: WowDungeonMap, floor: WowMapFloor, position: Vector3Tuple): boolean {
|
||||
const [x, y] = wowMapPoint(map, floor, position);
|
||||
return Number.isFinite(x) && Number.isFinite(y) && x >= 0 && x <= 1002 && y >= 0 && y <= 668;
|
||||
}
|
||||
|
||||
/** Smallest containing floor wins; stacked rooms can be selected explicitly in the map panel. */
|
||||
export function wowMapFloorFor(map: WowDungeonMap, position: Vector3Tuple, level?: number | null): WowMapFloor {
|
||||
const explicit = map.floors.find((floor) => floor.level === level);
|
||||
if (explicit) return explicit;
|
||||
const containing = map.floors.filter((floor) => floor.level !== 0 && wowMapContains(map, floor, position));
|
||||
const size = (floor: WowMapFloor) => (floor.bounds[1] - floor.bounds[0]) * (floor.bounds[3] - floor.bounds[2]);
|
||||
return containing.sort((a, b) => size(a) - size(b) || a.level - b.level)[0]
|
||||
?? map.floors.find((floor) => floor.level === 0) ?? map.floors[0];
|
||||
}
|
||||
|
||||
export function wowMapHeading(map: WowDungeonMap, floor: WowMapFloor, position: Vector3Tuple, yaw: number): readonly [number, number] {
|
||||
const [x, y] = wowMapPoint(map, floor, position);
|
||||
const [targetX, targetY] = wowMapPoint(map, floor, [position[0] + Math.sin(yaw), position[1], position[2] + Math.cos(yaw)]);
|
||||
const length = Math.hypot(targetX - x, targetY - y) || 1;
|
||||
return [(targetX - x) / length * 23, (targetY - y) / length * 23];
|
||||
}
|
||||
Reference in new issue
Block a user