azeroth-shell 0.0.0-stage → 0.1.1

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.
Files changed (1163) hide show
  1. package/README.md +138 -2
  2. package/bin/azsh.mjs +19 -0
  3. package/docs/aifid/eventai-texts.json +4414 -0
  4. package/docs/dungeons/atlas/atlas-rows-dungeons.json +8989 -0
  5. package/docs/dungeons/survey/pack-id-migration.json +2418 -0
  6. package/package.json +35 -4
  7. package/src/autopilot/bossSkip.ts +26 -0
  8. package/src/autopilot/combatRotation.ts +824 -0
  9. package/src/autopilot/config.ts +533 -0
  10. package/src/autopilot/consumables.ts +58 -0
  11. package/src/autopilot/encounterStand.ts +121 -0
  12. package/src/autopilot/objectGatePlan.ts +53 -0
  13. package/src/autopilot/pathEngage.ts +229 -0
  14. package/src/autopilot/plan.ts +1643 -0
  15. package/src/autopilot/questPolicy.ts +274 -0
  16. package/src/autopilot/routeStep.ts +69 -0
  17. package/src/autopilot/sessionReport.ts +88 -0
  18. package/src/autopilot/topOffPower.ts +26 -0
  19. package/src/autopilot/view.ts +476 -0
  20. package/src/cli/bootCheck.mjs +34 -0
  21. package/src/cli/bootData.mjs +57 -0
  22. package/src/cli/combatLogFilter.ts +153 -0
  23. package/src/cli/combatLogFormat.ts +613 -0
  24. package/src/cli/fileRepository.mjs +105 -0
  25. package/src/cli/gzLoader.mjs +31 -0
  26. package/src/cli/liveGauntletEscort.ts +978 -0
  27. package/src/cli/liveStratUndead.ts +305 -0
  28. package/src/cli/macroHostCombat.ts +545 -0
  29. package/src/cli/macroHostWorld.ts +330 -0
  30. package/src/cli/prefs.mjs +31 -0
  31. package/src/cli/register.mjs +4 -0
  32. package/src/cli/repl.mjs +693 -0
  33. package/src/cli/rotationText.mjs +226 -0
  34. package/src/cli/squad.mjs +105 -0
  35. package/src/cli/term.mjs +144 -0
  36. package/src/cli/text.mjs +122 -0
  37. package/src/cli/tui.mjs +626 -0
  38. package/src/cli/tuiArena.mjs +109 -0
  39. package/src/cli/tuiAutopilotSettings.mjs +93 -0
  40. package/src/cli/tuiBags.mjs +180 -0
  41. package/src/cli/tuiBars.mjs +133 -0
  42. package/src/cli/tuiBg.mjs +243 -0
  43. package/src/cli/tuiBulk.mjs +162 -0
  44. package/src/cli/tuiCheck.mjs +1882 -0
  45. package/src/cli/tuiCity.mjs +396 -0
  46. package/src/cli/tuiCompanionKit.mjs +300 -0
  47. package/src/cli/tuiCompanions.mjs +471 -0
  48. package/src/cli/tuiDev.mjs +62 -0
  49. package/src/cli/tuiDungeon.mjs +606 -0
  50. package/src/cli/tuiEnchantTarget.mjs +120 -0
  51. package/src/cli/tuiFight.mjs +577 -0
  52. package/src/cli/tuiFightPanes.mjs +228 -0
  53. package/src/cli/tuiFloor.mjs +506 -0
  54. package/src/cli/tuiGear.mjs +158 -0
  55. package/src/cli/tuiHonor.mjs +74 -0
  56. package/src/cli/tuiLoot.mjs +97 -0
  57. package/src/cli/tuiMacros.mjs +144 -0
  58. package/src/cli/tuiOutfitter.mjs +115 -0
  59. package/src/cli/tuiPet.mjs +116 -0
  60. package/src/cli/tuiProfessions.mjs +800 -0
  61. package/src/cli/tuiRaid.mjs +127 -0
  62. package/src/cli/tuiRep.mjs +65 -0
  63. package/src/cli/tuiSaves.mjs +69 -0
  64. package/src/cli/tuiSearch.mjs +363 -0
  65. package/src/cli/tuiSettings.mjs +151 -0
  66. package/src/cli/tuiSimLab.mjs +80 -0
  67. package/src/cli/tuiTalents.mjs +60 -0
  68. package/src/cli/tuiViews.mjs +1178 -0
  69. package/src/cli/tuiWiki.mjs +181 -0
  70. package/src/cli/tuiWorld.mjs +361 -0
  71. package/src/cli/wikiIndex.ts +259 -0
  72. package/src/cli/wikiSources.ts +355 -0
  73. package/src/data/alteracValley.ts +176 -0
  74. package/src/data/appearanceOptions.ts +534 -0
  75. package/src/data/applyLootChanceSanity.ts +21 -0
  76. package/src/data/createFlavor.ts +96 -0
  77. package/src/data/customItems.ts +33 -0
  78. package/src/data/dataStore.ts +1904 -0
  79. package/src/data/dungeonGameObjects.ts +84 -0
  80. package/src/data/dungeonPlateCover.ts +66 -0
  81. package/src/data/dungeonSpawns.ts +294 -0
  82. package/src/data/dungeons/alterac-valley.ts +135 -0
  83. package/src/data/dungeons/apply-dungeon-rooms.ts +29 -0
  84. package/src/data/dungeons/apply-encounter-outdoors.ts +72 -0
  85. package/src/data/dungeons/apply-instance-geometry.ts +65 -0
  86. package/src/data/dungeons/apply-spawn-placement.ts +171 -0
  87. package/src/data/dungeons/blackfathom-deeps.ts +539 -0
  88. package/src/data/dungeons/blackrock-depths.ts +1410 -0
  89. package/src/data/dungeons/blackwing-lair.ts +129 -0
  90. package/src/data/dungeons/boss-eventai.ts +8 -0
  91. package/src/data/dungeons/deadmines.ts +410 -0
  92. package/src/data/dungeons/dire-maul-east.ts +980 -0
  93. package/src/data/dungeons/dire-maul-north.ts +661 -0
  94. package/src/data/dungeons/dire-maul-west.ts +785 -0
  95. package/src/data/dungeons/dungeon-rooms.json +5479 -0
  96. package/src/data/dungeons/encounter-outdoors.json +359 -0
  97. package/src/data/dungeons/eventai/blackfathom-deeps.ts +308 -0
  98. package/src/data/dungeons/eventai/blackrock-depths.ts +1257 -0
  99. package/src/data/dungeons/eventai/deadmines.ts +264 -0
  100. package/src/data/dungeons/eventai/dire-maul-east.ts +320 -0
  101. package/src/data/dungeons/eventai/gnomeregan.ts +213 -0
  102. package/src/data/dungeons/eventai/helpers.ts +79 -0
  103. package/src/data/dungeons/eventai/index.ts +133 -0
  104. package/src/data/dungeons/eventai/lbrs.ts +372 -0
  105. package/src/data/dungeons/eventai/maraudon.ts +323 -0
  106. package/src/data/dungeons/eventai/ragefire-chasm.ts +108 -0
  107. package/src/data/dungeons/eventai/razorfen-downs.ts +207 -0
  108. package/src/data/dungeons/eventai/razorfen-kraul.ts +326 -0
  109. package/src/data/dungeons/eventai/scholomance.ts +680 -0
  110. package/src/data/dungeons/eventai/shadowfang-keep.ts +230 -0
  111. package/src/data/dungeons/eventai/sm-cathedral.ts +75 -0
  112. package/src/data/dungeons/eventai/sm-graveyard.ts +150 -0
  113. package/src/data/dungeons/eventai/sm-library.ts +55 -0
  114. package/src/data/dungeons/eventai/stratholme-undead.ts +127 -0
  115. package/src/data/dungeons/eventai/sunken-temple.ts +582 -0
  116. package/src/data/dungeons/eventai/the-stockade.ts +228 -0
  117. package/src/data/dungeons/eventai/ubrs.ts +225 -0
  118. package/src/data/dungeons/eventai/uldaman.ts +355 -0
  119. package/src/data/dungeons/eventai/wailing-caverns.ts +396 -0
  120. package/src/data/dungeons/eventai/zul-farrak.ts +591 -0
  121. package/src/data/dungeons/gnomeregan.ts +909 -0
  122. package/src/data/dungeons/index.ts +126 -0
  123. package/src/data/dungeons/instance-geometry.json +5233 -0
  124. package/src/data/dungeons/key-sources.json +169 -0
  125. package/src/data/dungeons/lbrs.ts +996 -0
  126. package/src/data/dungeons/maraudon.ts +786 -0
  127. package/src/data/dungeons/molten-core.ts +194 -0
  128. package/src/data/dungeons/naxxramas.ts +173 -0
  129. package/src/data/dungeons/onyxias-lair.ts +71 -0
  130. package/src/data/dungeons/pack-from-clusters.ts +1256 -0
  131. package/src/data/dungeons/ragefire-chasm.ts +238 -0
  132. package/src/data/dungeons/razorfen-downs.ts +698 -0
  133. package/src/data/dungeons/razorfen-kraul.ts +766 -0
  134. package/src/data/dungeons/ruins-of-ahnqiraj.ts +121 -0
  135. package/src/data/dungeons/scholomance.ts +1076 -0
  136. package/src/data/dungeons/shadowfang-keep.ts +740 -0
  137. package/src/data/dungeons/sm-armory.ts +266 -0
  138. package/src/data/dungeons/sm-cathedral.ts +430 -0
  139. package/src/data/dungeons/sm-graveyard.ts +482 -0
  140. package/src/data/dungeons/sm-library.ts +337 -0
  141. package/src/data/dungeons/stratholme-live.ts +808 -0
  142. package/src/data/dungeons/stratholme-undead.ts +1164 -0
  143. package/src/data/dungeons/sunken-temple.ts +931 -0
  144. package/src/data/dungeons/temple-of-ahnqiraj.ts +119 -0
  145. package/src/data/dungeons/the-stockade.ts +282 -0
  146. package/src/data/dungeons/ubrs.ts +1286 -0
  147. package/src/data/dungeons/uldaman.ts +685 -0
  148. package/src/data/dungeons/wailing-caverns.ts +356 -0
  149. package/src/data/dungeons/zul-farrak.ts +686 -0
  150. package/src/data/dungeons/zul-gurub.ts +142 -0
  151. package/src/data/dungeons.ts +42 -0
  152. package/src/data/fixtures.ts +446 -0
  153. package/src/data/gameobject-data.json.gz +0 -0
  154. package/src/data/item-data.json.gz +0 -0
  155. package/src/data/loot-data.json.gz +0 -0
  156. package/src/data/maps/atlas-approach-maps.json +1425 -0
  157. package/src/data/maps/atlas-landmarks.json +1711 -0
  158. package/src/data/maps/dungeon-viewports.json +392 -0
  159. package/src/data/materializeModDamagePercentTaken.ts +70 -0
  160. package/src/data/materializeModHealthRegen.ts +89 -0
  161. package/src/data/materializeSpellReputation.ts +26 -0
  162. package/src/data/pageTexts.ts +19 -0
  163. package/src/data/profession-data.json.gz +0 -0
  164. package/src/data/raid-plans/blackfathom-deeps.json +86 -0
  165. package/src/data/raid-plans/blackrock-depths.json +419 -0
  166. package/src/data/raid-plans/blackwing-lair.json +328 -0
  167. package/src/data/raid-plans/deadmines.json +55 -0
  168. package/src/data/raid-plans/dire-maul-east.json +94 -0
  169. package/src/data/raid-plans/dire-maul-north.json +70 -0
  170. package/src/data/raid-plans/dire-maul-west.json +75 -0
  171. package/src/data/raid-plans/gnomeregan.json +131 -0
  172. package/src/data/raid-plans/lbrs.json +176 -0
  173. package/src/data/raid-plans/maraudon.json +102 -0
  174. package/src/data/raid-plans/molten-core.json +169 -0
  175. package/src/data/raid-plans/naxxramas.json +354 -0
  176. package/src/data/raid-plans/onyxias-lair.json +18 -0
  177. package/src/data/raid-plans/ragefire-chasm.json +30 -0
  178. package/src/data/raid-plans/razorfen-downs.json +75 -0
  179. package/src/data/raid-plans/razorfen-kraul.json +53 -0
  180. package/src/data/raid-plans/ruins-of-ahnqiraj.json +110 -0
  181. package/src/data/raid-plans/scholomance.json +170 -0
  182. package/src/data/raid-plans/shadowfang-keep.json +87 -0
  183. package/src/data/raid-plans/sm-armory.json +53 -0
  184. package/src/data/raid-plans/sm-cathedral.json +72 -0
  185. package/src/data/raid-plans/sm-graveyard.json +63 -0
  186. package/src/data/raid-plans/sm-library.json +23 -0
  187. package/src/data/raid-plans/stratholme-live.json +129 -0
  188. package/src/data/raid-plans/stratholme-undead.json +73 -0
  189. package/src/data/raid-plans/sunken-temple.json +159 -0
  190. package/src/data/raid-plans/temple-of-ahnqiraj.json +163 -0
  191. package/src/data/raid-plans/the-stockade.json +42 -0
  192. package/src/data/raid-plans/ubrs.json +53 -0
  193. package/src/data/raid-plans/uldaman.json +131 -0
  194. package/src/data/raid-plans/wailing-caverns.json +90 -0
  195. package/src/data/raid-plans/zul-farrak.json +156 -0
  196. package/src/data/raid-plans/zul-gurub.json +307 -0
  197. package/src/data/raidInstanceCreatures.mjs +473 -0
  198. package/src/data/rotations/index.ts +152 -0
  199. package/src/data/rotations/layout.mjs +72 -0
  200. package/src/data/rotations/pve/druid/balance.json +754 -0
  201. package/src/data/rotations/pve/druid/feral-tank.json +2448 -0
  202. package/src/data/rotations/pve/druid/feral.json +2660 -0
  203. package/src/data/rotations/pve/druid/restoration.json +424 -0
  204. package/src/data/rotations/pve/hunter/beast-mastery.json +1288 -0
  205. package/src/data/rotations/pve/hunter/marksmanship.json +1260 -0
  206. package/src/data/rotations/pve/hunter/survival.json +1373 -0
  207. package/src/data/rotations/pve/mage/arcane-leveling.json +1798 -0
  208. package/src/data/rotations/pve/mage/fire-leveling.json +2003 -0
  209. package/src/data/rotations/pve/mage/frost-leveling.json +1912 -0
  210. package/src/data/rotations/pve/paladin/holy.json +755 -0
  211. package/src/data/rotations/pve/paladin/protection.json +962 -0
  212. package/src/data/rotations/pve/paladin/retribution.json +924 -0
  213. package/src/data/rotations/pve/priest/discipline.json +772 -0
  214. package/src/data/rotations/pve/priest/holy.json +707 -0
  215. package/src/data/rotations/pve/priest/shadow.json +787 -0
  216. package/src/data/rotations/pve/rogue/assassination.json +2477 -0
  217. package/src/data/rotations/pve/rogue/combat.json +2483 -0
  218. package/src/data/rotations/pve/rogue/subtlety.json +2523 -0
  219. package/src/data/rotations/pve/shaman/elemental.json +1157 -0
  220. package/src/data/rotations/pve/shaman/enhancement.json +1085 -0
  221. package/src/data/rotations/pve/shaman/restoration.json +592 -0
  222. package/src/data/rotations/pve/warlock/affliction.json +1185 -0
  223. package/src/data/rotations/pve/warlock/demonology.json +1165 -0
  224. package/src/data/rotations/pve/warlock/destruction.json +1177 -0
  225. package/src/data/rotations/pve/warrior/arms.json +3020 -0
  226. package/src/data/rotations/pve/warrior/fury.json +2996 -0
  227. package/src/data/rotations/pve/warrior/protection.json +2509 -0
  228. package/src/data/rotations/pvp/druid/balance.json +593 -0
  229. package/src/data/rotations/pvp/druid/feral.json +3276 -0
  230. package/src/data/rotations/pvp/druid/restoration.json +662 -0
  231. package/src/data/rotations/pvp/hunter/beast-mastery.json +665 -0
  232. package/src/data/rotations/pvp/hunter/marksmanship.json +2406 -0
  233. package/src/data/rotations/pvp/hunter/survival.json +635 -0
  234. package/src/data/rotations/pvp/mage/arcane.json +574 -0
  235. package/src/data/rotations/pvp/mage/fire.json +570 -0
  236. package/src/data/rotations/pvp/mage/frost.json +4048 -0
  237. package/src/data/rotations/pvp/paladin/holy.json +1498 -0
  238. package/src/data/rotations/pvp/paladin/protection.json +567 -0
  239. package/src/data/rotations/pvp/paladin/retribution.json +1110 -0
  240. package/src/data/rotations/pvp/priest/discipline.json +1848 -0
  241. package/src/data/rotations/pvp/priest/holy.json +6340 -0
  242. package/src/data/rotations/pvp/priest/shadow.json +2329 -0
  243. package/src/data/rotations/pvp/rogue/assassination.json +1322 -0
  244. package/src/data/rotations/pvp/rogue/combat.json +5258 -0
  245. package/src/data/rotations/pvp/rogue/subtlety.json +586 -0
  246. package/src/data/rotations/pvp/shaman/elemental.json +1404 -0
  247. package/src/data/rotations/pvp/shaman/enhancement.json +1277 -0
  248. package/src/data/rotations/pvp/shaman/restoration.json +2490 -0
  249. package/src/data/rotations/pvp/warlock/affliction.json +1017 -0
  250. package/src/data/rotations/pvp/warlock/demonology.json +1503 -0
  251. package/src/data/rotations/pvp/warlock/destruction.json +638 -0
  252. package/src/data/rotations/pvp/warrior/arms.json +5665 -0
  253. package/src/data/rotations/pvp/warrior/fury.json +850 -0
  254. package/src/data/rotations/pvp/warrior/protection.json +777 -0
  255. package/src/data/schema/bundle.ts +511 -0
  256. package/src/data/schema/constants.ts +49 -0
  257. package/src/data/schema/creature.ts +454 -0
  258. package/src/data/schema/encounter.ts +155 -0
  259. package/src/data/schema/faction.ts +48 -0
  260. package/src/data/schema/item.ts +297 -0
  261. package/src/data/schema/itemEnchant.ts +105 -0
  262. package/src/data/schema/npc.ts +44 -0
  263. package/src/data/schema/primitives.ts +295 -0
  264. package/src/data/schema/profession.ts +226 -0
  265. package/src/data/schema/quest.ts +154 -0
  266. package/src/data/schema/spell.ts +1149 -0
  267. package/src/data/schema/talent.ts +74 -0
  268. package/src/data/schema/world.ts +124 -0
  269. package/src/data/schema.ts +19 -0
  270. package/src/data/skinNodeGapFill.ts +68 -0
  271. package/src/data/spell-data.json.gz +0 -0
  272. package/src/data/spell-script-targets.json +1 -0
  273. package/src/data/tables/ahItemValues.json.gz +0 -0
  274. package/src/data/tables/alteracValley.json.gz +0 -0
  275. package/src/data/tables/areatriggerTeleports.json.gz +0 -0
  276. package/src/data/tables/botNames.json.gz +0 -0
  277. package/src/data/tables/botPopulation.json.gz +0 -0
  278. package/src/data/tables/botSpecs.json.gz +0 -0
  279. package/src/data/tables/classLevelStats.json.gz +0 -0
  280. package/src/data/tables/combatConditions.json.gz +0 -0
  281. package/src/data/tables/combatSkillMeta.json.gz +0 -0
  282. package/src/data/tables/conditions.json.gz +0 -0
  283. package/src/data/tables/createInfo.json.gz +0 -0
  284. package/src/data/tables/creatureAggroGroups.json.gz +0 -0
  285. package/src/data/tables/creatureClassLevelStats.json.gz +0 -0
  286. package/src/data/tables/creaturePatrolPacks.json.gz +0 -0
  287. package/src/data/tables/creatureWeapons.json.gz +0 -0
  288. package/src/data/tables/creatures.json.gz +0 -0
  289. package/src/data/tables/dbScripts.json.gz +0 -0
  290. package/src/data/tables/dungeonAuthoredRoutes.json.gz +0 -0
  291. package/src/data/tables/dungeonCensus.json.gz +0 -0
  292. package/src/data/tables/dungeonGameObjects.json.gz +0 -0
  293. package/src/data/tables/dungeonPacks.json.gz +0 -0
  294. package/src/data/tables/dungeonPlateCover.json.gz +0 -0
  295. package/src/data/tables/dungeonSpawns.json.gz +0 -0
  296. package/src/data/tables/dungeonSurvey.json.gz +0 -0
  297. package/src/data/tables/durabilityCosts.json.gz +0 -0
  298. package/src/data/tables/durabilityQuality.json.gz +0 -0
  299. package/src/data/tables/enchantApplicators.json.gz +0 -0
  300. package/src/data/tables/entranceYards.json.gz +0 -0
  301. package/src/data/tables/explorationBasexp.json.gz +0 -0
  302. package/src/data/tables/factionTemplates.json.gz +0 -0
  303. package/src/data/tables/factions.json.gz +0 -0
  304. package/src/data/tables/gameEvents.json.gz +0 -0
  305. package/src/data/tables/gameObjects.json.gz +0 -0
  306. package/src/data/tables/gossipMenus.json.gz +0 -0
  307. package/src/data/tables/graveyards.json.gz +0 -0
  308. package/src/data/tables/instanceMaps.json.gz +0 -0
  309. package/src/data/tables/itemEnchantmentTemplates.json.gz +0 -0
  310. package/src/data/tables/itemEnchants.json.gz +0 -0
  311. package/src/data/tables/itemRandomProperties.json.gz +0 -0
  312. package/src/data/tables/itemSets.json.gz +0 -0
  313. package/src/data/tables/items.json.gz +0 -0
  314. package/src/data/tables/levelStats.json.gz +0 -0
  315. package/src/data/tables/locks.json.gz +0 -0
  316. package/src/data/tables/map-pin-overrides.json.gz +0 -0
  317. package/src/data/tables/nonCombatTrash.json.gz +0 -0
  318. package/src/data/tables/npcTexts.json.gz +0 -0
  319. package/src/data/tables/pageTexts.json.gz +0 -0
  320. package/src/data/tables/petAbilityTP.json.gz +0 -0
  321. package/src/data/tables/petGenericSpells.json.gz +0 -0
  322. package/src/data/tables/petLevelStats.json.gz +0 -0
  323. package/src/data/tables/playerbot-weightscales.json.gz +0 -0
  324. package/src/data/tables/pools.json.gz +0 -0
  325. package/src/data/tables/quests.json.gz +0 -0
  326. package/src/data/tables/races.json.gz +0 -0
  327. package/src/data/tables/reputationRanks.json.gz +0 -0
  328. package/src/data/tables/reputationRates.json.gz +0 -0
  329. package/src/data/tables/reputationSpillover.json.gz +0 -0
  330. package/src/data/tables/ridingSpells.json.gz +0 -0
  331. package/src/data/tables/scriptTexts.json.gz +0 -0
  332. package/src/data/tables/soundClipVolume.json.gz +0 -0
  333. package/src/data/tables/spellChain.json.gz +0 -0
  334. package/src/data/tables/spellTeleports.json.gz +0 -0
  335. package/src/data/tables/spells.json.gz +0 -0
  336. package/src/data/tables/talents.json.gz +0 -0
  337. package/src/data/tables/tavernTriggers.json.gz +0 -0
  338. package/src/data/tables/taxiNodes.json.gz +0 -0
  339. package/src/data/tables/taxiRoutes.json.gz +0 -0
  340. package/src/data/tables/trainers.json.gz +0 -0
  341. package/src/data/tables/transports.json.gz +0 -0
  342. package/src/data/tables/travelAnchors.json.gz +0 -0
  343. package/src/data/tables/travelEdges.json.gz +0 -0
  344. package/src/data/tables/unitConditions.json.gz +0 -0
  345. package/src/data/tables/vendors.json.gz +0 -0
  346. package/src/data/tables/weaponEnchantProcs.json.gz +0 -0
  347. package/src/data/tables/xp.json.gz +0 -0
  348. package/src/data/tables/zoneWeather.json.gz +0 -0
  349. package/src/data/tables/zones.json.gz +0 -0
  350. package/src/data/world-data.ts +56 -0
  351. package/src/data/zone-music-sets.json +2751 -0
  352. package/src/dev/etl/lib/loot-chance-sanity.mjs +180 -0
  353. package/src/domain/audioQuality.mjs +145 -0
  354. package/src/domain/bg/ab.ts +433 -0
  355. package/src/domain/bg/arenaComps.ts +644 -0
  356. package/src/domain/bg/arenaLab.ts +695 -0
  357. package/src/domain/bg/arenaPace.ts +31 -0
  358. package/src/domain/bg/arenaRating.ts +110 -0
  359. package/src/domain/bg/av.ts +758 -0
  360. package/src/domain/bg/avEnemyPush.ts +219 -0
  361. package/src/domain/bg/avField.ts +283 -0
  362. package/src/domain/bg/avInstanceNodes.ts +197 -0
  363. package/src/domain/bg/avInstanceScore.ts +123 -0
  364. package/src/domain/bg/avQuestItems.ts +55 -0
  365. package/src/domain/bg/avQuests.ts +210 -0
  366. package/src/domain/bg/avSession.ts +196 -0
  367. package/src/domain/bg/bgConsumes.ts +269 -0
  368. package/src/domain/bg/bgPrebuff.ts +153 -0
  369. package/src/domain/bg/bgRest.ts +91 -0
  370. package/src/domain/bg/bgRoster.ts +305 -0
  371. package/src/domain/bg/bgTier.ts +61 -0
  372. package/src/domain/bg/bgWorld.ts +862 -0
  373. package/src/domain/bg/match.ts +215 -0
  374. package/src/domain/bg/strategies.ts +552 -0
  375. package/src/domain/bg/types.ts +291 -0
  376. package/src/domain/bg/wsg.ts +264 -0
  377. package/src/domain/bots/actionProviderSpec.ts +38 -0
  378. package/src/domain/bots/autoConsumables.ts +285 -0
  379. package/src/domain/bots/betweenPullRest.ts +239 -0
  380. package/src/domain/bots/botGear.ts +248 -0
  381. package/src/domain/bots/botInventory.ts +486 -0
  382. package/src/domain/bots/botPet.ts +535 -0
  383. package/src/domain/bots/botPool.ts +291 -0
  384. package/src/domain/bots/botProfessions.ts +334 -0
  385. package/src/domain/bots/companionActionBar.ts +209 -0
  386. package/src/domain/bots/companionHireCost.ts +236 -0
  387. package/src/domain/bots/companionMissions.ts +582 -0
  388. package/src/domain/bots/companionPrep.ts +254 -0
  389. package/src/domain/bots/companionQuests.ts +270 -0
  390. package/src/domain/bots/companionRep.ts +75 -0
  391. package/src/domain/bots/companionRotation.ts +708 -0
  392. package/src/domain/bots/companionXp.ts +66 -0
  393. package/src/domain/bots/consumableShare.ts +811 -0
  394. package/src/domain/bots/dpsMate.ts +1072 -0
  395. package/src/domain/bots/groupCompReport.ts +132 -0
  396. package/src/domain/bots/healthstoneSupply.ts +198 -0
  397. package/src/domain/bots/outfitter.ts +1056 -0
  398. package/src/domain/bots/paladinPrePull.ts +231 -0
  399. package/src/domain/bots/partyRole.ts +40 -0
  400. package/src/domain/bots/playerbotEquipCache.ts +412 -0
  401. package/src/domain/bots/playerbotItemEligibility.ts +60 -0
  402. package/src/domain/bots/playerbotStatWeight.ts +853 -0
  403. package/src/domain/bots/playerbotUnavailableItems.ts +147 -0
  404. package/src/domain/bots/prePullBuffs.ts +219 -0
  405. package/src/domain/bots/prePullStealth.ts +82 -0
  406. package/src/domain/bots/runSupply.ts +251 -0
  407. package/src/domain/bots/runSupplyPrefs.ts +28 -0
  408. package/src/domain/bots/sendTradeGoods.ts +394 -0
  409. package/src/domain/bots/soulShardCap.ts +35 -0
  410. package/src/domain/bots/squad.ts +842 -0
  411. package/src/domain/bots/squadRun.ts +81 -0
  412. package/src/domain/character/actionbar.ts +346 -0
  413. package/src/domain/character/appearance.ts +165 -0
  414. package/src/domain/character/buildCombatant.ts +1726 -0
  415. package/src/domain/character/character.ts +356 -0
  416. package/src/domain/character/characterName.ts +43 -0
  417. package/src/domain/character/characterRatings.ts +424 -0
  418. package/src/domain/character/characterSpells.ts +282 -0
  419. package/src/domain/character/characterStats.ts +1559 -0
  420. package/src/domain/character/characterTalents.ts +398 -0
  421. package/src/domain/character/combatSkills.ts +994 -0
  422. package/src/domain/character/displayForm.ts +72 -0
  423. package/src/domain/character/formTalentAuras.ts +171 -0
  424. package/src/domain/character/forms.ts +499 -0
  425. package/src/domain/character/races.ts +40 -0
  426. package/src/domain/character/resurrectionSickness.ts +49 -0
  427. package/src/domain/character/spellbook.ts +169 -0
  428. package/src/domain/character/stanceBar.ts +354 -0
  429. package/src/domain/character/stancePrereq.ts +70 -0
  430. package/src/domain/character/talentBuilds.ts +63 -0
  431. package/src/domain/character/talentImport.ts +130 -0
  432. package/src/domain/character/talentLink.ts +123 -0
  433. package/src/domain/character/talents.ts +201 -0
  434. package/src/domain/core/conditionSnapshot.ts +92 -0
  435. package/src/domain/core/hover.ts +14 -0
  436. package/src/domain/core/ids.ts +58 -0
  437. package/src/domain/core/internalNameTags.ts +5 -0
  438. package/src/domain/core/runtimeDataPatches.ts +357 -0
  439. package/src/domain/creature/aiTargeting.ts +588 -0
  440. package/src/domain/creature/combatCondition.ts +157 -0
  441. package/src/domain/creature/creatureAggro.ts +804 -0
  442. package/src/domain/creature/creatureAi.ts +206 -0
  443. package/src/domain/creature/creatureAiConstants.ts +661 -0
  444. package/src/domain/creature/creatureCastList.ts +1007 -0
  445. package/src/domain/creature/creatureEventAi.ts +1409 -0
  446. package/src/domain/creature/creatureGroups.ts +144 -0
  447. package/src/domain/creature/creatureLinking.ts +333 -0
  448. package/src/domain/creature/creatureScaling.ts +320 -0
  449. package/src/domain/creature/creatureTrigger.ts +53 -0
  450. package/src/domain/creature/creatureWander.ts +74 -0
  451. package/src/domain/creature/eventAiTexts.ts +145 -0
  452. package/src/domain/creature/faction.ts +287 -0
  453. package/src/domain/creature/forcedReaction.ts +48 -0
  454. package/src/domain/creature/outdoorHuntable.ts +74 -0
  455. package/src/domain/creature/patrolPacks.ts +210 -0
  456. package/src/domain/creature/reputation.ts +967 -0
  457. package/src/domain/creature/unitFlags.ts +74 -0
  458. package/src/domain/creature/worldBosses.ts +393 -0
  459. package/src/domain/dungeonMusic.mjs +48 -0
  460. package/src/domain/economy/auction.ts +282 -0
  461. package/src/domain/economy/auctionBot.ts +1060 -0
  462. package/src/domain/economy/honorPrice.ts +100 -0
  463. package/src/domain/economy/mail.ts +958 -0
  464. package/src/domain/economy/money.ts +42 -0
  465. package/src/domain/economy/syntheticClassTrainers.ts +62 -0
  466. package/src/domain/economy/trading.ts +296 -0
  467. package/src/domain/economy/vendorSellAll.ts +252 -0
  468. package/src/domain/economy/vendorStock.ts +146 -0
  469. package/src/domain/items/ammo.ts +817 -0
  470. package/src/domain/items/bank.ts +162 -0
  471. package/src/domain/items/consumableFamily.ts +205 -0
  472. package/src/domain/items/craftUpgrades.ts +83 -0
  473. package/src/domain/items/createItem.ts +93 -0
  474. package/src/domain/items/durability.ts +581 -0
  475. package/src/domain/items/equipment.ts +441 -0
  476. package/src/domain/items/equipmentHelper.ts +767 -0
  477. package/src/domain/items/inventory.ts +561 -0
  478. package/src/domain/items/itemBonding.ts +93 -0
  479. package/src/domain/items/itemContainer.ts +245 -0
  480. package/src/domain/items/itemDisplayName.ts +33 -0
  481. package/src/domain/items/itemInstance.ts +181 -0
  482. package/src/domain/items/itemRandomEnchantOutcomes.ts +315 -0
  483. package/src/domain/items/itemRandomProps.ts +77 -0
  484. package/src/domain/items/itemRestrictions.ts +329 -0
  485. package/src/domain/items/itemTeaches.ts +82 -0
  486. package/src/domain/items/itemUseCooldown.ts +52 -0
  487. package/src/domain/items/itemUseTarget.ts +90 -0
  488. package/src/domain/items/junkCategories.ts +174 -0
  489. package/src/domain/items/junkFilter.ts +368 -0
  490. package/src/domain/items/keyring.ts +131 -0
  491. package/src/domain/items/loot.ts +221 -0
  492. package/src/domain/items/mounts.ts +190 -0
  493. package/src/domain/items/onUsePayload.ts +102 -0
  494. package/src/domain/items/pendingLoot.ts +107 -0
  495. package/src/domain/items/relic.ts +105 -0
  496. package/src/domain/items/rocketBoots.ts +36 -0
  497. package/src/domain/items/sortContainer.ts +139 -0
  498. package/src/domain/items/spareContainers.ts +71 -0
  499. package/src/domain/items/spellReagentIndex.ts +131 -0
  500. package/src/domain/items/staleConsumables.ts +66 -0
  501. package/src/domain/items/weaponSpender.ts +110 -0
  502. package/src/domain/listDungeonIds.mjs +28 -0
  503. package/src/domain/macro/compose.ts +239 -0
  504. package/src/domain/macro/conditions.ts +260 -0
  505. package/src/domain/macro/creatureTypes.ts +40 -0
  506. package/src/domain/macro/describe.ts +169 -0
  507. package/src/domain/macro/icon.ts +60 -0
  508. package/src/domain/macro/index.ts +20 -0
  509. package/src/domain/macro/normalize.ts +112 -0
  510. package/src/domain/macro/parse.ts +316 -0
  511. package/src/domain/macro/plan.ts +288 -0
  512. package/src/domain/macro/rotation.ts +590 -0
  513. package/src/domain/macro/rotationEnv.ts +173 -0
  514. package/src/domain/macro/slots.ts +101 -0
  515. package/src/domain/macro/snapshot.ts +114 -0
  516. package/src/domain/macro/templates.ts +446 -0
  517. package/src/domain/macro/types.ts +70 -0
  518. package/src/domain/macro/units.ts +93 -0
  519. package/src/domain/macro/weaponTypes.ts +83 -0
  520. package/src/domain/nav/cityTeleports.ts +10 -0
  521. package/src/domain/nav/mounting.ts +113 -0
  522. package/src/domain/nav/nav.ts +43 -0
  523. package/src/domain/nav/navCollision.ts +606 -0
  524. package/src/domain/nav/navOutdoors.ts +91 -0
  525. package/src/domain/nav/navRegistry.ts +179 -0
  526. package/src/domain/nav/navRoomGraph.ts +302 -0
  527. package/src/domain/nav/navTypes.ts +43 -0
  528. package/src/domain/nav/navmesh.ts +1715 -0
  529. package/src/domain/nav/speed.ts +200 -0
  530. package/src/domain/nav/storey.ts +10 -0
  531. package/src/domain/nav/travel.ts +725 -0
  532. package/src/domain/nav/travelTypes.ts +75 -0
  533. package/src/domain/pet/pet.ts +1150 -0
  534. package/src/domain/pet/petActionBar.ts +180 -0
  535. package/src/domain/pet/petSpellbook.ts +39 -0
  536. package/src/domain/pet/petStable.ts +81 -0
  537. package/src/domain/professions/autoDisenchant.ts +236 -0
  538. package/src/domain/professions/characterEnchants.ts +176 -0
  539. package/src/domain/professions/craftCooldown.ts +52 -0
  540. package/src/domain/professions/enchantApply.ts +62 -0
  541. package/src/domain/professions/enchantTargets.ts +114 -0
  542. package/src/domain/professions/enchanting.ts +236 -0
  543. package/src/domain/professions/gatherFilter.ts +149 -0
  544. package/src/domain/professions/gearEnchant.ts +137 -0
  545. package/src/domain/professions/heldTools.ts +29 -0
  546. package/src/domain/professions/learnAllRecipes.ts +146 -0
  547. package/src/domain/professions/miningHarvest.ts +69 -0
  548. package/src/domain/professions/partyDisenchant.ts +294 -0
  549. package/src/domain/professions/partyWork.ts +83 -0
  550. package/src/domain/professions/pickpocket.ts +172 -0
  551. package/src/domain/professions/poisons.ts +240 -0
  552. package/src/domain/professions/professions.ts +677 -0
  553. package/src/domain/professions/rareNodes.ts +45 -0
  554. package/src/domain/professions/skinLoot.ts +27 -0
  555. package/src/domain/professions/vendorReagents.ts +152 -0
  556. package/src/domain/professions/weaponImbueHand.ts +171 -0
  557. package/src/domain/questFarmFilter.mjs +42 -0
  558. package/src/domain/quests/doQuest.ts +1204 -0
  559. package/src/domain/quests/gossip.ts +308 -0
  560. package/src/domain/quests/gossipTalk.ts +298 -0
  561. package/src/domain/quests/interpreter/canComplete.ts +150 -0
  562. package/src/domain/quests/interpreter/claim.ts +137 -0
  563. package/src/domain/quests/interpreter/dbscript/handlers.ts +1371 -0
  564. package/src/domain/quests/interpreter/dbscript/handlersBatch.ts +1251 -0
  565. package/src/domain/quests/interpreter/dbscript/hooks.ts +331 -0
  566. package/src/domain/quests/interpreter/dbscript/index.ts +212 -0
  567. package/src/domain/quests/interpreter/dbscript/opcodes.ts +257 -0
  568. package/src/domain/quests/interpreter/dbscript/registry.ts +1194 -0
  569. package/src/domain/quests/interpreter/dbscript/registryAreatriggerScripts.ts +539 -0
  570. package/src/domain/quests/interpreter/dbscript/registryAshenvale.ts +553 -0
  571. package/src/domain/quests/interpreter/dbscript/registryAzshara.ts +272 -0
  572. package/src/domain/quests/interpreter/dbscript/registryDarkshore.ts +637 -0
  573. package/src/domain/quests/interpreter/dbscript/registryDesolace.ts +501 -0
  574. package/src/domain/quests/interpreter/dbscript/registryDustwallowMarsh.ts +735 -0
  575. package/src/domain/quests/interpreter/dbscript/registryFelwood.ts +493 -0
  576. package/src/domain/quests/interpreter/dbscript/registryFeralas.ts +485 -0
  577. package/src/domain/quests/interpreter/dbscript/registryGoScripts.ts +203 -0
  578. package/src/domain/quests/interpreter/dbscript/registryMoonglade.ts +288 -0
  579. package/src/domain/quests/interpreter/dbscript/registryNpcProfessions.ts +230 -0
  580. package/src/domain/quests/interpreter/dbscript/registryNpcsSpecial.ts +545 -0
  581. package/src/domain/quests/interpreter/dbscript/registryRazorfenDowns.ts +293 -0
  582. package/src/domain/quests/interpreter/dbscript/registryRazorfenKraul.ts +221 -0
  583. package/src/domain/quests/interpreter/dbscript/registryRedridge.ts +112 -0
  584. package/src/domain/quests/interpreter/dbscript/registrySearingGorge.ts +125 -0
  585. package/src/domain/quests/interpreter/dbscript/registrySiblings.ts +51 -0
  586. package/src/domain/quests/interpreter/dbscript/registrySilverpineForest.ts +172 -0
  587. package/src/domain/quests/interpreter/dbscript/registryStonetalonMountains.ts +180 -0
  588. package/src/domain/quests/interpreter/dbscript/registryStormwindCity.ts +369 -0
  589. package/src/domain/quests/interpreter/dbscript/registryStranglethornVale.ts +115 -0
  590. package/src/domain/quests/interpreter/dbscript/registryStratholme.ts +146 -0
  591. package/src/domain/quests/interpreter/dbscript/registrySunkenTemple.ts +149 -0
  592. package/src/domain/quests/interpreter/dbscript/registrySwampOfSorrows.ts +163 -0
  593. package/src/domain/quests/interpreter/dbscript/registryTanaris.ts +318 -0
  594. package/src/domain/quests/interpreter/dbscript/registryTeldrassil.ts +120 -0
  595. package/src/domain/quests/interpreter/dbscript/registryTheBarrens.ts +603 -0
  596. package/src/domain/quests/interpreter/dbscript/registryThousandNeedles.ts +499 -0
  597. package/src/domain/quests/interpreter/dbscript/registryTirisfalGlades.ts +222 -0
  598. package/src/domain/quests/interpreter/dbscript/registryUngoroCrater.ts +291 -0
  599. package/src/domain/quests/interpreter/dbscript/registryWarEffort.ts +773 -0
  600. package/src/domain/quests/interpreter/dbscript/registryWesternPlaguelands.ts +206 -0
  601. package/src/domain/quests/interpreter/dbscript/registryWestfall.ts +190 -0
  602. package/src/domain/quests/interpreter/dbscript/registryWetlands.ts +186 -0
  603. package/src/domain/quests/interpreter/dbscript/registryWinterspring.ts +235 -0
  604. package/src/domain/quests/interpreter/dbscript/types.ts +817 -0
  605. package/src/domain/quests/interpreter/dbscript/vm.ts +171 -0
  606. package/src/domain/quests/interpreter/diff.ts +349 -0
  607. package/src/domain/quests/interpreter/fixtures/oracle-questlog-qi2.json +2417 -0
  608. package/src/domain/quests/interpreter/flags.ts +101 -0
  609. package/src/domain/quests/interpreter/index.ts +113 -0
  610. package/src/domain/quests/interpreter/live.ts +178 -0
  611. package/src/domain/quests/interpreter/types.ts +81 -0
  612. package/src/domain/quests/interpreter/updaters.ts +412 -0
  613. package/src/domain/quests/questCorpseUse.ts +155 -0
  614. package/src/domain/quests/questDialog.ts +43 -0
  615. package/src/domain/quests/questFight.ts +34 -0
  616. package/src/domain/quests/questObjectiveLabel.ts +39 -0
  617. package/src/domain/quests/questRewardChoice.ts +85 -0
  618. package/src/domain/quests/questScriptCredit.ts +26 -0
  619. package/src/domain/quests/questScriptItemUse.ts +74 -0
  620. package/src/domain/quests/questTameRods.ts +79 -0
  621. package/src/domain/quests/questlog.ts +1545 -0
  622. package/src/domain/quests/talkDeliver.ts +170 -0
  623. package/src/domain/raid/globalActionBar.ts +195 -0
  624. package/src/domain/raid/instanceRoster.ts +194 -0
  625. package/src/domain/raid/partySummon.ts +198 -0
  626. package/src/domain/raid/partyVault.ts +320 -0
  627. package/src/domain/raid/raidBossAbilities.ts +268 -0
  628. package/src/domain/raid/raidComp.ts +335 -0
  629. package/src/domain/raid/raidCustomRows.ts +453 -0
  630. package/src/domain/raid/raidEncounterGear.ts +298 -0
  631. package/src/domain/raid/raidEncounterTactics.ts +412 -0
  632. package/src/domain/raid/raidPlan.ts +509 -0
  633. package/src/domain/raid/raidPlanEdits.ts +98 -0
  634. package/src/domain/raid/raidPlanPacks.ts +480 -0
  635. package/src/domain/raid/raidRecovery.ts +183 -0
  636. package/src/domain/raid/raidRosterTemplate.ts +138 -0
  637. package/src/domain/rotation/auraSide.ts +68 -0
  638. package/src/domain/rotation/build.ts +3031 -0
  639. package/src/domain/rotation/classes/druid.ts +58 -0
  640. package/src/domain/rotation/classes/hooks.ts +59 -0
  641. package/src/domain/rotation/classes/hunter.ts +156 -0
  642. package/src/domain/rotation/classes/index.ts +104 -0
  643. package/src/domain/rotation/classes/mage.ts +99 -0
  644. package/src/domain/rotation/classes/paladin.ts +296 -0
  645. package/src/domain/rotation/classes/priest.ts +94 -0
  646. package/src/domain/rotation/classes/pullOpener.ts +92 -0
  647. package/src/domain/rotation/classes/rogue.ts +69 -0
  648. package/src/domain/rotation/classes/shaman.ts +29 -0
  649. package/src/domain/rotation/classes/supportSpec.ts +94 -0
  650. package/src/domain/rotation/classes/warlock.ts +81 -0
  651. package/src/domain/rotation/classes/warrior.ts +402 -0
  652. package/src/domain/rotation/classify.ts +1381 -0
  653. package/src/domain/rotation/condMetricPicker.ts +379 -0
  654. package/src/domain/rotation/consumables.ts +242 -0
  655. package/src/domain/rotation/evaluate.ts +1115 -0
  656. package/src/domain/rotation/finisherLadder.ts +145 -0
  657. package/src/domain/rotation/invent.ts +938 -0
  658. package/src/domain/rotation/killOrder.ts +30 -0
  659. package/src/domain/rotation/openerForm.ts +22 -0
  660. package/src/domain/rotation/paladinBuffs.ts +568 -0
  661. package/src/domain/rotation/prebuff.ts +283 -0
  662. package/src/domain/rotation/raidRowTuning.ts +34 -0
  663. package/src/domain/rotation/rotation.ts +11 -0
  664. package/src/domain/rotation/rotationProfiles.ts +180 -0
  665. package/src/domain/rotation/rotationSuggestions.ts +851 -0
  666. package/src/domain/rotation/ruleAfterChain.ts +49 -0
  667. package/src/domain/rotation/spec.ts +70 -0
  668. package/src/domain/rotation/spellPicker.ts +140 -0
  669. package/src/domain/rotation/stand.ts +143 -0
  670. package/src/domain/rotation/types.ts +718 -0
  671. package/src/domain/run/battlegroundRun.ts +111 -0
  672. package/src/domain/run/canEnterContext.ts +32 -0
  673. package/src/domain/run/death.ts +561 -0
  674. package/src/domain/run/deathRecovery.ts +289 -0
  675. package/src/domain/run/duel.ts +141 -0
  676. package/src/domain/run/dungeonRun.ts +344 -0
  677. package/src/domain/run/floorRest.ts +159 -0
  678. package/src/domain/run/honor.ts +557 -0
  679. package/src/domain/run/honorWeek.ts +180 -0
  680. package/src/domain/run/whenMap.ts +977 -0
  681. package/src/domain/scriptdev/arathiHighlands.ts +445 -0
  682. package/src/domain/scriptdev/ashenvale.ts +635 -0
  683. package/src/domain/scriptdev/ashenvaleHelpers.ts +1215 -0
  684. package/src/domain/scriptdev/azshara.ts +892 -0
  685. package/src/domain/scriptdev/blackfathomDeeps.ts +212 -0
  686. package/src/domain/scriptdev/blackrockDepths.ts +1434 -0
  687. package/src/domain/scriptdev/blackrockSpire.ts +730 -0
  688. package/src/domain/scriptdev/blackwingLair.ts +521 -0
  689. package/src/domain/scriptdev/burningSteppes.ts +62 -0
  690. package/src/domain/scriptdev/classFilter.ts +43 -0
  691. package/src/domain/scriptdev/darkshore.ts +817 -0
  692. package/src/domain/scriptdev/darkshoreHelpers.ts +853 -0
  693. package/src/domain/scriptdev/deadmines.ts +331 -0
  694. package/src/domain/scriptdev/desolace.ts +1239 -0
  695. package/src/domain/scriptdev/direMaul.ts +859 -0
  696. package/src/domain/scriptdev/durotar.ts +532 -0
  697. package/src/domain/scriptdev/dustwallowMarsh.ts +758 -0
  698. package/src/domain/scriptdev/dustwallowMarshHelpers.ts +994 -0
  699. package/src/domain/scriptdev/easternPlaguelands.ts +21 -0
  700. package/src/domain/scriptdev/felwood.ts +1055 -0
  701. package/src/domain/scriptdev/feralas.ts +571 -0
  702. package/src/domain/scriptdev/feralasHelpers.ts +838 -0
  703. package/src/domain/scriptdev/gnomeregan.ts +466 -0
  704. package/src/domain/scriptdev/guards.ts +616 -0
  705. package/src/domain/scriptdev/hinterlands.ts +693 -0
  706. package/src/domain/scriptdev/host.ts +1134 -0
  707. package/src/domain/scriptdev/index.ts +123 -0
  708. package/src/domain/scriptdev/instanceRaids.ts +136 -0
  709. package/src/domain/scriptdev/itemScripts.ts +37 -0
  710. package/src/domain/scriptdev/lochModan.ts +283 -0
  711. package/src/domain/scriptdev/maraudon.ts +232 -0
  712. package/src/domain/scriptdev/moltenCore.ts +831 -0
  713. package/src/domain/scriptdev/moonglade.ts +659 -0
  714. package/src/domain/scriptdev/moongladeHelpers.ts +933 -0
  715. package/src/domain/scriptdev/naxxramas.ts +577 -0
  716. package/src/domain/scriptdev/naxxramasConstruct.ts +364 -0
  717. package/src/domain/scriptdev/naxxramasFrostwyrm.ts +378 -0
  718. package/src/domain/scriptdev/naxxramasMilitary.ts +276 -0
  719. package/src/domain/scriptdev/npcProfessions.ts +1025 -0
  720. package/src/domain/scriptdev/npcsSpecial.ts +1379 -0
  721. package/src/domain/scriptdev/onyxiasLair.ts +313 -0
  722. package/src/domain/scriptdev/orgrimmar.ts +147 -0
  723. package/src/domain/scriptdev/professionSpecConsumer.ts +481 -0
  724. package/src/domain/scriptdev/razorfenDowns.ts +468 -0
  725. package/src/domain/scriptdev/razorfenKraul.ts +410 -0
  726. package/src/domain/scriptdev/redridgeMountains.ts +163 -0
  727. package/src/domain/scriptdev/registry.ts +945 -0
  728. package/src/domain/scriptdev/ruinsOfAhnqiraj.ts +356 -0
  729. package/src/domain/scriptdev/scarletMonastery.ts +713 -0
  730. package/src/domain/scriptdev/scholomance.ts +682 -0
  731. package/src/domain/scriptdev/searingGorge.ts +295 -0
  732. package/src/domain/scriptdev/shadowfangKeep.ts +181 -0
  733. package/src/domain/scriptdev/silithus.ts +71 -0
  734. package/src/domain/scriptdev/silverpineForest.ts +662 -0
  735. package/src/domain/scriptdev/stonetalonMountains.ts +493 -0
  736. package/src/domain/scriptdev/stormwindCity.ts +1192 -0
  737. package/src/domain/scriptdev/stranglethornVale.ts +402 -0
  738. package/src/domain/scriptdev/stratholme.ts +650 -0
  739. package/src/domain/scriptdev/stratholmeScripts.ts +505 -0
  740. package/src/domain/scriptdev/sunkenTemple.ts +736 -0
  741. package/src/domain/scriptdev/swampOfSorrows.ts +22 -0
  742. package/src/domain/scriptdev/tanaris.ts +391 -0
  743. package/src/domain/scriptdev/tanarisHelpers.ts +661 -0
  744. package/src/domain/scriptdev/teldrassil.ts +143 -0
  745. package/src/domain/scriptdev/templeOfAhnqiraj.ts +1013 -0
  746. package/src/domain/scriptdev/theBarrens.ts +709 -0
  747. package/src/domain/scriptdev/theBarrensHelpers.ts +1026 -0
  748. package/src/domain/scriptdev/thousandNeedles.ts +426 -0
  749. package/src/domain/scriptdev/thousandNeedlesHelpers.ts +566 -0
  750. package/src/domain/scriptdev/tirisfalGlades.ts +533 -0
  751. package/src/domain/scriptdev/types.ts +1026 -0
  752. package/src/domain/scriptdev/uldaman.ts +437 -0
  753. package/src/domain/scriptdev/ungoroCrater.ts +549 -0
  754. package/src/domain/scriptdev/ungoroCraterHelpers.ts +1006 -0
  755. package/src/domain/scriptdev/wailingCaverns.ts +700 -0
  756. package/src/domain/scriptdev/warEffort.ts +371 -0
  757. package/src/domain/scriptdev/westernPlaguelands.ts +952 -0
  758. package/src/domain/scriptdev/westfall.ts +767 -0
  759. package/src/domain/scriptdev/wetlands.ts +660 -0
  760. package/src/domain/scriptdev/winterspring.ts +482 -0
  761. package/src/domain/scriptdev/winterspringHelpers.ts +801 -0
  762. package/src/domain/scriptdev/worldBosses.ts +605 -0
  763. package/src/domain/scriptdev/zulfarrak.ts +478 -0
  764. package/src/domain/scriptdev/zulgurub.ts +1152 -0
  765. package/src/domain/sim/dummySim.ts +408 -0
  766. package/src/domain/sim/targetDummy.ts +29 -0
  767. package/src/domain/social/guild.ts +148 -0
  768. package/src/domain/spells/areaAuraMembership.ts +93 -0
  769. package/src/domain/spells/breakableStunCc.ts +166 -0
  770. package/src/domain/spells/cancelAura.ts +80 -0
  771. package/src/domain/spells/diminishing.ts +167 -0
  772. package/src/domain/spells/dispel.ts +149 -0
  773. package/src/domain/spells/dispelMechanic.ts +105 -0
  774. package/src/domain/spells/equipSpells.ts +247 -0
  775. package/src/domain/spells/learnOnTargets.ts +260 -0
  776. package/src/domain/spells/mergeSchoolImmunityFromRaw.ts +66 -0
  777. package/src/domain/spells/resurrectSpell.ts +124 -0
  778. package/src/domain/spells/spellPushback.ts +39 -0
  779. package/src/domain/spells/spellReflect.ts +43 -0
  780. package/src/domain/spells/stealth.ts +183 -0
  781. package/src/domain/spells/totem.ts +394 -0
  782. package/src/domain/spells/worldCast.ts +187 -0
  783. package/src/domain/world/areaTriggerLocks.ts +177 -0
  784. package/src/domain/world/dungeonMusic.ts +108 -0
  785. package/src/domain/world/gameEvents.ts +119 -0
  786. package/src/domain/world/gameObjects.ts +1030 -0
  787. package/src/domain/world/goEventFire.ts +234 -0
  788. package/src/domain/world/goMoTransport.ts +74 -0
  789. package/src/domain/world/goTransport.ts +81 -0
  790. package/src/domain/world/hazards.ts +459 -0
  791. package/src/domain/world/openLock.ts +398 -0
  792. package/src/domain/world/pools.ts +470 -0
  793. package/src/domain/world/restArea.ts +37 -0
  794. package/src/domain/world/weather.ts +201 -0
  795. package/src/domain/zoneAmbience.mjs +87 -0
  796. package/src/domain/zoneMusic.mjs +62 -0
  797. package/src/domain/zoneMusicQueue.mjs +7 -0
  798. package/src/engine/combat/activeSeal.ts +39 -0
  799. package/src/engine/combat/aiTargetResolve.ts +64 -0
  800. package/src/engine/combat/aoeCast.ts +289 -0
  801. package/src/engine/combat/applyConsumeAura.ts +74 -0
  802. package/src/engine/combat/applyDemonicSacrifice.ts +70 -0
  803. package/src/engine/combat/applyDispelMechanic.ts +30 -0
  804. package/src/engine/combat/applyHealEffect.ts +301 -0
  805. package/src/engine/combat/applySchoolAbsorb.ts +114 -0
  806. package/src/engine/combat/applySpell.ts +3169 -0
  807. package/src/engine/combat/applySpellLate.ts +2026 -0
  808. package/src/engine/combat/applySpellLateBag.ts +144 -0
  809. package/src/engine/combat/areaAura.ts +283 -0
  810. package/src/engine/combat/attackTable.ts +508 -0
  811. package/src/engine/combat/battleRez.ts +87 -0
  812. package/src/engine/combat/castAction.ts +36 -0
  813. package/src/engine/combat/castTargetGates.ts +75 -0
  814. package/src/engine/combat/castableKit.ts +68 -0
  815. package/src/engine/combat/ccMirrorUpgrade.ts +39 -0
  816. package/src/engine/combat/chainFan.ts +210 -0
  817. package/src/engine/combat/channel.ts +423 -0
  818. package/src/engine/combat/chaseCloseness.ts +95 -0
  819. package/src/engine/combat/cmangosCastGates.ts +129 -0
  820. package/src/engine/combat/combatFlag.ts +77 -0
  821. package/src/engine/combat/combatGeometry.ts +1329 -0
  822. package/src/engine/combat/combustion.ts +68 -0
  823. package/src/engine/combat/context.ts +730 -0
  824. package/src/engine/combat/createSession.ts +1165 -0
  825. package/src/engine/combat/creatureLeash.ts +38 -0
  826. package/src/engine/combat/crowdControl.ts +1259 -0
  827. package/src/engine/combat/dispelDuty.ts +54 -0
  828. package/src/engine/combat/dispelReflect.ts +609 -0
  829. package/src/engine/combat/displaceFloor.ts +113 -0
  830. package/src/engine/combat/duelBounds.ts +47 -0
  831. package/src/engine/combat/equippedItemGate.ts +297 -0
  832. package/src/engine/combat/evadeLifecycle.ts +63 -0
  833. package/src/engine/combat/eventAi.ts +2220 -0
  834. package/src/engine/combat/facing.ts +74 -0
  835. package/src/engine/combat/fearFlee.ts +137 -0
  836. package/src/engine/combat/fighterFactory.ts +1144 -0
  837. package/src/engine/combat/forceDespawnAction.ts +51 -0
  838. package/src/engine/combat/formulas.ts +807 -0
  839. package/src/engine/combat/friendlyFan.ts +55 -0
  840. package/src/engine/combat/groundPoolTick.ts +210 -0
  841. package/src/engine/combat/hazards.ts +114 -0
  842. package/src/engine/combat/healTargets.ts +226 -0
  843. package/src/engine/combat/heartbeatResist.ts +49 -0
  844. package/src/engine/combat/hostileItemUse.ts +75 -0
  845. package/src/engine/combat/interruptAuras.ts +66 -0
  846. package/src/engine/combat/itemRescue.ts +49 -0
  847. package/src/engine/combat/itemUse.ts +260 -0
  848. package/src/engine/combat/kitById.ts +23 -0
  849. package/src/engine/combat/knockBack.ts +201 -0
  850. package/src/engine/combat/leap.ts +89 -0
  851. package/src/engine/combat/mitigation.ts +587 -0
  852. package/src/engine/combat/modTaunt.ts +43 -0
  853. package/src/engine/combat/motionClaim.ts +268 -0
  854. package/src/engine/combat/motionGate.ts +150 -0
  855. package/src/engine/combat/motionGenerator.ts +27 -0
  856. package/src/engine/combat/navSight.ts +138 -0
  857. package/src/engine/combat/perfSink.ts +28 -0
  858. package/src/engine/combat/periodicDue.ts +55 -0
  859. package/src/engine/combat/petAuras.ts +86 -0
  860. package/src/engine/combat/pickAction.ts +3449 -0
  861. package/src/engine/combat/powerForm.ts +735 -0
  862. package/src/engine/combat/powerPools.ts +49 -0
  863. package/src/engine/combat/predicates.ts +538 -0
  864. package/src/engine/combat/procsDamage.ts +1823 -0
  865. package/src/engine/combat/reactiveGates.ts +135 -0
  866. package/src/engine/combat/roles.ts +389 -0
  867. package/src/engine/combat/rotationSubject.ts +78 -0
  868. package/src/engine/combat/ruleAfter.ts +106 -0
  869. package/src/engine/combat/seedDisplayAuras.ts +203 -0
  870. package/src/engine/combat/seedOocEffects.ts +317 -0
  871. package/src/engine/combat/seedSchoolImmunities.ts +45 -0
  872. package/src/engine/combat/session-types.ts +458 -0
  873. package/src/engine/combat/sessionApi.ts +1785 -0
  874. package/src/engine/combat/sessionCharge.ts +124 -0
  875. package/src/engine/combat/sessionChase.ts +869 -0
  876. package/src/engine/combat/sessionDeaths.ts +469 -0
  877. package/src/engine/combat/sessionFocus.ts +506 -0
  878. package/src/engine/combat/sessionFollow.ts +167 -0
  879. package/src/engine/combat/sessionGeometry.ts +188 -0
  880. package/src/engine/combat/sessionHome.ts +75 -0
  881. package/src/engine/combat/sessionInject.ts +719 -0
  882. package/src/engine/combat/sessionMechanicMove.ts +555 -0
  883. package/src/engine/combat/sessionMotion.ts +1553 -0
  884. package/src/engine/combat/sessionMotionKit.ts +247 -0
  885. package/src/engine/combat/sessionMoveIntent.ts +49 -0
  886. package/src/engine/combat/sessionMoveOrder.ts +200 -0
  887. package/src/engine/combat/sessionPathTo.ts +657 -0
  888. package/src/engine/combat/sessionPools.ts +688 -0
  889. package/src/engine/combat/sessionSteer.ts +144 -0
  890. package/src/engine/combat/sessionStepBack.ts +151 -0
  891. package/src/engine/combat/sessionStepWrap.ts +116 -0
  892. package/src/engine/combat/sessionView.ts +442 -0
  893. package/src/engine/combat/simEffects.ts +32 -0
  894. package/src/engine/combat/simFacade.ts +620 -0
  895. package/src/engine/combat/simPump.ts +264 -0
  896. package/src/engine/combat/simSnapshot.ts +165 -0
  897. package/src/engine/combat/simThreadPool.ts +35 -0
  898. package/src/engine/combat/skeramImages.ts +57 -0
  899. package/src/engine/combat/slowUpdate.ts +178 -0
  900. package/src/engine/combat/snapToFloor.ts +42 -0
  901. package/src/engine/combat/speedAura.ts +29 -0
  902. package/src/engine/combat/spellReagents.ts +71 -0
  903. package/src/engine/combat/stealthDetect.ts +93 -0
  904. package/src/engine/combat/stepBackMotion.ts +171 -0
  905. package/src/engine/combat/stepSession.ts +3102 -0
  906. package/src/engine/combat/summonCast.ts +243 -0
  907. package/src/engine/combat/thaddiusPolarity.ts +97 -0
  908. package/src/engine/combat/threat.ts +388 -0
  909. package/src/engine/combat/threatOps.ts +272 -0
  910. package/src/engine/combat/tickWorkerBody.ts +211 -0
  911. package/src/engine/combat/totemAuras.ts +122 -0
  912. package/src/engine/combat/triggerPayload.ts +42 -0
  913. package/src/engine/combat/triggeredCompanion.ts +63 -0
  914. package/src/engine/combat/types.ts +1897 -0
  915. package/src/engine/combat/useObjectTrap.ts +140 -0
  916. package/src/engine/combat/walkSurface.ts +54 -0
  917. package/src/engine/combat/weapon.ts +1248 -0
  918. package/src/engine/combat/worldFrame.ts +43 -0
  919. package/src/engine/combat.solo-golden.json +2242 -0
  920. package/src/engine/combat.ts +84 -0
  921. package/src/engine/core/detMath.ts +289 -0
  922. package/src/engine/core/events.ts +357 -0
  923. package/src/engine/core/rng.ts +36 -0
  924. package/src/engine/game/actionBars.ts +124 -0
  925. package/src/engine/game/activateObjectFromSpell.ts +320 -0
  926. package/src/engine/game/applyActiveObjectFromDbScript.ts +98 -0
  927. package/src/engine/game/applyDeathAndSpellScripts.ts +268 -0
  928. package/src/engine/game/applyDoorFromDbScript.ts +388 -0
  929. package/src/engine/game/applyEscortFromDbScript.ts +290 -0
  930. package/src/engine/game/applyGoSpellcasterCast.ts +40 -0
  931. package/src/engine/game/applyHoverFromDbScript.ts +110 -0
  932. package/src/engine/game/applyOocResurrect.ts +71 -0
  933. package/src/engine/game/applySpellDurability.ts +115 -0
  934. package/src/engine/game/applyTailFromDbScript.ts +478 -0
  935. package/src/engine/game/applyTerminateFromDbScript.ts +95 -0
  936. package/src/engine/game/auctionMail.ts +269 -0
  937. package/src/engine/game/bagOverflow.ts +130 -0
  938. package/src/engine/game/bank.ts +110 -0
  939. package/src/engine/game/barAutofill.ts +26 -0
  940. package/src/engine/game/battleground.ts +369 -0
  941. package/src/engine/game/combatEnemySpec.ts +216 -0
  942. package/src/engine/game/combatObjectTraps.ts +167 -0
  943. package/src/engine/game/combatSeed.ts +320 -0
  944. package/src/engine/game/combatSession.ts +3241 -0
  945. package/src/engine/game/combatSessionClock.ts +62 -0
  946. package/src/engine/game/companionQuestActions.ts +242 -0
  947. package/src/engine/game/companionTraining.ts +40 -0
  948. package/src/engine/game/consumables.ts +624 -0
  949. package/src/engine/game/context.ts +53 -0
  950. package/src/engine/game/createHealthstone.ts +45 -0
  951. package/src/engine/game/deathFlow.ts +127 -0
  952. package/src/engine/game/devGrant.ts +117 -0
  953. package/src/engine/game/dynamicObject.ts +365 -0
  954. package/src/engine/game/enchantItem.ts +177 -0
  955. package/src/engine/game/equipmentHelper.ts +806 -0
  956. package/src/engine/game/factionState.ts +108 -0
  957. package/src/engine/game/garmentsOoc.ts +69 -0
  958. package/src/engine/game/globalActionBar.ts +179 -0
  959. package/src/engine/game/goInteractQuestCredit.ts +51 -0
  960. package/src/engine/game/goMoTransportUse.ts +61 -0
  961. package/src/engine/game/goTransportUse.ts +60 -0
  962. package/src/engine/game/healthstoneUpkeep.ts +59 -0
  963. package/src/engine/game/killSkin.ts +124 -0
  964. package/src/engine/game/learnFromItem.ts +118 -0
  965. package/src/engine/game/loadReconcile.ts +551 -0
  966. package/src/engine/game/loot.ts +294 -0
  967. package/src/engine/game/macros.ts +125 -0
  968. package/src/engine/game/mail.ts +293 -0
  969. package/src/engine/game/meetingStoneQueue.ts +75 -0
  970. package/src/engine/game/meetingStoneUse.ts +54 -0
  971. package/src/engine/game/newGameState.ts +363 -0
  972. package/src/engine/game/oocAuraInterrupt.ts +92 -0
  973. package/src/engine/game/oocCast.ts +241 -0
  974. package/src/engine/game/oocCastEffects.ts +803 -0
  975. package/src/engine/game/oocCastMethods.ts +1077 -0
  976. package/src/engine/game/openLockFromSpell.ts +174 -0
  977. package/src/engine/game/outdoorPvp.ts +187 -0
  978. package/src/engine/game/outfitter.ts +644 -0
  979. package/src/engine/game/paladinBoard.ts +393 -0
  980. package/src/engine/game/partyAuras.ts +121 -0
  981. package/src/engine/game/persistCombatAuras.ts +91 -0
  982. package/src/engine/game/pets.ts +459 -0
  983. package/src/engine/game/prePullHealthstones.ts +154 -0
  984. package/src/engine/game/professions.ts +2227 -0
  985. package/src/engine/game/pruneStaleRuntime.ts +39 -0
  986. package/src/engine/game/questFightCredit.ts +36 -0
  987. package/src/engine/game/questItemOnCorpse.ts +166 -0
  988. package/src/engine/game/questItemOnCreature.ts +103 -0
  989. package/src/engine/game/questLog.ts +879 -0
  990. package/src/engine/game/questSpellComplete.ts +21 -0
  991. package/src/engine/game/questTurnIn.ts +598 -0
  992. package/src/engine/game/raidParty.ts +32 -0
  993. package/src/engine/game/reagentBuyIn.ts +39 -0
  994. package/src/engine/game/regenRest.ts +186 -0
  995. package/src/engine/game/rotation.ts +425 -0
  996. package/src/engine/game/runFullDungeon.ts +611 -0
  997. package/src/engine/game/runSupply.ts +80 -0
  998. package/src/engine/game/sanitizeDriftedItems.ts +135 -0
  999. package/src/engine/game/scriptDevGoUse.ts +397 -0
  1000. package/src/engine/game/scriptDevInnkeeper.ts +150 -0
  1001. package/src/engine/game/scriptDevProfessionSpec.ts +99 -0
  1002. package/src/engine/game/sendEventFromSpell.ts +87 -0
  1003. package/src/engine/game/sortContainers.ts +85 -0
  1004. package/src/engine/game/spellReputation.ts +69 -0
  1005. package/src/engine/game/squad/squadDungeonSeating.ts +197 -0
  1006. package/src/engine/game/squadDungeon.ts +4222 -0
  1007. package/src/engine/game/squadQuestShare.ts +260 -0
  1008. package/src/engine/game/summonObjectSlot.ts +69 -0
  1009. package/src/engine/game/summonObjectWild.ts +73 -0
  1010. package/src/engine/game/summoningRitualUse.ts +141 -0
  1011. package/src/engine/game/talents.ts +356 -0
  1012. package/src/engine/game/tamingRodUse.ts +66 -0
  1013. package/src/engine/game/tempSpawnCreature.ts +136 -0
  1014. package/src/engine/game/tickDungeonPatrolScripts.ts +205 -0
  1015. package/src/engine/game/tickTimedQuests.ts +28 -0
  1016. package/src/engine/game/trade.ts +586 -0
  1017. package/src/engine/game/travel.ts +1155 -0
  1018. package/src/engine/game/types.ts +1855 -0
  1019. package/src/engine/game/vendorOffers.ts +244 -0
  1020. package/src/engine/game/weaponImbueItem.ts +281 -0
  1021. package/src/engine/game/worldSession.ts +183 -0
  1022. package/src/engine/game/worldState.ts +166 -0
  1023. package/src/engine/game.ts +968 -0
  1024. package/src/engine/spells/GAP.md +67 -0
  1025. package/src/engine/spells/absorbs.ts +376 -0
  1026. package/src/engine/spells/addTargetTrigger.ts +53 -0
  1027. package/src/engine/spells/auraPerSecondCost.ts +50 -0
  1028. package/src/engine/spells/auraStacking.ts +497 -0
  1029. package/src/engine/spells/cmangos-special-cases-combustion.ts +13 -0
  1030. package/src/engine/spells/cmangos-special-cases-s18.ts +445 -0
  1031. package/src/engine/spells/cmangos-special-cases-s19.ts +324 -0
  1032. package/src/engine/spells/cmangos-special-cases-s20.ts +385 -0
  1033. package/src/engine/spells/cmangos-special-cases-s21.ts +116 -0
  1034. package/src/engine/spells/cmangos-special-cases-s22.ts +24 -0
  1035. package/src/engine/spells/cmangos-special-cases-s23.ts +52 -0
  1036. package/src/engine/spells/cmangos-special-cases.ts +1570 -0
  1037. package/src/engine/spells/conditions.ts +718 -0
  1038. package/src/engine/spells/effects.ts +203 -0
  1039. package/src/engine/spells/fixtures/oracle-effects-lock9a.json +1 -0
  1040. package/src/engine/spells/immunity.ts +942 -0
  1041. package/src/engine/spells/intentEffects.ts +351 -0
  1042. package/src/engine/spells/interpreter/GAPS.md +21 -0
  1043. package/src/engine/spells/interpreter/amount.ts +109 -0
  1044. package/src/engine/spells/interpreter/class-scripts-kit.ts +478 -0
  1045. package/src/engine/spells/interpreter/diff.ts +246 -0
  1046. package/src/engine/spells/interpreter/duration.ts +90 -0
  1047. package/src/engine/spells/interpreter/form-attrs.json +1 -0
  1048. package/src/engine/spells/interpreter/form-attrs.ts +95 -0
  1049. package/src/engine/spells/interpreter/handlers/aura-remove.ts +113 -0
  1050. package/src/engine/spells/interpreter/handlers/auras-control.ts +1547 -0
  1051. package/src/engine/spells/interpreter/handlers/auras-core.ts +1583 -0
  1052. package/src/engine/spells/interpreter/handlers/auras-misc.ts +1774 -0
  1053. package/src/engine/spells/interpreter/handlers/effect-disenchant.ts +17 -0
  1054. package/src/engine/spells/interpreter/handlers/effect-skinning.ts +20 -0
  1055. package/src/engine/spells/interpreter/handlers/effects-action-utility.ts +1455 -0
  1056. package/src/engine/spells/interpreter/handlers/effects-core.ts +432 -0
  1057. package/src/engine/spells/interpreter/handlers/effects-remainder.ts +105 -0
  1058. package/src/engine/spells/interpreter/handlers/effects-summon-item.ts +687 -0
  1059. package/src/engine/spells/interpreter/handlers/mod-increase-energy-percent.ts +36 -0
  1060. package/src/engine/spells/interpreter/handlers/mod-increase-energy.ts +36 -0
  1061. package/src/engine/spells/interpreter/handlers/periodic-trigger-zero.ts +327 -0
  1062. package/src/engine/spells/interpreter/handlers/procs.ts +131 -0
  1063. package/src/engine/spells/interpreter/handlers/registry.ts +975 -0
  1064. package/src/engine/spells/interpreter/handlers/shared.ts +667 -0
  1065. package/src/engine/spells/interpreter/handlers.ts +9 -0
  1066. package/src/engine/spells/interpreter/hunter-kit.ts +202 -0
  1067. package/src/engine/spells/interpreter/index.ts +525 -0
  1068. package/src/engine/spells/interpreter/item-triggers.ts +1121 -0
  1069. package/src/engine/spells/interpreter/lift-consume-energy.ts +37 -0
  1070. package/src/engine/spells/interpreter/mage-portals.ts +37 -0
  1071. package/src/engine/spells/interpreter/materialize-charm.ts +88 -0
  1072. package/src/engine/spells/interpreter/materialize-dispel-mechanic.ts +25 -0
  1073. package/src/engine/spells/interpreter/materialize-rating-buffs.ts +81 -0
  1074. package/src/engine/spells/interpreter/materialize-speed.ts +109 -0
  1075. package/src/engine/spells/interpreter/materialize-spell-magnet.ts +22 -0
  1076. package/src/engine/spells/interpreter/opcodes.ts +789 -0
  1077. package/src/engine/spells/interpreter/paladin-kit.ts +95 -0
  1078. package/src/engine/spells/interpreter/paladin-seals.ts +499 -0
  1079. package/src/engine/spells/interpreter/priest-warlock-kit.ts +135 -0
  1080. package/src/engine/spells/interpreter/proc.ts +443 -0
  1081. package/src/engine/spells/interpreter/registry/helpers.ts +16 -0
  1082. package/src/engine/spells/interpreter/registry/index.ts +216 -0
  1083. package/src/engine/spells/interpreter/registry/packs/class-abilities.ts +304 -0
  1084. package/src/engine/spells/interpreter/registry/packs/dire-maul.ts +44 -0
  1085. package/src/engine/spells/interpreter/registry/packs/dummy-script-tail.ts +1065 -0
  1086. package/src/engine/spells/interpreter/registry/packs/ex-wave-m.ts +70 -0
  1087. package/src/engine/spells/interpreter/registry/packs/life-tap.ts +107 -0
  1088. package/src/engine/spells/interpreter/registry/packs/paladin.ts +246 -0
  1089. package/src/engine/spells/interpreter/registry/packs/raid-script-summons.ts +26 -0
  1090. package/src/engine/spells/interpreter/registry/packs/raid-threat-wipe.ts +22 -0
  1091. package/src/engine/spells/interpreter/registry/packs/shaman.ts +214 -0
  1092. package/src/engine/spells/interpreter/registry/packs/si4-dummy-generic-a.ts +269 -0
  1093. package/src/engine/spells/interpreter/registry/packs/si4-dummy-generic-b.ts +370 -0
  1094. package/src/engine/spells/interpreter/registry/packs/si4-dummy-generic-c.ts +172 -0
  1095. package/src/engine/spells/interpreter/registry/packs/si4-dummy-hunter.ts +60 -0
  1096. package/src/engine/spells/interpreter/registry/packs/si4-dummy-warrior.ts +31 -0
  1097. package/src/engine/spells/interpreter/registry/packs/si4-script-generic-a.ts +114 -0
  1098. package/src/engine/spells/interpreter/registry/packs/si4-script-generic-b.ts +249 -0
  1099. package/src/engine/spells/interpreter/registry/packs/si4-script-generic-c.ts +233 -0
  1100. package/src/engine/spells/interpreter/registry/types.ts +48 -0
  1101. package/src/engine/spells/interpreter/talent-scripted.ts +329 -0
  1102. package/src/engine/spells/interpreter/targeting.ts +90 -0
  1103. package/src/engine/spells/interpreter/types-intent.ts +1501 -0
  1104. package/src/engine/spells/interpreter/types.ts +419 -0
  1105. package/src/engine/spells/interpreter/warrior-druid-kit.ts +314 -0
  1106. package/src/engine/spells/interpreter/weapon-imbue-kit.ts +384 -0
  1107. package/src/engine/spells/interrupt.ts +217 -0
  1108. package/src/engine/spells/meleeAttackReset.ts +60 -0
  1109. package/src/engine/spells/oocTriggerSpell.ts +49 -0
  1110. package/src/engine/spells/overrideClassScripts.ts +319 -0
  1111. package/src/engine/spells/parryHaste.ts +20 -0
  1112. package/src/engine/spells/procs.ts +300 -0
  1113. package/src/engine/spells/recovery.ts +203 -0
  1114. package/src/engine/spells/scriptTargetDest.ts +76 -0
  1115. package/src/engine/spells/scriptTargets.ts +85 -0
  1116. package/src/engine/spells/singleTargetAura.ts +82 -0
  1117. package/src/engine/spells/specialCasePayloads.ts +57 -0
  1118. package/src/engine/spells/spellAttributes.ts +249 -0
  1119. package/src/engine/spells/spellBonus.ts +143 -0
  1120. package/src/engine/spells/spellModIntents.ts +419 -0
  1121. package/src/engine/spells/spellMods.ts +283 -0
  1122. package/src/engine/spells/spellRadius.ts +15 -0
  1123. package/src/engine/spells/trapObjects.ts +26 -0
  1124. package/src/json.d.ts +7 -0
  1125. package/src/persistence/memoryRepository.ts +23 -0
  1126. package/src/persistence/saveBackups.ts +162 -0
  1127. package/src/persistence/saveFile.ts +68 -0
  1128. package/src/persistence/saveRepository.ts +11 -0
  1129. package/src/persistence/saveShape.ts +668 -0
  1130. package/src/progression/leveling.ts +89 -0
  1131. package/src/progression/rest.ts +1434 -0
  1132. package/src/progression/training.ts +226 -0
  1133. package/src/progression/xpGain.ts +369 -0
  1134. package/src/quests/quests.ts +1580 -0
  1135. package/src/world/aoePull.ts +198 -0
  1136. package/src/world/areaTableDbc.ts +39 -0
  1137. package/src/world/areaTableMapIdPairs.ts +141 -0
  1138. package/src/world/bakeSlug.ts +43 -0
  1139. package/src/world/continuousDungeon.ts +1250 -0
  1140. package/src/world/dungeonBakeProjection.ts +190 -0
  1141. package/src/world/dungeonMapDensity.ts +342 -0
  1142. package/src/world/dungeonMapProjection.ts +135 -0
  1143. package/src/world/dungeonNav.ts +904 -0
  1144. package/src/world/dungeonNpcSim.ts +147 -0
  1145. package/src/world/dungeonObjectives.ts +234 -0
  1146. package/src/world/dungeonPreset.ts +35 -0
  1147. package/src/world/dungeonRoute.ts +311 -0
  1148. package/src/world/dungeonRouteGeometry.ts +732 -0
  1149. package/src/world/dungeonRouteOrder.ts +1037 -0
  1150. package/src/world/dungeonWingRooms.ts +426 -0
  1151. package/src/world/escort.ts +296 -0
  1152. package/src/world/goPoolRoll.ts +75 -0
  1153. package/src/world/instanceObjects.ts +785 -0
  1154. package/src/world/instances.ts +1572 -0
  1155. package/src/world/meetingStones.ts +56 -0
  1156. package/src/world/navmeshFloors.ts +145 -0
  1157. package/src/world/nearGrid.ts +167 -0
  1158. package/src/world/packBudget.ts +613 -0
  1159. package/src/world/rareRoll.ts +335 -0
  1160. package/src/world/routeAuthoring.ts +132 -0
  1161. package/src/world/routeEdit.ts +209 -0
  1162. package/src/world/world.ts +812 -0
  1163. package/src/world/zoneHazards.ts +47 -0
