pull AtlasLoot rares + interactives into kg pixel space
- new tools/atlasloot_extras.py: matches AL bosses to kg cls>=3 enemies by name, fits per-(dungeon,wing) affine x/y transform, applies to AL pinType=None entries to recover ~14 rare bosses kg's spawn-bound data model omits (Blind Hunter, Stonespine, Deathsworn Captain, Spirestone Butcher, Bannok Grimaxe, Jed Runewatcher, Tsu'zee, …) plus 140+ AtlasLoot interactives (postboxes, summon stones, levers) - WING_FORCE map disambiguates multi-wing dungeons (BRS, Dire Maul, Scarlet Monastery) where the same AL coord transforms into multiple wings - frontend renders rare extras as silver-blue skull pins, non-rare extras as muted squares; both have hover-tooltips with their AtlasLoot name - start, graveyard, dot_yellow, gateway, door_locked icon types from kg now render with distinct shapes (were silently empty before) - kg_build_data.py merges atlasloot_extras.json into each dungeon's 'extras' field Note: Ascension always-spawns rare bosses (vs retail's RNG), so they're now reliably visible on the planner.
This commit is contained in:
+89
-2
@@ -194,6 +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) {
|
||||
for (const ex of state.current.extras) {
|
||||
svg.appendChild(makeExtraPin(ex));
|
||||
}
|
||||
}
|
||||
|
||||
// Route polyline
|
||||
if (wps.length > 1) {
|
||||
const path = document.createElementNS(SVG_NS, "polyline");
|
||||
@@ -419,6 +430,42 @@ function makeEnemyPin(e) {
|
||||
return g;
|
||||
}
|
||||
|
||||
function makeExtraPin(ex) {
|
||||
// Silver-blue ring with skull glyph for rares; muted square for non-rare
|
||||
// interactives (postboxes, summon spots, etc.). Strip the trailing
|
||||
// "(Rare)" / "(Rare, Wanders)" tag from the displayed tooltip — we
|
||||
// surface "rare" via the visual treatment.
|
||||
const g = document.createElementNS(SVG_NS, "g");
|
||||
g.setAttribute("class", ex.rare ? "extra rare" : "extra");
|
||||
g.setAttribute("transform", `translate(${ex.pos[0]},${ex.pos[1]})`);
|
||||
if (ex.rare) {
|
||||
const c = document.createElementNS(SVG_NS, "circle");
|
||||
c.setAttribute("r", 26);
|
||||
c.setAttribute("fill", "#bfd6f0");
|
||||
c.setAttribute("stroke", "#3b6db0");
|
||||
c.setAttribute("stroke-width", "5");
|
||||
g.appendChild(c);
|
||||
const t = document.createElementNS(SVG_NS, "text");
|
||||
t.setAttribute("y", 11);
|
||||
t.setAttribute("font-size", "30");
|
||||
t.setAttribute("text-anchor", "middle");
|
||||
t.setAttribute("fill", "#1a3360");
|
||||
t.setAttribute("font-weight", "900");
|
||||
t.textContent = "☠";
|
||||
g.appendChild(t);
|
||||
} else {
|
||||
const r = document.createElementNS(SVG_NS, "rect");
|
||||
r.setAttribute("x", -10); r.setAttribute("y", -10);
|
||||
r.setAttribute("width", 20); r.setAttribute("height", 20);
|
||||
r.setAttribute("fill", "#7e8290");
|
||||
r.setAttribute("stroke", "#1a1208");
|
||||
r.setAttribute("stroke-width", "2");
|
||||
g.appendChild(r);
|
||||
}
|
||||
g.dataset.tooltip = ex.name + (ex.rare ? "" : "");
|
||||
return g;
|
||||
}
|
||||
|
||||
function makeIconMarker(ic) {
|
||||
const g = document.createElementNS(SVG_NS, "g");
|
||||
g.setAttribute("class", `icon icon-${ic.type}`);
|
||||
@@ -438,14 +485,54 @@ function makeIconMarker(ic) {
|
||||
t.setAttribute("font-weight", "700");
|
||||
t.textContent = "i";
|
||||
g.appendChild(t);
|
||||
} else if (ic.type === "door") {
|
||||
} else if (ic.type === "door" || ic.type === "door_locked") {
|
||||
const r = document.createElementNS(SVG_NS, "rect");
|
||||
r.setAttribute("x", -10); r.setAttribute("y", -14);
|
||||
r.setAttribute("width", 20); r.setAttribute("height", 28);
|
||||
r.setAttribute("fill", "#B58A3F");
|
||||
r.setAttribute("fill", ic.type === "door_locked" ? "#7a4a1a" : "#B58A3F");
|
||||
r.setAttribute("stroke", "#000");
|
||||
r.setAttribute("stroke-width", "2");
|
||||
g.appendChild(r);
|
||||
} else if (ic.type === "start") {
|
||||
// Green entry-flag triangle
|
||||
const p = document.createElementNS(SVG_NS, "polygon");
|
||||
p.setAttribute("points", "-12,-14 14,0 -12,14");
|
||||
p.setAttribute("fill", "#6ad17b");
|
||||
p.setAttribute("stroke", "#0a2a12");
|
||||
p.setAttribute("stroke-width", "2");
|
||||
g.appendChild(p);
|
||||
} else if (ic.type === "graveyard") {
|
||||
// Tombstone: rounded-top rect with a cross
|
||||
const r = document.createElementNS(SVG_NS, "rect");
|
||||
r.setAttribute("x", -12); r.setAttribute("y", -14);
|
||||
r.setAttribute("width", 24); r.setAttribute("height", 28);
|
||||
r.setAttribute("rx", 10); r.setAttribute("ry", 10);
|
||||
r.setAttribute("fill", "#9aa1aa");
|
||||
r.setAttribute("stroke", "#000");
|
||||
r.setAttribute("stroke-width", "2");
|
||||
g.appendChild(r);
|
||||
const t = document.createElementNS(SVG_NS, "text");
|
||||
t.setAttribute("y", 6);
|
||||
t.setAttribute("font-size", "20");
|
||||
t.setAttribute("text-anchor", "middle");
|
||||
t.setAttribute("fill", "#1a1208");
|
||||
t.setAttribute("font-weight", "900");
|
||||
t.textContent = "✝";
|
||||
g.appendChild(t);
|
||||
} else if (ic.type === "dot_yellow") {
|
||||
const c = document.createElementNS(SVG_NS, "circle");
|
||||
c.setAttribute("r", 10);
|
||||
c.setAttribute("fill", "#f0c674");
|
||||
c.setAttribute("stroke", "#1a1208");
|
||||
c.setAttribute("stroke-width", "2");
|
||||
g.appendChild(c);
|
||||
} else if (ic.type === "gateway") {
|
||||
const c = document.createElementNS(SVG_NS, "circle");
|
||||
c.setAttribute("r", 14);
|
||||
c.setAttribute("fill", "#9b59b6");
|
||||
c.setAttribute("stroke", "#000");
|
||||
c.setAttribute("stroke-width", "2");
|
||||
g.appendChild(c);
|
||||
}
|
||||
if (ic.comment) {
|
||||
g.dataset.tooltip = ic.comment;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user