From e11dc1eed5997ef0d30b042dae72460be24baece Mon Sep 17 00:00:00 2001 From: Florian Date: Sat, 25 Apr 2026 23:26:24 +0200 Subject: [PATCH] per-floor extras + Ascension overrides + layer toggles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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. --- data/ascension_overrides.json | 12 + data/atlasloot_extras.json | 825 +++++++++++++++++---------------- tools/atlasloot_extras.py | 114 ++--- tools/kg_build_data.py | 33 ++ web/app.js | 26 +- web/assets/dungeons.json | 844 ++++++++++++++++------------------ web/index.html | 6 + web/style.css | 20 + 8 files changed, 984 insertions(+), 896 deletions(-) create mode 100644 data/ascension_overrides.json diff --git a/data/ascension_overrides.json b/data/ascension_overrides.json new file mode 100644 index 0000000..fb18404 --- /dev/null +++ b/data/ascension_overrides.json @@ -0,0 +1,12 @@ +{ + "_comment": "Ascension-specific corrections to the upstream kg / AtlasLoot data. Each entry overrides where an enemy/extra is rendered. Match by tile_key + name (case-insensitive substring). pos is in kg pixel space (z=4 stitched image, 6144x4096). kg_floor_id picks the floor (omit if the dungeon is single-floor).", + "overrides": [ + { + "tile_key": "stratholme", + "name": "Magistrate Barthilas", + "kg_floor_id": 235, + "pos": [3498, 3300], + "note": "Ascension moved Barthilas to the southern courtyard of the Undead Side" + } + ] +} diff --git a/data/atlasloot_extras.json b/data/atlasloot_extras.json index 3a8879e..4cc6d63 100644 --- a/data/atlasloot_extras.json +++ b/data/atlasloot_extras.json @@ -1,164 +1,249 @@ { "_comment": "Supplemental rare bosses + interactives lifted from AtlasLootAscension and transformed into keystone.guru pixel space. Generated by tools/atlasloot_extras.py.", "transforms": { - "RagefireChasm\u2192ragefire_chasm": [ + "RagefireChasm\u2192ragefire_chasm@floor216": [ 73.72443668498734, -643.6866761504352, 42.96310607515248, -122.87047634576129 ], - "TheDeadmines\u2192deadmines": [ - 38.86529733570145, - 795.3768071048042, - 42.675714797527434, - -4.190671073545933 + "TheDeadmines\u2192deadmines@floor196": [ + 66.26591999999972, + -234.06111999998757, + 44.597466666666755, + -303.3821333333399 ], - "WailingCaverns\u2192wailing_caverns": [ + "TheDeadmines\u2192deadmines@floor197": [ + 76.22242622951025, + -1563.346570491929, + 61.14531050583661, + -717.1209612451378 + ], + "WailingCaverns\u2192wailing_caverns@floor240": [ 81.43623828914878, -747.3569080929979, 34.84088492074497, 115.17092826840326 ], - "ShadowfangKeep\u2192shadowfang_keep": [ - 61.65109512912707, - 44.20626976136464, - 40.982516838487975, - -50.47485979381463 + "ShadowfangKeep\u2192shadowfang_keep@floor227": [ + 61.02459999999999, + 65.04460000000063, + 46.426533333333886, + -409.4137333333706 ], - "TheStockade\u2192the_stockade": [ + "ShadowfangKeep\u2192shadowfang_keep@floor228": [ + 62.30417777777773, + -50.73653333333141, + 43.851689795918375, + -132.65531428571467 + ], + "ShadowfangKeep\u2192shadowfang_keep@floor232": [ + 29.689000000000306, + 1920.5397999999814, + 34.11870476190476, + 138.36030476190467 + ], + "TheStockade\u2192the_stockade@floor236": [ 59.842452519084006, 61.74031633587583, 39.897596145904984, 21.673417205782425 ], - "Gnomeregan\u2192gnomeregan": [ - 111.07253811659204, - -1434.4782521973132, - 38.1758651250788, - 220.98302089552416 + "Gnomeregan\u2192gnomeregan@floor205": [ + 128.41971199999992, + -1675.7119999999968, + 54.99048421052646, + -1017.2874105263245 ], - "RazorfenKraul\u2192razorfen_kraul": [ + "Gnomeregan\u2192gnomeregan@floor207": [ + -7.172800000000279, + 2156.0112000000086, + 81.23751111111113, + -1217.8997333333346 + ], + "RazorfenKraul\u2192razorfen_kraul@floor218": [ 60.513804000979846, 88.27979514983198, 43.452935250680056, -74.45083218033032 ], - "RazorfenDowns\u2192razorfen_downs": [ + "RazorfenDowns\u2192razorfen_downs@floor217": [ 63.04291758924619, -290.16402952444923, 41.07698629536258, 102.3108550816687 ], - "ScarletMonastery\u2192scarlet_monastery_cathedral": [ + "ScarletMonastery\u2192scarlet_monastery_cathedral@floor220": [ 50.76749473684181, 557.1932350877345, 32.20170256410254, 167.73567179487236 ], - "ScarletMonastery\u2192scarlet_monastery_graveyard": [ + "ScarletMonastery\u2192scarlet_monastery_graveyard@floor221": [ 60.84316666666665, 37.29200000000128, 23.45159999999305, 995.9040000004034 ], - "ScarletMonastery\u2192scarlet_monastery_library": [ + "ScarletMonastery\u2192scarlet_monastery_library@floor222": [ 59.125464150943436, 212.3352754716957, 74.09100000000035, -2662.1046000000283 ], - "Uldaman\u2192uldaman": [ - 63.19322527727629, - -86.87969584730672, - 41.52615397709141, - -41.35400744707431 + "Uldaman\u2192uldaman@floor238": [ + 62.88415904279804, + -78.21449940175133, + 41.43594680607743, + -28.07042326417234 ], - "ZulFarrak\u2192zul_farrak": [ + "ZulFarrak\u2192zul_farrak@floor241": [ 71.87339593345645, -512.6565965671986, 39.668194090909076, -1.3930740909086776 ], - "Maraudon\u2192maraudon": [ - 61.77912121471568, - 25.543185142141738, - 42.19282336665975, - -65.8431254967295 + "Maraudon\u2192maraudon@floor214": [ + 66.7837434402333, + -211.68715102041006, + 41.3733804475854, + -96.69095123674924 ], - "BlackrockDepths\u2192blackrock_depths": [ - 63.390884474140194, - -129.9214250730094, - 43.72115533672626, - -43.96230823056116 + "Maraudon\u2192maraudon@floor215": [ + 56.73022056074778, + 249.97455476635076, + 41.50276494730274, + 12.258980149063428 ], - "BlackrockSpire\u2192lower_blackrock_spire": [ - 70.31609043478278, - -550.6383026087042, - 47.429734477825605, - -521.5857562231853 + "BlackrockDepths\u2192blackrock_depths@floor194": [ + 63.63756840148695, + -162.67121375464484, + 40.4048188308329, + 8.987177030522435 ], - "BlackrockSpire\u2192upper_blackrock_spire": [ - 61.504197773872264, - -76.49282249560493, - 34.005210582010584, - 222.27234962962956 + "BlackrockDepths\u2192blackrock_depths@floor195": [ + 62.94900546673541, + -86.73139102630073, + 46.48759478082394, + -77.53748107315732 ], - "Stratholme\u2192stratholme": [ - 47.28673540151238, - 713.5643322963654, - 42.71814474125836, - -161.87918672865834 + "BlackrockSpire\u2192upper_blackrock_spire@floor251": [ + 61.70100000000002, + -56.735800000000836, + 37.522399999999834, + 88.06320000000551 ], - "Scholomance\u2192scholomance": [ - 68.16995676302486, - -376.1030967834516, - 46.6690874521118, - -292.56897919878884 + "BlackrockSpire\u2192upper_blackrock_spire@floor252": [ + 63.47862546689313, + -192.3194648556922, + 32.72667881548972, + 280.8202697038737 ], - "DireMaul\u2192dire_maul_north": [ + "Stratholme\u2192stratholme@floor234": [ + 41.10740482022913, + 953.3460469379711, + 45.46983390016457, + -394.0354483817887 + ], + "Stratholme\u2192stratholme@floor235": [ + 62.999233525796434, + -128.2447165580294, + 42.25970441767067, + -69.48502811244937 + ], + "Scholomance\u2192scholomance@floor225": [ + 67.03862919012546, + -301.39203984408016, + 44.58635943070333, + -260.60278192621263 + ], + "Scholomance\u2192scholomance@floor226": [ + 68.56349344262266, + -379.79195901637434, + 52.39632279411766, + -445.17640367647107 + ], + "DireMaul\u2192dire_maul_north@floor198": [ 63.69477659517125, -52.97349769615799, 40.323820514843405, -15.287907437179715 ], - "DireMaul\u2192dire_maul_east": [ - 23.186187151976394, - 2032.82655823259, - 72.13990548255808, - -968.0175378916643 + "DireMaul\u2192dire_maul_east@floor203": [ + 6.555779141104249, + 3087.766655214726, + 86.08977339901453, + -1322.4088512315175 ], - "DireMaul\u2192dire_maul_west": [ - 50.567135013423375, - 526.7297255113892, - 37.66845336733329, - 254.15845163333543 + "DireMaul\u2192dire_maul_west@floor199": [ + 11.51677611940289, + 1694.8836776119429, + 48.91311020408154, + -444.9409959183613 ], - "MoltenCore\u2192moltencore": [ + "DireMaul\u2192dire_maul_west@floor201": [ + 63.43969465648849, + -82.18605190839389, + 32.69369302325585, + 460.44843534883603 + ], + "MoltenCore\u2192moltencore@floor309": [ 63.802558332453295, -161.93769244746218, 46.40771496165673, -344.9887211648951 ], - "BlackwingLair\u2192blackwinglair": [ - 56.096746961325906, - 325.5217337016602, - 24.000187425480892, - 738.8363241595489 + "BlackwingLair\u2192blackwinglair@floor310": [ + -87.09831111111109, + 5766.327466666666, + -30.799717647058795, + 3012.748894117646 ], - "Naxxramas60\u2192naxxramas_classic": [ - 54.729314117996196, - 329.7412320416867, - 13.38947624976002, - 1066.3540111552927 + "BlackwingLair\u2192blackwinglair@floor312": [ + 44.53386938775538, + 829.3184653061107, + 49.16421052631577, + -498.62152982456064 + ], + "BlackwingLair\u2192blackwinglair@floor313": [ + 71.16791057401812, + -516.2994392749242, + 43.71123200000003, + -257.80390400000215 + ], + "Naxxramas60\u2192naxxramas_classic@floor138": [ + 63.58405165354333, + -131.6644535433079, + 41.1352763693271, + 1.9000788732382716 + ], + "Naxxramas60\u2192naxxramas_classic@floor139": [ + 66.4364096514745, + -225.34979660410923, + 35.50802017654478, + 110.69960756620367 + ], + "Naxxramas60\u2192naxxramas_classic@floor141": [ + 63.421989155693126, + -63.41635135553042, + 42.14327589424573, + -69.00678071539703 + ], + "Naxxramas60\u2192naxxramas_classic@floor143": [ + -61.489040000000095, + 5753.316880000005, + -40.52355555555556, + 3695.091377777778 ] }, "extras": { "deadmines": [ { "name": "Defias Gunpowder", - "x": 1572.7, - "y": 2343.0, + "x": 1091.3, + "y": 2149.5, "rare": false, + "kg_floor_id": 196, "source": "atlasloot" } ], @@ -168,52 +253,49 @@ "x": 3080.1, "y": 1961.7, "rare": false, + "kg_floor_id": 240, "source": "atlasloot" } ], "shadowfang_keep": [ { "name": "Investigator Fezzen Brasstacks (Love is in the Air)", - "x": 3373.4, - "y": 2654.4, + "x": 3523.7, + "y": 2390.2, "rare": false, + "kg_floor_id": 232, "source": "atlasloot" }, { "name": "Deathstalker Vincent", - "x": 3558.3, - "y": 2408.5, + "x": 3612.8, + "y": 2185.5, "rare": false, + "kg_floor_id": 232, "source": "atlasloot" }, { "name": "Apothecary Trio (Love is in the Air)", - "x": 2448.6, - "y": 2039.6, + "x": 2445.0, + "y": 1958.3, "rare": false, + "kg_floor_id": 227, "source": "atlasloot" }, { "name": "Fel Steed", - "x": 2202.0, - "y": 2326.5, + "x": 2200.9, + "y": 2283.3, "rare": false, + "kg_floor_id": 227, "source": "atlasloot" }, { "name": "Deathsworn Captain (Rare)", - "x": 3681.6, - "y": 2121.6, + "x": 3672.2, + "y": 1946.7, "rare": true, - "source": "atlasloot" - } - ], - "gnomeregan": [ - { - "name": "Clean Room", - "x": 5674.2, - "y": 2664.2, - "rare": false, + "kg_floor_id": 232, "source": "atlasloot" } ], @@ -223,6 +305,7 @@ "x": 4021.7, "y": 2011.3, "rare": false, + "kg_floor_id": 218, "source": "atlasloot" }, { @@ -230,6 +313,7 @@ "x": 753.9, "y": 1272.6, "rare": true, + "kg_floor_id": 218, "source": "atlasloot" } ], @@ -239,6 +323,7 @@ "x": 4212.5, "y": 2099.8, "rare": false, + "kg_floor_id": 220, "source": "atlasloot" }, { @@ -246,6 +331,7 @@ "x": 2384.8, "y": 2196.4, "rare": false, + "kg_floor_id": 220, "source": "atlasloot" }, { @@ -253,6 +339,7 @@ "x": 1775.6, "y": 1971.0, "rare": false, + "kg_floor_id": 220, "source": "atlasloot" }, { @@ -260,6 +347,7 @@ "x": 2080.2, "y": 2904.9, "rare": false, + "kg_floor_id": 220, "source": "atlasloot" }, { @@ -267,6 +355,7 @@ "x": 4770.9, "y": 2647.3, "rare": false, + "kg_floor_id": 220, "source": "atlasloot" }, { @@ -274,6 +363,7 @@ "x": 4567.8, "y": 522.0, "rare": false, + "kg_floor_id": 220, "source": "atlasloot" } ], @@ -283,6 +373,7 @@ "x": 1862.6, "y": 2989.3, "rare": false, + "kg_floor_id": 221, "source": "atlasloot" }, { @@ -290,6 +381,7 @@ "x": 5087.3, "y": 2801.7, "rare": false, + "kg_floor_id": 221, "source": "atlasloot" }, { @@ -297,6 +389,7 @@ "x": 4843.9, "y": 1253.9, "rare": false, + "kg_floor_id": 221, "source": "atlasloot" }, { @@ -304,6 +397,7 @@ "x": 3444.5, "y": 1605.6, "rare": false, + "kg_floor_id": 221, "source": "atlasloot" }, { @@ -311,6 +405,7 @@ "x": 3018.6, "y": 1676.0, "rare": false, + "kg_floor_id": 221, "source": "atlasloot" }, { @@ -318,6 +413,7 @@ "x": 2957.8, "y": 1394.6, "rare": false, + "kg_floor_id": 221, "source": "atlasloot" } ], @@ -327,6 +423,7 @@ "x": 4469.4, "y": 1783.4, "rare": false, + "kg_floor_id": 222, "source": "atlasloot" }, { @@ -334,29 +431,33 @@ "x": 1631.3, "y": 1487.0, "rare": false, + "kg_floor_id": 222, "source": "atlasloot" } ], "uldaman": [ { "name": "Remains of a Paladin", - "x": 3262.4, - "y": 2616.3, + "x": 3254.6, + "y": 2623.8, "rare": false, + "kg_floor_id": 238, "source": "atlasloot" }, { "name": "The Discs of Norgannon (Lower)", - "x": 2440.8, - "y": 332.4, + "x": 2437.2, + "y": 344.9, "rare": false, + "kg_floor_id": 238, "source": "atlasloot" }, { "name": "The Discs of Norgannon (Lower)", - "x": 3072.8, - "y": 1370.5, + "x": 3066.0, + "y": 1380.8, "rare": false, + "kg_floor_id": 238, "source": "atlasloot" } ], @@ -366,459 +467,393 @@ "x": 1284.2, "y": 712.6, "rare": false, + "kg_floor_id": 241, "source": "atlasloot" } ], "maraudon": [ { "name": "Veng ", - "x": 3732.3, - "y": 946.8, + "x": 3795.3, + "y": 896.3, "rare": false, + "kg_floor_id": 214, "source": "atlasloot" }, { "name": "Maraudos ", - "x": 3299.8, - "y": 3056.4, + "x": 3256.7, + "y": 3083.5, "rare": false, + "kg_floor_id": 215, "source": "atlasloot" } ], "blackrock_depths": [ { "name": "Kharan Mighthammer", - "x": 3166.4, - "y": 3541.2, + "x": 3146.5, + "y": 3322.2, "rare": false, + "kg_floor_id": 194, "source": "atlasloot" }, { "name": "Commander Gor'shak ", - "x": 3293.2, - "y": 3759.8, + "x": 3273.8, + "y": 3524.2, "rare": false, + "kg_floor_id": 194, "source": "atlasloot" }, { "name": "Marshal Windsor", - "x": 3229.8, - "y": 4065.8, + "x": 3210.1, + "y": 3807.0, "rare": false, + "kg_floor_id": 194, "source": "atlasloot" }, { "name": "Ring of Law", - "x": 3103.0, - "y": 2623.0, + "x": 3082.8, + "y": 2473.7, "rare": false, + "kg_floor_id": 194, "source": "atlasloot" }, { "name": "The Vault", - "x": 3673.5, - "y": 2841.6, + "x": 3655.6, + "y": 2675.7, "rare": false, + "kg_floor_id": 194, "source": "atlasloot" }, { "name": "Ring of Law", - "x": 3103.0, - "y": 3847.2, + "x": 3082.8, + "y": 3605.0, "rare": false, + "kg_floor_id": 194, "source": "atlasloot" }, { "name": "Shadowforge Lock", - "x": 2532.5, - "y": 3934.7, + "x": 2510.1, + "y": 3685.8, "rare": false, + "kg_floor_id": 194, "source": "atlasloot" }, { "name": "The Grim Guzzler", - "x": 3039.6, - "y": 2710.5, + "x": 3019.2, + "y": 2554.5, "rare": false, + "kg_floor_id": 194, "source": "atlasloot" }, { "name": "Summoner's Tomb", - "x": 3293.2, - "y": 1049.1, + "x": 3273.8, + "y": 1019.1, "rare": false, + "kg_floor_id": 194, "source": "atlasloot" }, { "name": "The Lyceum", - "x": 4117.3, - "y": 480.7, + "x": 4101.0, + "y": 493.8, "rare": false, + "kg_floor_id": 194, "source": "atlasloot" }, { "name": "The Black Forge", - "x": 3863.7, - "y": 1049.1, + "x": 3846.5, + "y": 1019.1, "rare": false, + "kg_floor_id": 194, "source": "atlasloot" }, { "name": "Molten Core", - "x": 4180.7, - "y": 1530.0, - "rare": false, - "source": "atlasloot" - } - ], - "lower_blackrock_spire": [ - { - "name": "Mother Smolderweb", - "x": 3949.6, - "y": 2798.5, - "rare": false, - "source": "atlasloot" - }, - { - "name": "Burning Felguard (Rare, Summon)", - "x": 2473.0, - "y": 2039.6, - "rare": true, - "source": "atlasloot" - }, - { - "name": "Vaelan (Upper)", - "x": 3105.8, - "y": 1423.0, - "rare": false, - "source": "atlasloot" - }, - { - "name": "Warosh (Wanders)", - "x": 3738.6, - "y": 1517.9, - "rare": false, - "source": "atlasloot" - }, - { - "name": "Bijou", - "x": 3879.3, - "y": 2134.5, - "rare": false, - "source": "atlasloot" - }, - { - "name": "Roughshod Pike", - "x": 4160.5, - "y": 2229.3, - "rare": false, - "source": "atlasloot" - }, - { - "name": "Spirestone Butcher (Rare)", - "x": 3035.5, - "y": 2229.3, - "rare": true, - "source": "atlasloot" - }, - { - "name": "Human Remains (Lower)", - "x": 2473.0, - "y": 2134.5, - "rare": false, - "source": "atlasloot" - }, - { - "name": "Urok's Tribute Pile", - "x": 2683.9, - "y": 2087.0, - "rare": false, - "source": "atlasloot" - }, - { - "name": "Halycon", - "x": 2121.4, - "y": 3509.9, - "rare": false, - "source": "atlasloot" - }, - { - "name": "Pyroguard Emberseer", - "x": 1629.2, - "y": 759.0, - "rare": false, - "source": "atlasloot" - }, - { - "name": "Solakar Flamewreath", - "x": 2191.7, - "y": 1328.2, - "rare": false, - "source": "atlasloot" - }, - { - "name": "Goraluk Anvilcrack ", - "x": 1769.8, - "y": 759.0, - "rare": false, - "source": "atlasloot" - }, - { - "name": "Warchief Rend Blackhand", - "x": 2894.9, - "y": 759.0, - "rare": false, - "source": "atlasloot" - }, - { - "name": "The Beast", - "x": 3949.6, - "y": 996.2, - "rare": false, - "source": "atlasloot" - }, - { - "name": "General Drakkisath", - "x": 1980.7, - "y": 1849.9, + "x": 4164.7, + "y": 1463.6, "rare": false, + "kg_floor_id": 194, "source": "atlasloot" } ], "upper_blackrock_spire": [ { "name": "War Master Voone", - "x": 3121.7, - "y": 2058.6, + "x": 3108.6, + "y": 2048.1, "rare": false, + "kg_floor_id": 252, "source": "atlasloot" }, { "name": "Mother Smolderweb", - "x": 3859.8, - "y": 2602.6, + "x": 3870.3, + "y": 2571.7, "rare": false, + "kg_floor_id": 252, "source": "atlasloot" }, { "name": "Burning Felguard (Rare, Summon)", - "x": 2568.2, - "y": 2058.6, + "x": 2537.3, + "y": 2048.1, "rare": true, + "kg_floor_id": 252, "source": "atlasloot" }, { "name": "Shadow Hunter Vosh'gajin", - "x": 3367.7, - "y": 2602.6, + "x": 3362.5, + "y": 2571.7, "rare": false, + "kg_floor_id": 252, "source": "atlasloot" }, { "name": "Vaelan (Upper)", - "x": 3121.7, - "y": 1616.5, + "x": 3151.7, + "y": 1626.5, "rare": false, + "kg_floor_id": 251, "source": "atlasloot" }, { "name": "Warosh (Wanders)", - "x": 3675.3, - "y": 1684.5, + "x": 3679.9, + "y": 1688.1, "rare": false, + "kg_floor_id": 252, "source": "atlasloot" }, { "name": "Highlord Omokk", - "x": 2322.2, - "y": 2262.6, + "x": 2283.3, + "y": 2244.4, "rare": false, + "kg_floor_id": 252, "source": "atlasloot" }, { "name": "Urok's Tribute Pile", - "x": 2752.7, - "y": 2092.6, + "x": 2727.7, + "y": 2080.8, "rare": false, + "kg_floor_id": 252, "source": "atlasloot" }, { "name": "Bannok Grimaxe (Rare)", - "x": 2752.7, - "y": 2432.6, + "x": 2727.7, + "y": 2408.1, "rare": true, + "kg_floor_id": 252, "source": "atlasloot" }, { "name": "Quartermaster Zigris ", - "x": 3306.2, - "y": 3112.7, + "x": 3299.0, + "y": 3062.6, "rare": false, + "kg_floor_id": 252, "source": "atlasloot" }, { "name": "Darkstone Tablet", - "x": 1891.6, - "y": 1650.5, + "x": 1917.7, + "y": 1664.0, "rare": false, + "kg_floor_id": 251, "source": "atlasloot" }, { "name": "Overlord Wyrmthalak", - "x": 3490.8, - "y": 2398.6, + "x": 3489.4, + "y": 2375.3, "rare": false, + "kg_floor_id": 252, "source": "atlasloot" }, { "name": "Jed Runewatcher (Rare)", - "x": 2260.7, - "y": 1038.4, + "x": 2287.9, + "y": 988.6, "rare": true, + "kg_floor_id": 251, "source": "atlasloot" }, { "name": "Goraluk Anvilcrack ", - "x": 1953.1, - "y": 1140.4, + "x": 1979.4, + "y": 1101.2, "rare": false, + "kg_floor_id": 251, "source": "atlasloot" }, { "name": "Awbee", - "x": 2937.2, - "y": 1446.5, + "x": 2918.1, + "y": 1459.0, "rare": false, + "kg_floor_id": 252, "source": "atlasloot" }, { "name": "Blackwing Lair", - "x": 3306.2, - "y": 970.4, + "x": 3299.0, + "y": 1000.8, "rare": false, + "kg_floor_id": 252, "source": "atlasloot" } ], "stratholme": [ { "name": "Crusaders' Square Postbox", - "x": 2415.9, - "y": 1333.3, + "x": 2433.2, + "y": 1197.4, "rare": false, + "kg_floor_id": 234, "source": "atlasloot" }, { "name": "Market Row Postbox", - "x": 3976.3, - "y": 1034.2, + "x": 4218.7, + "y": 1113.8, "rare": false, + "kg_floor_id": 235, "source": "atlasloot" }, { "name": "Festival Lane Postbox", - "x": 4496.5, - "y": 1076.9, + "x": 4241.9, + "y": 924.6, "rare": false, + "kg_floor_id": 234, "source": "atlasloot" }, { "name": "King's Square Postbox", - "x": 3739.9, - "y": 2102.2, + "x": 3903.7, + "y": 2170.3, "rare": false, + "kg_floor_id": 235, "source": "atlasloot" }, { "name": "Fras Siabi's Postbox", - "x": 3314.3, - "y": 2785.7, + "x": 3336.7, + "y": 2846.4, "rare": false, + "kg_floor_id": 235, "source": "atlasloot" }, { "name": "Atiesh (Summon)", - "x": 4780.2, - "y": 1461.4, + "x": 4488.6, + "y": 1333.8, "rare": false, + "kg_floor_id": 234, "source": "atlasloot" }, { "name": "Elder Farwhisper (Lunar Festival)", - "x": 4449.2, - "y": 564.3, + "x": 4200.8, + "y": 379.0, "rare": false, + "kg_floor_id": 234, "source": "atlasloot" }, { "name": "Malor the Zealous", - "x": 2132.2, - "y": 1632.3, + "x": 2186.6, + "y": 1515.7, "rare": false, + "kg_floor_id": 234, "source": "atlasloot" }, { "name": "Crimson Hammersmith (Summon)", - "x": 1328.3, - "y": 1888.6, + "x": 1487.7, + "y": 1788.5, "rare": false, + "kg_floor_id": 234, "source": "atlasloot" }, { "name": "Cannon Master Willey", - "x": 950.0, - "y": 2016.7, + "x": 1158.9, + "y": 1924.9, "rare": false, + "kg_floor_id": 234, "source": "atlasloot" }, { "name": "Archivist Galford", - "x": 2037.6, - "y": 2999.3, + "x": 2104.4, + "y": 2970.7, "rare": false, + "kg_floor_id": 234, "source": "atlasloot" }, { "name": "Elders' Square Postbox", - "x": 3881.8, - "y": 3084.7, + "x": 4092.7, + "y": 3142.3, "rare": false, + "kg_floor_id": 235, "source": "atlasloot" }, { "name": "Aurius", - "x": 3929.1, - "y": 2999.3, + "x": 4155.7, + "y": 3057.7, "rare": false, + "kg_floor_id": 235, "source": "atlasloot" }, { "name": "Stonespine (Rare)", - "x": 4023.6, - "y": 2016.7, + "x": 4281.7, + "y": 2085.8, "rare": true, + "kg_floor_id": 235, "source": "atlasloot" } ], "scholomance": [ { "name": "Blood Steward of Kirtonos", - "x": 5213.8, - "y": 1854.2, + "x": 5195.8, + "y": 1790.4, "rare": false, + "kg_floor_id": 225, "source": "atlasloot" }, { "name": "The Deed to Tarren Mill", - "x": 1737.2, - "y": 2367.6, + "x": 1776.8, + "y": 2280.8, "rare": false, + "kg_floor_id": 225, "source": "atlasloot" }, { "name": "Torch Lever", - "x": 2964.2, - "y": 2274.2, + "x": 2983.5, + "y": 2191.6, "rare": false, + "kg_floor_id": 225, "source": "atlasloot" } ], @@ -828,6 +863,7 @@ "x": 1220.9, "y": 3130.0, "rare": false, + "kg_floor_id": 198, "source": "atlasloot" }, { @@ -835,6 +871,7 @@ "x": 2074.4, "y": 2142.0, "rare": false, + "kg_floor_id": 198, "source": "atlasloot" }, { @@ -842,6 +879,7 @@ "x": 1985.3, "y": 1811.4, "rare": false, + "kg_floor_id": 198, "source": "atlasloot" }, { @@ -849,6 +887,7 @@ "x": 2189.1, "y": 2327.5, "rare": false, + "kg_floor_id": 198, "source": "atlasloot" }, { @@ -856,6 +895,7 @@ "x": 896.1, "y": 2230.7, "rare": false, + "kg_floor_id": 198, "source": "atlasloot" }, { @@ -863,6 +903,7 @@ "x": 3857.9, "y": 593.6, "rare": false, + "kg_floor_id": 198, "source": "atlasloot" }, { @@ -870,6 +911,7 @@ "x": 2558.5, "y": 1968.6, "rare": false, + "kg_floor_id": 198, "source": "atlasloot" }, { @@ -877,6 +919,7 @@ "x": 2781.4, "y": 1863.8, "rare": false, + "kg_floor_id": 198, "source": "atlasloot" }, { @@ -884,217 +927,231 @@ "x": 3596.7, "y": 1150.1, "rare": false, + "kg_floor_id": 198, "source": "atlasloot" } ], "dire_maul_east": [ - { - "name": "Stomper Kreeg ", - "x": 3447.2, - "y": 3937.5, - "rare": false, - "source": "atlasloot" - }, { "name": "Guard Slip'kik", - "x": 2647.3, - "y": 3201.7, + "x": 3261.5, + "y": 3653.6, "rare": false, + "kg_floor_id": 203, "source": "atlasloot" }, { "name": "Captain Kromcrush", - "x": 2770.1, - "y": 2740.0, + "x": 3296.2, + "y": 3102.6, "rare": false, + "kg_floor_id": 203, "source": "atlasloot" }, { "name": "King Gordok", - "x": 2774.8, - "y": 1030.3, + "x": 3297.6, + "y": 1062.3, "rare": false, + "kg_floor_id": 203, "source": "atlasloot" }, { "name": "Pylons", - "x": 3655.9, - "y": 2711.1, + "x": 3546.7, + "y": 3068.2, "rare": false, + "kg_floor_id": 203, "source": "atlasloot" }, { "name": "Pylons", - "x": 2960.3, - "y": 619.1, + "x": 3350.0, + "y": 571.6, "rare": false, + "kg_floor_id": 203, "source": "atlasloot" }, { "name": "Tendris Warpwood", - "x": 2807.2, - "y": 2891.5, + "x": 3306.7, + "y": 3283.4, "rare": false, + "kg_floor_id": 203, "source": "atlasloot" }, { "name": "Magister Kalendris", - "x": 2774.8, - "y": 2299.9, + "x": 3297.6, + "y": 2577.5, "rare": false, + "kg_floor_id": 203, "source": "atlasloot" }, { "name": "Tsu'zee (Rare)", - "x": 3616.4, - "y": 756.1, + "x": 3535.5, + "y": 735.1, "rare": true, + "kg_floor_id": 203, "source": "atlasloot" }, { "name": "Immol'thar", - "x": 2849.0, - "y": 3223.3, + "x": 3318.5, + "y": 3679.4, "rare": false, + "kg_floor_id": 203, "source": "atlasloot" }, { "name": "Lord Hel'nurath (Summon)", - "x": 2378.3, - "y": 3050.2, + "x": 3185.4, + "y": 3472.8, "rare": false, + "kg_floor_id": 203, "source": "atlasloot" }, { "name": "Prince Tortheldrin", - "x": 3456.5, - "y": 121.3, + "x": 3490.3, + "y": -22.5, "rare": false, + "kg_floor_id": 203, "source": "atlasloot" }, { "name": "Pylons", - "x": 3053.0, - "y": 1556.9, - "rare": false, - "source": "atlasloot" - }, - { - "name": "Old Ironbark", - "x": 2960.3, - "y": 3937.5, + "x": 3376.2, + "y": 1690.7, "rare": false, + "kg_floor_id": 203, "source": "atlasloot" } ], "dire_maul_west": [ { "name": "Guard Mol'dar", - "x": 4061.4, - "y": 3117.0, + "x": 4352.2, + "y": 2945.2, "rare": false, + "kg_floor_id": 201, "source": "atlasloot" }, { "name": "Stomper Kreeg ", - "x": 3611.3, - "y": 2815.6, + "x": 3787.6, + "y": 2683.6, "rare": false, + "kg_floor_id": 201, "source": "atlasloot" }, { "name": "Guard Fengus", - "x": 2696.1, - "y": 3177.2, + "x": 2639.4, + "y": 2997.5, "rare": false, + "kg_floor_id": 201, "source": "atlasloot" }, { "name": "Guard Slip'kik", - "x": 1866.8, - "y": 2431.4, + "x": 2000.1, + "y": 2382.2, "rare": false, + "kg_floor_id": 199, "source": "atlasloot" }, { "name": "Captain Kromcrush", - "x": 2134.8, - "y": 2190.3, + "x": 2061.1, + "y": 2069.2, "rare": false, + "kg_floor_id": 199, "source": "atlasloot" }, { "name": "King Gordok", - "x": 2144.9, - "y": 1297.6, + "x": 2063.4, + "y": 910.0, "rare": false, + "kg_floor_id": 199, "source": "atlasloot" }, { "name": "Lord Hel'nurath (Summon)", - "x": 1280.2, - "y": 2352.3, + "x": 1866.5, + "y": 2279.5, "rare": false, + "kg_floor_id": 199, "source": "atlasloot" }, { "name": "Hydrospawn", - "x": 2600.0, - "y": 2107.4, + "x": 2167.1, + "y": 1961.6, "rare": false, + "kg_floor_id": 199, "source": "atlasloot" }, { "name": "Lethtendris", - "x": 2777.0, - "y": 2009.5, + "x": 2207.4, + "y": 1834.4, "rare": false, + "kg_floor_id": 199, "source": "atlasloot" }, { "name": "Alzzin the Wildshaper", - "x": 3424.2, - "y": 1342.8, + "x": 3552.9, + "y": 1405.3, "rare": false, + "kg_floor_id": 201, "source": "atlasloot" } ], "blackwinglair": [ { "name": "Draconic for Dummies (Chapter VII)", - "x": 2120.6, - "y": 1770.8, + "x": 2254.4, + "y": 1615.4, "rare": false, + "kg_floor_id": 312, "source": "atlasloot" }, { "name": "Master Elemental Shaper Krixix", - "x": 2569.4, - "y": 1722.8, + "x": 2610.7, + "y": 1517.1, "rare": false, + "kg_floor_id": 312, "source": "atlasloot" } ], "naxxramas_classic": [ { "name": "|cffcc6666Instructor Razuvious", - "x": 2683.1, - "y": 1682.3, + "x": 2602.4, + "y": 1894.1, "rare": false, + "kg_floor_id": 138, "source": "atlasloot" }, { "name": "|cffcc6666Gothik the Harvester", - "x": 3996.6, - "y": 1869.7, + "x": 4128.5, + "y": 2470.0, "rare": false, + "kg_floor_id": 138, "source": "atlasloot" }, { "name": "|cffcc6666Four Horsemen Chest", - "x": 1971.6, - "y": 2097.3, + "x": 1839.2, + "y": 3176.0, "rare": false, + "kg_floor_id": 141, "source": "atlasloot" } ] diff --git a/tools/atlasloot_extras.py b/tools/atlasloot_extras.py index 9ca20ba..859703f 100644 --- a/tools/atlasloot_extras.py +++ b/tools/atlasloot_extras.py @@ -98,28 +98,26 @@ def parse_js_var(p: Path) -> dict: def get_kg_bosses_per_floor(tile_key: str): - """Return list of (npc_id, name, x_px, y_px, classification) for - boss-like enemies in the dungeon's first floor only — enough to fit - a transform; later floors share the same coord scale anyway.""" + """Return list of dicts per boss-like enemy across ALL floors. + Caller groups by floor_id when fitting per-floor transforms.""" sf = parse_js_var(KG_DIR / tile_key / "split_floors.js") lang = parse_js_var(KG_DIR / tile_key / "lang.js") name_by_id = {n["id"]: n["name"] for n in lang.get("dungeonNpcs", [])} cls_by_id = {n["id"]: n.get("classification_id") for n in lang.get("dungeonNpcs", [])} - # First floor: pick the lowest floor_id present - enemies = sf["dungeon"].get("enemies", []) - if not enemies: - return [] out = [] - for e in enemies: + for e in sf["dungeon"].get("enemies", []): npc_id = e.get("npc_id") name = name_by_id.get(npc_id, "?") cls = cls_by_id.get(npc_id, 0) if cls < 3: - continue # only bosses - # kg coord transform: pixel_x = lng*16, pixel_y = -lat*16 (z=4) - pix_x = e["lng"] * 16 - pix_y = -e["lat"] * 16 - out.append((npc_id, name, pix_x, pix_y, cls, e.get("floor_id"))) + continue + out.append({ + "name": name, + "x": e["lng"] * 16, + "y": -e["lat"] * 16, + "cls": cls, + "floor_id": e.get("floor_id"), + }) return out @@ -192,40 +190,12 @@ def main() -> int: if not al_dungeon: continue al_entries = list(collect_al_entries(al_dungeon)) - # Match AL entries to kg bosses by normalized name - al_by_norm = {norm_name(e[0]): e for e in al_entries if not e[3]} # non-rare bosses for fitting - # For each kg wing, fit a transform from anchors that match + al_by_norm = {norm_name(e[0]): e for e in al_entries if not e[3]} + for kg_key in kg_keys: kg_b = kg_bosses.get(kg_key, []) if not kg_b: continue - kg_by_norm = {norm_name(b[1]): b for b in kg_b} - common_names = set(al_by_norm) & set(kg_by_norm) - if len(common_names) < 2: - summary.append(f"{al_id} → {kg_key}: only {len(common_names)} anchor(s); skipping") - continue - al_pts = [] - kg_pts = [] - for n in sorted(common_names): - al_e = al_by_norm[n] - kg_e = kg_by_norm[n] - al_pts.append((al_e[1], al_e[2])) - kg_pts.append((kg_e[2], kg_e[3])) - tr = fit_transform(al_pts, kg_pts) - if not tr: - summary.append(f"{al_id} → {kg_key}: degenerate fit") - continue - sx, ox, sy, oy = tr - transforms[(al_id, kg_key)] = tr - summary.append( - f"{al_id} → {kg_key}: {len(common_names)} anchors, " - f"scale=({sx:.2f},{sy:.2f}) offset=({ox:.0f},{oy:.0f})" - ) - - # Apply transform to AL entries that don't already exist as kg bosses - kg_existing_norms = {norm_name(b[1]) for b in kg_b} - # Build the set of "this dungeon's bosses pinned to a different - # wing" so we can exclude them here. other_wings = [k for k in kg_keys if k != kg_key] forced_elsewhere = set() for w in other_wings: @@ -233,24 +203,63 @@ def main() -> int: forced_elsewhere.add(needle.lower()) this_wing_pins = {n.lower() for n in WING_FORCE.get(kg_key, [])} + # Group kg bosses by floor_id and fit one transform per floor + # so a boss on floor B doesn't drag the floor-A fit off. + by_floor = defaultdict(list) + for b in kg_b: + by_floor[b["floor_id"]].append(b) + + floor_transforms = {} # floor_id → (sx, ox, sy, oy, anchor_pts) + for fid, fb in by_floor.items(): + kg_by_norm = {norm_name(b["name"]): b for b in fb} + common = set(al_by_norm) & set(kg_by_norm) + if len(common) < 2: + continue + al_pts, kg_pts = [], [] + for n in sorted(common): + al_pts.append((al_by_norm[n][1], al_by_norm[n][2])) + kg_pts.append((kg_by_norm[n]["x"], kg_by_norm[n]["y"])) + tr = fit_transform(al_pts, kg_pts) + if not tr: + continue + floor_transforms[fid] = (*tr, al_pts, kg_pts) + transforms[(al_id, kg_key, fid)] = tr + summary.append( + f"{al_id} → {kg_key} floor={fid}: {len(common)} anchors, " + f"scale=({tr[0]:.2f},{tr[2]:.2f}) offset=({tr[1]:.0f},{tr[3]:.0f})" + ) + + if not floor_transforms: + summary.append(f"{al_id} → {kg_key}: no per-floor transform fit") + continue + + kg_existing = set() + for fb in by_floor.values(): + for b in fb: + kg_existing.add(norm_name(b["name"])) + for e in al_entries: name = e[0] lname = name.lower() - if norm_name(name) in kg_existing_norms: - continue # already in kg - # If this boss is force-pinned to another wing, skip here. + if norm_name(name) in kg_existing: + continue if any(p in lname for p in forced_elsewhere) and \ not any(p in lname for p in this_wing_pins): continue + # Pick the floor whose anchors are nearest the AL coord — + # that's the floor this entry most likely belongs to. + best_fid = None + best_dist = float("inf") + for fid, (sx, ox, sy, oy, al_pts, kg_pts) in floor_transforms.items(): + d = min(((e[1] - a[0]) ** 2 + (e[2] - a[1]) ** 2) ** 0.5 for a in al_pts) + if d < best_dist: + best_dist = d + best_fid = fid + sx, ox, sy, oy, al_pts, kg_pts = floor_transforms[best_fid] px = e[1] * sx + ox py = e[2] * sy + oy - # Reject points outside the kg image bounds (multi-wing - # dungeons: a boss in a wing is OOB on a different wing's - # image). if not (-200 <= px <= 6344 and -200 <= py <= 4296): continue - # Also reject points that are >1.5x the diagonal away from - # all anchors — likely a wrong-wing match. anchor_dists = [ ((px - a[0]) ** 2 + (py - a[1]) ** 2) ** 0.5 for a in kg_pts ] @@ -261,12 +270,13 @@ def main() -> int: "x": round(px, 1), "y": round(py, 1), "rare": e[3], + "kg_floor_id": best_fid, "source": "atlasloot", }) OUT.write_text(json.dumps({ "_comment": "Supplemental rare bosses + interactives lifted from AtlasLootAscension and transformed into keystone.guru pixel space. Generated by tools/atlasloot_extras.py.", - "transforms": {f"{k[0]}→{k[1]}": v for k, v in transforms.items()}, + "transforms": {f"{k[0]}→{k[1]}@floor{k[2]}": v for k, v in transforms.items()}, "extras": dict(extras), }, indent=2)) diff --git a/tools/kg_build_data.py b/tools/kg_build_data.py index 6acd59c..ced05ae 100644 --- a/tools/kg_build_data.py +++ b/tools/kg_build_data.py @@ -26,6 +26,7 @@ REGISTRY = DATA / "kg_dungeons.json" WEB_ASSETS = ROOT / "web" / "assets" WEB_MAPS = WEB_ASSETS / "maps" EXTRAS_PATH = DATA / "atlasloot_extras.json" +OVERRIDES_PATH = DATA / "ascension_overrides.json" OUT_PATH = WEB_ASSETS / "dungeons.json" # Map kg's mapIconType names → simple labels we render in the UI. @@ -223,6 +224,22 @@ def main() -> int: if EXTRAS_PATH.exists(): extras_db = json.loads(EXTRAS_PATH.read_text()).get("extras", {}) + overrides = [] + if OVERRIDES_PATH.exists(): + overrides = json.loads(OVERRIDES_PATH.read_text()).get("overrides", []) + + def apply_overrides(tile_key, name, pos, floor_id): + """Return (pos, floor_id) possibly replaced by an Ascension override.""" + for o in overrides: + if o["tile_key"] != tile_key: + continue + if o["name"].lower() not in name.lower(): + continue + new_floor = o.get("kg_floor_id", floor_id) + new_pos = o.get("pos", pos) + return new_pos, new_floor + return pos, floor_id + # Build a global icon-type index from the static.js if present, else # fall back to known IDs. icon_index: dict[int, str] = { @@ -261,9 +278,25 @@ def main() -> int: "pos": [e["x"], e["y"]], "rare": bool(e.get("rare")), "source": e.get("source", "atlasloot"), + "kg_floor_id": e.get("kg_floor_id"), } for e in extras ] + + # Ascension overrides: swap pos / floor for a specific named entity + for m in entry["maps"]: + for e in m["enemies"]: + new_pos, new_floor = apply_overrides(d["tile_key"], e["name"], e["pos"], m.get("kg_floor_id")) + if new_pos is not e["pos"]: + e["pos"] = list(new_pos) + e["ascension_override"] = True + for ex in entry.get("extras", []): + new_pos, new_floor = apply_overrides(d["tile_key"], ex["name"], ex["pos"], ex.get("kg_floor_id")) + if new_pos is not ex["pos"]: + ex["pos"] = list(new_pos) + ex["kg_floor_id"] = new_floor + ex["ascension_override"] = True + dungeons.append(entry) dungeons.sort(key=lambda d: d["name"]) diff --git a/web/app.js b/web/app.js index 25f911d..39002f0 100644 --- a/web/app.js +++ b/web/app.js @@ -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"); diff --git a/web/assets/dungeons.json b/web/assets/dungeons.json index a14ac34..ac4d8f6 100644 --- a/web/assets/dungeons.json +++ b/web/assets/dungeons.json @@ -24986,110 +24986,122 @@ { "name": "Kharan Mighthammer", "pos": [ - 3166.4, - 3541.2 + 3146.5, + 3322.2 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 194 }, { "name": "Commander Gor'shak ", "pos": [ - 3293.2, - 3759.8 + 3273.8, + 3524.2 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 194 }, { "name": "Marshal Windsor", "pos": [ - 3229.8, - 4065.8 + 3210.1, + 3807.0 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 194 }, { "name": "Ring of Law", "pos": [ - 3103.0, - 2623.0 + 3082.8, + 2473.7 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 194 }, { "name": "The Vault", "pos": [ - 3673.5, - 2841.6 + 3655.6, + 2675.7 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 194 }, { "name": "Ring of Law", "pos": [ - 3103.0, - 3847.2 + 3082.8, + 3605.0 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 194 }, { "name": "Shadowforge Lock", "pos": [ - 2532.5, - 3934.7 + 2510.1, + 3685.8 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 194 }, { "name": "The Grim Guzzler", "pos": [ - 3039.6, - 2710.5 + 3019.2, + 2554.5 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 194 }, { "name": "Summoner's Tomb", "pos": [ - 3293.2, - 1049.1 + 3273.8, + 1019.1 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 194 }, { "name": "The Lyceum", "pos": [ - 4117.3, - 480.7 + 4101.0, + 493.8 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 194 }, { "name": "The Black Forge", "pos": [ - 3863.7, - 1049.1 + 3846.5, + 1019.1 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 194 }, { "name": "Molten Core", "pos": [ - 4180.7, - 1530.0 + 4164.7, + 1463.6 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 194 } ] }, @@ -27458,20 +27470,22 @@ { "name": "Draconic for Dummies (Chapter VII)", "pos": [ - 2120.6, - 1770.8 + 2254.4, + 1615.4 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 312 }, { "name": "Master Elemental Shaper Krixix", "pos": [ - 2569.4, - 1722.8 + 2610.7, + 1517.1 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 312 } ] }, @@ -34730,131 +34744,125 @@ } ], "extras": [ - { - "name": "Stomper Kreeg ", - "pos": [ - 3447.2, - 3937.5 - ], - "rare": false, - "source": "atlasloot" - }, { "name": "Guard Slip'kik", "pos": [ - 2647.3, - 3201.7 + 3261.5, + 3653.6 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 203 }, { "name": "Captain Kromcrush", "pos": [ - 2770.1, - 2740.0 + 3296.2, + 3102.6 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 203 }, { "name": "King Gordok", "pos": [ - 2774.8, - 1030.3 + 3297.6, + 1062.3 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 203 }, { "name": "Pylons", "pos": [ - 3655.9, - 2711.1 + 3546.7, + 3068.2 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 203 }, { "name": "Pylons", "pos": [ - 2960.3, - 619.1 + 3350.0, + 571.6 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 203 }, { "name": "Tendris Warpwood", "pos": [ - 2807.2, - 2891.5 + 3306.7, + 3283.4 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 203 }, { "name": "Magister Kalendris", "pos": [ - 2774.8, - 2299.9 + 3297.6, + 2577.5 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 203 }, { "name": "Tsu'zee (Rare)", "pos": [ - 3616.4, - 756.1 + 3535.5, + 735.1 ], "rare": true, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 203 }, { "name": "Immol'thar", "pos": [ - 2849.0, - 3223.3 + 3318.5, + 3679.4 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 203 }, { "name": "Lord Hel'nurath (Summon)", "pos": [ - 2378.3, - 3050.2 + 3185.4, + 3472.8 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 203 }, { "name": "Prince Tortheldrin", "pos": [ - 3456.5, - 121.3 + 3490.3, + -22.5 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 203 }, { "name": "Pylons", "pos": [ - 3053.0, - 1556.9 + 3376.2, + 1690.7 ], "rare": false, - "source": "atlasloot" - }, - { - "name": "Old Ironbark", - "pos": [ - 2960.3, - 3937.5 - ], - "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 203 } ] }, @@ -40991,7 +40999,8 @@ 3130.0 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 198 }, { "name": "Tendris Warpwood", @@ -41000,7 +41009,8 @@ 2142.0 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 198 }, { "name": "Magister Kalendris", @@ -41009,7 +41019,8 @@ 1811.4 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 198 }, { "name": "Immol'thar", @@ -41018,7 +41029,8 @@ 2327.5 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 198 }, { "name": "Lord Hel'nurath (Summon)", @@ -41027,7 +41039,8 @@ 2230.7 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 198 }, { "name": "Prince Tortheldrin", @@ -41036,7 +41049,8 @@ 593.6 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 198 }, { "name": "Hydrospawn", @@ -41045,7 +41059,8 @@ 1968.6 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 198 }, { "name": "Lethtendris", @@ -41054,7 +41069,8 @@ 1863.8 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 198 }, { "name": "Alzzin the Wildshaper", @@ -41063,7 +41079,8 @@ 1150.1 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 198 } ] }, @@ -46691,92 +46708,102 @@ { "name": "Guard Mol'dar", "pos": [ - 4061.4, - 3117.0 + 4352.2, + 2945.2 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 201 }, { "name": "Stomper Kreeg ", "pos": [ - 3611.3, - 2815.6 + 3787.6, + 2683.6 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 201 }, { "name": "Guard Fengus", "pos": [ - 2696.1, - 3177.2 + 2639.4, + 2997.5 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 201 }, { "name": "Guard Slip'kik", "pos": [ - 1866.8, - 2431.4 + 2000.1, + 2382.2 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 199 }, { "name": "Captain Kromcrush", "pos": [ - 2134.8, - 2190.3 + 2061.1, + 2069.2 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 199 }, { "name": "King Gordok", "pos": [ - 2144.9, - 1297.6 + 2063.4, + 910.0 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 199 }, { "name": "Lord Hel'nurath (Summon)", "pos": [ - 1280.2, - 2352.3 + 1866.5, + 2279.5 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 199 }, { "name": "Hydrospawn", "pos": [ - 2600.0, - 2107.4 + 2167.1, + 1961.6 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 199 }, { "name": "Lethtendris", "pos": [ - 2777.0, - 2009.5 + 2207.4, + 1834.4 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 199 }, { "name": "Alzzin the Wildshaper", "pos": [ - 3424.2, - 1342.8 + 3552.9, + 1405.3 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 201 } ] }, @@ -54589,17 +54616,6 @@ } ] } - ], - "extras": [ - { - "name": "Clean Room", - "pos": [ - 5674.2, - 2664.2 - ], - "rare": false, - "source": "atlasloot" - } ] }, { @@ -64214,152 +64230,6 @@ "patrols": [], "icons": [] } - ], - "extras": [ - { - "name": "Mother Smolderweb", - "pos": [ - 3949.6, - 2798.5 - ], - "rare": false, - "source": "atlasloot" - }, - { - "name": "Burning Felguard (Rare, Summon)", - "pos": [ - 2473.0, - 2039.6 - ], - "rare": true, - "source": "atlasloot" - }, - { - "name": "Vaelan (Upper)", - "pos": [ - 3105.8, - 1423.0 - ], - "rare": false, - "source": "atlasloot" - }, - { - "name": "Warosh (Wanders)", - "pos": [ - 3738.6, - 1517.9 - ], - "rare": false, - "source": "atlasloot" - }, - { - "name": "Bijou", - "pos": [ - 3879.3, - 2134.5 - ], - "rare": false, - "source": "atlasloot" - }, - { - "name": "Roughshod Pike", - "pos": [ - 4160.5, - 2229.3 - ], - "rare": false, - "source": "atlasloot" - }, - { - "name": "Spirestone Butcher (Rare)", - "pos": [ - 3035.5, - 2229.3 - ], - "rare": true, - "source": "atlasloot" - }, - { - "name": "Human Remains (Lower)", - "pos": [ - 2473.0, - 2134.5 - ], - "rare": false, - "source": "atlasloot" - }, - { - "name": "Urok's Tribute Pile", - "pos": [ - 2683.9, - 2087.0 - ], - "rare": false, - "source": "atlasloot" - }, - { - "name": "Halycon", - "pos": [ - 2121.4, - 3509.9 - ], - "rare": false, - "source": "atlasloot" - }, - { - "name": "Pyroguard Emberseer", - "pos": [ - 1629.2, - 759.0 - ], - "rare": false, - "source": "atlasloot" - }, - { - "name": "Solakar Flamewreath", - "pos": [ - 2191.7, - 1328.2 - ], - "rare": false, - "source": "atlasloot" - }, - { - "name": "Goraluk Anvilcrack ", - "pos": [ - 1769.8, - 759.0 - ], - "rare": false, - "source": "atlasloot" - }, - { - "name": "Warchief Rend Blackhand", - "pos": [ - 2894.9, - 759.0 - ], - "rare": false, - "source": "atlasloot" - }, - { - "name": "The Beast", - "pos": [ - 3949.6, - 996.2 - ], - "rare": false, - "source": "atlasloot" - }, - { - "name": "General Drakkisath", - "pos": [ - 1980.7, - 1849.9 - ], - "rare": false, - "source": "atlasloot" - } ] }, { @@ -78110,20 +77980,22 @@ { "name": "Veng ", "pos": [ - 3732.3, - 946.8 + 3795.3, + 896.3 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 214 }, { "name": "Maraudos ", "pos": [ - 3299.8, - 3056.4 + 3256.7, + 3083.5 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 215 } ] }, @@ -100268,29 +100140,32 @@ { "name": "|cffcc6666Instructor Razuvious", "pos": [ - 2683.1, - 1682.3 + 2602.4, + 1894.1 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 138 }, { "name": "|cffcc6666Gothik the Harvester", "pos": [ - 3996.6, - 1869.7 + 4128.5, + 2470.0 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 138 }, { "name": "|cffcc6666Four Horsemen Chest", "pos": [ - 1971.6, - 2097.3 + 1839.2, + 3176.0 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 141 } ] }, @@ -114583,7 +114458,8 @@ 2011.3 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 218 }, { "name": "Blind Hunter (Rare)", @@ -114592,7 +114468,8 @@ 1272.6 ], "rare": true, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 218 } ] }, @@ -119053,7 +118930,8 @@ 2099.8 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 220 }, { "name": "Pumpkin Shrine (Hallow's End)", @@ -119062,7 +118940,8 @@ 2196.4 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 220 }, { "name": "Bloodmage Thalnos", @@ -119071,7 +118950,8 @@ 1971.0 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 220 }, { "name": "Houndmaster Loksey", @@ -119080,7 +118960,8 @@ 2904.9 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 220 }, { "name": "Arcanist Doan", @@ -119089,7 +118970,8 @@ 2647.3 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 220 }, { "name": "Herod ", @@ -119098,7 +118980,8 @@ 522.0 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 220 } ] }, @@ -121327,7 +121210,8 @@ 2989.3 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 221 }, { "name": "Arcanist Doan", @@ -121336,7 +121220,8 @@ 2801.7 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 221 }, { "name": "Herod ", @@ -121345,7 +121230,8 @@ 1253.9 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 221 }, { "name": "High Inquisitor Fairbanks", @@ -121354,7 +121240,8 @@ 1605.6 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 221 }, { "name": "Scarlet Commander Mograine", @@ -121363,7 +121250,8 @@ 1676.0 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 221 }, { "name": "High Inquisitor Whitemane", @@ -121372,7 +121260,8 @@ 1394.6 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 221 } ] }, @@ -123539,7 +123428,8 @@ 1783.4 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 222 }, { "name": "Bloodmage Thalnos", @@ -123548,7 +123438,8 @@ 1487.0 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 222 } ] }, @@ -131991,29 +131882,32 @@ { "name": "Blood Steward of Kirtonos", "pos": [ - 5213.8, - 1854.2 + 5195.8, + 1790.4 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 225 }, { "name": "The Deed to Tarren Mill", "pos": [ - 1737.2, - 2367.6 + 1776.8, + 2280.8 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 225 }, { "name": "Torch Lever", "pos": [ - 2964.2, - 2274.2 + 2983.5, + 2191.6 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 225 } ] }, @@ -135675,47 +135569,52 @@ { "name": "Investigator Fezzen Brasstacks (Love is in the Air)", "pos": [ - 3373.4, - 2654.4 + 3523.7, + 2390.2 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 232 }, { "name": "Deathstalker Vincent", "pos": [ - 3558.3, - 2408.5 + 3612.8, + 2185.5 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 232 }, { "name": "Apothecary Trio (Love is in the Air)", "pos": [ - 2448.6, - 2039.6 + 2445.0, + 1958.3 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 227 }, { "name": "Fel Steed", "pos": [ - 2202.0, - 2326.5 + 2200.9, + 2283.3 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 227 }, { "name": "Deathsworn Captain (Rare)", "pos": [ - 3681.6, - 2121.6 + 3672.2, + 1946.7 ], "rare": true, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 232 } ] }, @@ -141403,15 +141302,16 @@ "npc_id": 10435, "name": "Magistrate Barthilas", "pos": [ - 3497.7872, - 615.7024 + 3498, + 3300 ], "classification": 3, "skippable": false, "required": false, "kill_priority": null, "pack_id": null, - "patrol_id": null + "patrol_id": null, + "ascension_override": true }, { "id": 33074, @@ -145174,128 +145074,142 @@ { "name": "Crusaders' Square Postbox", "pos": [ - 2415.9, - 1333.3 + 2433.2, + 1197.4 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 234 }, { "name": "Market Row Postbox", "pos": [ - 3976.3, - 1034.2 + 4218.7, + 1113.8 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 235 }, { "name": "Festival Lane Postbox", "pos": [ - 4496.5, - 1076.9 + 4241.9, + 924.6 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 234 }, { "name": "King's Square Postbox", "pos": [ - 3739.9, - 2102.2 + 3903.7, + 2170.3 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 235 }, { "name": "Fras Siabi's Postbox", "pos": [ - 3314.3, - 2785.7 + 3336.7, + 2846.4 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 235 }, { "name": "Atiesh (Summon)", "pos": [ - 4780.2, - 1461.4 + 4488.6, + 1333.8 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 234 }, { "name": "Elder Farwhisper (Lunar Festival)", "pos": [ - 4449.2, - 564.3 + 4200.8, + 379.0 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 234 }, { "name": "Malor the Zealous", "pos": [ - 2132.2, - 1632.3 + 2186.6, + 1515.7 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 234 }, { "name": "Crimson Hammersmith (Summon)", "pos": [ - 1328.3, - 1888.6 + 1487.7, + 1788.5 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 234 }, { "name": "Cannon Master Willey", "pos": [ - 950.0, - 2016.7 + 1158.9, + 1924.9 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 234 }, { "name": "Archivist Galford", "pos": [ - 2037.6, - 2999.3 + 2104.4, + 2970.7 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 234 }, { "name": "Elders' Square Postbox", "pos": [ - 3881.8, - 3084.7 + 4092.7, + 3142.3 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 235 }, { "name": "Aurius", "pos": [ - 3929.1, - 2999.3 + 4155.7, + 3057.7 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 235 }, { "name": "Stonespine (Rare)", "pos": [ - 4023.6, - 2016.7 + 4281.7, + 2085.8 ], "rare": true, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 235 } ] }, @@ -150838,11 +150752,12 @@ { "name": "Defias Gunpowder", "pos": [ - 1572.7, - 2343.0 + 1091.3, + 2149.5 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 196 } ] }, @@ -158803,29 +158718,32 @@ { "name": "Remains of a Paladin", "pos": [ - 3262.4, - 2616.3 + 3254.6, + 2623.8 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 238 }, { "name": "The Discs of Norgannon (Lower)", "pos": [ - 2440.8, - 332.4 + 2437.2, + 344.9 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 238 }, { "name": "The Discs of Norgannon (Lower)", "pos": [ - 3072.8, - 1370.5 + 3066.0, + 1380.8 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 238 } ] }, @@ -164357,146 +164275,162 @@ { "name": "War Master Voone", "pos": [ - 3121.7, - 2058.6 + 3108.6, + 2048.1 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 252 }, { "name": "Mother Smolderweb", "pos": [ - 3859.8, - 2602.6 + 3870.3, + 2571.7 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 252 }, { "name": "Burning Felguard (Rare, Summon)", "pos": [ - 2568.2, - 2058.6 + 2537.3, + 2048.1 ], "rare": true, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 252 }, { "name": "Shadow Hunter Vosh'gajin", "pos": [ - 3367.7, - 2602.6 + 3362.5, + 2571.7 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 252 }, { "name": "Vaelan (Upper)", "pos": [ - 3121.7, - 1616.5 + 3151.7, + 1626.5 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 251 }, { "name": "Warosh (Wanders)", "pos": [ - 3675.3, - 1684.5 + 3679.9, + 1688.1 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 252 }, { "name": "Highlord Omokk", "pos": [ - 2322.2, - 2262.6 + 2283.3, + 2244.4 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 252 }, { "name": "Urok's Tribute Pile", "pos": [ - 2752.7, - 2092.6 + 2727.7, + 2080.8 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 252 }, { "name": "Bannok Grimaxe (Rare)", "pos": [ - 2752.7, - 2432.6 + 2727.7, + 2408.1 ], "rare": true, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 252 }, { "name": "Quartermaster Zigris ", "pos": [ - 3306.2, - 3112.7 + 3299.0, + 3062.6 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 252 }, { "name": "Darkstone Tablet", "pos": [ - 1891.6, - 1650.5 + 1917.7, + 1664.0 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 251 }, { "name": "Overlord Wyrmthalak", "pos": [ - 3490.8, - 2398.6 + 3489.4, + 2375.3 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 252 }, { "name": "Jed Runewatcher (Rare)", "pos": [ - 2260.7, - 1038.4 + 2287.9, + 988.6 ], "rare": true, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 251 }, { "name": "Goraluk Anvilcrack ", "pos": [ - 1953.1, - 1140.4 + 1979.4, + 1101.2 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 251 }, { "name": "Awbee", "pos": [ - 2937.2, - 1446.5 + 2918.1, + 1459.0 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 252 }, { "name": "Blackwing Lair", "pos": [ - 3306.2, - 970.4 + 3299.0, + 1000.8 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 252 } ] }, @@ -172276,7 +172210,8 @@ 1961.7 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 240 } ] }, @@ -179000,7 +178935,8 @@ 712.6 ], "rare": false, - "source": "atlasloot" + "source": "atlasloot", + "kg_floor_id": 241 } ] }, diff --git a/web/index.html b/web/index.html index 2f8ea17..d1a6448 100644 --- a/web/index.html +++ b/web/index.html @@ -33,6 +33,12 @@ + + + + + + diff --git a/web/style.css b/web/style.css index 9661b57..1b5380f 100644 --- a/web/style.css +++ b/web/style.css @@ -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 ----------------------------------------------------- */