@@ -0,0 +1,1256 @@
1
+ // DP1 — trash packs from CFH/Detection clusters (pack-clusters.json). Never invent entries or
2
+ // counts. JSON is imported rather than read with node:fs so this loads in the browser bundle.
3
+
4
+ import dungeonPacksJson from '../tables/dungeonPacks.json' with { type: 'json' };
5
+ import dungeonSurveyJson from '../tables/dungeonSurvey.json' with { type: 'json' };
6
+ import areatriggerTeleportsJson from '../tables/areatriggerTeleports.json' with { type: 'json' };
7
+ import nonCombatTrashJson from '../tables/nonCombatTrash.json' with { type: 'json' };
8
+ import dungeonRoomsJson from './dungeon-rooms.json' with { type: 'json' };
9
+ import { TECHNICAL_TRIGGER_ENTRIES } from '../../domain/creature/creatureTrigger.ts';
10
+ import type { EncounterDef, EncounterEvent, EncounterPackMember } from '../schema.ts';
11
+
12
+ // ---- Friendly / non-combat trash strip (faction-driven) ----
13
+ // A class rule, not id lists: a creature friendly to every standard player template is never trash.
14
+
15
+ let _nonCombatTrashEntries: ReadonlySet<number> | null = null;
16
+
17
+ // Creature entries no standard player may attack without declaring war — non-combat presence, not
18
+ // kill population. Baked from creatures.factionId × factionTemplates into nonCombatTrash.json.
19
+ export function nonCombatTrashEntries(): ReadonlySet<number> {
20
+ if (_nonCombatTrashEntries) return _nonCombatTrashEntries;
21
+ const raw = nonCombatTrashJson as { entries?: number[] };
22
+ _nonCombatTrashEntries = new Set(raw.entries ?? []);
23
+ return _nonCombatTrashEntries;
24
+ }
25
+
26
+ /** True when entry may appear as trash kill supply (or is unknown / fail-open). */
27
+ export function isCombatTrashEntry(entry: number): boolean {
28
+ return !nonCombatTrashEntries().has(entry);
29
+ }
30
+
31
+ // ---- Types (pack-clusters.json) ---------------------------------------------
32
+
33
+ export type ClusterMember = {
34
+ guid: number;
35
+ entry: number;
36
+ x: number;
37
+ y: number;
38
+ /** World z from creature.position_z (dmapfid W2). Planar combat seed ignores z. */
39
+ z?: number;
40
+ };
41
+
42
+ export type ClusterPack = {
43
+ map: number;
44
+ packId: string;
45
+ guids: number[];
46
+ members: ClusterMember[];
47
+ centroid: { x: number; y: number; z?: number };
48
+ size: number;
49
+ };
50
+
51
+ /** One storey of Blackrock Spire is ~14 yd; 8 clears a ramp but not a floor. */
52
+ const PACK_FLOOR_DZ = 8;
53
+
54
+ // Where the pull actually happens: the centroid of the pack's LARGEST z-cluster. 336 of 1843 packs
55
+ // span storeys, and a between-floors mean sends the party to an empty floor (worst 78.5 yd).
56
+ export function modalFloorCentroid(
57
+ members: readonly ClusterMember[],
58
+ fallback: { x: number; y: number; z?: number },
59
+ ): { x: number; y: number; z?: number } {
60
+ const withZ = members.filter((m) => Number.isFinite(m.z));
61
+ if (withZ.length < 2) return { ...fallback };
62
+ const sorted = [...withZ].sort((a, b) => (a.z as number) - (b.z as number));
63
+ const groups: ClusterMember[][] = [[sorted[0]!]];
64
+ for (let i = 1; i < sorted.length; i++) {
65
+ const prev = sorted[i - 1]!.z as number;
66
+ const cur = sorted[i]!.z as number;
67
+ if (cur - prev <= PACK_FLOOR_DZ) groups[groups.length - 1]!.push(sorted[i]!);
68
+ else groups.push([sorted[i]!]);
69
+ }
70
+ // Not `fallback` on a single floor: that is the pack's UNFILTERED centroid, and the caller may
71
+ // have dropped a whole wing's members. The origin is the centroid of the members carried here.
72
+ let best = groups[0]!;
73
+ for (const g of groups) {
74
+ if (g.length > best.length) best = g;
75
+ else if (g.length === best.length) {
76
+ const dg = Math.hypot(
77
+ g.reduce((a, m) => a + m.x, 0) / g.length - fallback.x,
78
+ g.reduce((a, m) => a + m.y, 0) / g.length - fallback.y,
79
+ );
80
+ const db = Math.hypot(
81
+ best.reduce((a, m) => a + m.x, 0) / best.length - fallback.x,
82
+ best.reduce((a, m) => a + m.y, 0) / best.length - fallback.y,
83
+ );
84
+ if (dg < db) best = g;
85
+ }
86
+ }
87
+ const n = best.length;
88
+ return {
89
+ x: best.reduce((a, m) => a + m.x, 0) / n,
90
+ y: best.reduce((a, m) => a + m.y, 0) / n,
91
+ z: best.reduce((a, m) => a + (m.z as number), 0) / n,
92
+ };
93
+ }
94
+
95
+ // `packs` is the only field any caller reads; the survey's per-map name/slug/counters were
96
+ // measured unread and are not in the baked table.
97
+ export type ClusterMapData = {
98
+ packs: ClusterPack[];
99
+ };
100
+
101
+ /** [guid, entry, x, y, z] — dungeonPacks.json memberFields. */
102
+ type PackedMember = [number, number, number, number, number | null];
103
+ /** [packId, cx, cy, cz, members]. `size` and `guids` are derived; the baker asserts they can be. */
104
+ type PackedPack = [string, number | null, number | null, number | null, PackedMember[]];
105
+
106
+ type PackClustersFile = {
107
+ maps: Record<string, PackedPack[]>;
108
+ };
109
+
110
+ type SurveyDungeon = {
111
+ map: number;
112
+ census: Array<{
113
+ entry: number;
114
+ name?: string;
115
+ pool?: boolean;
116
+ poolCandidates?: number[];
117
+ poolGuids?: number[];
118
+ }>;
119
+ bosses?: Array<{ entry: number; name?: string; pos?: (number | null)[] }>;
120
+ };
121
+
122
+ type SurveyFile = { maps: Record<string, SurveyDungeon> };
123
+
124
+ // ---- Loaders (baked tables — browser + node) --------------------------------
125
+ // bake-dungeon-packs.mjs projects docs/dungeons/survey/{pack-clusters,survey}.json down to the
126
+ // fields read here. Importing those raw made the browser parse 2.33 MB (minified) for eight
127
+ // mapId lookups; the tables are 0.60 MB, and packs decode one map at a time.
128
+
129
+ const packsFile = dungeonPacksJson as unknown as PackClustersFile;
130
+ const surveyFile = dungeonSurveyJson as unknown as SurveyFile;
131
+
132
+ /** mapId → rehydrated packs. Entering Deadmines decodes Deadmines, not the other 25 maps. */
133
+ const clusterMapCache = new Map<number, ClusterMapData>();
134
+
135
+ export function getClusterMap(mapId: number): ClusterMapData | undefined {
136
+ const hit = clusterMapCache.get(mapId);
137
+ if (hit) return hit;
138
+ const rows = packsFile.maps?.[String(mapId)];
139
+ if (!rows) return undefined;
140
+ const packs: ClusterPack[] = rows.map(([packId, cx, cy, cz, packed]) => {
141
+ const members: ClusterMember[] = packed.map(([guid, entry, x, y, z]) =>
142
+ (z == null ? { guid, entry, x, y } : { guid, entry, x, y, z }));
143
+ const centroid = cz == null
144
+ ? { x: cx ?? 0, y: cy ?? 0 }
145
+ : { x: cx ?? 0, y: cy ?? 0, z: cz };
146
+ return {
147
+ map: mapId,
148
+ packId,
149
+ guids: members.map((m) => m.guid),
150
+ members,
151
+ centroid,
152
+ size: members.length,
153
+ };
154
+ });
155
+ const out: ClusterMapData = { packs };
156
+ clusterMapCache.set(mapId, out);
157
+ return out;
158
+ }
159
+
160
+ export function getSurveyDungeon(mapId: number): SurveyDungeon | undefined {
161
+ // Raids used to live in their own survey block with the same row shape; the bake merges both
162
+ // into one map-keyed lookup, so surveyBossPos and friends still work on either unchanged.
163
+ return surveyFile.maps?.[String(mapId)];
164
+ }
165
+
166
+ // ---- Named rooms (WMOAreaTable × VMAP groups) ----
167
+ // Committed bake dungeon-rooms.json. A pack belongs to the room its centroid falls in; no snap.
168
+
169
+ export type DungeonRoom = {
170
+ id: string;
171
+ name: string;
172
+ areaId: number;
173
+ rootWmoId: number;
174
+ groupWmoIds: number[];
175
+ model: string;
176
+ /** XYZ min/max. `number[]`, not a 3-tuple: JSON imports infer arrays, and a tuple
177
+ * declaration made the whole dungeon-rooms.json cast incomparable. Read via `[x, y] =`. */
178
+ bbox: { min: number[]; max: number[] };
179
+ };
180
+
181
+ // Mirrors dungeon-rooms.json's real top level; without these four keys the cast had no
182
+ // overlap with the imported literal type and tsc rejected it.
183
+ type DungeonRoomsFile = {
184
+ generated: string;
185
+ generator: string;
186
+ sources: string[];
187
+ notes: string[];
188
+ maps: Record<
189
+ string,
190
+ { name: string; slug: string; models: string[]; rooms: DungeonRoom[] }
191
+ >;
192
+ unassigned: Record<string, { count: number; packIds: string[] }>;
193
+ instances?: Record<
194
+ string,
195
+ { mapId: number; roomCount: number; unassignedPackCount: number; terrainOnly: boolean }
196
+ >;
197
+ };
198
+
199
+ function loadRoomsFile(): DungeonRoomsFile {
200
+ return dungeonRoomsJson as DungeonRoomsFile;
201
+ }
202
+
203
+ /** Named rooms for a classic dungeon map (empty when terrain-only / no WMO names). */
204
+ export function roomsForMap(mapId: number): readonly DungeonRoom[] {
205
+ return loadRoomsFile().maps[String(mapId)]?.rooms ?? [];
206
+ }
207
+
208
+ /** Committed unassigned pack list for a map (centroid in no room). */
209
+ export function unassignedPacksForMap(mapId: number): { count: number; packIds: readonly string[] } {
210
+ const u = loadRoomsFile().unassigned[String(mapId)];
211
+ return u ? { count: u.count, packIds: u.packIds } : { count: 0, packIds: [] };
212
+ }
213
+
214
+ // Room whose plan-XY bbox contains `pos`, smallest area winning on overlap; a known z beats a
215
+ // stacked floor that only matches in plan. Undefined when the point is in no room — never snaps.
216
+ export function roomAtPosition(
217
+ mapId: number,
218
+ pos: { x: number; y: number; z?: number },
219
+ ): DungeonRoom | undefined {
220
+ const rooms = roomsForMap(mapId);
221
+ if (!rooms.length) return undefined;
222
+ const xyHits: DungeonRoom[] = [];
223
+ for (const r of rooms) {
224
+ const [x0, y0] = r.bbox.min;
225
+ const [x1, y1] = r.bbox.max;
226
+ if (pos.x < x0 || pos.x > x1 || pos.y < y0 || pos.y > y1) continue;
227
+ xyHits.push(r);
228
+ }
229
+ if (!xyHits.length) return undefined;
230
+ const z = pos.z;
231
+ const zHits =
232
+ z != null && Number.isFinite(z)
233
+ ? xyHits.filter((r) => {
234
+ const z0 = r.bbox.min[2];
235
+ const z1 = r.bbox.max[2];
236
+ return z0 != null && z1 != null && Number.isFinite(z0) && Number.isFinite(z1)
237
+ && z >= z0 && z <= z1;
238
+ })
239
+ : [];
240
+ const pool = zHits.length ? zHits : xyHits;
241
+ let best: DungeonRoom | undefined;
242
+ let bestArea = Infinity;
243
+ for (const r of pool) {
244
+ const [x0, y0] = r.bbox.min;
245
+ const [x1, y1] = r.bbox.max;
246
+ const area = (x1 - x0) * (y1 - y0);
247
+ if (area < bestArea) {
248
+ bestArea = area;
249
+ best = r;
250
+ }
251
+ }
252
+ return best;
253
+ }
254
+
255
+ // Resolve the named room for a pack centroid (or any world point), reusing the same spatial claim as
256
+ // packIdAtPosition / clusterSpatialCandidates.
257
+ export function roomForPack(
258
+ mapId: number,
259
+ pack: { centroid: { x: number; y: number; z?: number }; packId?: string },
260
+ ): DungeonRoom | undefined {
261
+ return roomAtPosition(mapId, pack.centroid);
262
+ }
263
+
264
+ // Guid → packId for a map's CFH/Detection clusters. Used so spatial pulls join by authored pack, not by raw
265
+ // radius overlap across neighbouring packs.
266
+ export function packIdByGuid(mapId: number): Map<number, string> {
267
+ const out = new Map<number, string>();
268
+ const map = getClusterMap(mapId);
269
+ if (!map) return out;
270
+ for (const pack of map.packs) {
271
+ for (const g of pack.guids) out.set(g, pack.packId);
272
+ for (const m of pack.members) out.set(m.guid, pack.packId);
273
+ }
274
+ return out;
275
+ }
276
+
277
+ // Resolve packId for a world point: nearest cluster member within `maxDistYd` (default 2 yards, so
278
+ // the same spawn), else nearest pack centroid within 5 yards. Undefined when unclaimed.
279
+ export function packIdAtPosition(
280
+ mapId: number,
281
+ pos: { x: number; y: number },
282
+ maxDistYd = 2,
283
+ ): string | undefined {
284
+ const map = getClusterMap(mapId);
285
+ if (!map?.packs.length) return undefined;
286
+ let bestId: string | undefined;
287
+ let bestD = maxDistYd;
288
+ for (const pack of map.packs) {
289
+ for (const m of pack.members) {
290
+ const d = dist2d(pos, m);
291
+ if (d <= bestD) {
292
+ bestD = d;
293
+ bestId = pack.packId;
294
+ }
295
+ }
296
+ }
297
+ if (bestId) return bestId;
298
+ // Centroid fallback for encounter origins (centroid may sit slightly off members).
299
+ let cBest: string | undefined;
300
+ let cD = 5;
301
+ for (const pack of map.packs) {
302
+ const d = dist2d(pos, pack.centroid);
303
+ if (d <= cD) {
304
+ cD = d;
305
+ cBest = pack.packId;
306
+ }
307
+ }
308
+ return cBest;
309
+ }
310
+
311
+ // All static pack members on a map as spatial-pull candidates (with packId + z). Caller supplies level /
312
+ // detection / flags from the creature template.
313
+ export function clusterSpatialCandidates(
314
+ mapId: number,
315
+ creatureOf: (entry: number) =>
316
+ | { level: number; detectionRange?: number; extraFlags?: number }
317
+ | undefined,
318
+ ): Array<{
319
+ entry: number;
320
+ x: number;
321
+ y: number;
322
+ z?: number;
323
+ map: number;
324
+ level: number;
325
+ detectionRange?: number;
326
+ extraFlags?: number;
327
+ packId: string;
328
+ guid: number;
329
+ }> {
330
+ const map = getClusterMap(mapId);
331
+ if (!map) return [];
332
+ const out: Array<{
333
+ entry: number;
334
+ x: number;
335
+ y: number;
336
+ z?: number;
337
+ map: number;
338
+ level: number;
339
+ detectionRange?: number;
340
+ extraFlags?: number;
341
+ packId: string;
342
+ guid: number;
343
+ }> = [];
344
+ for (const pack of map.packs) {
345
+ for (const m of pack.members) {
346
+ if (!m.entry) continue;
347
+ const cdef = creatureOf(m.entry);
348
+ if (!cdef) continue;
349
+ out.push({
350
+ entry: m.entry,
351
+ x: m.x,
352
+ y: m.y,
353
+ z: m.z,
354
+ map: mapId,
355
+ level: cdef.level,
356
+ detectionRange: cdef.detectionRange,
357
+ extraFlags: cdef.extraFlags,
358
+ packId: pack.packId,
359
+ guid: m.guid,
360
+ });
361
+ }
362
+ }
363
+ return out;
364
+ }
365
+
366
+ /** Largest authored cluster pack size on a map (0 when unknown). */
367
+ export function maxClusterPackSize(mapId: number): number {
368
+ const map = getClusterMap(mapId);
369
+ if (!map?.packs.length) return 0;
370
+ let max = 0;
371
+ for (const p of map.packs) if (p.size > max) max = p.size;
372
+ return max;
373
+ }
374
+
375
+ /** guid → uniform CSE candidate list (survey census poolGuids / poolCandidates). */
376
+ export function loadPoolGuidCandidates(mapId: number): Map<number, number[]> {
377
+ const out = new Map<number, number[]>();
378
+ const dung = getSurveyDungeon(mapId);
379
+ if (!dung) return out;
380
+ for (const row of dung.census ?? []) {
381
+ if (!row.pool || !row.poolCandidates?.length || !row.poolGuids?.length) continue;
382
+ const cands = [...row.poolCandidates];
383
+ for (const g of row.poolGuids) {
384
+ if (!out.has(g)) out.set(g, cands);
385
+ }
386
+ }
387
+ return out;
388
+ }
389
+
390
+ /** entry → display name from survey census. */
391
+ export function loadEntryNames(mapId: number): Map<number, string> {
392
+ const out = new Map<number, string>();
393
+ const dung = getSurveyDungeon(mapId);
394
+ if (!dung) return out;
395
+ for (const row of dung.census ?? []) {
396
+ if (row.name) out.set(row.entry, row.name);
397
+ }
398
+ for (const b of dung.bosses ?? []) {
399
+ if (b.name) out.set(b.entry, b.name);
400
+ }
401
+ return out;
402
+ }
403
+
404
+ export function dist2d(
405
+ a: { x: number; y: number },
406
+ b: { x: number; y: number },
407
+ ): number {
408
+ const dx = a.x - b.x;
409
+ const dy = a.y - b.y;
410
+ return Math.hypot(dx, dy);
411
+ }
412
+
413
+ // ---- Survey boss positions + areatrigger entrances (no hand-typed coords) ----
414
+
415
+ export type WorldPoint = { x: number; y: number; z?: number };
416
+
417
+ // Survey boss avg position for (mapId, creature entry). Source: survey.json bosses[].pos (creature static
418
+ // avg on that map). Returns undefined when pos is null/missing.
419
+ export function surveyBossPos(mapId: number, entry: number): WorldPoint | undefined {
420
+ const dung = getSurveyDungeon(mapId);
421
+ if (!dung?.bosses) return undefined;
422
+ for (const b of dung.bosses) {
423
+ if (b.entry !== entry) continue;
424
+ const pos = b.pos;
425
+ if (!pos || pos[0] == null || pos[1] == null) return undefined;
426
+ const pt: WorldPoint = { x: Number(pos[0]), y: Number(pos[1]) };
427
+ if (pos[2] != null && Number.isFinite(Number(pos[2]))) pt.z = Number(pos[2]);
428
+ return pt;
429
+ }
430
+ return undefined;
431
+ }
432
+
433
+ type AreatriggerTeleportRow = {
434
+ id: number;
435
+ name?: string;
436
+ targetMap: number;
437
+ targetX: number;
438
+ targetY: number;
439
+ targetZ?: number;
440
+ };
441
+
442
+ // Per-instance areatrigger teleport id for the real dungeon entrance, from areatriggerTeleports.json.
443
+ // Multi-wing maps pick the wing-specific trigger; LBRS and UBRS share Blackrock Spire's.
444
+ export const INSTANCE_ENTRANCE_TRIGGER: Readonly<Record<string, number>> = {
445
+ 'ragefire-chasm': 2230,
446
+ 'wailing-caverns': 228,
447
+ deadmines: 78,
448
+ 'shadowfang-keep': 145,
449
+ 'blackfathom-deeps': 257,
450
+ 'the-stockade': 101,
451
+ gnomeregan: 324, // main Gnomeregan entrance (train depot is 523)
452
+ 'razorfen-kraul': 244,
453
+ 'sm-graveyard': 45,
454
+ 'sm-library': 614,
455
+ 'sm-armory': 612,
456
+ 'sm-cathedral': 610,
457
+ 'razorfen-downs': 442,
458
+ uldaman: 286,
459
+ 'zul-farrak': 924,
460
+ maraudon: 3134, // Purple entrance (single InstanceDef covers both sides)
461
+ 'sunken-temple': 446,
462
+ 'blackrock-depths': 1466,
463
+ lbrs: 1468,
464
+ ubrs: 1468, // same physical BRS portal; seal is a separate gate
465
+ 'dire-maul-east': 3183,
466
+ 'dire-maul-west': 3186,
467
+ 'dire-maul-north': 3189,
468
+ scholomance: 2567,
469
+ 'stratholme-live': 2216, // left front (scarlet/live)
470
+ 'stratholme-undead': 2214, // service/back door
471
+ // Raids (docs/archive/raids/PLAN.md §1). MC uses the searinggorge window 3528, not the
472
+ // ungated BRD bridge 2886 — the bridge is the walk-in residual, not the product entry.
473
+ 'onyxias-lair': 2848,
474
+ 'molten-core': 3528,
475
+ 'zul-gurub': 3928,
476
+ 'blackwing-lair': 3726,
477
+ 'ruins-of-ahnqiraj': 4008,
478
+ 'temple-of-ahnqiraj': 4010,
479
+ // 4055, not 4156: 4156's own AreaTrigger.dbc map is 533 (the in-instance Frostwyrm Lair
480
+ // teleporter). It is the only trigger of the 33 whose map equals its targetMap.
481
+ naxxramas: 4055,
482
+ };
483
+
484
+ // Extra world doors on the same InstanceDef. dungeon-done B2 scans `areatriggerId`.
485
+ // Cite: areatrigger_teleport; worldView extra Enter buttons; enterInstance opts.entranceTriggerId.
486
+ export const EXTRA_ENTRANCE_TRIGGERS: readonly { instanceId: string; areatriggerId: number }[] = [
487
+ { instanceId: 'maraudon', areatriggerId: 3133 }, // Maraudon Orange - Entering
488
+ { instanceId: 'gnomeregan', areatriggerId: 523 }, // Train Depot
489
+ { instanceId: 'uldaman', areatriggerId: 902 }, // Badlands back door
490
+ { instanceId: 'stratholme-live', areatriggerId: 2217 }, // Right Front
491
+ { instanceId: 'dire-maul-east', areatriggerId: 3184 }, // unnamed Dire Maul door
492
+ { instanceId: 'dire-maul-east', areatriggerId: 3185 }, // East back door
493
+ ];
494
+
495
+ function loadAreatriggerRows(): AreatriggerTeleportRow[] {
496
+ return areatriggerTeleportsJson as AreatriggerTeleportRow[];
497
+ }
498
+
499
+ function triggerRow(id: number): AreatriggerTeleportRow | undefined {
500
+ return loadAreatriggerRows().find((r) => r.id === id);
501
+ }
502
+
503
+ function pointFromTrigger(row: AreatriggerTeleportRow): WorldPoint {
504
+ const pt: WorldPoint = { x: Number(row.targetX), y: Number(row.targetY) };
505
+ if (row.targetZ != null && Number.isFinite(Number(row.targetZ))) {
506
+ pt.z = Number(row.targetZ);
507
+ }
508
+ return pt;
509
+ }
510
+
511
+ // Real entrance world point for an InstanceDef id, from areatriggerTeleports. Replaces hand-typed ENTRANCE
512
+ // tables and the fabricated "first trash with origin" spine start.
513
+ export function entranceForInstance(instanceId: string, triggerId?: number): WorldPoint | undefined {
514
+ const extra = triggerId != null
515
+ && EXTRA_ENTRANCE_TRIGGERS.some((e) => e.instanceId === instanceId && e.areatriggerId === triggerId);
516
+ const tid = extra ? triggerId : INSTANCE_ENTRANCE_TRIGGER[instanceId];
517
+ if (tid == null) return undefined;
518
+ const row = triggerRow(tid);
519
+ return row ? pointFromTrigger(row) : undefined;
520
+ }
521
+
522
+ export function extraEntrancesForInstance(instanceId: string): AreatriggerTeleportRow[] {
523
+ const ids = EXTRA_ENTRANCE_TRIGGERS.filter((e) => e.instanceId === instanceId).map((e) => e.areatriggerId);
524
+ return ids.map(triggerRow).filter((r): r is AreatriggerTeleportRow => r != null);
525
+ }
526
+
527
+ // Shared-map wing → boss creature entries used as spatial anchors. Positions come from surveyBossPos (DB
528
+ // avg), never hand-typed tables. Cite: survey.json bosses; dmapfid O5 wing partition.
529
+ export const WING_BOSS_ENTRIES: Readonly<
530
+ Record<number, Readonly<Record<string, readonly number[]>>>
531
+ > = {
532
+ // Scarlet Monastery
533
+ 189: {
534
+ gy: [3983, 4543, 6489, 6490, 6488], // Vishas, Thalnos, rare pool
535
+ lib: [3974, 6487], // Loksey, Doan
536
+ arm: [3975], // Herod
537
+ cat: [4542, 3976, 3977], // Fairbanks, Mograine, Whitemane
538
+ },
539
+ // Blackrock Spire
540
+ 229: {
541
+ lbrs: [9196, 9236, 9237, 10596, 10584, 9736, 10268, 10220, 9568],
542
+ ubrs: [9816, 10264, 10509, 10899, 10339, 10429, 10430, 10363],
543
+ },
544
+ // Stratholme
545
+ 329: {
546
+ live: [10516, 10808, 10997, 10811, 10812, 11143],
547
+ undead: [10436, 10437, 10438, 10435, 10439, 10440],
548
+ },
549
+ // Dire Maul
550
+ 429: {
551
+ east: [14354, 11490, 13280, 14327, 11492],
552
+ west: [11489, 11488, 11487, 11467, 11496, 11486],
553
+ north: [14326, 14322, 14321, 14323, 14325, 14324, 11501],
554
+ },
555
+ };
556
+
557
+ // Signature trash entries that identify a wing when spatial nearest-boss is ambiguous, sourced from
558
+ // the other wing's historical strip lists. Boss entries are already hard votes.
559
+ export const WING_SIGNATURE_ENTRIES: Readonly<
560
+ Record<number, Readonly<Record<string, readonly number[]>>>
561
+ > = {
562
+ 229: {
563
+ // UBRS trash families (from lbrs.ts LBRS_EXCLUDED UBRS block)
564
+ ubrs: [
565
+ 9096, 10083, 10366, 10372, 10371, 9817, 9818, 9819, 10318, 10317, 10319,
566
+ 10762, 10316, 10814, 10442, 10447, 10742, 10683, 10258, 10161,
567
+ ],
568
+ // LBRS trash families (from ubrs.ts UBRS_EXCLUDED LBRS block — keep in sync)
569
+ lbrs: [
570
+ 9197, 9198, 9199, 9200, 9201, 9216, 9217, 9218, 9219, 9239, 9240, 9241,
571
+ 9257, 9258, 9259, 9260, 9261, 9262, 9263, 9264, 9265, 9266, 9267, 9268,
572
+ 9269, 9583, 9692, 9693, 9716, 9717, 9736, 10221, 10374, 10375, 10376,
573
+ 10463, 10464, 10584,
574
+ ],
575
+ },
576
+ };
577
+
578
+ // ---- Cluster → trash EncounterDef -------------------------------------------
579
+
580
+ export type TrashFromClustersOpts = {
581
+ mapId: number;
582
+ /** Boss / rare / other-wing entries stripped from trash (kept as hand boss rows). */
583
+ stripEntries: ReadonlySet<number> | readonly number[];
584
+ /** Multi-wing: keep only packs that pass this filter. */
585
+ includePack?: (pack: ClusterPack) => boolean;
586
+ /** Guids claimed by hand event packs (avoid double-count). Usually empty — clusters already drop event-gated. */
587
+ excludeGuids?: ReadonlySet<number>;
588
+ /** Optional name overrides. */
589
+ entryName?: (entry: number) => string | undefined;
590
+ idPrefix?: string;
591
+ };
592
+
593
+ type Slot = {
594
+ entry: number;
595
+ poolCandidates?: number[];
596
+ guid: number;
597
+ };
598
+
599
+ // Convert one CFH/Detection cluster into a trash EncounterDef. CSE (entry===0): one pack slot per guid with
600
+ // survey poolCandidates. Returns null when empty after boss strip / filters.
601
+ export function clusterPackToTrash(
602
+ pack: ClusterPack,
603
+ strip: ReadonlySet<number>,
604
+ poolByGuid: Map<number, number[]>,
605
+ names: Map<number, string>,
606
+ opts?: {
607
+ excludeGuids?: ReadonlySet<number>;
608
+ entryName?: (e: number) => string | undefined;
609
+ idPrefix?: string;
610
+ /** When set, stamp roomId/roomName from the pack centroid. */
611
+ mapId?: number;
612
+ },
613
+ ): EncounterDef | null {
614
+ const exclude = opts?.excludeGuids;
615
+ const nonCombat = nonCombatTrashEntries();
616
+ // Never a pack slot: friendly-to-all, plus script triggers. A trigger's guid lands in spawnGuids
617
+ // with no floor body, so route credit waits forever on a corpse that cannot exist.
618
+ const notASlot = (entry: number) => nonCombat.has(entry) || TECHNICAL_TRIGGER_ENTRIES.has(entry);
619
+ const slots: Slot[] = [];
620
+ for (const m of pack.members) {
621
+ if (strip.has(m.entry)) continue;
622
+ if (exclude?.has(m.guid)) continue;
623
+ if (m.entry === 0) {
624
+ const cands = (poolByGuid.get(m.guid) ?? []).filter((e) => !strip.has(e) && !notASlot(e));
625
+ if (cands.length === 0) {
626
+ // No survey candidates — skip (never invent). Static CSE without table row is a data gap.
627
+ continue;
628
+ }
629
+ // Placeholder entry = first candidate (CMaNGOS-style until ResetEntry roll).
630
+ slots.push({ entry: cands[0]!, poolCandidates: [...cands], guid: m.guid });
631
+ } else {
632
+ if (notASlot(m.entry)) continue;
633
+ slots.push({ entry: m.entry, guid: m.guid });
634
+ }
635
+ }
636
+ if (slots.length === 0) return null;
637
+
638
+ // Primary = first non-pool member in stable guid/member order; else first slot.
639
+ let primaryIdx = slots.findIndex((s) => !s.poolCandidates);
640
+ if (primaryIdx < 0) primaryIdx = 0;
641
+ const primary = slots[primaryIdx]!;
642
+
643
+ // Aggregate remaining fixed entries; CSE stay one-slot-per-guid (count 1).
644
+ const fixedCounts = new Map<number, number>();
645
+ const cseRows: EncounterPackMember[] = [];
646
+ for (let i = 0; i < slots.length; i++) {
647
+ if (i === primaryIdx) continue;
648
+ const s = slots[i]!;
649
+ if (s.poolCandidates) {
650
+ cseRows.push({
651
+ creatureEntry: s.entry,
652
+ count: 1,
653
+ poolCandidates: s.poolCandidates,
654
+ });
655
+ } else {
656
+ fixedCounts.set(s.entry, (fixedCounts.get(s.entry) ?? 0) + 1);
657
+ }
658
+ }
659
+
660
+ const packRows: EncounterPackMember[] = [];
661
+ const primaryExtra = fixedCounts.get(primary.entry) ?? 0;
662
+ if (primaryExtra > 0) {
663
+ packRows.push({ creatureEntry: primary.entry, count: primaryExtra });
664
+ fixedCounts.delete(primary.entry);
665
+ }
666
+ for (const [entry, count] of fixedCounts) {
667
+ packRows.push({ creatureEntry: entry, count });
668
+ }
669
+ packRows.push(...cseRows);
670
+
671
+ const nameOf = (e: number) =>
672
+ opts?.entryName?.(e) ?? names.get(e) ?? `Creature ${e}`;
673
+ const primaryName = nameOf(primary.entry);
674
+ const mixed = new Set(slots.map((s) => s.entry)).size > 1 || cseRows.length > 0;
675
+ const display =
676
+ slots.length === 1
677
+ ? primaryName
678
+ : mixed
679
+ ? `${primaryName} pack`
680
+ : `${primaryName}s`;
681
+
682
+ // Over the SLOTS, not pack.members: strip/exclude/non-combat filters already ran, and a
683
+ // centroid over members this encounter does not carry points at nobody.
684
+ const inSlots = new Set(slots.map((s) => s.guid));
685
+ const seed = modalFloorCentroid(
686
+ pack.members.filter((m) => inSlots.has(m.guid)),
687
+ pack.centroid,
688
+ );
689
+ const origin: { x: number; y: number; z?: number } = { x: seed.x, y: seed.y };
690
+ if (seed.z != null && Number.isFinite(seed.z)) origin.z = seed.z;
691
+ const enc: EncounterDef = {
692
+ id: opts?.idPrefix ? `${opts.idPrefix}-${pack.packId}` : pack.packId,
693
+ name: display,
694
+ kind: 'trash',
695
+ creatureEntry: primary.entry,
696
+ origin,
697
+ spawnGuids: slots.map((s) => s.guid),
698
+ };
699
+ if (primary.poolCandidates) enc.poolCandidates = primary.poolCandidates;
700
+ if (packRows.length) enc.pack = packRows;
701
+ // Room membership from centroid — null when outside every named room (reported
702
+ // in dungeon-rooms.json unassigned; never nearest-snapped).
703
+ if (opts?.mapId != null) {
704
+ const room = roomForPack(opts.mapId, pack);
705
+ if (room) {
706
+ enc.roomId = room.id;
707
+ enc.roomName = room.name;
708
+ } else {
709
+ enc.roomId = null;
710
+ enc.roomName = null;
711
+ }
712
+ }
713
+ return enc;
714
+ }
715
+
716
+ // All cluster-derived trash for a map (bosses stripped, optional wing filter). Sorted by distance from
717
+ // `entrance` when provided, else cluster packId order.
718
+ export function trashFromClusters(opts: TrashFromClustersOpts & {
719
+ entrance?: { x: number; y: number };
720
+ }): EncounterDef[] {
721
+ const map = getClusterMap(opts.mapId);
722
+ if (!map) return [];
723
+ // Always strip non-combat (friendly-to-all) creatures — class gate, not id lists.
724
+ const strip = new Set<number>(
725
+ opts.stripEntries instanceof Set ? opts.stripEntries : opts.stripEntries,
726
+ );
727
+ for (const e of nonCombatTrashEntries()) strip.add(e);
728
+ const poolByGuid = loadPoolGuidCandidates(opts.mapId);
729
+ const names = loadEntryNames(opts.mapId);
730
+ const out: EncounterDef[] = [];
731
+ for (const pack of map.packs) {
732
+ if (opts.includePack && !opts.includePack(pack)) continue;
733
+ const enc = clusterPackToTrash(pack, strip, poolByGuid, names, {
734
+ excludeGuids: opts.excludeGuids,
735
+ entryName: opts.entryName,
736
+ idPrefix: opts.idPrefix,
737
+ mapId: opts.mapId,
738
+ });
739
+ if (enc) out.push(enc);
740
+ }
741
+ if (opts.entrance) {
742
+ const ent = opts.entrance;
743
+ out.sort((a, b) => {
744
+ const da = a.origin ? dist2d(a.origin, ent) : 0;
745
+ const db = b.origin ? dist2d(b.origin, ent) : 0;
746
+ if (da !== db) return da - db;
747
+ return a.id.localeCompare(b.id);
748
+ });
749
+ }
750
+ return out;
751
+ }
752
+
753
+ // ---- Route assembly ---------------------------------------------------------
754
+
755
+ export type BossAnchor = {
756
+ encounter: EncounterDef;
757
+ /** Survey boss avg pos; used to place trash before this boss + stamp origin. */
758
+ pos: { x: number; y: number; z?: number };
759
+ };
760
+
761
+ // Interleave spatially-sorted trash with bosses: `distance` assigns each pack to the segment before
762
+ // the nearest boss, `equal-bands` splits into bosses.length+1 bands when boss coords are missing.
763
+ export function interleaveTrashAndBosses(
764
+ trash: EncounterDef[],
765
+ bosses: BossAnchor[],
766
+ entrance: { x: number; y: number },
767
+ afterBoss?: Record<string, EncounterDef[]>,
768
+ mode: 'distance' | 'equal-bands' = 'distance',
769
+ ): EncounterDef[] {
770
+ if (bosses.length === 0) return [...trash];
771
+
772
+ if (mode === 'equal-bands') {
773
+ const out: EncounterDef[] = [];
774
+ const bands = bosses.length + 1;
775
+ const n = trash.length;
776
+ let ti = 0;
777
+ for (let bi = 0; bi < bosses.length; bi++) {
778
+ const end = Math.round(((bi + 1) * n) / bands);
779
+ while (ti < end) out.push(trash[ti++]!);
780
+ out.push(stampBossOrigin(bosses[bi]!));
781
+ const inserts = afterBoss?.[bosses[bi]!.encounter.id];
782
+ if (inserts) out.push(...inserts);
783
+ }
784
+ while (ti < n) out.push(trash[ti++]!);
785
+ return out;
786
+ }
787
+
788
+ const bossDists = bosses.map((b) => dist2d(b.pos, entrance));
789
+ const used = new Set<number>();
790
+ const out: EncounterDef[] = [];
791
+
792
+ for (let bi = 0; bi < bosses.length; bi++) {
793
+ const bDist = bossDists[bi]!;
794
+ const nextDist = bi + 1 < bossDists.length ? bossDists[bi + 1]! : Infinity;
795
+ const cutoff =
796
+ bi + 1 < bosses.length
797
+ ? (bDist + nextDist) / 2
798
+ : Infinity;
799
+
800
+ for (let ti = 0; ti < trash.length; ti++) {
801
+ if (used.has(ti)) continue;
802
+ const t = trash[ti]!;
803
+ const td = t.origin ? dist2d(t.origin, entrance) : bDist;
804
+ const prevCutoff = bi === 0 ? -Infinity : (bossDists[bi - 1]! + bDist) / 2;
805
+ if (td >= prevCutoff && td < cutoff) {
806
+ out.push(t);
807
+ used.add(ti);
808
+ }
809
+ }
810
+ out.push(stampBossOrigin(bosses[bi]!));
811
+ const inserts = afterBoss?.[bosses[bi]!.encounter.id];
812
+ if (inserts) out.push(...inserts);
813
+ }
814
+
815
+ for (let ti = 0; ti < trash.length; ti++) {
816
+ if (!used.has(ti)) out.push(trash[ti]!);
817
+ }
818
+ return out;
819
+ }
820
+
821
+ /** Survey/interleave pos becomes encounter.origin when the boss row lacks one. */
822
+ function stampBossOrigin(b: BossAnchor): EncounterDef {
823
+ const enc = b.encounter;
824
+ const has =
825
+ enc.origin && Number.isFinite(enc.origin.x) && Number.isFinite(enc.origin.y);
826
+ if (has) return enc;
827
+ const origin: { x: number; y: number; z?: number } = { x: b.pos.x, y: b.pos.y };
828
+ if (b.pos.z != null && Number.isFinite(b.pos.z)) origin.z = b.pos.z;
829
+ return { ...enc, origin };
830
+ }
831
+
832
+ /** guid → cluster member (entry + world position) for a map's packs. */
833
+ export function clusterMemberByGuid(mapId: number): Map<number, ClusterMember> {
834
+ const out = new Map<number, ClusterMember>();
835
+ for (const pack of getClusterMap(mapId)?.packs ?? []) {
836
+ for (const m of pack.members) out.set(m.guid, m);
837
+ }
838
+ return out;
839
+ }
840
+
841
+ /** Every mapped guid, for the callers that hold guids and no mapId (InstanceDef carries none).
842
+ * Decodes all 26 maps, so it is built on first ask and only that path pays for it. */
843
+ let allMapMembers: Map<number, ClusterMember> | null = null;
844
+ export function clusterMemberByGuidAllMaps(): Map<number, ClusterMember> {
845
+ if (allMapMembers) return allMapMembers;
846
+ const out = new Map<number, ClusterMember>();
847
+ for (const mapId of Object.keys(packsFile.maps ?? {})) {
848
+ for (const pack of getClusterMap(Number(mapId))?.packs ?? []) {
849
+ for (const m of pack.members) if (!out.has(m.guid)) out.set(m.guid, m);
850
+ }
851
+ }
852
+ allMapMembers = out;
853
+ return out;
854
+ }
855
+
856
+ // Rebuild a trash pull from a guid subset: origin centroid, primary and pack counts. Pass `pools`
857
+ // whenever the subset can contain CSE spawns, or a slot ships as `creatureEntry: 0`.
858
+ export function repackFromGuids(
859
+ base: EncounterDef,
860
+ guids: readonly number[],
861
+ members: Map<number, { entry: number; x: number; y: number; z?: number }>,
862
+ opts?: {
863
+ id?: string; name?: string; events?: EncounterEvent[]; pools?: Map<number, number[]>;
864
+ },
865
+ ): EncounterDef {
866
+ type Slot = { entry: number; guid: number; poolCandidates?: number[] };
867
+ const rows: { x: number; y: number; z?: number }[] = [];
868
+ const slots: Slot[] = [];
869
+ for (const g of guids) {
870
+ const m = members.get(g);
871
+ if (!m) continue;
872
+ rows.push(m);
873
+ const cands = m.entry === 0 ? (opts?.pools?.get(g) ?? []) : [];
874
+ if (cands.length) slots.push({ entry: cands[0]!, guid: g, poolCandidates: [...cands] });
875
+ else slots.push({ entry: m.entry, guid: g });
876
+ }
877
+ // Primary is a FIXED slot: keep the base's when it survives the split, else the most
878
+ // numerous. A pool slot only wins when the subset is nothing but pool slots.
879
+ const fixedCounts = new Map<number, number>();
880
+ for (const s of slots) {
881
+ if (!s.poolCandidates) fixedCounts.set(s.entry, (fixedCounts.get(s.entry) ?? 0) + 1);
882
+ }
883
+ let primaryIdx = slots.findIndex(
884
+ (s) => !s.poolCandidates && s.entry === base.creatureEntry,
885
+ );
886
+ if (primaryIdx < 0) {
887
+ const top = [...fixedCounts.entries()].sort((a, b) => b[1] - a[1])[0];
888
+ primaryIdx = top ? slots.findIndex((s) => !s.poolCandidates && s.entry === top[0]) : 0;
889
+ }
890
+ const primary = slots[primaryIdx];
891
+ const extra = new Map<number, number>();
892
+ const cseRows: EncounterPackMember[] = [];
893
+ for (let i = 0; i < slots.length; i++) {
894
+ if (i === primaryIdx) continue;
895
+ const s = slots[i]!;
896
+ if (s.poolCandidates) {
897
+ cseRows.push({ creatureEntry: s.entry, count: 1, poolCandidates: [...s.poolCandidates] });
898
+ } else {
899
+ extra.set(s.entry, (extra.get(s.entry) ?? 0) + 1);
900
+ }
901
+ }
902
+ const pack: EncounterPackMember[] = [];
903
+ for (const [entry, count] of extra) if (count > 0) pack.push({ creatureEntry: entry, count });
904
+ pack.push(...cseRows);
905
+ // Origin on the members' MODAL FLOOR, not their mean — the same seed trashFromClusters uses. A
906
+ // raw mean over a two-storey remainder lands between them, in the void, and the router noPaths.
907
+ const mean = {
908
+ x: rows.reduce((s, m) => s + m.x, 0) / rows.length,
909
+ y: rows.reduce((s, m) => s + m.y, 0) / rows.length,
910
+ z: rows.reduce((s, m) => s + (m.z ?? 0), 0) / rows.length,
911
+ };
912
+ const enc: EncounterDef = {
913
+ ...base,
914
+ id: opts?.id ?? base.id,
915
+ name: opts?.name ?? base.name,
916
+ creatureEntry: primary?.entry ?? base.creatureEntry,
917
+ origin: modalFloorCentroid(
918
+ rows.map((m, i) => ({ guid: slots[i]?.guid ?? 0, entry: 0, x: m.x, y: m.y, z: m.z })),
919
+ mean,
920
+ ),
921
+ spawnGuids: [...guids],
922
+ };
923
+ if (primary?.poolCandidates) enc.poolCandidates = [...primary.poolCandidates];
924
+ else delete enc.poolCandidates;
925
+ if (pack.length) enc.pack = pack;
926
+ else delete enc.pack;
927
+ if (opts?.events?.length) enc.events = opts.events;
928
+ else delete enc.events;
929
+ return enc;
930
+ }
931
+
932
+ // Land a `setsFlag` on the last cluster pack before `beforeId` holding a member `match` accepts,
933
+ // else the last trash pull. `trashFromCensus` returns [] now, so a census band dropped the flag.
934
+ export function setsFlagOnPackBefore(
935
+ encs: EncounterDef[],
936
+ opts: { mapId: number; flag: string; beforeId: string; match: (m: ClusterMember) => boolean },
937
+ ): EncounterDef[] {
938
+ const gate = encs.findIndex((e) => e.id === opts.beforeId);
939
+ if (gate < 0) return encs;
940
+ const members = clusterMemberByGuid(opts.mapId);
941
+ let pick = -1;
942
+ let last = -1;
943
+ for (let i = 0; i < gate; i++) {
944
+ const e = encs[i]!;
945
+ if (e.kind !== 'trash') continue;
946
+ last = i;
947
+ const hit = (e.spawnGuids ?? []).some((g) => {
948
+ const m = members.get(g);
949
+ return !!m && opts.match(m);
950
+ });
951
+ if (hit) pick = i;
952
+ }
953
+ const at = pick >= 0 ? pick : last;
954
+ if (at < 0) return encs;
955
+ const out = encs.slice();
956
+ const e = out[at]!;
957
+ out[at] = { ...e, events: [...(e.events ?? []), { kind: 'setsFlag', flag: opts.flag }] };
958
+ return out;
959
+ }
960
+
961
+ /** Apply the same events array onto every encounter (e.g. ship requiresFlag). */
962
+ export function withEvents(
963
+ encs: EncounterDef[],
964
+ events: EncounterEvent[],
965
+ ): EncounterDef[] {
966
+ return encs.map((e) => ({
967
+ ...e,
968
+ events: [...(e.events ?? []), ...events],
969
+ }));
970
+ }
971
+
972
+ // Interleave cluster trash evenly through a hand-authored spine (bosses + event patrols/gates already in
973
+ // story order). Spine order is preserved; trash is split into spine.length+1 bands.
974
+ export function interleaveSpineWithTrash(
975
+ trash: EncounterDef[],
976
+ spine: EncounterDef[],
977
+ ): EncounterDef[] {
978
+ if (spine.length === 0) return [...trash];
979
+ if (trash.length === 0) return [...spine];
980
+ const out: EncounterDef[] = [];
981
+ const bands = spine.length + 1;
982
+ const n = trash.length;
983
+ let ti = 0;
984
+ for (let si = 0; si < spine.length; si++) {
985
+ const end = Math.round(((si + 1) * n) / bands);
986
+ while (ti < end) out.push(trash[ti++]!);
987
+ out.push(spine[si]!);
988
+ }
989
+ while (ti < n) out.push(trash[ti++]!);
990
+ return out;
991
+ }
992
+
993
+ // Full cutover helper: cluster trash + hand spine (bosses/events). Strip entries = all creatureEntry on
994
+ // spine bosses (and optional extras).
995
+ export function buildClusterEncounters(opts: {
996
+ mapId: number;
997
+ spine: EncounterDef[];
998
+ entrance?: { x: number; y: number };
999
+ // Extra strip beyond spine boss entries — only entries that DO have a static cluster spawn here.
1000
+ // Never summon-only: those have zero cluster members, so there is nothing to strip.
1001
+ extraStrip?: readonly number[];
1002
+ includePack?: (pack: ClusterPack) => boolean;
1003
+ excludeGuids?: ReadonlySet<number>;
1004
+ }): EncounterDef[] {
1005
+ const strip = new Set<number>(opts.extraStrip ?? []);
1006
+ for (const e of opts.spine) {
1007
+ if (e.kind === 'boss') {
1008
+ strip.add(e.creatureEntry);
1009
+ for (const ev of e.events ?? []) {
1010
+ if (ev.kind === 'onDeathSummon') strip.add(ev.creatureEntry);
1011
+ }
1012
+ }
1013
+ }
1014
+ const trash = trashFromClusters({
1015
+ mapId: opts.mapId,
1016
+ stripEntries: strip,
1017
+ entrance: opts.entrance,
1018
+ includePack: opts.includePack,
1019
+ excludeGuids: opts.excludeGuids,
1020
+ });
1021
+ // Boss rows on the spine gain origin and spawnGuids from the cluster pack that still holds that
1022
+ // boss entry. Wing-filtered so dual-listed rares on shared maps do not double-claim guids.
1023
+ const spine = attachBossClusterGeometry(opts.spine, opts.mapId, opts.includePack);
1024
+ return interleaveSpineWithTrash(trash, spine);
1025
+ }
1026
+
1027
+ /** Pack size (primary + pack counts), ignoring CSE expansion. */
1028
+ export function encounterPackSize(enc: EncounterDef): number {
1029
+ let n = 1;
1030
+ for (const p of enc.pack ?? []) n += p.count;
1031
+ return n;
1032
+ }
1033
+
1034
+ /** True when primary+pack has ≥2 distinct creatureEntry values (CSE placeholder counts). */
1035
+ export function isMixedTrashPack(enc: EncounterDef): boolean {
1036
+ if (enc.kind !== 'trash') return false;
1037
+ const entries = new Set<number>([enc.creatureEntry]);
1038
+ for (const p of enc.pack ?? []) entries.add(p.creatureEntry);
1039
+ if (enc.poolCandidates || (enc.pack ?? []).some((p) => p.poolCandidates)) {
1040
+ // CSE + fixed of different types, or multiple distinct fixed
1041
+ return entries.size > 1 || (enc.pack?.length ?? 0) > 0;
1042
+ }
1043
+ return entries.size > 1;
1044
+ }
1045
+
1046
+ // Count kill supply with the CSE max-coverage model: a concrete row adds count for its entry, a CSE
1047
+ // slot adds count for EACH candidate. The physical slot count is still the sum of counts.
1048
+ export function killSupplyFromEncounter(enc: EncounterDef): Map<number, number> {
1049
+ const map = new Map<number, number>();
1050
+ const add = (entry: number, n: number) => map.set(entry, (map.get(entry) ?? 0) + n);
1051
+
1052
+ const addRow = (entry: number, count: number, pool?: number[]) => {
1053
+ if (pool && pool.length > 0) {
1054
+ for (const c of pool) add(c, count);
1055
+ } else {
1056
+ add(entry, count);
1057
+ }
1058
+ };
1059
+
1060
+ addRow(enc.creatureEntry, 1, enc.poolCandidates);
1061
+ for (const p of enc.pack ?? []) {
1062
+ addRow(p.creatureEntry, p.count, p.poolCandidates);
1063
+ }
1064
+ for (const ev of enc.events ?? []) {
1065
+ if (ev.kind === 'onDeathSummon') add(ev.creatureEntry, 1);
1066
+ if (ev.kind === 'waves') {
1067
+ for (const w of ev.waves) {
1068
+ for (const row of w.pack) addRow(row.creatureEntry, row.count, row.poolCandidates);
1069
+ }
1070
+ }
1071
+ if (ev.kind === 'hpThreshold' && ev.spawn) {
1072
+ for (const row of ev.spawn) addRow(row.creatureEntry, row.count, row.poolCandidates);
1073
+ }
1074
+ }
1075
+ return map;
1076
+ }
1077
+
1078
+ /** Physical spawn slots (CSE = 1 each, no candidate expansion). */
1079
+ export function physicalSlotCount(enc: EncounterDef): number {
1080
+ return encounterPackSize(enc);
1081
+ }
1082
+
1083
+ // Majority-entry wing filter: keep pack if ≥ half of non-CSE members are in `allowed`. Packs that are pure
1084
+ // CSE with any candidate in allowed are kept when any candidate matches.
1085
+ export function wingFilterByEntries(
1086
+ allowed: ReadonlySet<number>,
1087
+ ): (pack: ClusterPack) => boolean {
1088
+ return (pack) => {
1089
+ const fixed = pack.members.filter((m) => m.entry !== 0);
1090
+ if (fixed.length === 0) {
1091
+ // Pure CSE — include if we cannot tell (caller should prefer spatial filter)
1092
+ return true;
1093
+ }
1094
+ const hit = fixed.filter((m) => allowed.has(m.entry)).length;
1095
+ return hit * 2 >= fixed.length;
1096
+ };
1097
+ }
1098
+
1099
+ // Nearest-boss-wing filter: partitions packs on a shared map by nearest SURVEY boss position for
1100
+ // each wing's boss list, with no hand-typed anchors. Plan-view wing overlap is ~0–5%.
1101
+ export function wingFilterByNearestBoss(
1102
+ mapIdOrWingId: number | string,
1103
+ wingIdOrWings?: string | Record<string, { x: number; y: number }[]>,
1104
+ maybeWings?: Record<string, { x: number; y: number }[]>,
1105
+ ): (pack: ClusterPack) => boolean {
1106
+ // Legacy: wingFilterByNearestBoss(wingId, wingsRecord)
1107
+ if (typeof mapIdOrWingId === 'string' && wingIdOrWings && typeof wingIdOrWings === 'object') {
1108
+ const wingId = mapIdOrWingId;
1109
+ const wings = wingIdOrWings as Record<string, { x: number; y: number }[]>;
1110
+ const entries = Object.entries(wings);
1111
+ return (pack) => {
1112
+ let bestId = '';
1113
+ let bestD = Infinity;
1114
+ for (const [id, anchors] of entries) {
1115
+ for (const a of anchors) {
1116
+ const d = dist2d(pack.centroid, a);
1117
+ if (d < bestD) {
1118
+ bestD = d;
1119
+ bestId = id;
1120
+ }
1121
+ }
1122
+ }
1123
+ return bestId === wingId;
1124
+ };
1125
+ }
1126
+
1127
+ // W2: wingFilterByNearestBoss(mapId, wingId)
1128
+ const mapId = Number(mapIdOrWingId);
1129
+ const wingId = String(wingIdOrWings ?? '');
1130
+ const wingEntries = WING_BOSS_ENTRIES[mapId];
1131
+ if (!wingEntries || !wingId) {
1132
+ return () => true;
1133
+ }
1134
+
1135
+ /** wingId → survey anchors (skip bosses with null pos). */
1136
+ const anchorsByWing = new Map<string, WorldPoint[]>();
1137
+ for (const [wid, entries] of Object.entries(wingEntries)) {
1138
+ const pts: WorldPoint[] = [];
1139
+ for (const entry of entries) {
1140
+ const p = surveyBossPos(mapId, entry);
1141
+ if (p) pts.push(p);
1142
+ }
1143
+ if (pts.length) anchorsByWing.set(wid, pts);
1144
+ }
1145
+
1146
+ /** wingId → signature entry set (boss + characteristic trash). */
1147
+ const sigByWing = new Map<string, Set<number>>();
1148
+ for (const [wid, entries] of Object.entries(wingEntries)) {
1149
+ const set = new Set<number>(entries);
1150
+ for (const e of WING_SIGNATURE_ENTRIES[mapId]?.[wid] ?? []) set.add(e);
1151
+ sigByWing.set(wid, set);
1152
+ }
1153
+
1154
+ return (pack) => {
1155
+ // 1) Signature-entry majority: fixes packs of wing-A trash near wing-B bosses
1156
+ // (the LBRS↔UBRS strip interaction that ate pack 229-51's neighbours).
1157
+ const sigVotes = new Map<string, number>();
1158
+ let sigTotal = 0;
1159
+ for (const m of pack.members) {
1160
+ if (m.entry === 0) continue;
1161
+ for (const [wid, set] of sigByWing) {
1162
+ if (set.has(m.entry)) {
1163
+ sigVotes.set(wid, (sigVotes.get(wid) ?? 0) + 1);
1164
+ sigTotal++;
1165
+ break; // first matching wing only (sets should be disjoint)
1166
+ }
1167
+ }
1168
+ }
1169
+ if (sigTotal > 0) {
1170
+ let bestSig = '';
1171
+ let bestN = -1;
1172
+ let tie = false;
1173
+ for (const [wid, n] of sigVotes) {
1174
+ if (n > bestN) {
1175
+ bestN = n;
1176
+ bestSig = wid;
1177
+ tie = false;
1178
+ } else if (n === bestN) {
1179
+ tie = true;
1180
+ }
1181
+ }
1182
+ if (!tie && bestSig) return bestSig === wingId;
1183
+ }
1184
+
1185
+ // 2) Nearest survey boss anchor (plan-view; 0–5% pairwise wing overlap).
1186
+ let bestId = '';
1187
+ let bestD = Infinity;
1188
+ for (const [id, anchors] of anchorsByWing) {
1189
+ for (const a of anchors) {
1190
+ const d = dist2d(pack.centroid, a);
1191
+ if (d < bestD) {
1192
+ bestD = d;
1193
+ bestId = id;
1194
+ }
1195
+ }
1196
+ }
1197
+ return bestId === wingId;
1198
+ };
1199
+ }
1200
+
1201
+ // Attach survey/cluster origin and spawnGuids onto boss encounters from packs that still contain
1202
+ // that boss entry. `includePack` prevents a dual claim when two InstanceDefs share a map.
1203
+ export function attachBossClusterGeometry(
1204
+ encounters: EncounterDef[],
1205
+ mapId: number,
1206
+ includePack?: (pack: ClusterPack) => boolean,
1207
+ ): EncounterDef[] {
1208
+ const map = getClusterMap(mapId);
1209
+ if (!map) return encounters;
1210
+ /** entry → packs containing it (wing-filtered) */
1211
+ const packsByBoss = new Map<number, ClusterPack[]>();
1212
+ for (const pack of map.packs) {
1213
+ if (includePack && !includePack(pack)) continue;
1214
+ for (const m of pack.members) {
1215
+ if (m.entry <= 0) continue;
1216
+ if (!packsByBoss.has(m.entry)) packsByBoss.set(m.entry, []);
1217
+ packsByBoss.get(m.entry)!.push(pack);
1218
+ }
1219
+ }
1220
+ return encounters.map((enc) => {
1221
+ if (enc.kind !== 'boss') return enc;
1222
+ if (enc.origin && enc.spawnGuids?.length) return enc;
1223
+ const candidates = packsByBoss.get(enc.creatureEntry) ?? [];
1224
+ const pack = candidates[0];
1225
+ if (!pack) {
1226
+ // Fall back to survey boss avg pos when no static pack (script-summoned).
1227
+ const sp = surveyBossPos(mapId, enc.creatureEntry);
1228
+ if (sp && !enc.origin) return { ...enc, origin: sp };
1229
+ return enc;
1230
+ }
1231
+ const bossMembers = pack.members.filter((m) => m.entry === enc.creatureEntry);
1232
+ const seed = modalFloorCentroid(pack.members, pack.centroid);
1233
+ const origin: { x: number; y: number; z?: number } = { x: seed.x, y: seed.y };
1234
+ if (seed.z != null) origin.z = seed.z;
1235
+ // Prefer boss member position when present.
1236
+ if (bossMembers.length === 1) {
1237
+ const m = bossMembers[0]!;
1238
+ origin.x = m.x;
1239
+ origin.y = m.y;
1240
+ if (m.z != null) origin.z = m.z;
1241
+ }
1242
+ return {
1243
+ ...enc,
1244
+ origin: enc.origin ?? origin,
1245
+ spawnGuids: enc.spawnGuids ?? bossMembers.map((m) => m.guid),
1246
+ };
1247
+ });
1248
+ }
1249
+
1250
+ /** @deprecated Prefer wingFilterByNearestBoss(mapId, wingId). Kept name alias. */
1251
+ export function wingFilterByMapWing(
1252
+ mapId: number,
1253
+ wingId: string,
1254
+ ): (pack: ClusterPack) => boolean {
1255
+ return wingFilterByNearestBoss(mapId, wingId);
1256
+ }