per-floor extras + Ascension overrides + layer toggles

- atlasloot_extras: fit one transform per (kg_dungeon, floor_id) instead of mixing all kg bosses into one fit. Each AL extra is assigned to whichever floor's anchors it's nearest to (in AL coord space). Strat's Stonespine now correctly lands on floor 235 (Undead) instead of being hidden because the mixed-floor fit pushed it off.
- new data/ascension_overrides.json: per-name position/floor patches for places where Ascension diverges from retail. Seeded with Magistrate Barthilas → moved to the southern courtyard (3498, 3300 on Undead Side) per Ascension spawns.
- frontend renders extras only on their assigned floor; previously hard-coded to floor 0.
- new layer-toggle checkboxes (Enemies / Packs / Patrols / Icons) in the toolbar — flip patrols off if mob routes are noise for your route.
This commit is contained in:
2026-04-25 23:26:24 +02:00
parent 48c401909e
commit e11dc1eed5
8 changed files with 984 additions and 896 deletions
+20 -6
View File
@@ -194,13 +194,17 @@ function renderOverlay() {
}
}
// AtlasLoot-derived extras: rare bosses + interactives kg doesn't ship.
// These are dungeon-level (not per-floor) and only render on floor 0
// unless we get richer data; for single-floor dungeons that's all that
// matters, and for multi-floor we leave them on the first floor by
// default — the user can drag a Note over them on any floor.
if (state.floorIndex === 0 && state.current?.extras) {
// AtlasLoot-derived extras: render only ones that match the current
// floor. Single-floor dungeons have kg_floor_id null on every extra,
// so they all render on floor 0.
if (state.current?.extras) {
const curFloor = m.kg_floor_id;
for (const ex of state.current.extras) {
// If the extra has no floor assignment, show only on floor 0.
// If it does, show on the matching floor only.
const fid = ex.kg_floor_id;
const matches = fid == null ? state.floorIndex === 0 : fid === curFloor;
if (!matches) continue;
svg.appendChild(makeExtraPin(ex));
}
}
@@ -1175,6 +1179,16 @@ function hookEvents() {
$("export").addEventListener("click", exportJson);
const importBtn = $("import");
if (importBtn) importBtn.addEventListener("click", importJson);
// Layer toggles — repaint overlay on change. Persisted in state.show.
for (const layer of ["enemies", "packs", "patrols", "icons"]) {
const cb = $(`layer-${layer}`);
if (!cb) continue;
cb.checked = state.show[layer];
cb.addEventListener("change", () => {
state.show[layer] = cb.checked;
renderOverlay();
});
}
$("tool-route").addEventListener("click", () => setTool("route"));
$("tool-pull").addEventListener("click", () => setTool("pull"));
const noteBtn = $("tool-note");
+390 -454
View File
File diff suppressed because it is too large Load Diff
+6
View File
@@ -33,6 +33,12 @@
<button id="tool-pull" class="tool" title="Click map to drop pull markers">Pull</button>
<button id="tool-note" class="tool" title="Drop an (i) info icon — text shows on hover">Note</button>
<button id="tool-text" class="tool" title="Drop a freetext label — text always visible on the map">Text</button>
<span class="toolbar-sep"></span>
<label class="layer-toggle" title="Show enemy/trash spawns"><input type="checkbox" id="layer-enemies" checked> Enemies</label>
<label class="layer-toggle" title="Show enemy pack polygons"><input type="checkbox" id="layer-packs" checked> Packs</label>
<label class="layer-toggle" title="Show enemy patrol routes"><input type="checkbox" id="layer-patrols" checked> Patrols</label>
<label class="layer-toggle" title="Show map icons (start, doors, comments)"><input type="checkbox" id="layer-icons" checked> Icons</label>
<span class="toolbar-sep"></span>
<button id="undo" title="Undo (⌘Z)">Undo</button>
<button id="clear" title="Clear current floor">Clear</button>
<button id="share">Share</button>
+20
View File
@@ -194,6 +194,26 @@ body {
border-color: var(--accent);
font-weight: 600;
}
.toolbar-sep {
width: 1px;
height: 22px;
background: var(--line);
align-self: center;
margin: 0 4px;
}
.layer-toggle {
display: inline-flex;
align-items: center;
gap: 5px;
font-size: 12px;
color: var(--text-dim);
cursor: pointer;
padding: 4px 6px;
user-select: none;
white-space: nowrap;
}
.layer-toggle:hover { color: var(--text); }
.layer-toggle input { margin: 0; cursor: pointer; }
/* --- canvas / overlay ----------------------------------------------------- */