mudlet-map-renderer 0.11.1-konva → 0.11.3-konva
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/AreaMapRenderer.d.ts +88 -0
- package/dist/Renderer.d.ts +124 -0
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.mjs +1114 -676
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { default as MapReader } from './reader/MapReader';
|
|
2
|
+
import { PlanarDirection } from './directions';
|
|
3
|
+
type AreaConnection = {
|
|
4
|
+
fromAreaId: number;
|
|
5
|
+
toAreaId: number;
|
|
6
|
+
fromRoomId: number;
|
|
7
|
+
toRoomId: number;
|
|
8
|
+
direction: PlanarDirection | null;
|
|
9
|
+
fromRoomPosition: {
|
|
10
|
+
x: number;
|
|
11
|
+
y: number;
|
|
12
|
+
};
|
|
13
|
+
toRoomPosition: {
|
|
14
|
+
x: number;
|
|
15
|
+
y: number;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
type AreaNode = {
|
|
19
|
+
areaId: number;
|
|
20
|
+
name: string;
|
|
21
|
+
x: number;
|
|
22
|
+
y: number;
|
|
23
|
+
width: number;
|
|
24
|
+
height: number;
|
|
25
|
+
connections: AreaConnection[];
|
|
26
|
+
roomCount: number;
|
|
27
|
+
};
|
|
28
|
+
type ConnectionGroup = {
|
|
29
|
+
fromAreaId: number;
|
|
30
|
+
toAreaId: number;
|
|
31
|
+
connections: AreaConnection[];
|
|
32
|
+
primaryDirection: PlanarDirection | null;
|
|
33
|
+
averageOffset: {
|
|
34
|
+
x: number;
|
|
35
|
+
y: number;
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
export declare class AreaMapSettings {
|
|
39
|
+
static areaWidth: number;
|
|
40
|
+
static areaHeight: number;
|
|
41
|
+
static areaSpacing: number;
|
|
42
|
+
static fontSize: number;
|
|
43
|
+
static connectionLineWidth: number;
|
|
44
|
+
static areaFillColor: string;
|
|
45
|
+
static areaStrokeColor: string;
|
|
46
|
+
static textColor: string;
|
|
47
|
+
static connectionColor: string;
|
|
48
|
+
static highlightColor: string;
|
|
49
|
+
}
|
|
50
|
+
export declare class AreaMapRenderer {
|
|
51
|
+
private readonly stage;
|
|
52
|
+
private readonly areaLayer;
|
|
53
|
+
private readonly connectionLayer;
|
|
54
|
+
private readonly mapReader;
|
|
55
|
+
private areaNodes;
|
|
56
|
+
private connectionGroups;
|
|
57
|
+
private currentZoom;
|
|
58
|
+
private highlightedArea?;
|
|
59
|
+
constructor(container: HTMLDivElement, mapReader: MapReader);
|
|
60
|
+
private initResize;
|
|
61
|
+
private initScaling;
|
|
62
|
+
setZoom(zoom: number): void;
|
|
63
|
+
getZoom(): number;
|
|
64
|
+
render(): void;
|
|
65
|
+
private analyzeConnections;
|
|
66
|
+
private getLockedDirections;
|
|
67
|
+
private createConnection;
|
|
68
|
+
private addConnection;
|
|
69
|
+
private createConnectionGroup;
|
|
70
|
+
private parseDirection;
|
|
71
|
+
private toPlanarDirection;
|
|
72
|
+
private layoutAreas;
|
|
73
|
+
private findConnectedComponents;
|
|
74
|
+
private forceDirectedLayout;
|
|
75
|
+
private getDirectionOffset;
|
|
76
|
+
private applyForces;
|
|
77
|
+
private drawConnections;
|
|
78
|
+
private getEdgePoint;
|
|
79
|
+
private drawAreas;
|
|
80
|
+
private centerView;
|
|
81
|
+
highlightArea(areaId: number | undefined): void;
|
|
82
|
+
centerOnArea(areaId: number): void;
|
|
83
|
+
private emitAreaClickEvent;
|
|
84
|
+
getAreaNode(areaId: number): AreaNode | undefined;
|
|
85
|
+
getConnectionGroups(): ConnectionGroup[];
|
|
86
|
+
destroy(): void;
|
|
87
|
+
}
|
|
88
|
+
export {};
|
package/dist/Renderer.d.ts
CHANGED
|
@@ -13,33 +13,143 @@ export type RoomContextMenuEventDetail = {
|
|
|
13
13
|
export type ZoomChangeEventDetail = {
|
|
14
14
|
zoom: number;
|
|
15
15
|
};
|
|
16
|
+
/**
|
|
17
|
+
* Style configuration for the player position marker.
|
|
18
|
+
* The player marker is a circle that indicates the current player position on the map.
|
|
19
|
+
*/
|
|
16
20
|
export type PlayerMarkerStyle = {
|
|
21
|
+
/**
|
|
22
|
+
* Hex color for the marker's stroke/border (e.g., "#00e5b2" for cyan-green).
|
|
23
|
+
*/
|
|
17
24
|
strokeColor: string;
|
|
25
|
+
/**
|
|
26
|
+
* Opacity for the stroke/border (0.0 = fully transparent, 1.0 = fully opaque).
|
|
27
|
+
*/
|
|
18
28
|
strokeAlpha: number;
|
|
29
|
+
/**
|
|
30
|
+
* Hex color for the marker's fill (e.g., "#00e5b2" for cyan-green).
|
|
31
|
+
*/
|
|
19
32
|
fillColor: string;
|
|
33
|
+
/**
|
|
34
|
+
* Opacity for the fill (0.0 = fully transparent, 1.0 = fully opaque).
|
|
35
|
+
* Setting this to 0 creates a hollow circle effect.
|
|
36
|
+
*/
|
|
20
37
|
fillAlpha: number;
|
|
38
|
+
/**
|
|
39
|
+
* Width of the marker's stroke/border in map units (typically 0.01-0.3).
|
|
40
|
+
*/
|
|
21
41
|
strokeWidth: number;
|
|
42
|
+
/**
|
|
43
|
+
* Size multiplier relative to the room size.
|
|
44
|
+
* - 1.0 = marker radius equals room radius (matches room size)
|
|
45
|
+
* - Values > 1.0 make the marker larger than rooms
|
|
46
|
+
* - Values < 1.0 make the marker smaller than rooms
|
|
47
|
+
*
|
|
48
|
+
* Note: Room circles have radius = roomSize / 2, so sizeFactor is applied to that radius.
|
|
49
|
+
*/
|
|
22
50
|
sizeFactor: number;
|
|
51
|
+
/**
|
|
52
|
+
* Dash pattern for the stroke as an array of [dash length, gap length].
|
|
53
|
+
* Example: [0.05, 0.05] creates evenly spaced dashes.
|
|
54
|
+
* Only applied when dashEnabled is true.
|
|
55
|
+
*/
|
|
23
56
|
dash?: number[];
|
|
57
|
+
/**
|
|
58
|
+
* Whether to apply the dash pattern to the stroke.
|
|
59
|
+
* When false, the stroke is solid regardless of the dash property.
|
|
60
|
+
*/
|
|
24
61
|
dashEnabled: boolean;
|
|
25
62
|
};
|
|
63
|
+
/**
|
|
64
|
+
* Global settings for map rendering.
|
|
65
|
+
* All properties are static and can be modified at runtime to change the map's appearance and behavior.
|
|
66
|
+
*/
|
|
26
67
|
export declare class Settings {
|
|
68
|
+
/**
|
|
69
|
+
* Size of each room in map units (width/height for rectangles, diameter for circles).
|
|
70
|
+
* Typical values: 0.2 - 1.5
|
|
71
|
+
* Default: 0.6
|
|
72
|
+
*/
|
|
27
73
|
static roomSize: number;
|
|
74
|
+
/**
|
|
75
|
+
* Width of lines (exit connections, room borders) in map units.
|
|
76
|
+
* Typical values: 0.01 - 0.1
|
|
77
|
+
* Default: 0.025
|
|
78
|
+
*/
|
|
28
79
|
static lineWidth: number;
|
|
80
|
+
/**
|
|
81
|
+
* Color of exit connection lines as RGB string.
|
|
82
|
+
* Example: 'rgb(225, 255, 225)' for light green
|
|
83
|
+
*/
|
|
29
84
|
static lineColor: string;
|
|
85
|
+
/**
|
|
86
|
+
* When true, map instantly jumps to the new position when the current room changes.
|
|
87
|
+
* When false, the map smoothly animates/pans to the new position.
|
|
88
|
+
* Default: false (animated movement)
|
|
89
|
+
*/
|
|
30
90
|
static instantMapMove: boolean;
|
|
91
|
+
/**
|
|
92
|
+
* When true, highlights the current room and its exits with an overlay.
|
|
93
|
+
* The overlay uses a semi-transparent color to emphasize the current position.
|
|
94
|
+
* Default: true
|
|
95
|
+
*/
|
|
31
96
|
static highlightCurrentRoom: boolean;
|
|
97
|
+
/**
|
|
98
|
+
* Legacy flag for enabling/disabling culling (prefer using cullingMode instead).
|
|
99
|
+
* Default: true
|
|
100
|
+
*/
|
|
32
101
|
static cullingEnabled: boolean;
|
|
102
|
+
/**
|
|
103
|
+
* Determines how off-screen elements are culled to improve performance:
|
|
104
|
+
* - "none": No culling, render everything (worst performance, best accuracy)
|
|
105
|
+
* - "basic": Classic viewport-based culling (good performance)
|
|
106
|
+
* - "indexed": Spatial index culling using R-tree (best performance)
|
|
107
|
+
*
|
|
108
|
+
* Default: "indexed"
|
|
109
|
+
*/
|
|
33
110
|
static cullingMode: CullingMode;
|
|
111
|
+
/**
|
|
112
|
+
* Custom culling bounds for manually specifying the visible area.
|
|
113
|
+
* When set, only elements within these bounds are rendered.
|
|
114
|
+
* Format: { x, y, width, height } in map coordinates.
|
|
115
|
+
* Default: null (uses viewport bounds)
|
|
116
|
+
*/
|
|
34
117
|
static cullingBounds: {
|
|
35
118
|
x: number;
|
|
36
119
|
y: number;
|
|
37
120
|
width: number;
|
|
38
121
|
height: number;
|
|
39
122
|
} | null;
|
|
123
|
+
/**
|
|
124
|
+
* How to render room labels:
|
|
125
|
+
* - "image": Render labels as images (better performance for many labels)
|
|
126
|
+
* - "data": Render labels as text data (better for dynamic content)
|
|
127
|
+
*
|
|
128
|
+
* Default: "image"
|
|
129
|
+
*/
|
|
40
130
|
static labelRenderMode: LabelRenderMode;
|
|
131
|
+
/**
|
|
132
|
+
* When true, room labels have transparent backgrounds.
|
|
133
|
+
* When false, labels have opaque backgrounds for better readability.
|
|
134
|
+
*/
|
|
41
135
|
static transparentLabels: boolean;
|
|
136
|
+
/**
|
|
137
|
+
* Shape used to render rooms:
|
|
138
|
+
* - "rectangle": Rooms are drawn as squares/rectangles
|
|
139
|
+
* - "circle": Rooms are drawn as circles
|
|
140
|
+
*
|
|
141
|
+
* Default: "rectangle"
|
|
142
|
+
*
|
|
143
|
+
* Note: Exit line calculations automatically adjust based on room shape.
|
|
144
|
+
* Circle mode calculates exact tangent points on the circle's edge.
|
|
145
|
+
*/
|
|
42
146
|
static roomShape: RoomShape;
|
|
147
|
+
/**
|
|
148
|
+
* Style configuration for the player position marker.
|
|
149
|
+
* See PlayerMarkerStyle type for details on individual properties.
|
|
150
|
+
*
|
|
151
|
+
* Default configuration creates a cyan-green dashed circle that's 1.7x the room size.
|
|
152
|
+
*/
|
|
43
153
|
static playerMarker: PlayerMarkerStyle;
|
|
44
154
|
}
|
|
45
155
|
export declare class Renderer {
|
|
@@ -89,6 +199,20 @@ export declare class Renderer {
|
|
|
89
199
|
setCullingMode(mode: CullingMode): void;
|
|
90
200
|
getCullingMode(): CullingMode;
|
|
91
201
|
getCurrentArea(): Area | undefined;
|
|
202
|
+
/**
|
|
203
|
+
* Refreshes the current room overlay to reflect any changes to Settings.
|
|
204
|
+
* Call this after modifying Settings properties (like roomSize, roomShape, lineWidth, etc.)
|
|
205
|
+
* to update the visual appearance of the current room and its exits without changing position.
|
|
206
|
+
*/
|
|
207
|
+
refreshCurrentRoomOverlay(): void;
|
|
208
|
+
/**
|
|
209
|
+
* Completely refreshes the map to reflect changes to Settings.
|
|
210
|
+
* This re-renders the entire current area and updates the player position marker.
|
|
211
|
+
* Call this after changing Settings properties like roomSize, roomShape, lineWidth, etc.
|
|
212
|
+
*
|
|
213
|
+
* Note: This is more expensive than refreshCurrentRoomOverlay() but ensures everything is updated.
|
|
214
|
+
*/
|
|
215
|
+
refresh(): void;
|
|
92
216
|
setPosition(roomId: number): void;
|
|
93
217
|
renderPath(locations: number[], color?: string): import('konva/lib/shapes/Line').Line<{
|
|
94
218
|
points: number[];
|
package/dist/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const p=require("konva"),ee=["north","south","east","west","northeast","northwest","southeast","southwest"],I={north:"n",south:"s",east:"e",west:"w",northeast:"ne",northwest:"nw",southeast:"se",southwest:"sw",up:"u",down:"d",in:"i",out:"o"},_={north:{x:0,y:-1},south:{x:0,y:1},east:{x:1,y:0},west:{x:-1,y:0},northeast:{x:1,y:-1},northwest:{x:-1,y:-1},southeast:{x:1,y:1},southwest:{x:-1,y:1}},te=["north","south","east","west","northeast","northwest","southeast","southwest"],pe={north:"south",south:"north",east:"west",west:"east",northeast:"southwest",northwest:"southeast",southeast:"northwest",southwest:"northeast"};function de(c){return c?Object.prototype.hasOwnProperty.call(_,c):!1}function S(c,e,t,s=1){if(!de(t))return{x:c,y:e};const i=_[t];return{x:c+i.x*s,y:e+i.y*s}}function fe(c,e,t,s=1){if(!de(t))return{x:c,y:e};const i=_[t],o=Math.atan2(i.y,i.x);return{x:c+Math.cos(o)*s,y:e+Math.sin(o)*s}}const V={OPEN_DOOR:"rgb(10, 155, 10)",CLOSED_DOOR:"rgb(226, 205, 59)",LOCKED_DOOR:"rgb(155, 10, 10)",ONE_WAY_FILL:"rgb(155, 10, 10)"},xe={1:"north",2:"northeast",3:"northwest",4:"east",5:"west",6:"south",7:"southeast",8:"southwest",9:"up",10:"down",11:"in",12:"out"},be=["up","down","in","out"];function ye(c){switch(c){case 1:return V.OPEN_DOOR;case 2:return V.CLOSED_DOOR;default:return V.LOCKED_DOOR}}class Re{constructor(e,t){this.mapReader=e,this.mapRenderer=t}getRoomEdgePoint(e,t,s,i){return a.roomShape==="circle"?fe(e,t,s,i):S(e,t,s,i)}render(e,t){return this.renderWithColor(e,a.lineColor,t)}renderWithColor(e,t,s){return e.aDir&&e.bDir?this.renderTwoWayExit(e,t,s):this.renderOneWayExit(e,t)}renderTwoWayExit(e,t,s){const i=this.mapReader.getRoom(e.a),o=this.mapReader.getRoom(e.b);if(!i||!o||!e.aDir||!e.bDir||!ee.includes(e.aDir)||!ee.includes(e.bDir)||i.customLines[I[e.aDir]]&&o.customLines[I[e.bDir]]||i.z!==o.z&&(s!==o.z&&i.customLines[I[e.aDir]]||s!==i.z&&o.customLines[I[e.bDir]]))return;const r=new p.Group,n=[];if(n.push(...Object.values(this.getRoomEdgePoint(i.x,i.y,e.aDir,a.roomSize/2))),n.push(...Object.values(this.getRoomEdgePoint(o.x,o.y,e.bDir,a.roomSize/2))),i.doors[I[e.aDir]]||o.doors[I[e.bDir]]){const d=this.renderDoor(n,i.doors[I[e.aDir]]??o.doors[I[e.bDir]]);r.add(d)}const h=new p.Line({points:n,stroke:t,strokeWidth:a.lineWidth,perfectDrawEnabled:!1});return r.add(h),r}renderOneWayExit(e,t){const s=e.aDir?this.mapReader.getRoom(e.a):this.mapReader.getRoom(e.b),i=e.aDir?this.mapReader.getRoom(e.b):this.mapReader.getRoom(e.a),o=e.aDir?e.aDir:e.bDir;if(!o||!s||!i||s.customLines[I[o]||o])return;if(s.area!=i.area&&o)return this.renderAreaExit(s,o,t);let r={x:i.x,y:i.y};(i.area!==s.area||i.z!==s.z)&&(r=S(s.x,s.y,o,a.roomSize/2));const n=S(s.x,s.y,o,.3),h=n.x-(n.x-r.x)/2,d=n.y-(n.y-r.y)/2,u=new p.Group,l=[];l.push(...Object.values(this.getRoomEdgePoint(s.x,s.y,o,a.roomSize/2))),l.push(r.x,r.y);const b=new p.Line({points:l,stroke:t,strokeWidth:a.lineWidth,dashEnabled:!0,dash:[.1,.05],perfectDrawEnabled:!1});u.add(b);const y=new p.Arrow({points:[l[0],l[1],h,d],pointerLength:.5,pointerWidth:.35,strokeWidth:a.lineWidth*1.4,stroke:t,fill:V.ONE_WAY_FILL,dashEnabled:!0,dash:[.1,.05]});return u.add(y),u}renderAreaExit(e,t,s){const i=this.getRoomEdgePoint(e.x,e.y,t,a.roomSize/2),o=S(e.x,e.y,t,a.roomSize*1.5),r=s??this.mapReader.getColorValue(e.env);return new p.Arrow({points:[i.x,i.y,o.x,o.y],pointerLength:.3,pointerWidth:.3,strokeWidth:a.lineWidth*1.4,stroke:r,fill:r})}renderSpecialExits(e,t){return Object.entries(e.customLines).map(([s,i])=>{const o=[e.x,e.y];i.points.reduce((u,l)=>(u.push(l.x,-l.y),u),o);const r=i.attributes.arrow?p.Arrow:p.Line,n=t??`rgb(${i.attributes.color.r}, ${i.attributes.color.g}, ${i.attributes.color.b})`,h=new r({points:o,strokeWidth:a.lineWidth,stroke:n,fill:t??`rgb(${i.attributes.color.r}, ${i.attributes.color.g} , ${i.attributes.color.b})`,pointerLength:.3,pointerWidth:.2,perfectDrawEnabled:!1});let d=i.attributes.style;return d==="dot line"?(h.dash([.05,.05]),h.dashOffset(.1)):d==="dash line"?h.dash([.4,.2]):d==="solid line"||d!==void 0&&console.log("Brak opisu stylu: "+d),h})}renderStubs(e,t=a.lineColor){return e.stubs.map(s=>{const i=xe[s],o=this.getRoomEdgePoint(e.x,e.y,i,a.roomSize/2),r=S(e.x,e.y,i,a.roomSize/2+.5),n=[o.x,o.y,r.x,r.y];return new p.Line({points:n,stroke:t,strokeWidth:a.lineWidth})})}renderInnerExits(e){return be.map(t=>{if(e.exits[t]){const s=new p.Group,i=new p.RegularPolygon({x:e.x,y:e.y,sides:3,fill:this.mapReader.getSymbolColor(e.env,.6),stroke:this.mapReader.getSymbolColor(e.env),strokeWidth:a.lineWidth,radius:a.roomSize/5,scaleX:1.4,scaleY:.8,perfectDrawEnabled:!1});s.add(i);let o=e.doors[t];if(o!==void 0)switch(o){case 1:i.stroke(V.OPEN_DOOR);break;case 2:i.stroke(V.CLOSED_DOOR);break;default:i.stroke(V.LOCKED_DOOR)}switch(t){case"up":i.position(S(e.x,e.y,"south",a.roomSize/4));break;case"down":i.rotation(180),i.position(S(e.x,e.y,"north",a.roomSize/4));break;case"in":const r=i.clone();r.rotation(-90),r.position(S(e.x,e.y,"east",a.roomSize/4)),s.add(r),i.rotation(90),i.position(S(e.x,e.y,"west",a.roomSize/4));break;case"out":const n=i.clone();n.rotation(90),n.position(S(e.x,e.y,"east",a.roomSize/4)),s.add(n),i.rotation(-90),i.position(S(e.x,e.y,"west",a.roomSize/4));break}return s}}).filter(t=>t!==void 0)}renderDoor(e,t){const s={x:e[0]+(e[2]-e[0])/2,y:e[1]+(e[3]-e[1])/2};return new p.Rect({x:s.x-a.roomSize/4,y:s.y-a.roomSize/4,width:a.roomSize/2,height:a.roomSize/2,stroke:ye(t),strokeWidth:a.lineWidth})}}class ue{constructor(e,t){this.rooms=[],this.labels=[],this.rooms=e,this.bounds=this.createBounds(),this.labels=t}getRooms(){return this.rooms}getLabels(){return this.labels}getBounds(){return this.bounds}createBounds(){return this.rooms.reduce((e,t)=>({minX:Math.min(e.minX,t.x),maxX:Math.max(e.maxX,t.x),minY:Math.min(e.minY,t.y),maxY:Math.max(e.maxY,t.y)}),{minX:Number.POSITIVE_INFINITY,maxX:Number.NEGATIVE_INFINITY,minY:Number.POSITIVE_INFINITY,maxY:Number.NEGATIVE_INFINITY})}}class G{constructor(e){this.planes={},this.exits=new Map,this.version=0,this.area=e,this.planes=this.createPlanes(),this.createExits()}getAreaName(){return this.area.areaName}getAreaId(){return parseInt(this.area.areaId)}getVersion(){return this.version}markDirty(){this.version++}getPlane(e){return this.planes[e]}getPlanes(){return Object.values(this.planes)}getRooms(){return this.area.rooms}getLinkExits(e){return Array.from(this.exits.values()).filter(t=>t.zIndex.includes(e))}createPlanes(){const e=this.area.rooms.reduce((t,s)=>(t[s.z]||(t[s.z]=[]),t[s.z].push(s),t),{});return Object.entries(e).reduce((t,[s,i])=>(t[+s]=new ue(i,this.area.labels.filter(o=>o.Z===+s)),t),{})}createExits(){this.area.rooms.forEach(e=>{Object.entries(e.specialExits).forEach(([t,s])=>this.createHalfExit(e.id,s,e.z,t)),Object.entries(e.exits).forEach(([t,s])=>this.createHalfExit(e.id,s,e.z,t))})}createHalfExit(e,t,s,i){if(e===t)return;const o=Math.min(e,t),r=Math.max(e,t),n=`${o}-${r}`;let h=this.exits.get(n);h||(h={a:o,b:r,zIndex:[s]}),o==e?h.aDir=i:h.bDir=i,h.zIndex.push(s),this.exits.set(n,h)}}class se extends ue{constructor(e,t){super(e.getRooms(),e.getLabels()),this.basePlane=e,this.visitedRooms=t}getRooms(){return this.basePlane.getRooms().filter(e=>this.visitedRooms.has(e.id))}getLabels(){return this.basePlane.getLabels()}getBounds(){const e=this.getRooms();return e.length?e.reduce((t,s)=>({minX:Math.min(t.minX,s.x),maxX:Math.max(t.maxX,s.x),minY:Math.min(t.minY,s.y),maxY:Math.max(t.maxY,s.y)}),{minX:Number.POSITIVE_INFINITY,maxX:Number.NEGATIVE_INFINITY,minY:Number.POSITIVE_INFINITY,maxY:Number.NEGATIVE_INFINITY}):this.basePlane.getBounds()}}class X extends G{constructor(e,t){super(e),this.planeCache=new WeakMap,this.visitedRooms=t instanceof Set?t:new Set(t??[]),this.areaRoomIds=new Set(e.rooms.map(s=>s.id))}getPlane(e){const t=super.getPlane(e);if(!t)return t;let s=this.planeCache.get(t);return s||(s=new se(t,this.visitedRooms),this.planeCache.set(t,s)),s}getPlanes(){return super.getPlanes().map(e=>{let t=this.planeCache.get(e);return t||(t=new se(e,this.visitedRooms),this.planeCache.set(e,t)),t})}getLinkExits(e){return super.getLinkExits(e).filter(t=>this.visitedRooms.has(t.a)||this.visitedRooms.has(t.b))}getVisitedRoomCount(){return super.getRooms().reduce((e,t)=>e+(this.visitedRooms.has(t.id)?1:0),0)}getTotalRoomCount(){return this.areaRoomIds.size}hasVisitedRoom(e){return this.areaRoomIds.has(e)&&this.visitedRooms.has(e)}getVisitedRoomIds(){return super.getRooms().filter(e=>this.visitedRooms.has(e.id)).map(e=>e.id)}addVisitedRoom(e){const t=this.visitedRooms.has(e);this.visitedRooms.add(e);const s=!t&&this.areaRoomIds.has(e);return s&&this.markDirty(),s}addVisitedRooms(e){let t=0;for(const s of e){const i=this.visitedRooms.has(s);this.visitedRooms.add(s),!i&&this.areaRoomIds.has(s)&&t++}return t>0&&this.markDirty(),t}}class we{constructor(e,t){this.paths=[],this.mapReader=e,this.overlayLayer=t}renderPath(e,t,s,i="#66E64D"){if(t===void 0||s===void 0)return;const o=e.map(l=>this.mapReader.getRoom(l)).filter(l=>l!==void 0),r=[];let n=null;const h=()=>{n&&(n.length<4&&r.pop(),n=null)},d=()=>(n||(n=[],r.push(n)),n);o.forEach((l,b)=>{if(!this.isRoomVisible(l,t,s))return;const y=b>0?o[b-1]:void 0,w=b<o.length-1?o[b+1]:void 0;if(this.isRoomVisible(y,t,s))d();else{h();const g=d();if(y){const f=this.getDirectionTowards(l,y);if(f){const M=S(l.x,l.y,f,a.roomSize);g.push(M.x,M.y)}}}if(n?.push(l.x,l.y),!this.isRoomVisible(w,t,s)&&w){const g=this.getDirectionTowards(l,w);if(g){const f=S(l.x,l.y,g,a.roomSize);n?.push(f.x,f.y)}h()}}),h();const u=r.filter(l=>l.length>=4).map(l=>new p.Line({points:l,stroke:i,strokeWidth:a.lineWidth*4}));return u.forEach(l=>{this.overlayLayer.add(l),this.paths.push(l)}),u[0]}clearPaths(){this.paths.forEach(e=>{e.destroy()}),this.paths=[]}isRoomVisible(e,t,s){return e?e.area===t&&e.z===s:!1}getDirectionTowards(e,t){for(const s of te)if(e.exits[s]===t.id)return s;for(const s of te)if(t.exits[s]===e.id)return pe[s]}}const ve=.6,T=75,Ee=.025,Se="rgb(225, 255, 225)",W="rgb(120, 72, 0)";function ie(c,e){const t=parseInt(c.slice(1,3),16),s=parseInt(c.slice(3,5),16),i=parseInt(c.slice(5,7),16);return`rgba(${t}, ${s}, ${i}, ${e})`}const k=class k{};k.roomSize=ve,k.lineWidth=Ee,k.lineColor=Se,k.instantMapMove=!1,k.highlightCurrentRoom=!0,k.cullingEnabled=!0,k.cullingMode="indexed",k.cullingBounds=null,k.labelRenderMode="image",k.roomShape="rectangle",k.playerMarker={strokeColor:"#00e5b2",strokeAlpha:1,fillColor:"#00e5b2",fillAlpha:0,strokeWidth:.1,sizeFactor:1.7,dash:[.05,.05],dashEnabled:!0};let a=k;class ke{constructor(e,t){this.highlights=new Map,this.currentZoom=1,this.currentRoomOverlay=[],this.roomNodes=new Map,this.standaloneExitNodes=[],this.spatialBucketSize=5,this.roomSpatialIndex=new Map,this.exitSpatialIndex=new Map,this.visibleRooms=new Set,this.visibleStandaloneExitNodes=new Set,this.cullingScheduled=!1,this.stage=new p.Stage({container:e,width:e.clientWidth,height:e.clientHeight,draggable:!0}),window.addEventListener("resize",()=>{this.onResize(e)}),e.addEventListener("resize",()=>{this.onResize(e)}),this.linkLayer=new p.Layer({listening:!1}),this.stage.add(this.linkLayer),this.roomLayer=new p.Layer,this.stage.add(this.roomLayer),this.positionLayer=new p.Layer({listening:!1}),this.stage.add(this.positionLayer),this.overlayLayer=new p.Layer({listening:!1}),this.stage.add(this.overlayLayer),this.mapReader=t,this.exitRenderer=new Re(t,this),this.pathRenderer=new we(t,this.overlayLayer),this.initScaling(1.1),this.stage.on("dragmove",()=>this.scheduleRoomCulling()),this.stage.on("dragend",()=>this.scheduleRoomCulling())}onResize(e){this.stage.width(e.clientWidth),this.stage.height(e.clientHeight),this.currentRoomId&&this.centerOnRoom(this.mapReader.getRoom(this.currentRoomId),!1),this.stage.batchDraw(),this.scheduleRoomCulling()}initScaling(e){p.hitOnDragEnabled=!0;let t,s=!1,i=!1;this.stage.on("touchstart",o=>{const r=o.evt.touches;r&&r.length>1?(i=!0,this.stage.isDragging()&&(this.stage.stopDrag(),s=!0),this.stage.draggable(!1)):(i=!1,this.stage.draggable(!0))}),this.stage.on("touchend touchcancel",o=>{t=void 0;const r=o.evt.touches;(!r||r.length<=1)&&(i=!1,this.stage.draggable(!0))}),this.stage.on("wheel",o=>{o.evt.preventDefault();const r=this.stage.scaleX(),n=this.stage.getPointerPosition();if(!n)return;const h={x:(n.x-this.stage.x())/r,y:(n.y-this.stage.y())/r};let d=o.evt.deltaY>0?-1:1;o.evt.ctrlKey&&(d=-d);const u=d>0?this.currentZoom*e:this.currentZoom/e,l=u*T,b=this.setZoom(u),y={x:n.x-h.x*l,y:n.y-h.y*l};this.stage.position(y),this.scheduleRoomCulling(),b&&this.emitZoomChangeEvent()}),this.stage.on("touchmove",o=>{const r=o.evt.touches,n=r?.[0],h=r?.[1];if(h||i&&(i=!1,this.stage.draggable(!0)),n&&!h&&s&&!this.stage.isDragging()&&(this.stage.startDrag(),s=!1),!n||!h){t=void 0;return}o.evt.preventDefault(),this.stage.isDragging()&&(this.stage.stopDrag(),s=!0),i||(i=!0,this.stage.draggable(!1));const d=this.stage.container().getBoundingClientRect(),u={x:n.clientX-d.left,y:n.clientY-d.top},l={x:h.clientX-d.left,y:h.clientY-d.top},b=Math.hypot(u.x-l.x,u.y-l.y);if(t===void 0){t=b;return}if(t===0)return;const y=this.stage.scaleX(),w=this.stage.x(),R=this.stage.y(),m={x:this.stage.width()/2,y:this.stage.height()/2},g={x:(m.x-w)/y,y:(m.y-R)/y},f=this.currentZoom*(b/t),M=this.setZoom(f),L=this.stage.scaleX(),P={x:m.x-g.x*L,y:m.y-g.y*L};this.stage.position(P),this.stage.batchDraw(),this.scheduleRoomCulling(),t=b,M&&this.emitZoomChangeEvent()})}drawArea(e,t){const s=this.mapReader.getArea(e);if(!s)return;const i=s.getPlane(t);i&&(this.currentArea=e,this.currentAreaInstance=s,this.currentZIndex=t,this.currentAreaVersion=s.getVersion(),this.clearCurrentRoomOverlay(),this.roomLayer.destroyChildren(),this.linkLayer.destroyChildren(),this.roomNodes.clear(),this.standaloneExitNodes=[],this.standaloneExitBoundsRoomSize=void 0,this.roomSpatialIndex.clear(),this.exitSpatialIndex.clear(),this.visibleRooms.clear(),this.visibleStandaloneExitNodes.clear(),this.spatialBucketSize=this.computeSpatialBucketSize(),this.stage.scale({x:T*this.currentZoom,y:T*this.currentZoom}),this.renderLabels(i.getLabels()),this.renderExits(s.getLinkExits(t)),this.renderRooms(i.getRooms()??[]),this.refreshHighlights(),this.stage.batchDraw(),this.scheduleRoomCulling())}computeSpatialBucketSize(){return Math.max(a.roomSize*10,5)}getBucketKey(e,t){return`${e},${t}`}forEachBucket(e,t,s,i,o){const r=this.spatialBucketSize,n=Math.min(e,s),h=Math.max(e,s),d=Math.min(t,i),u=Math.max(t,i),l=Math.floor(n/r),b=Math.floor(h/r),y=Math.floor(d/r),w=Math.floor(u/r);for(let R=l;R<=b;R++)for(let m=y;m<=w;m++)o(this.getBucketKey(R,m))}addRoomToSpatialIndex(e){const t=a.roomSize/2,s=e.room.x-t,i=e.room.x+t,o=e.room.y-t,r=e.room.y+t;this.forEachBucket(s,o,i,r,n=>{let h=this.roomSpatialIndex.get(n);h||(h=new Set,this.roomSpatialIndex.set(n,h)),h.add(e)})}addStandaloneExitToSpatialIndex(e){const{bounds:t}=e,s=t.x,i=t.x+t.width,o=t.y,r=t.y+t.height;this.forEachBucket(s,o,i,r,n=>{let h=this.exitSpatialIndex.get(n);h||(h=new Set,this.exitSpatialIndex.set(n,h)),h.add(e)})}collectRoomCandidates(e,t,s,i){const o=new Set;return this.forEachBucket(e,t,s,i,r=>{this.roomSpatialIndex.get(r)?.forEach(h=>o.add(h))}),o}collectStandaloneExitCandidates(e,t,s,i){const o=new Set;return this.forEachBucket(e,t,s,i,r=>{this.exitSpatialIndex.get(r)?.forEach(h=>o.add(h))}),o}refreshStandaloneExitBoundsIfNeeded(){this.standaloneExitBoundsRoomSize!==a.roomSize&&(this.exitSpatialIndex.clear(),this.standaloneExitNodes.forEach(e=>{e.bounds=e.node.getClientRect({relativeTo:this.linkLayer}),this.addStandaloneExitToSpatialIndex(e)}),this.standaloneExitBoundsRoomSize=a.roomSize)}emitRoomContextEvent(e,t,s){const i=this.stage.container(),o=i.getBoundingClientRect(),r={roomId:e,position:{x:t-o.left,y:s-o.top}},n=new CustomEvent("roomcontextmenu",{detail:r});i.dispatchEvent(n)}emitZoomChangeEvent(){const e=new CustomEvent("zoom",{detail:{zoom:this.currentZoom}});this.stage.container().dispatchEvent(e)}setZoom(e){return this.currentZoom===e?!1:(this.currentZoom=e,this.stage.scale({x:T*e,y:T*e}),this.scheduleRoomCulling(),!0)}getZoom(){return this.currentZoom}setCullingMode(e){a.cullingMode=e,a.cullingEnabled=e!=="none",this.scheduleRoomCulling()}getCullingMode(){return a.cullingMode}getCurrentArea(){return this.currentArea?this.mapReader.getArea(this.currentArea):void 0}setPosition(e){const t=this.mapReader.getRoom(e);if(!t)return;const s=this.mapReader.getArea(t.area),i=s?.getVersion();let o=this.currentArea!==t.area||this.currentZIndex!==t.z;(this.currentArea!==t.area||this.currentZIndex!==t.z||i!==void 0&&this.currentAreaVersion!==i||s!==void 0&&this.currentAreaInstance!==s)&&this.drawArea(t.area,t.z),this.centerOnRoom(t,o),this.updateCurrentRoomOverlay(t);const r=ie(a.playerMarker.strokeColor,a.playerMarker.strokeAlpha),n=ie(a.playerMarker.fillColor,a.playerMarker.fillAlpha),h=a.roomSize/2*a.playerMarker.sizeFactor;this.positionRender?(this.positionRender.radius(h),this.positionRender.stroke(r),this.positionRender.fill(n),this.positionRender.strokeWidth(a.playerMarker.strokeWidth),this.positionRender.dash(a.playerMarker.dash??[]),this.positionRender.dashEnabled(a.playerMarker.dashEnabled)):(this.positionRender=new p.Circle({x:t.x,y:t.y,radius:h,stroke:r,fill:n,strokeWidth:a.playerMarker.strokeWidth,dash:a.playerMarker.dash,dashEnabled:a.playerMarker.dashEnabled}),this.positionLayer.add(this.positionRender))}renderPath(e,t){return this.pathRenderer.renderPath(e,this.currentArea,this.currentZIndex,t)}clearPaths(){this.pathRenderer.clearPaths()}renderHighlight(e,t){const s=this.mapReader.getRoom(e);if(!s)return;const i=this.highlights.get(e);i?.shape&&(i.shape.destroy(),delete i.shape);const o={color:t,area:s.area,z:s.z};if(this.highlights.set(e,o),s.area===this.currentArea&&s.z===this.currentZIndex){const r=this.createHighlightShape(s,t);return this.overlayLayer.add(r),o.shape=r,this.overlayLayer.batchDraw(),r}return o.shape}clearHighlights(){this.highlights.forEach(({shape:e})=>e?.destroy()),this.highlights.clear(),this.overlayLayer.batchDraw()}refreshHighlights(){this.highlights.forEach((e,t)=>{if(e.shape?.destroy(),delete e.shape,e.area!==this.currentArea||e.z!==this.currentZIndex)return;const s=this.mapReader.getRoom(t);if(!s)return;const i=this.createHighlightShape(s,e.color);this.overlayLayer.add(i),e.shape=i}),this.overlayLayer.batchDraw()}createHighlightShape(e,t){return a.roomShape==="circle"?new p.Circle({x:e.x,y:e.y,radius:a.roomSize/2*1.5,stroke:t,strokeWidth:.1,dash:[.05,.05],dashEnabled:!0,listening:!1}):new p.Rect({x:e.x-a.roomSize/2*1.5,y:e.y-a.roomSize/2*1.5,width:a.roomSize*1.5,height:a.roomSize*1.5,stroke:t,strokeWidth:.1,dash:[.05,.05],dashEnabled:!0,listening:!1})}centerOnRoom(e,t=!1){this.currentRoomId=e.id;const s={x:e.x,y:e.y};this.positionRender?.position(e);const o=this.stage.getAbsoluteTransform().point(s),r={x:this.stage.width()/2,y:this.stage.height()/2},n=r.x-o.x,h=r.y-o.y;this.currentTransition&&(this.currentTransition.pause(),this.currentTransition.destroy(),delete this.currentTransition),t||a.instantMapMove?(this.stage.position({x:this.stage.x()+n,y:this.stage.y()+h}),this.scheduleRoomCulling()):(this.currentTransition=new p.Tween({node:this.stage,x:this.stage.x()+n,y:this.stage.y()+h,duration:.2,easing:p.Easings.EaseInOut,onUpdate:()=>this.scheduleRoomCulling(),onFinish:()=>this.scheduleRoomCulling()}),this.currentTransition.play())}renderRooms(e){e.forEach(t=>{const s=new p.Group({x:t.x-a.roomSize/2,y:t.y-a.roomSize/2}),i=this.mapReader.getColorValue(t.env),o=a.lineColor,n=a.roomShape==="circle"?new p.Circle({x:a.roomSize/2,y:a.roomSize/2,radius:a.roomSize/2,fill:i,strokeWidth:a.lineWidth,stroke:o,perfectDrawEnabled:!1}):new p.Rect({x:0,y:0,width:a.roomSize,height:a.roomSize,fill:i,strokeWidth:a.lineWidth,stroke:o,perfectDrawEnabled:!1}),h=(m,g)=>this.emitRoomContextEvent(t.id,m,g);s.on("mouseenter",()=>{this.stage.container().style.cursor="pointer"}),s.on("mouseleave",()=>{this.stage.container().style.cursor="auto"}),s.on("contextmenu",m=>{m.evt.preventDefault();const g=m.evt;h(g.clientX,g.clientY)});let d,u,l;const b=()=>{l!==void 0&&(this.stage.draggable(l),l=void 0)},y=()=>{d!==void 0&&(window.clearTimeout(d),d=void 0),u=void 0,b()};s.on("touchstart",m=>{if(y(),m.evt.touches&&m.evt.touches.length>1)return;const g=m.evt.touches?.[0];g&&(u={clientX:g.clientX,clientY:g.clientY},l=this.stage.draggable(),this.stage.draggable(!1),d=window.setTimeout(()=>{u&&h(u.clientX,u.clientY),y()},500))}),s.on("touchend",y),s.on("touchmove",m=>{if(!u)return;const g=m.evt.touches?.[0];if(!g){y();return}const f=g.clientX-u.clientX,M=g.clientY-u.clientY,L=f*f+M*M,P=10;if(L>P*P){const Y=l;y(),Y&&this.stage.startDrag()}}),s.on("touchcancel",y),s.add(n),this.renderSymbol(t,s),this.roomLayer.add(s);const w=[];this.exitRenderer.renderSpecialExits(t).forEach(m=>{this.linkLayer.add(m);const g=m.getClientRect({relativeTo:this.linkLayer}),f={node:m,bounds:g};this.standaloneExitNodes.push(f),this.addStandaloneExitToSpatialIndex(f)}),this.exitRenderer.renderStubs(t).forEach(m=>{this.linkLayer.add(m),w.push(m)}),this.exitRenderer.renderInnerExits(t).forEach(m=>{this.roomLayer.add(m)});const R={room:t,group:s,linkNodes:w};this.roomNodes.set(t.id,R),this.addRoomToSpatialIndex(R)})}scheduleRoomCulling(){this.cullingScheduled||(this.cullingScheduled=!0,window.requestAnimationFrame(()=>{this.cullingScheduled=!1,this.updateRoomCulling()}))}updateRoomCulling(){if(this.roomNodes.size===0&&this.standaloneExitNodes.length===0)return;const e=this.stage.scaleX();if(!e)return;const t=this.stage.position(),s=a.roomSize/2,i=a.cullingBounds,o=i?i.x:0,r=i?i.x+i.width:this.stage.width(),n=i?i.y:0,h=i?i.y+i.height:this.stage.height(),d=Math.min(o,r),u=Math.max(o,r),l=Math.min(n,h),b=Math.max(n,h),y=(d-t.x)/e,w=(u-t.x)/e,R=(l-t.y)/e,m=(b-t.y)/e;let g=!1,f=!1;const M=a.cullingEnabled?a.cullingMode??"indexed":"none",L=y-s,P=w+s,Y=R-s,H=m+s;if(this.refreshStandaloneExitBoundsIfNeeded(),M==="none"){this.roomNodes.forEach(x=>{x.group.visible()||(x.group.visible(!0),g=!0),x.linkNodes.forEach(E=>{E.visible()||(E.visible(!0),f=!0)})}),this.standaloneExitNodes.forEach(x=>{const{node:E}=x;E.visible()||(f=!0,E.visible(!0))}),g&&this.roomLayer.batchDraw(),f&&this.linkLayer.batchDraw(),this.visibleRooms=new Set(this.roomNodes.values()),this.visibleStandaloneExitNodes=new Set(this.standaloneExitNodes);return}if(M==="basic"){const x=new Set;this.roomNodes.forEach(v=>{const O=v.room.x-s,C=v.room.x+s,D=v.room.y-s,N=v.room.y+s,z=C>=y&&O<=w&&N>=R&&D<=m;v.group.visible()!==z&&(v.group.visible(z),g=!0),v.linkNodes.forEach(A=>{A.visible()!==z&&(A.visible(z),f=!0)}),z&&x.add(v)});const E=new Set;this.standaloneExitNodes.forEach(v=>{const{node:O,bounds:C}=v,D=C.x,N=C.x+C.width,z=C.y,A=C.y+C.height,B=N>=y&&D<=w&&A>=R&&z<=m;O.visible()!==B&&(O.visible(B),f=!0),B&&E.add(v)}),this.visibleRooms=x,this.visibleStandaloneExitNodes=E,g&&this.roomLayer.batchDraw(),f&&this.linkLayer.batchDraw();return}const ge=this.collectRoomCandidates(L,Y,P,H),K=new Set,Q=new Set;ge.forEach(x=>{K.add(x);const E=x.room.x-s,v=x.room.x+s,O=x.room.y-s,C=x.room.y+s,D=v>=y&&E<=w&&C>=R&&O<=m;x.group.visible()!==D&&(x.group.visible(D),g=!0),x.linkNodes.forEach(N=>{N.visible()!==D&&(N.visible(D),f=!0)}),D&&Q.add(x)}),this.visibleRooms.forEach(x=>{K.has(x)||(x.group.visible()&&(x.group.visible(!1),g=!0),x.linkNodes.forEach(E=>{E.visible()&&(E.visible(!1),f=!0)}))}),this.visibleRooms=Q;const me=this.collectStandaloneExitCandidates(L,Y,P,H),U=new Set,J=new Set;me.forEach(x=>{U.add(x);const{node:E,bounds:v}=x,O=v.x,C=v.x+v.width,D=v.y,N=v.y+v.height,z=C>=y&&O<=w&&N>=R&&D<=m;E.visible()!==z&&(E.visible(z),f=!0),z&&J.add(x)}),this.visibleStandaloneExitNodes.forEach(x=>{const{node:E}=x;!U.has(x)&&E.visible()&&(E.visible(!1),f=!0)}),this.visibleStandaloneExitNodes=J,g&&this.roomLayer.batchDraw(),f&&this.linkLayer.batchDraw()}clearCurrentRoomOverlay(){this.currentRoomOverlay.forEach(e=>e.destroy()),this.currentRoomOverlay=[],this.positionLayer.batchDraw()}updateCurrentRoomOverlay(e){if(this.clearCurrentRoomOverlay(),e.area!==this.currentArea||e.z!==this.currentZIndex){this.positionLayer.batchDraw();return}const t=new Map;t.set(e.id,e);const s=[],i=this.currentAreaInstance instanceof X?this.currentAreaInstance:void 0;this.currentAreaInstance&&this.currentZIndex!==void 0&&this.currentAreaInstance.getLinkExits(this.currentZIndex).filter(h=>h.a===e.id||h.b===e.id).forEach(h=>{const d=a.highlightCurrentRoom?this.exitRenderer.renderWithColor(h,W,this.currentZIndex):this.exitRenderer.render(h,this.currentZIndex);d&&s.push(d)});const o=a.highlightCurrentRoom?W:void 0;this.exitRenderer.renderSpecialExits(e,o).forEach(n=>{s.push(n)}),(a.highlightCurrentRoom?this.exitRenderer.renderStubs(e,W):this.exitRenderer.renderStubs(e)).forEach(n=>{s.push(n)}),[...Object.values(e.exits),...Object.values(e.specialExits)].forEach(n=>{const h=this.mapReader.getRoom(n),d=!i||i.hasVisitedRoom(n);h&&h.area===this.currentArea&&h.z===this.currentZIndex&&d&&t.set(n,h)}),s.forEach(n=>{this.positionLayer.add(n),this.currentRoomOverlay.push(n)}),t.forEach((n,h)=>{const d=h===e.id,u=this.createOverlayRoomGroup(n,{stroke:d&&a.highlightCurrentRoom?W:a.lineColor});this.positionLayer.add(u),this.currentRoomOverlay.push(u),this.exitRenderer.renderInnerExits(n).forEach(l=>{this.positionLayer.add(l),this.currentRoomOverlay.push(l)})}),this.positionRender&&this.positionRender.moveToTop(),this.positionLayer.batchDraw()}createOverlayRoomGroup(e,t){const s=new p.Group({x:e.x-a.roomSize/2,y:e.y-a.roomSize/2,listening:!1}),i=this.mapReader.getColorValue(e.env),o=t.stroke,r=a.roomShape==="circle"?new p.Circle({x:a.roomSize/2,y:a.roomSize/2,radius:a.roomSize/2,fill:i,stroke:o,strokeWidth:a.lineWidth}):new p.Rect({x:0,y:0,width:a.roomSize,height:a.roomSize,fill:i,stroke:o,strokeWidth:a.lineWidth});return s.add(r),this.renderSymbol(e,s),s}renderSymbol(e,t){if(e.roomChar!==void 0){const s=new p.Text({x:0,y:0,text:e.roomChar,fontSize:.45,fontStyle:"bold",fill:this.mapReader.getSymbolColor(e.env),align:"center",verticalAlign:"middle",width:a.roomSize,height:a.roomSize});t.add(s)}}renderExits(e){e.forEach(t=>{const s=this.exitRenderer.render(t,this.currentZIndex);if(!s)return;this.linkLayer.add(s);const i=s.getClientRect({relativeTo:this.linkLayer}),o={node:s,bounds:i};this.standaloneExitNodes.push(o),this.addStandaloneExitToSpatialIndex(o)}),this.standaloneExitBoundsRoomSize=a.roomSize}renderLabels(e){e.forEach(t=>{if(a.labelRenderMode==="image"){if(!t.pixMap)return;const s=new Image;s.src=`data:image/png;base64,${t.pixMap}`;const i=new p.Image({x:t.X,y:-t.Y,width:t.Width,height:t.Height,image:s,listening:!1});this.linkLayer.add(i);return}this.renderLabelAsData(t)})}renderLabelAsData(e){const t=new p.Group({listening:!1}),s=new p.Rect({x:e.X,y:-e.Y,width:e.Width,height:e.Height,listening:!1});(e.BgColor?.alpha??0)>0&&!a.transparentLabels?s.fill(this.getLabelColor(e.BgColor)):s.fillEnabled(!1),t.add(s);const i=Math.min(.75,e.Width/Math.max(e.Text.length/2,1)),o=Math.max(.1,Math.min(i,Math.max(e.Height*.9,.1))),r=new p.Text({x:e.X,y:-e.Y,width:e.Width,height:e.Height,text:e.Text,fontSize:o,fillEnabled:!0,fill:this.getLabelColor(e.FgColor),align:"center",verticalAlign:"middle",listening:!1});t.add(r),this.linkLayer.add(t)}getLabelColor(e){const t=(e?.alpha??255)/255,s=i=>Math.min(255,Math.max(0,i??0));return`rgba(${s(e?.r)}, ${s(e?.g)}, ${s(e?.b)}, ${t})`}}const oe={rgbValue:"rgb(114, 1, 0)",symbolColor:[225,225,225]};function re(c){const e=c[0]/255,t=c[1]/255,s=c[2]/255,i=Math.max(e,t,s),o=Math.min(e,t,s);return(i+o)/2}class Me{constructor(e,t){this.rooms={},this.areas={},this.areaSources={},this.explorationEnabled=!1,this.colors={},e.forEach(s=>{s.rooms.forEach(o=>{o.y=-o.y,this.rooms[o.id]=o});const i=parseInt(s.areaId);this.areas[i]=new G(s),this.areaSources[i]=s}),this.colors=t.reduce((s,i)=>({...s,[i.envId]:{rgb:i.colors,rgbValue:`rgb(${i.colors.join(",")})`,symbolColor:re(i.colors)>.41?[25,25,25]:[225,255,255],symbolColorValue:re(i.colors)>.41?"rgb(25,25,25)":"rgb(225,255,255)"}}),{})}getArea(e){return this.areas[e]}getExplorationArea(e){const t=this.areas[e];if(t instanceof X)return t}getAreas(){return Object.values(this.areas)}getRooms(){return Object.values(this.rooms)}getRoom(e){return this.rooms[e]}ensureVisitedRooms(){return this.visitedRooms||(this.visitedRooms=new Set),this.visitedRooms}applyExplorationDecoration(){this.visitedRooms&&Object.entries(this.areaSources).forEach(([e,t])=>{const s=parseInt(e,10);this.areas[s]=new X(t,this.visitedRooms)})}decorateWithExploration(e){return e!==void 0?this.setVisitedRooms(e):this.ensureVisitedRooms(),this.applyExplorationDecoration(),this.explorationEnabled=!0,this.visitedRooms}getVisitedRooms(){return this.visitedRooms}clearExplorationDecoration(){Object.entries(this.areaSources).forEach(([e,t])=>{const s=parseInt(e,10);this.areas[s]=new G(t)}),this.explorationEnabled=!1}isExplorationEnabled(){return this.explorationEnabled}setVisitedRooms(e){return this.visitedRooms=e instanceof Set?e:new Set(e),this.explorationEnabled&&this.applyExplorationDecoration(),this.visitedRooms}addVisitedRoom(e){if(this.explorationEnabled){const i=this.getRoom(e);if(i){const o=this.getExplorationArea(i.area);if(o)return o.addVisitedRoom(e)}}const t=this.ensureVisitedRooms(),s=t.has(e);return t.add(e),!s}addVisitedRooms(e){const t=this.ensureVisitedRooms();let s=0;for(const i of e){if(this.explorationEnabled){const r=this.getRoom(i);if(r){const n=this.getExplorationArea(r.area);if(n){n.addVisitedRoom(i)&&s++;continue}}}const o=t.has(i);t.add(i),o||s++}return s}hasVisitedRoom(e){return this.visitedRooms?.has(e)??!1}getColorValue(e){return this.colors[e]?.rgbValue??oe.rgbValue}getSymbolColor(e,t){const s=this.colors[e]?.symbolColor??oe.symbolColor,i=Math.min(Math.max(t??1,0),1),o=s.join(",");return i!=1?`rgba(${o}, ${i})`:`rgba(${o})`}}function Ce(c){return c&&c.__esModule&&Object.prototype.hasOwnProperty.call(c,"default")?c.default:c}var Z,ne;function De(){if(ne)return Z;ne=1;class c{constructor(){this.keys=new Set,this.queue=[]}sort(){this.queue.sort((t,s)=>t.priority-s.priority)}set(t,s){const i=Number(s);if(isNaN(i))throw new TypeError('"priority" must be a number');return this.keys.has(t)?this.queue.map(o=>(o.key===t&&Object.assign(o,{priority:i}),o)):(this.keys.add(t),this.queue.push({key:t,priority:i})),this.sort(),this.queue.length}next(){const t=this.queue.shift();return this.keys.delete(t.key),t}isEmpty(){return this.queue.length===0}has(t){return this.keys.has(t)}get(t){return this.queue.find(s=>s.key===t)}}return Z=c,Z}var $,ae;function ze(){if(ae)return $;ae=1;function c(e,t){const s=new Map;for(const[i,o]of e)i!==t&&o instanceof Map?s.set(i,c(o,t)):i!==t&&s.set(i,o);return s}return $=c,$}var F,he;function Le(){if(he)return F;he=1;function c(t){const s=Number(t);return!(isNaN(s)||s<=0)}function e(t){const s=new Map;return Object.keys(t).forEach(o=>{const r=t[o];if(r!==null&&typeof r=="object"&&!Array.isArray(r))return s.set(o,e(r));if(!c(r))throw new Error(`Could not add node at key "${o}", make sure it's a valid node`,r);return s.set(o,Number(r))}),s}return F=e,F}var j,le;function Ie(){if(le)return j;le=1;function c(e){if(!(e instanceof Map))throw new Error(`Invalid graph: Expected Map instead found ${typeof e}`);e.forEach((t,s)=>{if(typeof t=="object"&&t instanceof Map){c(t);return}if(typeof t!="number"||t<=0)throw new Error(`Values must be numbers greater than 0. Found value ${t} at ${s}`)})}return j=c,j}var q,ce;function Oe(){if(ce)return q;ce=1;const c=De(),e=ze(),t=Le(),s=Ie();class i{constructor(r){r instanceof Map?(s(r),this.graph=r):r?this.graph=t(r):this.graph=new Map}addNode(r,n){let h;return n instanceof Map?(s(n),h=n):h=t(n),this.graph.set(r,h),this}addVertex(r,n){return this.addNode(r,n)}removeNode(r){return this.graph=e(this.graph,r),this}path(r,n,h={}){if(!this.graph.size)return h.cost?{path:null,cost:0}:null;const d=new Set,u=new c,l=new Map;let b=[],y=0,w=[];if(h.avoid&&(w=[].concat(h.avoid)),w.includes(r))throw new Error(`Starting node (${r}) cannot be avoided`);if(w.includes(n))throw new Error(`Ending node (${n}) cannot be avoided`);for(u.set(r,0);!u.isEmpty();){const R=u.next();if(R.key===n){y=R.priority;let g=R.key;for(;l.has(g);)b.push(g),g=l.get(g);break}d.add(R.key),(this.graph.get(R.key)||new Map).forEach((g,f)=>{if(d.has(f)||w.includes(f))return null;if(!u.has(f))return l.set(f,R.key),u.set(f,R.priority+g);const M=u.get(f).priority,L=R.priority+g;return L<M?(l.set(f,R.key),u.set(f,L)):null})}return b.length?(h.trim?b.shift():b=b.concat([r]),h.reverse||(b=b.reverse()),h.cost?{path:b,cost:y}:b):h.cost?{path:null,cost:0}:null}shortestPath(...r){return this.path(...r)}}return q=i,q}var Ne=Oe();const Pe=Ce(Ne),Ve={1:"north",2:"northeast",3:"northwest",4:"east",5:"west",6:"south",7:"southeast",8:"southwest",9:"up",10:"down",11:"in",12:"out"};class Te{constructor(e){this.cache=new Map,this.mapReader=e,this.graph=this.buildGraph()}buildGraph(){const e={};return this.mapReader.getRooms().forEach(t=>{const s={},i=new Set((t.exitLocks??[]).map(r=>Ve[r]).filter(r=>!!r)),o=new Set(t.mSpecialExitLocks??[]);Object.entries(t.exits??{}).forEach(([r,n])=>{i.has(r)||this.mapReader.getRoom(n)&&(s[n.toString()]=1)}),Object.values(t.specialExits??{}).forEach(r=>{o.has(r)||this.mapReader.getRoom(r)&&(s[r.toString()]=1)}),e[t.id.toString()]=s}),new Pe(e)}findPath(e,t){const s=`${e}->${t}`;if(this.cache.has(s))return this.cache.get(s);if(e===t){const n=this.mapReader.getRoom(e)?[e]:null;return this.cache.set(s,n),n}if(!this.mapReader.getRoom(e)||!this.mapReader.getRoom(t))return this.cache.set(s,null),null;const i=this.graph.path(e.toString(),t.toString()),o=Array.isArray(i)?i:i?.path,r=o?o.map(n=>Number(n)):null;return this.cache.set(s,r),r}}exports.ExplorationArea=X;exports.MapReader=Me;exports.PathFinder=Te;exports.Renderer=ke;exports.Settings=a;
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const m=require("konva"),it=["north","south","east","west","northeast","northwest","southeast","southwest"],O={north:"n",south:"s",east:"e",west:"w",northeast:"ne",northwest:"nw",southeast:"se",southwest:"sw",up:"u",down:"d",in:"i",out:"o"},Q={north:{x:0,y:-1},south:{x:0,y:1},east:{x:1,y:0},west:{x:-1,y:0},northeast:{x:1,y:-1},northwest:{x:-1,y:-1},southeast:{x:1,y:1},southwest:{x:-1,y:1}},K=["north","south","east","west","northeast","northwest","southeast","southwest"],gt={north:"south",south:"north",east:"west",west:"east",northeast:"southwest",northwest:"southeast",southeast:"northwest",southwest:"northeast"};function ft(f){return f?Object.prototype.hasOwnProperty.call(Q,f):!1}function C(f,t,e,s=1){if(!ft(e))return{x:f,y:t};const i=Q[e];return{x:f+i.x*s,y:t+i.y*s}}function yt(f,t,e,s=1){if(!ft(e))return{x:f,y:t};const i=Q[e],o=Math.atan2(i.y,i.x);return{x:f+Math.cos(o)*s,y:t+Math.sin(o)*s}}const Y={OPEN_DOOR:"rgb(10, 155, 10)",CLOSED_DOOR:"rgb(226, 205, 59)",LOCKED_DOOR:"rgb(155, 10, 10)",ONE_WAY_FILL:"rgb(155, 10, 10)"},wt={1:"north",2:"northeast",3:"northwest",4:"east",5:"west",6:"south",7:"southeast",8:"southwest",9:"up",10:"down",11:"in",12:"out"},Rt=["up","down","in","out"];function bt(f){switch(f){case 1:return Y.OPEN_DOOR;case 2:return Y.CLOSED_DOOR;default:return Y.LOCKED_DOOR}}class vt{constructor(t,e){this.mapReader=t,this.mapRenderer=e}getRoomEdgePoint(t,e,s,i){return h.roomShape==="circle"?yt(t,e,s,i):C(t,e,s,i)}render(t,e){return this.renderWithColor(t,h.lineColor,e)}renderWithColor(t,e,s){return t.aDir&&t.bDir?this.renderTwoWayExit(t,e,s):this.renderOneWayExit(t,e)}renderTwoWayExit(t,e,s){const i=this.mapReader.getRoom(t.a),o=this.mapReader.getRoom(t.b);if(!i||!o||!t.aDir||!t.bDir||!it.includes(t.aDir)||!it.includes(t.bDir)||i.customLines[O[t.aDir]]&&o.customLines[O[t.bDir]]||i.z!==o.z&&(s!==o.z&&i.customLines[O[t.aDir]]||s!==i.z&&o.customLines[O[t.bDir]]))return;const r=new m.Group,n=[];if(n.push(...Object.values(this.getRoomEdgePoint(i.x,i.y,t.aDir,h.roomSize/2))),n.push(...Object.values(this.getRoomEdgePoint(o.x,o.y,t.bDir,h.roomSize/2))),i.doors[O[t.aDir]]||o.doors[O[t.bDir]]){const d=this.renderDoor(n,i.doors[O[t.aDir]]??o.doors[O[t.bDir]]);r.add(d)}const a=new m.Line({points:n,stroke:e,strokeWidth:h.lineWidth,perfectDrawEnabled:!1});return r.add(a),r}renderOneWayExit(t,e){const s=t.aDir?this.mapReader.getRoom(t.a):this.mapReader.getRoom(t.b),i=t.aDir?this.mapReader.getRoom(t.b):this.mapReader.getRoom(t.a),o=t.aDir?t.aDir:t.bDir;if(!o||!s||!i||s.customLines[O[o]||o])return;if(s.area!=i.area&&o)return this.renderAreaExit(s,o,e);let r={x:i.x,y:i.y};(i.area!==s.area||i.z!==s.z)&&(r=C(s.x,s.y,o,h.roomSize/2));const n=C(s.x,s.y,o,.3),a=n.x-(n.x-r.x)/2,d=n.y-(n.y-r.y)/2,l=new m.Group,c=[];c.push(...Object.values(this.getRoomEdgePoint(s.x,s.y,o,h.roomSize/2))),c.push(r.x,r.y);const u=new m.Line({points:c,stroke:e,strokeWidth:h.lineWidth,dashEnabled:!0,dash:[.1,.05],perfectDrawEnabled:!1});l.add(u);const g=new m.Arrow({points:[c[0],c[1],a,d],pointerLength:.5,pointerWidth:.35,strokeWidth:h.lineWidth*1.4,stroke:e,fill:Y.ONE_WAY_FILL,dashEnabled:!0,dash:[.1,.05]});return l.add(g),l}renderAreaExit(t,e,s){const i=this.getRoomEdgePoint(t.x,t.y,e,h.roomSize/2),o=C(t.x,t.y,e,h.roomSize*1.5),r=s??this.mapReader.getColorValue(t.env);return new m.Arrow({points:[i.x,i.y,o.x,o.y],pointerLength:.3,pointerWidth:.3,strokeWidth:h.lineWidth*1.4,stroke:r,fill:r})}renderSpecialExits(t,e){return Object.entries(t.customLines).map(([s,i])=>{const o=[t.x,t.y];i.points.reduce((l,c)=>(l.push(c.x,-c.y),l),o);const r=i.attributes.arrow?m.Arrow:m.Line,n=e??`rgb(${i.attributes.color.r}, ${i.attributes.color.g}, ${i.attributes.color.b})`,a=new r({points:o,strokeWidth:h.lineWidth,stroke:n,fill:e??`rgb(${i.attributes.color.r}, ${i.attributes.color.g} , ${i.attributes.color.b})`,pointerLength:.3,pointerWidth:.2,perfectDrawEnabled:!1});let d=i.attributes.style;return d==="dot line"?(a.dash([.05,.05]),a.dashOffset(.1)):d==="dash line"?a.dash([.4,.2]):d==="solid line"||d!==void 0&&console.log("Brak opisu stylu: "+d),a})}renderStubs(t,e=h.lineColor){return t.stubs.map(s=>{const i=wt[s],o=this.getRoomEdgePoint(t.x,t.y,i,h.roomSize/2),r=C(t.x,t.y,i,h.roomSize/2+.5),n=[o.x,o.y,r.x,r.y];return new m.Line({points:n,stroke:e,strokeWidth:h.lineWidth})})}renderInnerExits(t){return Rt.map(e=>{if(t.exits[e]){const s=new m.Group,i=new m.RegularPolygon({x:t.x,y:t.y,sides:3,fill:this.mapReader.getSymbolColor(t.env,.6),stroke:this.mapReader.getSymbolColor(t.env),strokeWidth:h.lineWidth,radius:h.roomSize/5,scaleX:1.4,scaleY:.8,perfectDrawEnabled:!1});s.add(i);let o=t.doors[e];if(o!==void 0)switch(o){case 1:i.stroke(Y.OPEN_DOOR);break;case 2:i.stroke(Y.CLOSED_DOOR);break;default:i.stroke(Y.LOCKED_DOOR)}switch(e){case"up":i.position(C(t.x,t.y,"south",h.roomSize/4));break;case"down":i.rotation(180),i.position(C(t.x,t.y,"north",h.roomSize/4));break;case"in":const r=i.clone();r.rotation(-90),r.position(C(t.x,t.y,"east",h.roomSize/4)),s.add(r),i.rotation(90),i.position(C(t.x,t.y,"west",h.roomSize/4));break;case"out":const n=i.clone();n.rotation(90),n.position(C(t.x,t.y,"east",h.roomSize/4)),s.add(n),i.rotation(-90),i.position(C(t.x,t.y,"west",h.roomSize/4));break}return s}}).filter(e=>e!==void 0)}renderDoor(t,e){const s={x:t[0]+(t[2]-t[0])/2,y:t[1]+(t[3]-t[1])/2};return new m.Rect({x:s.x-h.roomSize/4,y:s.y-h.roomSize/4,width:h.roomSize/2,height:h.roomSize/2,stroke:bt(e),strokeWidth:h.lineWidth})}}class mt{constructor(t,e){this.rooms=[],this.labels=[],this.rooms=t,this.bounds=this.createBounds(),this.labels=e}getRooms(){return this.rooms}getLabels(){return this.labels}getBounds(){return this.bounds}createBounds(){return this.rooms.reduce((t,e)=>({minX:Math.min(t.minX,e.x),maxX:Math.max(t.maxX,e.x),minY:Math.min(t.minY,e.y),maxY:Math.max(t.maxY,e.y)}),{minX:Number.POSITIVE_INFINITY,maxX:Number.NEGATIVE_INFINITY,minY:Number.POSITIVE_INFINITY,maxY:Number.NEGATIVE_INFINITY})}}class _{constructor(t){this.planes={},this.exits=new Map,this.version=0,this.area=t,this.planes=this.createPlanes(),this.createExits()}getAreaName(){return this.area.areaName}getAreaId(){return parseInt(this.area.areaId)}getVersion(){return this.version}markDirty(){this.version++}getPlane(t){return this.planes[t]}getPlanes(){return Object.values(this.planes)}getRooms(){return this.area.rooms}getLinkExits(t){return Array.from(this.exits.values()).filter(e=>e.zIndex.includes(t))}createPlanes(){const t=this.area.rooms.reduce((e,s)=>(e[s.z]||(e[s.z]=[]),e[s.z].push(s),e),{});return Object.entries(t).reduce((e,[s,i])=>(e[+s]=new mt(i,this.area.labels.filter(o=>o.Z===+s)),e),{})}createExits(){this.area.rooms.forEach(t=>{Object.entries(t.specialExits).forEach(([e,s])=>this.createHalfExit(t.id,s,t.z,e)),Object.entries(t.exits).forEach(([e,s])=>this.createHalfExit(t.id,s,t.z,e))})}createHalfExit(t,e,s,i){if(t===e)return;const o=Math.min(t,e),r=Math.max(t,e),n=`${o}-${r}`;let a=this.exits.get(n);a||(a={a:o,b:r,zIndex:[s]}),o==t?a.aDir=i:a.bDir=i,a.zIndex.push(s),this.exits.set(n,a)}}class ot extends mt{constructor(t,e){super(t.getRooms(),t.getLabels()),this.basePlane=t,this.visitedRooms=e}getRooms(){return this.basePlane.getRooms().filter(t=>this.visitedRooms.has(t.id))}getLabels(){return this.basePlane.getLabels()}getBounds(){const t=this.getRooms();return t.length?t.reduce((e,s)=>({minX:Math.min(e.minX,s.x),maxX:Math.max(e.maxX,s.x),minY:Math.min(e.minY,s.y),maxY:Math.max(e.maxY,s.y)}),{minX:Number.POSITIVE_INFINITY,maxX:Number.NEGATIVE_INFINITY,minY:Number.POSITIVE_INFINITY,maxY:Number.NEGATIVE_INFINITY}):this.basePlane.getBounds()}}class B extends _{constructor(t,e){super(t),this.planeCache=new WeakMap,this.visitedRooms=e instanceof Set?e:new Set(e??[]),this.areaRoomIds=new Set(t.rooms.map(s=>s.id))}getPlane(t){const e=super.getPlane(t);if(!e)return e;let s=this.planeCache.get(e);return s||(s=new ot(e,this.visitedRooms),this.planeCache.set(e,s)),s}getPlanes(){return super.getPlanes().map(t=>{let e=this.planeCache.get(t);return e||(e=new ot(t,this.visitedRooms),this.planeCache.set(t,e)),e})}getLinkExits(t){return super.getLinkExits(t).filter(e=>this.visitedRooms.has(e.a)||this.visitedRooms.has(e.b))}getVisitedRoomCount(){return super.getRooms().reduce((t,e)=>t+(this.visitedRooms.has(e.id)?1:0),0)}getTotalRoomCount(){return this.areaRoomIds.size}hasVisitedRoom(t){return this.areaRoomIds.has(t)&&this.visitedRooms.has(t)}getVisitedRoomIds(){return super.getRooms().filter(t=>this.visitedRooms.has(t.id)).map(t=>t.id)}addVisitedRoom(t){const e=this.visitedRooms.has(t);this.visitedRooms.add(t);const s=!e&&this.areaRoomIds.has(t);return s&&this.markDirty(),s}addVisitedRooms(t){let e=0;for(const s of t){const i=this.visitedRooms.has(s);this.visitedRooms.add(s),!i&&this.areaRoomIds.has(s)&&e++}return e>0&&this.markDirty(),e}}class Et{constructor(t,e){this.paths=[],this.mapReader=t,this.overlayLayer=e}renderPath(t,e,s,i="#66E64D"){if(e===void 0||s===void 0)return;const o=t.map(c=>this.mapReader.getRoom(c)).filter(c=>c!==void 0),r=[];let n=null;const a=()=>{n&&(n.length<4&&r.pop(),n=null)},d=()=>(n||(n=[],r.push(n)),n);o.forEach((c,u)=>{if(!this.isRoomVisible(c,e,s))return;const g=u>0?o[u-1]:void 0,y=u<o.length-1?o[u+1]:void 0;if(this.isRoomVisible(g,e,s))d();else{a();const x=d();if(g){const w=this.getDirectionTowards(c,g);if(w){const I=C(c.x,c.y,w,h.roomSize);x.push(I.x,I.y)}}}if(n?.push(c.x,c.y),!this.isRoomVisible(y,e,s)&&y){const x=this.getDirectionTowards(c,y);if(x){const w=C(c.x,c.y,x,h.roomSize);n?.push(w.x,w.y)}a()}}),a();const l=r.filter(c=>c.length>=4).map(c=>new m.Line({points:c,stroke:i,strokeWidth:h.lineWidth*4}));return l.forEach(c=>{this.overlayLayer.add(c),this.paths.push(c)}),l[0]}clearPaths(){this.paths.forEach(t=>{t.destroy()}),this.paths=[]}isRoomVisible(t,e,s){return t?t.area===e&&t.z===s:!1}getDirectionTowards(t,e){for(const s of K)if(t.exits[s]===e.id)return s;for(const s of K)if(e.exits[s]===t.id)return gt[s]}}const St=.6,X=75,Ct=.025,kt="rgb(225, 255, 225)",Z="rgb(120, 72, 0)";function rt(f,t){const e=parseInt(f.slice(1,3),16),s=parseInt(f.slice(3,5),16),i=parseInt(f.slice(5,7),16);return`rgba(${e}, ${s}, ${i}, ${t})`}const k=class k{};k.roomSize=St,k.lineWidth=Ct,k.lineColor=kt,k.instantMapMove=!1,k.highlightCurrentRoom=!0,k.cullingEnabled=!0,k.cullingMode="indexed",k.cullingBounds=null,k.labelRenderMode="image",k.roomShape="rectangle",k.playerMarker={strokeColor:"#00e5b2",strokeAlpha:1,fillColor:"#00e5b2",fillAlpha:0,strokeWidth:.1,sizeFactor:1.7,dash:[.05,.05],dashEnabled:!0};let h=k;class It{constructor(t,e){this.highlights=new Map,this.currentZoom=1,this.currentRoomOverlay=[],this.roomNodes=new Map,this.standaloneExitNodes=[],this.spatialBucketSize=5,this.roomSpatialIndex=new Map,this.exitSpatialIndex=new Map,this.visibleRooms=new Set,this.visibleStandaloneExitNodes=new Set,this.cullingScheduled=!1,this.stage=new m.Stage({container:t,width:t.clientWidth,height:t.clientHeight,draggable:!0}),window.addEventListener("resize",()=>{this.onResize(t)}),t.addEventListener("resize",()=>{this.onResize(t)}),this.linkLayer=new m.Layer({listening:!1}),this.stage.add(this.linkLayer),this.roomLayer=new m.Layer,this.stage.add(this.roomLayer),this.positionLayer=new m.Layer({listening:!1}),this.stage.add(this.positionLayer),this.overlayLayer=new m.Layer({listening:!1}),this.stage.add(this.overlayLayer),this.mapReader=e,this.exitRenderer=new vt(e,this),this.pathRenderer=new Et(e,this.overlayLayer),this.initScaling(1.1),this.stage.on("dragmove",()=>this.scheduleRoomCulling()),this.stage.on("dragend",()=>this.scheduleRoomCulling())}onResize(t){this.stage.width(t.clientWidth),this.stage.height(t.clientHeight),this.currentRoomId&&this.centerOnRoom(this.mapReader.getRoom(this.currentRoomId),!1),this.stage.batchDraw(),this.scheduleRoomCulling()}initScaling(t){m.hitOnDragEnabled=!0;let e,s=!1,i=!1;this.stage.on("touchstart",o=>{const r=o.evt.touches;r&&r.length>1?(i=!0,this.stage.isDragging()&&(this.stage.stopDrag(),s=!0),this.stage.draggable(!1)):(i=!1,this.stage.draggable(!0))}),this.stage.on("touchend touchcancel",o=>{e=void 0;const r=o.evt.touches;(!r||r.length<=1)&&(i=!1,this.stage.draggable(!0))}),this.stage.on("wheel",o=>{o.evt.preventDefault();const r=this.stage.scaleX(),n=this.stage.getPointerPosition();if(!n)return;const a={x:(n.x-this.stage.x())/r,y:(n.y-this.stage.y())/r};let d=o.evt.deltaY>0?-1:1;o.evt.ctrlKey&&(d=-d);const l=d>0?this.currentZoom*t:this.currentZoom/t,c=l*X,u=this.setZoom(l),g={x:n.x-a.x*c,y:n.y-a.y*c};this.stage.position(g),this.scheduleRoomCulling(),u&&this.emitZoomChangeEvent()}),this.stage.on("touchmove",o=>{const r=o.evt.touches,n=r?.[0],a=r?.[1];if(a||i&&(i=!1,this.stage.draggable(!0)),n&&!a&&s&&!this.stage.isDragging()&&(this.stage.startDrag(),s=!1),!n||!a){e=void 0;return}o.evt.preventDefault(),this.stage.isDragging()&&(this.stage.stopDrag(),s=!0),i||(i=!0,this.stage.draggable(!1));const d=this.stage.container().getBoundingClientRect(),l={x:n.clientX-d.left,y:n.clientY-d.top},c={x:a.clientX-d.left,y:a.clientY-d.top},u=Math.hypot(l.x-c.x,l.y-c.y);if(e===void 0){e=u;return}if(e===0)return;const g=this.stage.scaleX(),y=this.stage.x(),R=this.stage.y(),p={x:this.stage.width()/2,y:this.stage.height()/2},x={x:(p.x-y)/g,y:(p.y-R)/g},w=this.currentZoom*(u/e),I=this.setZoom(w),z=this.stage.scaleX(),V={x:p.x-x.x*z,y:p.y-x.y*z};this.stage.position(V),this.stage.batchDraw(),this.scheduleRoomCulling(),e=u,I&&this.emitZoomChangeEvent()})}drawArea(t,e){const s=this.mapReader.getArea(t);if(!s)return;const i=s.getPlane(e);i&&(this.currentArea=t,this.currentAreaInstance=s,this.currentZIndex=e,this.currentAreaVersion=s.getVersion(),this.clearCurrentRoomOverlay(),this.roomLayer.destroyChildren(),this.linkLayer.destroyChildren(),this.roomNodes.clear(),this.standaloneExitNodes=[],this.standaloneExitBoundsRoomSize=void 0,this.roomSpatialIndex.clear(),this.exitSpatialIndex.clear(),this.visibleRooms.clear(),this.visibleStandaloneExitNodes.clear(),this.spatialBucketSize=this.computeSpatialBucketSize(),this.stage.scale({x:X*this.currentZoom,y:X*this.currentZoom}),this.renderLabels(i.getLabels()),this.renderExits(s.getLinkExits(e)),this.renderRooms(i.getRooms()??[]),this.refreshHighlights(),this.stage.batchDraw(),this.scheduleRoomCulling())}computeSpatialBucketSize(){return Math.max(h.roomSize*10,5)}getBucketKey(t,e){return`${t},${e}`}forEachBucket(t,e,s,i,o){const r=this.spatialBucketSize,n=Math.min(t,s),a=Math.max(t,s),d=Math.min(e,i),l=Math.max(e,i),c=Math.floor(n/r),u=Math.floor(a/r),g=Math.floor(d/r),y=Math.floor(l/r);for(let R=c;R<=u;R++)for(let p=g;p<=y;p++)o(this.getBucketKey(R,p))}addRoomToSpatialIndex(t){const e=h.roomSize/2,s=t.room.x-e,i=t.room.x+e,o=t.room.y-e,r=t.room.y+e;this.forEachBucket(s,o,i,r,n=>{let a=this.roomSpatialIndex.get(n);a||(a=new Set,this.roomSpatialIndex.set(n,a)),a.add(t)})}addStandaloneExitToSpatialIndex(t){const{bounds:e}=t,s=e.x,i=e.x+e.width,o=e.y,r=e.y+e.height;this.forEachBucket(s,o,i,r,n=>{let a=this.exitSpatialIndex.get(n);a||(a=new Set,this.exitSpatialIndex.set(n,a)),a.add(t)})}collectRoomCandidates(t,e,s,i){const o=new Set;return this.forEachBucket(t,e,s,i,r=>{this.roomSpatialIndex.get(r)?.forEach(a=>o.add(a))}),o}collectStandaloneExitCandidates(t,e,s,i){const o=new Set;return this.forEachBucket(t,e,s,i,r=>{this.exitSpatialIndex.get(r)?.forEach(a=>o.add(a))}),o}refreshStandaloneExitBoundsIfNeeded(){this.standaloneExitBoundsRoomSize!==h.roomSize&&(this.exitSpatialIndex.clear(),this.standaloneExitNodes.forEach(t=>{t.bounds=t.node.getClientRect({relativeTo:this.linkLayer}),this.addStandaloneExitToSpatialIndex(t)}),this.standaloneExitBoundsRoomSize=h.roomSize)}emitRoomContextEvent(t,e,s){const i=this.stage.container(),o=i.getBoundingClientRect(),r={roomId:t,position:{x:e-o.left,y:s-o.top}},n=new CustomEvent("roomcontextmenu",{detail:r});i.dispatchEvent(n)}emitZoomChangeEvent(){const t=new CustomEvent("zoom",{detail:{zoom:this.currentZoom}});this.stage.container().dispatchEvent(t)}setZoom(t){return this.currentZoom===t?!1:(this.currentZoom=t,this.stage.scale({x:X*t,y:X*t}),this.scheduleRoomCulling(),!0)}getZoom(){return this.currentZoom}setCullingMode(t){h.cullingMode=t,h.cullingEnabled=t!=="none",this.scheduleRoomCulling()}getCullingMode(){return h.cullingMode}getCurrentArea(){return this.currentArea?this.mapReader.getArea(this.currentArea):void 0}refreshCurrentRoomOverlay(){if(this.currentRoomId!==void 0){const t=this.mapReader.getRoom(this.currentRoomId);t&&this.updateCurrentRoomOverlay(t)}}refresh(){this.currentRoomId!==void 0&&this.currentArea!==void 0&&this.currentZIndex!==void 0&&(this.drawArea(this.currentArea,this.currentZIndex),this.setPosition(this.currentRoomId))}setPosition(t){const e=this.mapReader.getRoom(t);if(!e)return;const s=this.mapReader.getArea(e.area),i=s?.getVersion();let o=this.currentArea!==e.area||this.currentZIndex!==e.z;(this.currentArea!==e.area||this.currentZIndex!==e.z||i!==void 0&&this.currentAreaVersion!==i||s!==void 0&&this.currentAreaInstance!==s)&&this.drawArea(e.area,e.z),this.centerOnRoom(e,o),this.updateCurrentRoomOverlay(e);const r=rt(h.playerMarker.strokeColor,h.playerMarker.strokeAlpha),n=rt(h.playerMarker.fillColor,h.playerMarker.fillAlpha),a=h.roomSize/2*h.playerMarker.sizeFactor;this.positionRender?(this.positionRender.radius(a),this.positionRender.stroke(r),this.positionRender.fill(n),this.positionRender.strokeWidth(h.playerMarker.strokeWidth),this.positionRender.dash(h.playerMarker.dash??[]),this.positionRender.dashEnabled(h.playerMarker.dashEnabled)):(this.positionRender=new m.Circle({x:e.x,y:e.y,radius:a,stroke:r,fill:n,strokeWidth:h.playerMarker.strokeWidth,dash:h.playerMarker.dash,dashEnabled:h.playerMarker.dashEnabled}),this.positionLayer.add(this.positionRender))}renderPath(t,e){return this.pathRenderer.renderPath(t,this.currentArea,this.currentZIndex,e)}clearPaths(){this.pathRenderer.clearPaths()}renderHighlight(t,e){const s=this.mapReader.getRoom(t);if(!s)return;const i=this.highlights.get(t);i?.shape&&(i.shape.destroy(),delete i.shape);const o={color:e,area:s.area,z:s.z};if(this.highlights.set(t,o),s.area===this.currentArea&&s.z===this.currentZIndex){const r=this.createHighlightShape(s,e);return this.overlayLayer.add(r),o.shape=r,this.overlayLayer.batchDraw(),r}return o.shape}clearHighlights(){this.highlights.forEach(({shape:t})=>t?.destroy()),this.highlights.clear(),this.overlayLayer.batchDraw()}refreshHighlights(){this.highlights.forEach((t,e)=>{if(t.shape?.destroy(),delete t.shape,t.area!==this.currentArea||t.z!==this.currentZIndex)return;const s=this.mapReader.getRoom(e);if(!s)return;const i=this.createHighlightShape(s,t.color);this.overlayLayer.add(i),t.shape=i}),this.overlayLayer.batchDraw()}createHighlightShape(t,e){return h.roomShape==="circle"?new m.Circle({x:t.x,y:t.y,radius:h.roomSize/2*1.5,stroke:e,strokeWidth:.1,dash:[.05,.05],dashEnabled:!0,listening:!1}):new m.Rect({x:t.x-h.roomSize/2*1.5,y:t.y-h.roomSize/2*1.5,width:h.roomSize*1.5,height:h.roomSize*1.5,stroke:e,strokeWidth:.1,dash:[.05,.05],dashEnabled:!0,listening:!1})}centerOnRoom(t,e=!1){this.currentRoomId=t.id;const s={x:t.x,y:t.y};this.positionRender?.position(t);const o=this.stage.getAbsoluteTransform().point(s),r={x:this.stage.width()/2,y:this.stage.height()/2},n=r.x-o.x,a=r.y-o.y;this.currentTransition&&(this.currentTransition.pause(),this.currentTransition.destroy(),delete this.currentTransition),e||h.instantMapMove?(this.stage.position({x:this.stage.x()+n,y:this.stage.y()+a}),this.scheduleRoomCulling()):(this.currentTransition=new m.Tween({node:this.stage,x:this.stage.x()+n,y:this.stage.y()+a,duration:.2,easing:m.Easings.EaseInOut,onUpdate:()=>this.scheduleRoomCulling(),onFinish:()=>this.scheduleRoomCulling()}),this.currentTransition.play())}renderRooms(t){t.forEach(e=>{const s=new m.Group({x:e.x-h.roomSize/2,y:e.y-h.roomSize/2}),i=this.mapReader.getColorValue(e.env),o=h.lineColor,n=h.roomShape==="circle"?new m.Circle({x:h.roomSize/2,y:h.roomSize/2,radius:h.roomSize/2,fill:i,strokeWidth:h.lineWidth,stroke:o,perfectDrawEnabled:!1}):new m.Rect({x:0,y:0,width:h.roomSize,height:h.roomSize,fill:i,strokeWidth:h.lineWidth,stroke:o,perfectDrawEnabled:!1}),a=(p,x)=>this.emitRoomContextEvent(e.id,p,x);s.on("mouseenter",()=>{this.stage.container().style.cursor="pointer"}),s.on("mouseleave",()=>{this.stage.container().style.cursor="auto"}),s.on("contextmenu",p=>{p.evt.preventDefault();const x=p.evt;a(x.clientX,x.clientY)});let d,l,c;const u=()=>{c!==void 0&&(this.stage.draggable(c),c=void 0)},g=()=>{d!==void 0&&(window.clearTimeout(d),d=void 0),l=void 0,u()};s.on("touchstart",p=>{if(g(),p.evt.touches&&p.evt.touches.length>1)return;const x=p.evt.touches?.[0];x&&(l={clientX:x.clientX,clientY:x.clientY},c=this.stage.draggable(),this.stage.draggable(!1),d=window.setTimeout(()=>{l&&a(l.clientX,l.clientY),g()},500))}),s.on("touchend",g),s.on("touchmove",p=>{if(!l)return;const x=p.evt.touches?.[0];if(!x){g();return}const w=x.clientX-l.clientX,I=x.clientY-l.clientY,z=w*w+I*I,V=10;if(z>V*V){const T=c;g(),T&&this.stage.startDrag()}}),s.on("touchcancel",g),s.add(n),this.renderSymbol(e,s),this.roomLayer.add(s);const y=[];this.exitRenderer.renderSpecialExits(e).forEach(p=>{this.linkLayer.add(p);const x=p.getClientRect({relativeTo:this.linkLayer}),w={node:p,bounds:x};this.standaloneExitNodes.push(w),this.addStandaloneExitToSpatialIndex(w)}),this.exitRenderer.renderStubs(e).forEach(p=>{this.linkLayer.add(p),y.push(p)}),this.exitRenderer.renderInnerExits(e).forEach(p=>{this.roomLayer.add(p)});const R={room:e,group:s,linkNodes:y};this.roomNodes.set(e.id,R),this.addRoomToSpatialIndex(R)})}scheduleRoomCulling(){this.cullingScheduled||(this.cullingScheduled=!0,window.requestAnimationFrame(()=>{this.cullingScheduled=!1,this.updateRoomCulling()}))}updateRoomCulling(){if(this.roomNodes.size===0&&this.standaloneExitNodes.length===0)return;const t=this.stage.scaleX();if(!t)return;const e=this.stage.position(),s=h.roomSize/2,i=h.cullingBounds,o=i?i.x:0,r=i?i.x+i.width:this.stage.width(),n=i?i.y:0,a=i?i.y+i.height:this.stage.height(),d=Math.min(o,r),l=Math.max(o,r),c=Math.min(n,a),u=Math.max(n,a),g=(d-e.x)/t,y=(l-e.x)/t,R=(c-e.y)/t,p=(u-e.y)/t;let x=!1,w=!1;const I=h.cullingEnabled?h.cullingMode??"indexed":"none",z=g-s,V=y+s,T=R-s,U=p+s;if(this.refreshStandaloneExitBoundsIfNeeded(),I==="none"){this.roomNodes.forEach(b=>{b.group.visible()||(b.group.visible(!0),x=!0),b.linkNodes.forEach(S=>{S.visible()||(S.visible(!0),w=!0)})}),this.standaloneExitNodes.forEach(b=>{const{node:S}=b;S.visible()||(w=!0,S.visible(!0))}),x&&this.roomLayer.batchDraw(),w&&this.linkLayer.batchDraw(),this.visibleRooms=new Set(this.roomNodes.values()),this.visibleStandaloneExitNodes=new Set(this.standaloneExitNodes);return}if(I==="basic"){const b=new Set;this.roomNodes.forEach(E=>{const A=E.room.x-s,M=E.room.x+s,L=E.room.y-s,P=E.room.y+s,N=M>=g&&A<=y&&P>=R&&L<=p;E.group.visible()!==N&&(E.group.visible(N),x=!0),E.linkNodes.forEach(W=>{W.visible()!==N&&(W.visible(N),w=!0)}),N&&b.add(E)});const S=new Set;this.standaloneExitNodes.forEach(E=>{const{node:A,bounds:M}=E,L=M.x,P=M.x+M.width,N=M.y,W=M.y+M.height,F=P>=g&&L<=y&&W>=R&&N<=p;A.visible()!==F&&(A.visible(F),w=!0),F&&S.add(E)}),this.visibleRooms=b,this.visibleStandaloneExitNodes=S,x&&this.roomLayer.batchDraw(),w&&this.linkLayer.batchDraw();return}const pt=this.collectRoomCandidates(z,T,V,U),J=new Set,tt=new Set;pt.forEach(b=>{J.add(b);const S=b.room.x-s,E=b.room.x+s,A=b.room.y-s,M=b.room.y+s,L=E>=g&&S<=y&&M>=R&&A<=p;b.group.visible()!==L&&(b.group.visible(L),x=!0),b.linkNodes.forEach(P=>{P.visible()!==L&&(P.visible(L),w=!0)}),L&&tt.add(b)}),this.visibleRooms.forEach(b=>{J.has(b)||(b.group.visible()&&(b.group.visible(!1),x=!0),b.linkNodes.forEach(S=>{S.visible()&&(S.visible(!1),w=!0)}))}),this.visibleRooms=tt;const xt=this.collectStandaloneExitCandidates(z,T,V,U),et=new Set,st=new Set;xt.forEach(b=>{et.add(b);const{node:S,bounds:E}=b,A=E.x,M=E.x+E.width,L=E.y,P=E.y+E.height,N=M>=g&&A<=y&&P>=R&&L<=p;S.visible()!==N&&(S.visible(N),w=!0),N&&st.add(b)}),this.visibleStandaloneExitNodes.forEach(b=>{const{node:S}=b;!et.has(b)&&S.visible()&&(S.visible(!1),w=!0)}),this.visibleStandaloneExitNodes=st,x&&this.roomLayer.batchDraw(),w&&this.linkLayer.batchDraw()}clearCurrentRoomOverlay(){this.currentRoomOverlay.forEach(t=>t.destroy()),this.currentRoomOverlay=[],this.positionLayer.batchDraw()}updateCurrentRoomOverlay(t){if(this.clearCurrentRoomOverlay(),t.area!==this.currentArea||t.z!==this.currentZIndex){this.positionLayer.batchDraw();return}const e=new Map;e.set(t.id,t);const s=[],i=this.currentAreaInstance instanceof B?this.currentAreaInstance:void 0;this.currentAreaInstance&&this.currentZIndex!==void 0&&this.currentAreaInstance.getLinkExits(this.currentZIndex).filter(a=>a.a===t.id||a.b===t.id).forEach(a=>{const d=h.highlightCurrentRoom?this.exitRenderer.renderWithColor(a,Z,this.currentZIndex):this.exitRenderer.render(a,this.currentZIndex);d&&s.push(d)});const o=h.highlightCurrentRoom?Z:void 0;this.exitRenderer.renderSpecialExits(t,o).forEach(n=>{s.push(n)}),(h.highlightCurrentRoom?this.exitRenderer.renderStubs(t,Z):this.exitRenderer.renderStubs(t)).forEach(n=>{s.push(n)}),[...Object.values(t.exits),...Object.values(t.specialExits)].forEach(n=>{const a=this.mapReader.getRoom(n),d=!i||i.hasVisitedRoom(n);a&&a.area===this.currentArea&&a.z===this.currentZIndex&&d&&e.set(n,a)}),s.forEach(n=>{this.positionLayer.add(n),this.currentRoomOverlay.push(n)}),e.forEach((n,a)=>{const d=a===t.id,l=this.createOverlayRoomGroup(n,{stroke:d&&h.highlightCurrentRoom?Z:h.lineColor});this.positionLayer.add(l),this.currentRoomOverlay.push(l),this.exitRenderer.renderInnerExits(n).forEach(c=>{this.positionLayer.add(c),this.currentRoomOverlay.push(c)})}),this.positionRender&&this.positionRender.moveToTop(),this.positionLayer.batchDraw()}createOverlayRoomGroup(t,e){const s=new m.Group({x:t.x-h.roomSize/2,y:t.y-h.roomSize/2,listening:!1}),i=this.mapReader.getColorValue(t.env),o=e.stroke,r=h.roomShape==="circle"?new m.Circle({x:h.roomSize/2,y:h.roomSize/2,radius:h.roomSize/2,fill:i,stroke:o,strokeWidth:h.lineWidth}):new m.Rect({x:0,y:0,width:h.roomSize,height:h.roomSize,fill:i,stroke:o,strokeWidth:h.lineWidth});return s.add(r),this.renderSymbol(t,s),s}renderSymbol(t,e){if(t.roomChar!==void 0){const s=h.roomSize*.75,i=new m.Text({x:0,y:0,text:t.roomChar,fontSize:s,fontStyle:"bold",fill:this.mapReader.getSymbolColor(t.env),align:"center",verticalAlign:"middle",width:h.roomSize,height:h.roomSize});e.add(i)}}renderExits(t){t.forEach(e=>{const s=this.exitRenderer.render(e,this.currentZIndex);if(!s)return;this.linkLayer.add(s);const i=s.getClientRect({relativeTo:this.linkLayer}),o={node:s,bounds:i};this.standaloneExitNodes.push(o),this.addStandaloneExitToSpatialIndex(o)}),this.standaloneExitBoundsRoomSize=h.roomSize}renderLabels(t){t.forEach(e=>{if(h.labelRenderMode==="image"){if(!e.pixMap)return;const s=new Image;s.src=`data:image/png;base64,${e.pixMap}`;const i=new m.Image({x:e.X,y:-e.Y,width:e.Width,height:e.Height,image:s,listening:!1});this.linkLayer.add(i);return}this.renderLabelAsData(e)})}renderLabelAsData(t){const e=new m.Group({listening:!1}),s=new m.Rect({x:t.X,y:-t.Y,width:t.Width,height:t.Height,listening:!1});(t.BgColor?.alpha??0)>0&&!h.transparentLabels?s.fill(this.getLabelColor(t.BgColor)):s.fillEnabled(!1),e.add(s);const i=Math.min(.75,t.Width/Math.max(t.Text.length/2,1)),o=Math.max(.1,Math.min(i,Math.max(t.Height*.9,.1))),r=new m.Text({x:t.X,y:-t.Y,width:t.Width,height:t.Height,text:t.Text,fontSize:o,fillEnabled:!0,fill:this.getLabelColor(t.FgColor),align:"center",verticalAlign:"middle",listening:!1});e.add(r),this.linkLayer.add(e)}getLabelColor(t){const e=(t?.alpha??255)/255,s=i=>Math.min(255,Math.max(0,i??0));return`rgba(${s(t?.r)}, ${s(t?.g)}, ${s(t?.b)}, ${e})`}}const nt={rgbValue:"rgb(114, 1, 0)",symbolColor:[225,225,225]};function at(f){const t=f[0]/255,e=f[1]/255,s=f[2]/255,i=Math.max(t,e,s),o=Math.min(t,e,s);return(i+o)/2}class Mt{constructor(t,e){this.rooms={},this.areas={},this.areaSources={},this.explorationEnabled=!1,this.colors={},t.forEach(s=>{s.rooms.forEach(o=>{o.y=-o.y,this.rooms[o.id]=o});const i=parseInt(s.areaId);this.areas[i]=new _(s),this.areaSources[i]=s}),this.colors=e.reduce((s,i)=>({...s,[i.envId]:{rgb:i.colors,rgbValue:`rgb(${i.colors.join(",")})`,symbolColor:at(i.colors)>.41?[25,25,25]:[225,255,255],symbolColorValue:at(i.colors)>.41?"rgb(25,25,25)":"rgb(225,255,255)"}}),{})}getArea(t){return this.areas[t]}getExplorationArea(t){const e=this.areas[t];if(e instanceof B)return e}getAreas(){return Object.values(this.areas)}getRooms(){return Object.values(this.rooms)}getRoom(t){return this.rooms[t]}ensureVisitedRooms(){return this.visitedRooms||(this.visitedRooms=new Set),this.visitedRooms}applyExplorationDecoration(){this.visitedRooms&&Object.entries(this.areaSources).forEach(([t,e])=>{const s=parseInt(t,10);this.areas[s]=new B(e,this.visitedRooms)})}decorateWithExploration(t){return t!==void 0?this.setVisitedRooms(t):this.ensureVisitedRooms(),this.applyExplorationDecoration(),this.explorationEnabled=!0,this.visitedRooms}getVisitedRooms(){return this.visitedRooms}clearExplorationDecoration(){Object.entries(this.areaSources).forEach(([t,e])=>{const s=parseInt(t,10);this.areas[s]=new _(e)}),this.explorationEnabled=!1}isExplorationEnabled(){return this.explorationEnabled}setVisitedRooms(t){return this.visitedRooms=t instanceof Set?t:new Set(t),this.explorationEnabled&&this.applyExplorationDecoration(),this.visitedRooms}addVisitedRoom(t){if(this.explorationEnabled){const i=this.getRoom(t);if(i){const o=this.getExplorationArea(i.area);if(o)return o.addVisitedRoom(t)}}const e=this.ensureVisitedRooms(),s=e.has(t);return e.add(t),!s}addVisitedRooms(t){const e=this.ensureVisitedRooms();let s=0;for(const i of t){if(this.explorationEnabled){const r=this.getRoom(i);if(r){const n=this.getExplorationArea(r.area);if(n){n.addVisitedRoom(i)&&s++;continue}}}const o=e.has(i);e.add(i),o||s++}return s}hasVisitedRoom(t){return this.visitedRooms?.has(t)??!1}getColorValue(t){return this.colors[t]?.rgbValue??nt.rgbValue}getSymbolColor(t,e){const s=this.colors[t]?.symbolColor??nt.symbolColor,i=Math.min(Math.max(e??1,0),1),o=s.join(",");return i!=1?`rgba(${o}, ${i})`:`rgba(${o})`}}function Dt(f){return f&&f.__esModule&&Object.prototype.hasOwnProperty.call(f,"default")?f.default:f}var $,ht;function Lt(){if(ht)return $;ht=1;class f{constructor(){this.keys=new Set,this.queue=[]}sort(){this.queue.sort((e,s)=>e.priority-s.priority)}set(e,s){const i=Number(s);if(isNaN(i))throw new TypeError('"priority" must be a number');return this.keys.has(e)?this.queue.map(o=>(o.key===e&&Object.assign(o,{priority:i}),o)):(this.keys.add(e),this.queue.push({key:e,priority:i})),this.sort(),this.queue.length}next(){const e=this.queue.shift();return this.keys.delete(e.key),e}isEmpty(){return this.queue.length===0}has(e){return this.keys.has(e)}get(e){return this.queue.find(s=>s.key===e)}}return $=f,$}var G,ct;function Nt(){if(ct)return G;ct=1;function f(t,e){const s=new Map;for(const[i,o]of t)i!==e&&o instanceof Map?s.set(i,f(o,e)):i!==e&&s.set(i,o);return s}return G=f,G}var j,dt;function zt(){if(dt)return j;dt=1;function f(e){const s=Number(e);return!(isNaN(s)||s<=0)}function t(e){const s=new Map;return Object.keys(e).forEach(o=>{const r=e[o];if(r!==null&&typeof r=="object"&&!Array.isArray(r))return s.set(o,t(r));if(!f(r))throw new Error(`Could not add node at key "${o}", make sure it's a valid node`,r);return s.set(o,Number(r))}),s}return j=t,j}var q,lt;function Ot(){if(lt)return q;lt=1;function f(t){if(!(t instanceof Map))throw new Error(`Invalid graph: Expected Map instead found ${typeof t}`);t.forEach((e,s)=>{if(typeof e=="object"&&e instanceof Map){f(e);return}if(typeof e!="number"||e<=0)throw new Error(`Values must be numbers greater than 0. Found value ${e} at ${s}`)})}return q=f,q}var H,ut;function At(){if(ut)return H;ut=1;const f=Lt(),t=Nt(),e=zt(),s=Ot();class i{constructor(r){r instanceof Map?(s(r),this.graph=r):r?this.graph=e(r):this.graph=new Map}addNode(r,n){let a;return n instanceof Map?(s(n),a=n):a=e(n),this.graph.set(r,a),this}addVertex(r,n){return this.addNode(r,n)}removeNode(r){return this.graph=t(this.graph,r),this}path(r,n,a={}){if(!this.graph.size)return a.cost?{path:null,cost:0}:null;const d=new Set,l=new f,c=new Map;let u=[],g=0,y=[];if(a.avoid&&(y=[].concat(a.avoid)),y.includes(r))throw new Error(`Starting node (${r}) cannot be avoided`);if(y.includes(n))throw new Error(`Ending node (${n}) cannot be avoided`);for(l.set(r,0);!l.isEmpty();){const R=l.next();if(R.key===n){g=R.priority;let x=R.key;for(;c.has(x);)u.push(x),x=c.get(x);break}d.add(R.key),(this.graph.get(R.key)||new Map).forEach((x,w)=>{if(d.has(w)||y.includes(w))return null;if(!l.has(w))return c.set(w,R.key),l.set(w,R.priority+x);const I=l.get(w).priority,z=R.priority+x;return z<I?(c.set(w,R.key),l.set(w,z)):null})}return u.length?(a.trim?u.shift():u=u.concat([r]),a.reverse||(u=u.reverse()),a.cost?{path:u,cost:g}:u):a.cost?{path:null,cost:0}:null}shortestPath(...r){return this.path(...r)}}return H=i,H}var Pt=At();const Vt=Dt(Pt),Yt={1:"north",2:"northeast",3:"northwest",4:"east",5:"west",6:"south",7:"southeast",8:"southwest",9:"up",10:"down",11:"in",12:"out"};class Xt{constructor(t){this.cache=new Map,this.mapReader=t,this.graph=this.buildGraph()}buildGraph(){const t={};return this.mapReader.getRooms().forEach(e=>{const s={},i=new Set((e.exitLocks??[]).map(r=>Yt[r]).filter(r=>!!r)),o=new Set(e.mSpecialExitLocks??[]);Object.entries(e.exits??{}).forEach(([r,n])=>{i.has(r)||this.mapReader.getRoom(n)&&(s[n.toString()]=1)}),Object.values(e.specialExits??{}).forEach(r=>{o.has(r)||this.mapReader.getRoom(r)&&(s[r.toString()]=1)}),t[e.id.toString()]=s}),new Vt(t)}findPath(t,e){const s=`${t}->${e}`;if(this.cache.has(s))return this.cache.get(s);if(t===e){const n=this.mapReader.getRoom(t)?[t]:null;return this.cache.set(s,n),n}if(!this.mapReader.getRoom(t)||!this.mapReader.getRoom(e))return this.cache.set(s,null),null;const i=this.graph.path(t.toString(),e.toString()),o=Array.isArray(i)?i:i?.path,r=o?o.map(n=>Number(n)):null;return this.cache.set(s,r),r}}const Tt={1:"north",2:"northeast",3:"northwest",4:"east",5:"west",6:"south",7:"southeast",8:"southwest",9:"up",10:"down",11:"in",12:"out"},D=class D{};D.areaWidth=150,D.areaHeight=80,D.areaSpacing=100,D.fontSize=14,D.connectionLineWidth=2,D.areaFillColor="#2a2a3e",D.areaStrokeColor="#4a4a6e",D.textColor="#e0e0e0",D.connectionColor="#6a6a8e",D.highlightColor="#ff9900";let v=D;class Wt{constructor(t,e){this.areaNodes=new Map,this.connectionGroups=[],this.currentZoom=1,this.stage=new m.Stage({container:t,width:t.clientWidth,height:t.clientHeight,draggable:!0}),this.connectionLayer=new m.Layer({listening:!1}),this.stage.add(this.connectionLayer),this.areaLayer=new m.Layer,this.stage.add(this.areaLayer),this.mapReader=e,this.initScaling(),this.initResize(t)}initResize(t){new ResizeObserver(()=>{this.stage.width(t.clientWidth),this.stage.height(t.clientHeight),this.stage.batchDraw()}).observe(t)}initScaling(){this.stage.on("wheel",e=>{e.evt.preventDefault();const s=this.stage.scaleX(),i=this.stage.getPointerPosition();if(!i)return;const o={x:(i.x-this.stage.x())/s,y:(i.y-this.stage.y())/s},n=(e.evt.deltaY>0?-1:1)>0?this.currentZoom*1.1:this.currentZoom/1.1;this.setZoom(n);const a=this.stage.scaleX(),d={x:i.x-o.x*a,y:i.y-o.y*a};this.stage.position(d),this.stage.batchDraw()})}setZoom(t){this.currentZoom=Math.max(.1,Math.min(5,t)),this.stage.scale({x:this.currentZoom,y:this.currentZoom})}getZoom(){return this.currentZoom}render(){this.analyzeConnections(),this.layoutAreas(),this.drawConnections(),this.drawAreas(),this.centerView(),this.stage.batchDraw()}analyzeConnections(){this.areaNodes.clear(),this.connectionGroups=[];const t=this.mapReader.getRooms(),e=this.mapReader.getAreas();for(const i of e){const o=i.getAreaId(),r=i.getRooms().length;this.areaNodes.set(o,{areaId:o,name:i.getAreaName(),x:0,y:0,width:v.areaWidth,height:v.areaHeight,connections:[],roomCount:r})}const s=new Map;for(const i of t){const o=i.area,r=this.getLockedDirections(i),n=new Set(i.mSpecialExitLocks??[]);for(const[a,d]of Object.entries(i.exits??{})){if(r.has(a))continue;const l=this.mapReader.getRoom(d);if(!l||l.area===o)continue;const c=this.createConnection(i,l,a);c&&this.addConnection(s,c)}for(const[a,d]of Object.entries(i.specialExits??{})){if(n.has(d))continue;const l=this.mapReader.getRoom(d);if(!l||l.area===o)continue;const c=this.parseDirection(a),u=this.createConnection(i,l,c);u&&this.addConnection(s,u)}}for(const[i,o]of s){const[r,n]=i.split("-").map(Number),a=this.createConnectionGroup(r,n,o);this.connectionGroups.push(a);const d=this.areaNodes.get(r),l=this.areaNodes.get(n);if(d&&d.connections.push(...o),l)for(const c of o)l.connections.push({...c,fromAreaId:c.toAreaId,toAreaId:c.fromAreaId,fromRoomId:c.toRoomId,toRoomId:c.fromRoomId,direction:c.direction?gt[c.direction]:null,fromRoomPosition:c.toRoomPosition,toRoomPosition:c.fromRoomPosition})}}getLockedDirections(t){return new Set((t.exitLocks??[]).map(e=>Tt[e]).filter(e=>!!e))}createConnection(t,e,s){const i=this.toPlanarDirection(s);return{fromAreaId:t.area,toAreaId:e.area,fromRoomId:t.id,toRoomId:e.id,direction:i,fromRoomPosition:{x:t.x,y:t.y},toRoomPosition:{x:e.x,y:e.y}}}addConnection(t,e){const s=e.fromAreaId<e.toAreaId?`${e.fromAreaId}-${e.toAreaId}`:`${e.toAreaId}-${e.fromAreaId}`;t.has(s)||t.set(s,[]),t.get(s).push(e)}createConnectionGroup(t,e,s){const i=new Map;let o=0,r=0;for(const d of s)d.direction&&i.set(d.direction,(i.get(d.direction)??0)+1),o+=d.toRoomPosition.x-d.fromRoomPosition.x,r+=d.toRoomPosition.y-d.fromRoomPosition.y;let n=null,a=0;for(const[d,l]of i)l>a&&(a=l,n=d);return{fromAreaId:t,toAreaId:e,connections:s,primaryDirection:n,averageOffset:{x:o/s.length,y:r/s.length}}}parseDirection(t){const e=t.toLowerCase().trim();return{n:"north",north:"north",s:"south",south:"south",e:"east",east:"east",w:"west",west:"west",ne:"northeast",northeast:"northeast",nw:"northwest",northwest:"northwest",se:"southeast",southeast:"southeast",sw:"southwest",southwest:"southwest",u:"up",up:"up",d:"down",down:"down",i:"in",in:"in",o:"out",out:"out"}[e]??null}toPlanarDirection(t){return t&&K.includes(t)?t:null}layoutAreas(){if(Array.from(this.areaNodes.values()).length===0)return;const e=this.findConnectedComponents();let s=0;const i=v.areaWidth*3;for(const o of e)if(o.length===1){const r=this.areaNodes.get(o[0]);r.x=s,r.y=0,s+=v.areaWidth+i}else{const r=this.forceDirectedLayout(o);for(const n of o){const a=this.areaNodes.get(n);a.x-=r.minX,a.x+=s,a.y-=r.minY}s+=r.maxX-r.minX+i}}findConnectedComponents(){const t=new Set,e=[];for(const[s]of this.areaNodes){if(t.has(s))continue;const i=[],o=[s];for(;o.length>0;){const r=o.shift();if(t.has(r))continue;t.add(r),i.push(r);const n=this.areaNodes.get(r);if(n)for(const a of n.connections)t.has(a.toAreaId)||o.push(a.toAreaId)}e.push(i)}return e}forceDirectedLayout(t){const e=new Set,s=[],i=t[0],o=this.areaNodes.get(i);for(o.x=0,o.y=0,e.add(i),s.push(i);s.length>0;){const l=s.shift(),c=this.areaNodes.get(l);for(const u of c.connections){if(e.has(u.toAreaId))continue;const g=this.areaNodes.get(u.toAreaId);if(!g)continue;const y=this.getDirectionOffset(u.direction);g.x=c.x+y.x*(v.areaWidth+v.areaSpacing),g.y=c.y+y.y*(v.areaHeight+v.areaSpacing),e.add(u.toAreaId),s.push(u.toAreaId)}}this.applyForces(t,50);let r=1/0,n=1/0,a=-1/0,d=-1/0;for(const l of t){const c=this.areaNodes.get(l);r=Math.min(r,c.x),n=Math.min(n,c.y),a=Math.max(a,c.x+c.width),d=Math.max(d,c.y+c.height)}return{minX:r,minY:n,maxX:a,maxY:d}}getDirectionOffset(t){const e={north:{x:0,y:-1},south:{x:0,y:1},east:{x:1,y:0},west:{x:-1,y:0},northeast:{x:.7,y:-.7},northwest:{x:-.7,y:-.7},southeast:{x:.7,y:.7},southwest:{x:-.7,y:.7}};return t&&e[t]?e[t]:{x:1,y:0}}applyForces(t,e){const r=new Map;for(const n of t)r.set(n,{vx:0,vy:0});for(let n=0;n<e;n++){for(const a of t){const d=this.areaNodes.get(a),l=r.get(a);for(const c of t){if(a===c)continue;const u=this.areaNodes.get(c),g=d.x-u.x,y=d.y-u.y,R=g*g+y*y,p=Math.sqrt(R)||1,x=5e3/R;l.vx+=g/p*x,l.vy+=y/p*x}for(const c of d.connections){const u=this.areaNodes.get(c.toAreaId);if(!u)continue;const g=this.getDirectionOffset(c.direction),y=d.x+g.x*(v.areaWidth+v.areaSpacing),R=d.y+g.y*(v.areaHeight+v.areaSpacing),p=r.get(c.toAreaId);p&&(p.vx+=(y-u.x)*.01,p.vy+=(R-u.y)*.01)}}for(const a of t){const d=this.areaNodes.get(a),l=r.get(a);d.x+=l.vx,d.y+=l.vy,l.vx*=.9,l.vy*=.9}}}drawConnections(){this.connectionLayer.destroyChildren();for(const t of this.connectionGroups){const e=this.areaNodes.get(t.fromAreaId),s=this.areaNodes.get(t.toAreaId);if(!e||!s)continue;const i={x:e.x+e.width/2,y:e.y+e.height/2},o={x:s.x+s.width/2,y:s.y+s.height/2},r=this.getEdgePoint(e,o),n=this.getEdgePoint(s,i),a=new m.Line({points:[r.x,r.y,n.x,n.y],stroke:v.connectionColor,strokeWidth:Math.min(v.connectionLineWidth,1+t.connections.length*.5),lineCap:"round",listening:!1});this.connectionLayer.add(a);const d=(r.x+n.x)/2,l=(r.y+n.y)/2;if(t.connections.length>1){const c=new m.Group({x:d,y:l,listening:!1}),u=new m.Circle({radius:12,fill:v.areaFillColor,stroke:v.connectionColor,strokeWidth:1});c.add(u);const g=new m.Text({text:String(t.connections.length),fontSize:10,fill:v.textColor,align:"center",verticalAlign:"middle"});g.x(-g.width()/2),g.y(-g.height()/2),c.add(g),this.connectionLayer.add(c)}}}getEdgePoint(t,e){const s=t.x+t.width/2,i=t.y+t.height/2,o=e.x-s,r=e.y-i,n=t.width/2,a=t.height/2;if(o===0&&r===0)return{x:s,y:i};const d=Math.abs(o),l=Math.abs(r);let c;return d/n>l/a?c=n/d:c=a/l,{x:s+o*c,y:i+r*c}}drawAreas(){this.areaLayer.destroyChildren();for(const[,t]of this.areaNodes){const e=new m.Group({x:t.x,y:t.y}),s=t.areaId===this.highlightedArea,i=new m.Rect({width:t.width,height:t.height,fill:v.areaFillColor,stroke:s?v.highlightColor:v.areaStrokeColor,strokeWidth:s?3:2,cornerRadius:8}),o=new m.Text({text:t.name,fontSize:v.fontSize,fill:v.textColor,width:t.width-10,height:t.height-20,x:5,y:10,align:"center",verticalAlign:"middle",ellipsis:!0,wrap:"word"}),r=new m.Text({text:`${t.roomCount} rooms`,fontSize:10,fill:v.connectionColor,width:t.width-10,x:5,y:t.height-18,align:"center"});e.add(i),e.add(o),e.add(r),e.on("click tap",()=>{this.emitAreaClickEvent(t.areaId)}),e.on("mouseenter",()=>{this.stage.container().style.cursor="pointer",i.stroke(v.highlightColor),this.areaLayer.batchDraw()}),e.on("mouseleave",()=>{this.stage.container().style.cursor="auto",i.stroke(s?v.highlightColor:v.areaStrokeColor),this.areaLayer.batchDraw()}),this.areaLayer.add(e)}}centerView(){let t=1/0,e=1/0,s=-1/0,i=-1/0;for(const[,y]of this.areaNodes)t=Math.min(t,y.x),e=Math.min(e,y.y),s=Math.max(s,y.x+y.width),i=Math.max(i,y.y+y.height);if(!isFinite(t))return;const o=s-t,r=i-e,n=t+o/2,a=e+r/2,d=50,l=(this.stage.width()-d*2)/o,c=(this.stage.height()-d*2)/r,u=Math.min(l,c,1.5);this.setZoom(u);const g=this.stage.scaleX();this.stage.position({x:this.stage.width()/2-n*g,y:this.stage.height()/2-a*g})}highlightArea(t){this.highlightedArea=t,this.drawAreas(),this.stage.batchDraw()}centerOnArea(t){const e=this.areaNodes.get(t);if(!e)return;const s=this.stage.scaleX(),i=e.x+e.width/2,o=e.y+e.height/2;this.stage.position({x:this.stage.width()/2-i*s,y:this.stage.height()/2-o*s}),this.stage.batchDraw()}emitAreaClickEvent(t){const e=new CustomEvent("areaclick",{detail:{areaId:t}});this.stage.container().dispatchEvent(e)}getAreaNode(t){return this.areaNodes.get(t)}getConnectionGroups(){return this.connectionGroups}destroy(){this.stage.destroy()}}exports.AreaMapRenderer=Wt;exports.AreaMapSettings=v;exports.ExplorationArea=B;exports.MapReader=Mt;exports.PathFinder=Xt;exports.Renderer=It;exports.Settings=h;
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|