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,1250 @@
1
+ // The continuous dungeon party world: walk on nav, live DB spawns, and a player-driven pull. The live
2
+ // controller must drive this module; the instant hop and auto-chain are dead.
3
+
4
+ /** Product policy — live UI and probes assert these stay false. */
5
+ export const CONTINUOUS_PRODUCT = {
6
+ autoPullOnEnter: false,
7
+ autoChainAfterKill: false,
8
+ hopOnTravel: false,
9
+ } as const;
10
+
11
+ import {
12
+ isDungeonNpcSpawn,
13
+ type DungeonSpawn,
14
+ } from '../data/dungeonSpawns.ts';
15
+ import { spawnsForInstanceWing } from './dungeonWingRooms.ts';
16
+ import { getCreatureAttackDistance } from '../domain/creature/creatureAggro.ts';
17
+ import { AGGRO_LEVEL_DIFF_CAP, DEFAULT_DETECTION_RANGE } from '../domain/creature/creatureAiConstants.ts';
18
+ import {
19
+ createNearGrid,
20
+ getNear,
21
+ nearClear,
22
+ nearGet,
23
+ nearInsert,
24
+ nearMove,
25
+ nearRemove,
26
+ type NearGrid,
27
+ } from './nearGrid.ts';
28
+ import {
29
+ findPathForMap,
30
+ isSwimPointForMap,
31
+ isWalkablePointForMap,
32
+ pathLength,
33
+ connectedFloorZForMap,
34
+ floorZForMap,
35
+ SWIM_STEP_COST,
36
+ Z_HINT_TOL,
37
+ type NavPos,
38
+ } from '../domain/nav/nav.ts';
39
+ // Not on the barrel; `pathEditorView.ts` and `walkSurface.ts` import the mesh leaf the same way.
40
+ import { followPathNavMesh, navMeshForMap, snapOntoNavMesh } from '../domain/nav/navmesh.ts';
41
+ import type { EncounterDef } from '../data/schema/encounter.ts';
42
+ import { entranceWorld, type WorldPos } from './dungeonRouteGeometry.ts';
43
+ import { floorGauntletWaves, hasFlag, requiredFlags, type InstanceRun } from './instances.ts';
44
+ import { filterSpawnsByPoolRoll, type DungeonPoolRoll } from './rareRoll.ts';
45
+ import { STOREY_DZ_YD } from '../domain/nav/storey.ts';
46
+
47
+ /** Same radius as the dest snap in liveDungeonController. */
48
+ const ENTRANCE_SNAP_YD = 20;
49
+
50
+ /** First finite z stamp on a path (findPathStack); overview paths leave z unset. */
51
+ export function pathFloorHint(path: readonly NavPos[]): number | undefined {
52
+ for (let i = 0; i < path.length; i++) {
53
+ const z = path[i]!.z;
54
+ if (z != null && Number.isFinite(z)) return z;
55
+ }
56
+ return undefined;
57
+ }
58
+
59
+ // The floor z for one step. A route stamp beats the sticky previous z, since once latched wrong the
60
+ // stacked read re-picks that storey every tick. Null keeps the prior z and never invents one.
61
+ export function partyFloorZ(
62
+ x: number,
63
+ y: number,
64
+ prevZ: number | undefined,
65
+ pathZ?: number,
66
+ mapId?: number,
67
+ ): number | null {
68
+ // The route z is the z of the waypoint being walked TOWARD, so hinting the resolver with it adopts
69
+ // the destination's storey on the FIRST step. Ask for the floor the party STANDS on instead.
70
+ if (mapId != null && prevZ != null) {
71
+ const cz = connectedFloorZForMap(mapId, x, y, prevZ, pathZ);
72
+ if (cz != null) return cz;
73
+ }
74
+ const hint = pathZ ?? prevZ;
75
+ // The mesh keeps stacked floors as separate polys. With no map id there is nothing
76
+ // registered to ask — the raster tier that used to answer that case is gone (E7.6).
77
+ const z = mapId != null ? floorZForMap(mapId, x, y, hint) : null;
78
+ if (z == null || pathZ == null) return z;
79
+ return Math.abs(z - pathZ) > Z_HINT_TOL ? pathZ : z;
80
+ }
81
+
82
+ /** Snap start onto the mesh; nothing near → keep raw (never invent a far floor). */
83
+ function snapStartToNav(mapId: number, start: WorldPos): WorldPos {
84
+ // Any registered surface calling this floor keeps the authored entrance; `null` is nothing
85
+ // registered at all (navRegistry.ts isWalkablePointForMap), which is also "not ours to judge".
86
+ if (isWalkablePointForMap(mapId, start.x, start.y) !== false) return start;
87
+ const mesh = navMeshForMap(mapId);
88
+ const s = mesh ? snapOntoNavMesh(mesh, start.x, start.y, start.z, ENTRANCE_SNAP_YD) : null;
89
+ if (!s) return start;
90
+ const hz = (start.z != null ? connectedFloorZForMap(mapId, s.x, s.y, start.z) : null)
91
+ ?? floorZForMap(mapId, s.x, s.y, start.z);
92
+ return { x: s.x, y: s.y, z: hz ?? start.z };
93
+ }
94
+
95
+ export type ContinuousEntityState = 'alive' | 'engaged' | 'dead' | 'skipped';
96
+
97
+ export type ContinuousEntity = {
98
+ guid: number;
99
+ entry: number;
100
+ // The party SEAT this body is, absent on every DB spawn. The party was not in the world at all: a
101
+ // mob was a body in the near grid while we were one coordinate plus a session.
102
+ party?: string;
103
+ x: number;
104
+ y: number;
105
+ z?: number;
106
+ /** Facing from SET_FACING / MOVE_TO. Cite: ScriptMgr.cpp:2757–2776 / :1829–1874. */
107
+ o?: number;
108
+ // WHERE THIS BODY STOOD WHEN THE PULL OPENED, stamped once on engage. The live coordinates used to
109
+ // mean both "where it is" and "where it was", which blocked the fight write-back entirely.
110
+ homeX?: number;
111
+ homeY?: number;
112
+ homeZ?: number;
113
+ state: ContinuousEntityState;
114
+ /** creature_template Detection when known; else default. */
115
+ detectionRange: number;
116
+ /** Midpoint of creature min/max level when known; else default for GetAttackDistance. */
117
+ level: number;
118
+ /** MovementType from bake (2 = waypoint patrol). */
119
+ movementType: number;
120
+ npcFlags: number;
121
+ /** Live SetDefaultGossipMenuId override; unset = template gossipMenuId. */
122
+ gossipMenuId?: number;
123
+ // Faction reaction below unfriendly toward the player. A critter or a friendly service NPC is false
124
+ // and never aggros or pulls, but still lives on the floor for paint.
125
+ hostile: boolean;
126
+ /** True when walking (not running). Cite: ScriptMgr.cpp:2439–2456 SET_RUN. */
127
+ walking?: boolean;
128
+ /** Waypoint pause. Cite: ScriptMgr.cpp:2684–2692 PAUSE_WAYPOINTS. */
129
+ waypointsPaused?: boolean;
130
+ // How far this body's patrol clock is BEHIND the run's elapsed time, because it was paused. The C++
131
+ // holds the body where it stands and resumes from THERE, and the pose is a function of elapsed time.
132
+ waypointPauseMs?: number;
133
+ waypointPausedAtMs?: number;
134
+ /** DESPAWN_SELF delay>0 pending ms — no ticker. Cite: ScriptMgr.cpp:2237–2250. */
135
+ despawnDelay?: number;
136
+ /** UNIT_FIELD_MOUNTDISPLAYID. Cite: Unit.cpp:7748 Mount; ScriptMgr.cpp:2409–2437. */
137
+ mounted?: boolean;
138
+ mountDisplayId?: number;
139
+ mountCreatureId?: number;
140
+ };
141
+
142
+ export type ContinuousWorld = {
143
+ instanceId: string;
144
+ mapId: number;
145
+ party: WorldPos;
146
+ entities: ContinuousEntity[];
147
+ // The party rows inside the entity list, by reference — an INDEX, not a second store. Re-filtering a
148
+ // 1,120-row wing every controller tick to find at most 41 bodies is the cost this avoids.
149
+ partyBodies?: ContinuousEntity[];
150
+ /** Cumulative yards walked via pathfind steps (never hop). */
151
+ walkedYd: number;
152
+ /** True only if a hop/teleport API was invoked — continuous path keeps this false. */
153
+ hopUsed: boolean;
154
+ /** Guids that received clear credit (kill). Skip does not add here. */
155
+ clearedGuids: number[];
156
+ /** Active move path (world waypoints); mutated by tickWalk. */
157
+ movePath: NavPos[];
158
+ /** Last ordered destination — kept even when A* found no corridor, so tickWalk can slide. */
159
+ moveDest?: { x: number; y: number };
160
+ /** Currently engaged guids (combat in place). */
161
+ engagedGuids: number[];
162
+ /** 8 yd instance grid (recoil-scale C3). Built lazily; query via floorBodiesNear. */
163
+ near?: NearGrid<ContinuousEntity>;
164
+ /** `entities.length` last time the tail was indexed. */
165
+ nearIndexed?: number;
166
+ /** Max template Detection seen while indexing — sizes the aggro query. */
167
+ maxDetectionYd?: number;
168
+ };
169
+
170
+ export type CreateContinuousOpts = {
171
+ instanceId: string;
172
+ mapId: number;
173
+ /** Override entrance (default: areatrigger entrance for instance). */
174
+ start?: WorldPos | null;
175
+ /** Include service NPCs (npcFlags ≠ 0). Default false — combat trash only. */
176
+ includeNpcs?: boolean;
177
+ // The faction reaction gate, threaded in from the caller that holds the data store so this pure layer
178
+ // does not import it. Absent, a service NPC is non-hostile and trash stays hostile.
179
+ isHostile?: (entry: number) => boolean;
180
+ /** Filter spawns (e.g. on-walk only). Default: all map spawns. */
181
+ spawns?: readonly DungeonSpawn[];
182
+ /** Guids already killed this run — restored dead so a re-mount does not resurrect them. */
183
+ clearedGuids?: readonly number[];
184
+ // The once-per-run pool roll: a losing pool member stays off the floor while a winning substitute
185
+ // spawns. Absent means no pool filter. Cite: MapPersistentStateMgr.cpp InitPools ~198-207.
186
+ poolRoll?: DungeonPoolRoll;
187
+ /** See LiveEntitiesFromSpawnsOpts.skipEntry. */
188
+ skipEntry?: (entry: number) => boolean;
189
+ // The party seats that get a floor body. Absent is the player alone, which is the stand every reader
190
+ // already measures to; the live controller passes its real squad.
191
+ partySides?: readonly string[];
192
+ };
193
+
194
+ export type LiveEntitiesFromSpawnsOpts = {
195
+ includeNpcs?: boolean;
196
+ /** See CreateContinuousOpts.isHostile. */
197
+ isHostile?: (entry: number) => boolean;
198
+ // Entries with no floor body at all — the script triggers, whose template the caller reads. One is
199
+ // invisible in Classic; here it stood in a boss chamber with a health bar.
200
+ skipEntry?: (entry: number) => boolean;
201
+ };
202
+
203
+ /** Default hostility when no faction lookup is threaded in. */
204
+ function defaultHostile(npcFlags: number): boolean {
205
+ // Service / questgiver / vendor rows are talk targets — nearestTalkableNpc skips hostile.
206
+ return (npcFlags | 0) === 0;
207
+ }
208
+
209
+ /** Hostile / trash spawns as floor entities at DB coordinates. */
210
+ export function liveEntitiesFromSpawns(
211
+ spawns: readonly DungeonSpawn[],
212
+ opts?: LiveEntitiesFromSpawnsOpts,
213
+ ): ContinuousEntity[] {
214
+ const out: ContinuousEntity[] = [];
215
+ for (const s of spawns) {
216
+ if (!opts?.includeNpcs && isDungeonNpcSpawn(s)) continue;
217
+ if (opts?.skipEntry?.(s.entry)) continue;
218
+ const npcFlags = s.npcFlags ?? 0;
219
+ out.push({
220
+ guid: s.guid,
221
+ entry: s.entry,
222
+ x: s.x,
223
+ y: s.y,
224
+ z: s.z,
225
+ state: 'alive',
226
+ detectionRange: DEFAULT_DETECTION_RANGE,
227
+ level: 18,
228
+ movementType: s.MovementType | 0,
229
+ npcFlags,
230
+ // Cite: domain/creature/faction.ts isHostileCreature (caller-supplied); npcFlags fallback.
231
+ hostile: opts?.isHostile ? opts.isHostile(s.entry) : defaultHostile(npcFlags),
232
+ });
233
+ }
234
+ return out;
235
+ }
236
+
237
+ /** Open a continuous instance world: party at entrance, every combat spawn on the floor. */
238
+ export function createContinuousWorld(opts: CreateContinuousOpts): ContinuousWorld {
239
+ const rawStart =
240
+ opts.start
241
+ ?? entranceWorld(opts.instanceId)
242
+ ?? { x: 0, y: 0 };
243
+ const start = snapStartToNav(opts.mapId, rawStart);
244
+ // Shared mapIds (SM/BRS/DM/Strat) filter to this wing's rooms; opts.spawns still wins.
245
+ const base = opts.spawns ?? spawnsForInstanceWing(opts.instanceId, opts.mapId);
246
+ // Pool losers never spawn; winners (rare or equal-chance substitute) do.
247
+ const raw = opts.poolRoll ? filterSpawnsByPoolRoll(base, opts.poolRoll) : base;
248
+ const entities = liveEntitiesFromSpawns(raw, {
249
+ includeNpcs: opts.includeNpcs,
250
+ isHostile: opts.isHostile,
251
+ skipEntry: opts.skipEntry,
252
+ });
253
+ // Restore prior kills. The floor is rebuilt from the spawn bake on every mount, so without
254
+ // this a Continue after a wipe handed back a full dungeon.
255
+ const cleared = opts.clearedGuids?.length ? new Set(opts.clearedGuids) : null;
256
+ if (cleared) {
257
+ for (const e of entities) if (cleared.has(e.guid)) e.state = 'dead';
258
+ }
259
+ // THE PARTY IS IN THE WORLD: one row per seat, appended before any grid exists so the grid indexes
260
+ // them with the tail. Placing them here would force the whole wing to index at open for nothing.
261
+ const partyBodies = partyFloorBodies(opts.partySides ?? DEFAULT_PARTY_SIDES, start);
262
+ for (const p of partyBodies) entities.push(p);
263
+ // The party point IS the player's row, the same object. Aliasing is the collapse the phase asked for,
264
+ // with no accessor and no sweep. A roster with no player seat keeps the plain point.
265
+ const playerBody = partyBodies.find((e) => e.party === 'player');
266
+ return {
267
+ instanceId: opts.instanceId,
268
+ mapId: opts.mapId,
269
+ party: playerBody ?? { x: start.x, y: start.y, z: start.z },
270
+ entities,
271
+ partyBodies,
272
+ walkedYd: 0,
273
+ hopUsed: false,
274
+ clearedGuids: cleared ? [...cleared] : [],
275
+ movePath: [],
276
+ engagedGuids: [],
277
+ };
278
+ }
279
+
280
+ // A stable floor guid for an encounter the world DB never spawns. Negative so it cannot collide with a
281
+ // real guid, and derived from the id so the cleared set still matches after a re-mount.
282
+ export function summonedBodyGuid(encounterId: string): number {
283
+ let h = 2166136261;
284
+ for (let i = 0; i < encounterId.length; i++) {
285
+ h ^= encounterId.charCodeAt(i);
286
+ h = Math.imul(h, 16777619);
287
+ }
288
+ return -(1 + ((h >>> 0) % 0x7fffffff));
289
+ }
290
+
291
+ /** Body key for a death-script summon whose summoner was not a route encounter. */
292
+ export function deathSummonKey(fromGuid: number, creatureEntry: number): string {
293
+ return `death-summon#${fromGuid | 0}#${creatureEntry | 0}`;
294
+ }
295
+
296
+ /** The seat that owns the party point when no roster is threaded in. */
297
+ const DEFAULT_PARTY_SIDES: readonly string[] = ['player'];
298
+
299
+ /** Stable floor guid for a party seat. Negative, like every other body the DB never spawns. */
300
+ export function partyBodyGuid(side: string): number {
301
+ return summonedBodyGuid(`party#${side}`);
302
+ }
303
+
304
+ // ONE FLOOR BODY PER PARTY SEAT. A party row has no entry, is not hostile and has no flags, which is
305
+ // what makes this additive: every floor reader is already keyed on one of those.
306
+ function partyFloorBodies(
307
+ sides: readonly string[],
308
+ at: { x: number; y: number; z?: number },
309
+ ): ContinuousEntity[] {
310
+ const out: ContinuousEntity[] = [];
311
+ for (const side of sides) {
312
+ out.push({
313
+ guid: partyBodyGuid(side),
314
+ entry: 0,
315
+ party: side,
316
+ x: at.x,
317
+ y: at.y,
318
+ ...(at.z != null ? { z: at.z } : {}),
319
+ state: 'alive',
320
+ detectionRange: 0,
321
+ level: 0,
322
+ movementType: 0,
323
+ npcFlags: 0,
324
+ hostile: false,
325
+ });
326
+ }
327
+ return out;
328
+ }
329
+
330
+ // Move every party body to one point — a teleport, a regroup or a walk step — through the placer, which
331
+ // REINDEXES. This also moves the party point, because the player's row IS that point.
332
+ export function placePartyBodies(
333
+ world: ContinuousWorld,
334
+ x: number,
335
+ y: number,
336
+ z?: number,
337
+ ): boolean {
338
+ const bodies = world.partyBodies;
339
+ if (!bodies || bodies.length === 0) return false;
340
+ for (const e of bodies) placeFloorBody(world, e, x, y, z);
341
+ return true;
342
+ }
343
+
344
+ // The party point and the bodies standing on it, moved in one statement. The plain assignment is the
345
+ // NO-ROWS case only: with rows the point IS the player's row, and a fresh object breaks the aliasing.
346
+ function stepPartyTo(world: ContinuousWorld, x: number, y: number, z: number | undefined): void {
347
+ if (placePartyBodies(world, x, y, z)) return;
348
+ world.party = { x, y, z };
349
+ }
350
+
351
+ // Inject the quest-end script's temp-spawn bodies onto the free-walk floor, at the absolute map yards
352
+ // the baked rows carry. Idempotent per quest, creature and index, and friendly ambient by default.
353
+ export function injectQuestEndTempSpawns(
354
+ world: ContinuousWorld,
355
+ questEntry: number,
356
+ spawns: ReadonlyArray<{
357
+ creatureEntry: number;
358
+ x: number;
359
+ y: number;
360
+ z?: number;
361
+ o?: number;
362
+ }>,
363
+ opts?: {
364
+ /** When true (default), bodies are non-hostile ambient. */
365
+ friendly?: boolean;
366
+ level?: number;
367
+ detectionRange?: number;
368
+ npcFlags?: number;
369
+ },
370
+ ): ContinuousEntity[] {
371
+ const friendly = opts?.friendly !== false;
372
+ const created: ContinuousEntity[] = [];
373
+ for (let i = 0; i < spawns.length; i++) {
374
+ const sp = spawns[i]!;
375
+ const entry = sp.creatureEntry | 0;
376
+ if (!(entry > 0)) continue;
377
+ const guid = summonedBodyGuid(`quest-end-${questEntry | 0}#${entry}#${i}`);
378
+ // Idempotent per script row index — batch mates may sit <10 yd apart (7461 spirits).
379
+ if (world.entities.some((e) => e.guid === guid)) continue;
380
+ const ent: ContinuousEntity = {
381
+ guid,
382
+ entry,
383
+ x: sp.x,
384
+ y: sp.y,
385
+ z: sp.z,
386
+ state: 'alive',
387
+ detectionRange: opts?.detectionRange ?? 0,
388
+ level: opts?.level ?? 56,
389
+ movementType: 0,
390
+ npcFlags: opts?.npcFlags ?? 0,
391
+ hostile: !friendly,
392
+ };
393
+ world.entities.push(ent);
394
+ created.push(ent);
395
+ }
396
+ return created;
397
+ }
398
+
399
+ /** The summoned body for this encounter if it is on the floor — `[]` when it is not. */
400
+ export function summonedBodyGuids(
401
+ world: ContinuousWorld,
402
+ encounter: { id: string; spawnGuids?: readonly number[] },
403
+ ): number[] {
404
+ if (encounter.spawnGuids?.length) return [];
405
+ const guid = summonedBodyGuid(encounter.id);
406
+ return world.entities.some((e) => e.guid === guid) ? [guid] : [];
407
+ }
408
+
409
+ // Put a body on the floor for every boss the spawn bake cannot: 32 of 212 boss encounters have no
410
+ // creature row, so free-walk left them unfightable AND unclearable. The gate is every required flag.
411
+ export function spawnUnlockedBodies(
412
+ world: ContinuousWorld,
413
+ encounters: readonly EncounterDef[],
414
+ run: InstanceRun,
415
+ isQuestOpen?: (questId: number) => boolean,
416
+ ): ContinuousEntity[] {
417
+ const cleared = new Set(world.clearedGuids);
418
+ const added: ContinuousEntity[] = [];
419
+ for (const enc of encounters) {
420
+ if (enc.kind !== 'boss' || enc.spawnGuids?.length) continue;
421
+ const entry = enc.creatureEntry ?? 0;
422
+ // Path-dependent summons (Strat Malown) stamp run.encounterOrigins at gate complete.
423
+ const o = run.encounterOrigins?.[enc.id] ?? enc.origin;
424
+ if (!(entry > 0) || !o || !Number.isFinite(o.x) || !Number.isFinite(o.y)) continue;
425
+ // Same quest gate the auto-route obeys (questBlockReason): a startQuestId body
426
+ // (Gor'shak jail 9398) must not appear at mount before the quest is in the log.
427
+ if (enc.startQuestId && isQuestOpen && !isQuestOpen(enc.startQuestId)) continue;
428
+ const need = requiredFlags(enc);
429
+ const waves = floorGauntletWaves(enc);
430
+ const selfWave = !!waves && waves.length === 1
431
+ && waves[0]!.every((m) => m.entry === enc.creatureEntry);
432
+ // Gauntlet owns multi-wave (adds first) and flag-gated self-wave (Kirtonos 5s after brazier).
433
+ // A body here made tickGauntlet abort on need.length + existing summonedBodyGuid.
434
+ if (waves && (!selfWave || need.length)) continue;
435
+ if (need.some((f) => !hasFlag(run, f))) continue;
436
+ // One body per entry. Emberseer 9816 already stands as guid 2290394 from the spawn
437
+ // bake; synthesizing summonedBodyGuid beside him is a second Pyroguard.
438
+ if (world.entities.some((e) => e.entry === entry)) continue;
439
+ const guid = summonedBodyGuid(enc.id);
440
+ if (world.entities.some((e) => e.guid === guid)) continue;
441
+ const ent: ContinuousEntity = {
442
+ guid,
443
+ entry,
444
+ x: o.x,
445
+ y: o.y,
446
+ ...(o.z != null && Number.isFinite(o.z) ? { z: o.z } : {}),
447
+ state: cleared.has(guid) ? 'dead' : 'alive',
448
+ detectionRange: DEFAULT_DETECTION_RANGE,
449
+ level: 18,
450
+ movementType: 0,
451
+ npcFlags: 0,
452
+ // Emberseer stands UNINTERACTIBLE from Reset (boss_pyroguard_emberseer.cpp:79-80)
453
+ // until 20 Growing stacks. Other synthesized bosses are live on spawn.
454
+ hostile: !selfWave,
455
+ };
456
+ world.entities.push(ent);
457
+ if (ent.state === 'alive') added.push(ent);
458
+ }
459
+ // ScriptDev GO-use queue (postmen / Malown) with authored coords → floor bodies.
460
+ // Idempotent by guid; leaves the queue on the run (resume-safe without clearing).
461
+ added.push(...injectScriptPendingSummons(world, run));
462
+ return added;
463
+ }
464
+
465
+ // Materialise the run's pending script summons that carry coordinates onto the floor. A row without
466
+ // them is skipped, since the combat inject is a separate surface. Cite: stratholmeScripts.cpp:110.
467
+ export function injectScriptPendingSummons(
468
+ world: ContinuousWorld,
469
+ run: InstanceRun,
470
+ ): ContinuousEntity[] {
471
+ const pending = run.scriptPendingSummons;
472
+ if (!pending?.length) return [];
473
+ const cleared = new Set(world.clearedGuids);
474
+ const added: ContinuousEntity[] = [];
475
+ for (let rowIdx = 0; rowIdx < pending.length; rowIdx++) {
476
+ const row = pending[rowIdx]!;
477
+ const entry = row.creatureEntry | 0;
478
+ const count = row.count | 0;
479
+ if (!(entry > 0) || !(count > 0)) continue;
480
+ if (row.x == null || row.y == null || !Number.isFinite(row.x) || !Number.isFinite(row.y)) {
481
+ continue;
482
+ }
483
+ for (let i = 0; i < count; i++) {
484
+ const guid =
485
+ row.encounterId && i === 0
486
+ ? summonedBodyGuid(row.encounterId)
487
+ : summonedBodyGuid(`script-pending#${rowIdx}.${entry}.${i}`);
488
+ if (world.entities.some((e) => e.guid === guid)) continue;
489
+ // Postmen: GetRandomPoint radius 3.0f about the box. Cite: stratholmeScripts.cpp:118-122.
490
+ const ang = (i * 2.399963) % (2 * Math.PI);
491
+ const r = row.encounterId && i === 0 ? 0 : count > 1 ? 3 : 0;
492
+ const ent: ContinuousEntity = {
493
+ guid,
494
+ entry,
495
+ x: row.x + r * Math.cos(ang),
496
+ y: row.y + r * Math.sin(ang),
497
+ ...(row.z != null && Number.isFinite(row.z) ? { z: row.z } : {}),
498
+ state: cleared.has(guid) ? 'dead' : 'alive',
499
+ detectionRange: DEFAULT_DETECTION_RANGE,
500
+ level: 18,
501
+ movementType: 0,
502
+ npcFlags: 0,
503
+ hostile: true,
504
+ };
505
+ world.entities.push(ent);
506
+ if (ent.state === 'alive') added.push(ent);
507
+ }
508
+ }
509
+ return added;
510
+ }
511
+
512
+ // Put one gauntlet wave on the floor. A standing friendly body of a wave entry is CLAIMED, as the C++
513
+ // flips its faction; a missing member is synthesized at the spawn point with a small deterministic jitter.
514
+ export function spawnGauntletWave(
515
+ world: ContinuousWorld,
516
+ enc: EncounterDef,
517
+ wave: readonly { entry: number; count: number }[],
518
+ phase: number,
519
+ isFinal: boolean,
520
+ spawnAt?: { x: number; y: number; z?: number },
521
+ claimMaxYd?: number,
522
+ ): { claimed: ContinuousEntity[]; created: ContinuousEntity[] } {
523
+ const cleared = new Set(world.clearedGuids);
524
+ const o = spawnAt ?? enc.origin;
525
+ const claimed: ContinuousEntity[] = [];
526
+ const created: ContinuousEntity[] = [];
527
+ let memberIdx = 0;
528
+ for (const m of wave) {
529
+ if (!(m.entry > 0)) continue;
530
+ for (let i = 0; i < Math.max(1, m.count | 0); i++, memberIdx++) {
531
+ // Claim the NEAREST standing non-hostile body of this entry, capped to the same room: a
532
+ // whole-map nearest plus an aggro sweep is a far pull. Default 48; Rajaxx passes 200.
533
+ const CLAIM_MAX_YD = claimMaxYd ?? 48;
534
+ const candidates = world.entities
535
+ .filter((e) => {
536
+ if (e.entry !== m.entry || e.state !== 'alive') return false;
537
+ // Standing event actors (Emberseer grow) may already be hostile from the floor
538
+ // applier on the same tick — still claim, or the wave synthesizes a second body.
539
+ if (e.hostile && m.entry !== enc.creatureEntry) return false;
540
+ if (!o) return true;
541
+ return Math.hypot(e.x - o.x, e.y - o.y) <= CLAIM_MAX_YD;
542
+ })
543
+ .sort((a, b) =>
544
+ (o ? Math.hypot(a.x - o.x, a.y - o.y) - Math.hypot(b.x - o.x, b.y - o.y) : 0));
545
+ const claimable = candidates.find((e) => !claimed.includes(e));
546
+ if (claimable) {
547
+ claimed.push(claimable);
548
+ continue;
549
+ }
550
+ if (!o || !Number.isFinite(o.x) || !Number.isFinite(o.y)) continue;
551
+ const guid = isFinal && m.entry === enc.creatureEntry && i === 0
552
+ ? summonedBodyGuid(enc.id)
553
+ : summonedBodyGuid(`${enc.id}#w${phase}.${memberIdx}`);
554
+ if (world.entities.some((e) => e.guid === guid)) continue;
555
+ const ang = (memberIdx * 2.399963) % (2 * Math.PI); // golden-angle fan, deterministic
556
+ const r = memberIdx === 0 ? 0 : 2;
557
+ const ent: ContinuousEntity = {
558
+ guid,
559
+ entry: m.entry,
560
+ x: o.x + r * Math.cos(ang),
561
+ y: o.y + r * Math.sin(ang),
562
+ ...(o.z != null && Number.isFinite(o.z) ? { z: o.z } : {}),
563
+ state: cleared.has(guid) ? 'dead' : 'alive',
564
+ detectionRange: DEFAULT_DETECTION_RANGE,
565
+ level: 18,
566
+ movementType: 0,
567
+ npcFlags: 0,
568
+ hostile: true,
569
+ };
570
+ world.entities.push(ent);
571
+ if (ent.state === 'alive') created.push(ent);
572
+ }
573
+ }
574
+ return { claimed, created };
575
+ }
576
+
577
+ // Yards between the party and a point, 3-D when both ends have a z. The server's own default is 3-D,
578
+ // and planar makes every range an infinite cylinder — 60.6% of Blackrock Spire pairs are cross-storey.
579
+ export function partyDistTo(
580
+ world: ContinuousWorld,
581
+ x: number,
582
+ y: number,
583
+ z?: number,
584
+ ): number {
585
+ const planar = Math.hypot(world.party.x - x, world.party.y - y);
586
+ const pz = world.party.z;
587
+ if (z == null || pz == null || !Number.isFinite(z) || !Number.isFinite(pz)) return planar;
588
+ const dz = Math.abs(pz - z);
589
+ if (dz <= STOREY_DZ_YD) return planar;
590
+ return Math.hypot(planar, dz - STOREY_DZ_YD);
591
+ }
592
+
593
+ // A deprecated alias of the one owner in domain/nav/storey.ts, kept exported because two dev
594
+ // instruments import this name. There is one such constant in the tree; this is not a second value.
595
+ export const STOREY_DZ_TOLERANCE_YD = STOREY_DZ_YD;
596
+
597
+
598
+ export type StreamOrigin = { x: number; y: number; z?: number };
599
+
600
+ // Extra stream origins past the party stand, and how far apart two must be to both count. Each origin
601
+ // costs a grid query per floor tick, so a formation collapses to the stand and only a scout adds one.
602
+ export const STREAM_ORIGIN_MAX = 4;
603
+ export const STREAM_ORIGIN_DEDUP_YD = 16;
604
+
605
+ // Where the floor is watched from: the party stand plus any member standing away from it. With the
606
+ // stand alone, a unit sent ahead to pull walks into an empty room — nothing streams and nothing draws.
607
+ export function streamOriginsFrom(
608
+ stand: StreamOrigin,
609
+ sensors: readonly StreamOrigin[],
610
+ opts?: { max?: number; dedupYd?: number },
611
+ ): StreamOrigin[] {
612
+ const max = opts?.max ?? STREAM_ORIGIN_MAX;
613
+ const dedup = opts?.dedupYd ?? STREAM_ORIGIN_DEDUP_YD;
614
+ const out: StreamOrigin[] = [
615
+ { x: stand.x, y: stand.y, ...(stand.z != null ? { z: stand.z } : {}) },
616
+ ];
617
+ for (const s of sensors) {
618
+ if (out.length > max) break;
619
+ if (out.some((o) => Math.hypot(s.x - o.x, s.y - o.y) <= dedup)) continue;
620
+ out.push({ x: s.x, y: s.y, ...(s.z != null ? { z: s.z } : {}) });
621
+ }
622
+ return out;
623
+ }
624
+
625
+ // The distance to the NEAREST origin. Same shape as the party distance: a z inside the storey tolerance
626
+ // is free and the overshoot past it costs. Both stream bands must use this one function or they thrash.
627
+ export function nearestOriginDist(
628
+ origins: readonly StreamOrigin[],
629
+ x: number,
630
+ y: number,
631
+ z?: number,
632
+ ): number {
633
+ let best = Infinity;
634
+ for (const o of origins) {
635
+ const planar = Math.hypot(o.x - x, o.y - y);
636
+ const dz = z == null || o.z == null || !Number.isFinite(z) || !Number.isFinite(o.z)
637
+ ? null
638
+ : Math.abs(o.z - z);
639
+ const d = dz == null || dz <= STOREY_DZ_YD
640
+ ? planar
641
+ : Math.hypot(planar, dz - STOREY_DZ_YD);
642
+ if (d < best) best = d;
643
+ }
644
+ return best;
645
+ }
646
+
647
+ /** Same floor as the party? Missing z stays true (HEIGHT_UNSTAMPED). */
648
+ export function sameStoreyAsParty(world: ContinuousWorld, z?: number): boolean {
649
+ const pz = world.party.z;
650
+ if (z == null || pz == null || !Number.isFinite(z) || !Number.isFinite(pz)) return true;
651
+ return Math.abs(pz - z) <= STOREY_DZ_YD;
652
+ }
653
+
654
+ // ON THE STOREY OF ANY PARTY MEMBER, not just the stand's. The sensor SET was widened to every member
655
+ // and the storey test was left on the player, so a companion down a ramp had its surroundings filtered.
656
+ export function sameStoreyAsAnyParty(world: ContinuousWorld, z?: number): boolean {
657
+ if (z == null || !Number.isFinite(z)) return true;
658
+ const bodies = world.partyBodies;
659
+ if (bodies && bodies.length > 0) {
660
+ let anyZ = false;
661
+ for (const e of bodies) {
662
+ const pz = e.z;
663
+ if (pz == null || !Number.isFinite(pz)) continue;
664
+ anyZ = true;
665
+ if (Math.abs(pz - z) <= STOREY_DZ_YD) return true;
666
+ }
667
+ if (anyZ) return false;
668
+ }
669
+ return sameStoreyAsParty(world, z);
670
+ }
671
+
672
+ /** Alive entities (still on floor, not dead/skipped). */
673
+ export function floorEntities(world: ContinuousWorld): ContinuousEntity[] {
674
+ return world.entities.filter((e) => e.state === 'alive' || e.state === 'engaged');
675
+ }
676
+
677
+ // Ambient detection admits the NEAREST authored pack, never two at once — the rule every other pull
678
+ // already follows. Packs already in the fight are never scoped out, and unclustered bodies never grouped.
679
+ export function scopeToNearestPack(
680
+ world: ContinuousWorld,
681
+ detected: readonly ContinuousEntity[],
682
+ packOf: ReadonlyMap<number, string>,
683
+ sensors?: readonly AggroSensor[],
684
+ ): ContinuousEntity[] {
685
+ if (detected.length < 2) return [...detected];
686
+ if (!packOf.size) return [...detected];
687
+ const engagedPacks = new Set<string>();
688
+ for (const guid of world.engagedGuids) {
689
+ const id = packOf.get(guid);
690
+ if (id) engagedPacks.add(id);
691
+ }
692
+ const distOf = sensors && sensors.length > 0
693
+ ? (e: ContinuousEntity) => nearestOriginDist(sensors, e.x, e.y, e.z)
694
+ : (e: ContinuousEntity) => partyDistTo(world, e.x, e.y, e.z);
695
+ let nearest: string | null = null;
696
+ let nearestD = Infinity;
697
+ for (const e of detected) {
698
+ const id = packOf.get(e.guid);
699
+ if (!id || engagedPacks.has(id)) continue;
700
+ const d = distOf(e);
701
+ if (d < nearestD) { nearestD = d; nearest = id; }
702
+ }
703
+ if (!nearest) return [...detected];
704
+ return detected.filter((e) => {
705
+ const id = packOf.get(e.guid);
706
+ return !id || id === nearest || engagedPacks.has(id);
707
+ });
708
+ }
709
+
710
+ // Aggro radius for a spawn vs player level — Unit::GetAttackDistance. Cite: creatureAggro.ts / Unit.cpp
711
+ // GetAttackDistance.
712
+ export function detectionYdFor(
713
+ entity: ContinuousEntity,
714
+ creatureLevel: number,
715
+ playerLevel: number,
716
+ ): number {
717
+ return getCreatureAttackDistance(creatureLevel, playerLevel, {
718
+ detectionRange: entity.detectionRange,
719
+ });
720
+ }
721
+
722
+ /** World point that can pull (player / ally / pet). Cite: MoveInLineOfSight any unit. */
723
+ export type AggroSensor = { x: number; y: number; z?: number };
724
+
725
+ /** Sight test between two world points. `z` picks the storey on stacked masks. */
726
+ export type AggroSight = (
727
+ from: { x: number; y: number; z?: number },
728
+ to: { x: number; y: number; z?: number },
729
+ ) => boolean;
730
+
731
+ function considerDetection(world: ContinuousWorld, e: ContinuousEntity): void {
732
+ const d = e.detectionRange ?? 0;
733
+ if (d > (world.maxDetectionYd ?? 0)) world.maxDetectionYd = d;
734
+ }
735
+
736
+ function indexOne(world: ContinuousWorld, e: ContinuousEntity): void {
737
+ if (e.state === 'dead' || e.state === 'skipped') return;
738
+ nearInsert(world.near!, e.guid, e.x, e.y, e);
739
+ considerDetection(world, e);
740
+ }
741
+
742
+ /** Rebuild the instance grid from living / engaged floor bodies. */
743
+ export function indexFloorGrid(world: ContinuousWorld): NearGrid<ContinuousEntity> {
744
+ const g = world.near ?? createNearGrid<ContinuousEntity>();
745
+ nearClear(g);
746
+ world.near = g;
747
+ world.maxDetectionYd = 0;
748
+ for (const e of world.entities) indexOne(world, e);
749
+ if (!(world.maxDetectionYd! > 0)) world.maxDetectionYd = DEFAULT_DETECTION_RANGE;
750
+ world.nearIndexed = world.entities.length;
751
+ return g;
752
+ }
753
+
754
+ /** Insert new tail + first-query build. Callers of getNear go through this. */
755
+ export function ensureFloorGrid(world: ContinuousWorld): NearGrid<ContinuousEntity> {
756
+ if (!world.near) return indexFloorGrid(world);
757
+ const from = world.nearIndexed ?? 0;
758
+ if (from < world.entities.length) {
759
+ for (let i = from; i < world.entities.length; i++) indexOne(world, world.entities[i]!);
760
+ world.nearIndexed = world.entities.length;
761
+ }
762
+ return world.near;
763
+ }
764
+
765
+ /** Detection query radius: max template Detection plus the GetAttackDistance level pad. */
766
+ export function floorAggroQueryYd(world: ContinuousWorld): number {
767
+ const det = world.maxDetectionYd ?? DEFAULT_DETECTION_RANGE;
768
+ return det - AGGRO_LEVEL_DIFF_CAP;
769
+ }
770
+
771
+ export function noteFloorDetection(world: ContinuousWorld, detectionYd: number): void {
772
+ if (detectionYd > (world.maxDetectionYd ?? 0)) world.maxDetectionYd = detectionYd;
773
+ }
774
+
775
+ export function floorBodiesNear(
776
+ world: ContinuousWorld,
777
+ x: number,
778
+ y: number,
779
+ r: number,
780
+ out?: ContinuousEntity[],
781
+ ): ContinuousEntity[] {
782
+ return getNear(ensureFloorGrid(world), x, y, r, out);
783
+ }
784
+
785
+ export function floorBodyByGuid(
786
+ world: ContinuousWorld,
787
+ guid: number,
788
+ ): ContinuousEntity | undefined {
789
+ const hit = nearGet(ensureFloorGrid(world), guid);
790
+ if (hit) return hit;
791
+ return world.entities.find((e) => e.guid === guid);
792
+ }
793
+
794
+ export function reindexFloorBody(world: ContinuousWorld, e: ContinuousEntity): void {
795
+ const g = ensureFloorGrid(world);
796
+ if (e.state === 'dead' || e.state === 'skipped') {
797
+ nearRemove(g, e.guid);
798
+ return;
799
+ }
800
+ nearMove(g, e.guid, e.x, e.y, e);
801
+ considerDetection(world, e);
802
+ }
803
+
804
+ export function dropFloorBody(world: ContinuousWorld, guid: number): void {
805
+ if (world.near) nearRemove(world.near, guid);
806
+ }
807
+
808
+ export function placeFloorBody(
809
+ world: ContinuousWorld,
810
+ e: ContinuousEntity,
811
+ x: number,
812
+ y: number,
813
+ z?: number,
814
+ ): void {
815
+ e.x = x;
816
+ e.y = y;
817
+ if (z != null) e.z = z;
818
+ reindexFloorBody(world, e);
819
+ }
820
+
821
+ // Alive hostiles whose detection covers ANY party sensor. Distance first, then sight for the shortlist,
822
+ // and the sight test runs against EVERY in-range sensor — nearest-only turned a real pull into none.
823
+ export function entitiesInAggroRange(
824
+ world: ContinuousWorld,
825
+ playerLevel: number,
826
+ creatureLevel = 18,
827
+ hasLos?: AggroSight,
828
+ sensors?: readonly AggroSensor[],
829
+ ): ContinuousEntity[] {
830
+ const pts = sensors && sensors.length > 0
831
+ ? sensors
832
+ : [{ x: world.party.x, y: world.party.y, z: world.party.z }];
833
+ const g = ensureFloorGrid(world);
834
+ const q = floorAggroQueryYd(world);
835
+ const seen = new Set<number>();
836
+ const out: ContinuousEntity[] = [];
837
+ const tmp: ContinuousEntity[] = [];
838
+ for (const p of pts) {
839
+ getNear(g, p.x, p.y, q, tmp);
840
+ for (const e of tmp) {
841
+ if (seen.has(e.guid)) continue;
842
+ if (e.state !== 'alive') continue;
843
+ // Hostile is the combat gate — gossip/npcFlags do not make a hostile body unfightable.
844
+ if (!e.hostile) continue;
845
+ const r = detectionYdFor(e, e.level > 0 ? e.level : creatureLevel, playerLevel);
846
+ const ez = e.z;
847
+ const ezOk = ez != null && Number.isFinite(ez);
848
+ const pz = p.z;
849
+ const d = ezOk && pz != null && Number.isFinite(pz)
850
+ ? Math.hypot(p.x - e.x, p.y - e.y, pz - ez)
851
+ : Math.hypot(p.x - e.x, p.y - e.y);
852
+ if (d > r) continue;
853
+ if (ezOk && pz != null && Number.isFinite(pz)
854
+ && Math.abs(pz - ez) > STOREY_DZ_YD) continue;
855
+ if (hasLos && !hasLos(p, e)) continue;
856
+ seen.add(e.guid);
857
+ out.push(e);
858
+ }
859
+ }
860
+ out.sort((a, b) => a.guid - b.guid);
861
+ return out;
862
+ }
863
+
864
+ // Set a pathfind move order, replacing any prior path, and return its length or null. The destination is
865
+ // recorded EVEN WHEN the search fails, so the walk can still slide toward it.
866
+ export function setMoveOrder(
867
+ world: ContinuousWorld,
868
+ dest: NavPos,
869
+ mapId?: number,
870
+ ): { path: NavPos[]; pathYd: number } | null {
871
+ world.moveDest = { x: dest.x, y: dest.y };
872
+ // The path search is mesh-first and needs only the map id. The id-less arm below it was a raster call
873
+ // with no mesh twin — a mesh is only reachable by map id — so it went with the one caller that had none.
874
+ if (mapId == null) { world.movePath = []; return null; }
875
+ const path = findPathForMap(mapId, world.party, dest);
876
+ if (!path || path.length < 1) { world.movePath = []; return null; }
877
+ // Overview paths have no z; bake answering-mask height so tickWalk cannot sticky-latch
878
+ // a wrong storey (ras: overview ends 83.8, sticky pins 143.8). HEIGHT_UNSTAMPED stays unset.
879
+ if (pathFloorHint(path) == null) {
880
+ for (const p of path) {
881
+ const hz = floorZForMap(mapId, p.x, p.y);
882
+ if (hz != null) p.z = hz;
883
+ }
884
+ }
885
+ world.movePath = path.slice();
886
+ return { path: world.movePath, pathYd: pathLength(path) };
887
+ }
888
+
889
+ // Advance party along movePath by at most stepYd (nav followPath). Counts walkedYd from actual displacement
890
+ // — never a hop teleport.
891
+ export function tickWalk(
892
+ world: ContinuousWorld,
893
+ stepYd: number,
894
+ ): { moved: number; arrived: boolean } {
895
+ if (!(stepYd > 0)) return { moved: 0, arrived: world.movePath.length === 0 };
896
+ const from = { x: world.party.x, y: world.party.y };
897
+ const walkMesh = navMeshForMap(world.mapId);
898
+ if (!walkMesh || world.movePath.length === 0) {
899
+ // This used to promise a Euclidean fallback in the comment and return "moved nothing, arrived",
900
+ // which is why a walk order the search could not solve froze the party and reported success.
901
+ const dest = world.moveDest;
902
+ if (!dest) return { moved: 0, arrived: true };
903
+ const dx = dest.x - from.x;
904
+ const dy = dest.y - from.y;
905
+ const d = Math.hypot(dx, dy);
906
+ if (d <= 0.4) { world.moveDest = undefined; return { moved: 0, arrived: true }; }
907
+ const travel = Math.min(stepYd, d);
908
+ const nx = from.x + (dx / d) * travel;
909
+ const ny = from.y + (dy / d) * travel;
910
+ // Prefer staying on mesh; refuse only the step that would leave it, so we slide along a
911
+ // wall instead of walking into the void. Off-mesh already (bad spawn) → move freely back.
912
+ if (isWalkablePointForMap(world.mapId, from.x, from.y) === true
913
+ && isWalkablePointForMap(world.mapId, nx, ny) === false) {
914
+ return { moved: 0, arrived: false };
915
+ }
916
+ const z = partyFloorZ(nx, ny, world.party.z, undefined, world.mapId);
917
+ stepPartyTo(world, nx, ny, z ?? world.party.z);
918
+ world.walkedYd += travel;
919
+ return { moved: travel, arrived: false };
920
+ }
921
+ // Swimming is slower than running, so crossing a cove costs real time rather than a glide. Null means
922
+ // nothing is registered for this map, which is dry as far as this walk knows.
923
+ const swim = isSwimPointForMap(world.mapId, from.x, from.y, world.party.z) === true;
924
+ const eff = swim ? stepYd / SWIM_STEP_COST : stepYd;
925
+ // Mesh first, raster below. The mesh follower gets the party z because its arrival test is the server
926
+ // climb; without a z it degrades to the plan-only arrival the raster twin already does.
927
+ const next = walkMesh
928
+ ? followPathNavMesh(walkMesh, { ...from, z: world.party.z }, world.movePath, eff)
929
+ : from;
930
+ const moved = Math.hypot(next.x - from.x, next.y - from.y);
931
+ // Route stamp > sticky prev (no re-pin); no stamp → sticky (deck over water).
932
+ const pathZ = pathFloorHint(world.movePath);
933
+ const z = partyFloorZ(next.x, next.y, world.party.z, pathZ, world.mapId);
934
+ stepPartyTo(world, next.x, next.y, z ?? world.party.z);
935
+ world.walkedYd += moved;
936
+ return { moved, arrived: world.movePath.length === 0 };
937
+ }
938
+
939
+ // Walk the full current path (or a fresh pathfind to dest) in steps. Prefer this over teleport for probes
940
+ // and continuous product.
941
+ export function walkTo(
942
+ world: ContinuousWorld,
943
+ dest: NavPos,
944
+ opts?: { stepYd?: number; maxSteps?: number },
945
+ ): {
946
+ ok: boolean;
947
+ walkedYd: number;
948
+ pathYd: number | null;
949
+ usedPathfind: boolean;
950
+ reason?: string;
951
+ } {
952
+ const stepYd = opts?.stepYd ?? 2;
953
+ const maxSteps = opts?.maxSteps ?? 50_000;
954
+ let pathYd: number | null = null;
955
+ let usedPathfind = false;
956
+
957
+ // `setMoveOrder` routes off the map id alone, mesh-first through `findPathForMap`.
958
+ const planned = setMoveOrder(world, dest, world.mapId > 0 ? world.mapId : undefined);
959
+ if (planned) {
960
+ pathYd = planned.pathYd;
961
+ usedPathfind = true;
962
+ const startWalk = world.walkedYd;
963
+ for (let i = 0; i < maxSteps; i++) {
964
+ const { arrived } = tickWalk(world, stepYd);
965
+ if (arrived) break;
966
+ }
967
+ return {
968
+ ok: world.movePath.length === 0,
969
+ walkedYd: world.walkedYd - startWalk,
970
+ pathYd,
971
+ usedPathfind,
972
+ reason: world.movePath.length ? 'maxSteps' : undefined,
973
+ };
974
+ }
975
+
976
+ // The Euclidean step fallback — never freeze — still accumulating walked yards rather than hopping.
977
+ // Prefer walkable cells, but keep stepping when the nav components disconnect.
978
+ const startWalk = world.walkedYd;
979
+ let guard = 0;
980
+ let blockedStreak = 0;
981
+ while (guard++ < maxSteps) {
982
+ const dx = dest.x - world.party.x;
983
+ const dy = dest.y - world.party.y;
984
+ const d = Math.hypot(dx, dy);
985
+ if (d <= 0.4) break;
986
+ const travel = Math.min(stepYd, d);
987
+ const nx = world.party.x + (dx / d) * travel;
988
+ const ny = world.party.y + (dy / d) * travel;
989
+ if (
990
+ blockedStreak < 3
991
+ && isWalkablePointForMap(world.mapId, world.party.x, world.party.y) === true
992
+ && isWalkablePointForMap(world.mapId, nx, ny) === false
993
+ ) {
994
+ blockedStreak += 1;
995
+ // Try a half-step; if still blocked thrice, cross the gap (disconnected storeys/ship).
996
+ if (blockedStreak < 3) continue;
997
+ }
998
+ blockedStreak = 0;
999
+ const z = partyFloorZ(nx, ny, world.party.z, undefined, world.mapId);
1000
+ stepPartyTo(world, nx, ny, z ?? world.party.z);
1001
+ world.walkedYd += travel;
1002
+ }
1003
+ const walked = world.walkedYd - startWalk;
1004
+ // Last-resort: if still multi-yard away after blocked corridor, close the remaining gap.
1005
+ const remain = Math.hypot(dest.x - world.party.x, dest.y - world.party.y);
1006
+ if (remain > 1 && walked < 0.5) {
1007
+ const z = partyFloorZ(dest.x, dest.y, world.party.z, undefined, world.mapId);
1008
+ stepPartyTo(world, dest.x, dest.y, z ?? world.party.z);
1009
+ world.walkedYd += remain;
1010
+ }
1011
+ const walkedFinal = world.walkedYd - startWalk;
1012
+ return {
1013
+ ok: Math.hypot(dest.x - world.party.x, dest.y - world.party.y) <= 1,
1014
+ walkedYd: walkedFinal,
1015
+ pathYd,
1016
+ usedPathfind,
1017
+ reason: usedPathfind ? undefined : (walkedFinal > walked ? 'euclidean-disconnected' : 'euclidean-fallback'),
1018
+ };
1019
+ }
1020
+
1021
+ // Attempt proximity pull. Fails unless party is within detection of every guid (or of the pack centroid
1022
+ // when pulling a set).
1023
+ export function tryEngage(
1024
+ world: ContinuousWorld,
1025
+ guids: readonly number[],
1026
+ opts?: { playerLevel?: number; creatureLevel?: number },
1027
+ ): { ok: true; guids: number[] } | { ok: false; reason: string } {
1028
+ if (world.hopUsed) {
1029
+ return { ok: false, reason: 'hop path is not continuous engage' };
1030
+ }
1031
+ if (!guids.length) return { ok: false, reason: 'no guids' };
1032
+ const playerLevel = opts?.playerLevel ?? 20;
1033
+ const creatureLevel = opts?.creatureLevel ?? 18;
1034
+ const resolved: ContinuousEntity[] = [];
1035
+ for (const g of guids) {
1036
+ const e = world.entities.find((x) => x.guid === g);
1037
+ if (!e) return { ok: false, reason: `unknown guid ${g}` };
1038
+ if (e.state === 'dead') return { ok: false, reason: `guid ${g} already dead` };
1039
+ if (e.state === 'skipped') return { ok: false, reason: `guid ${g} was skipped` };
1040
+ const r = detectionYdFor(e, e.level > 0 ? e.level : creatureLevel, playerLevel);
1041
+ const d = partyDistTo(world, e.x, e.y, e.z);
1042
+ if (!sameStoreyAsParty(world, e.z) || d > r) {
1043
+ return {
1044
+ ok: false,
1045
+ reason: `out of range guid ${g}: ${d.toFixed(1)} yd > detection ${r.toFixed(1)}`,
1046
+ };
1047
+ }
1048
+ resolved.push(e);
1049
+ }
1050
+ // Anyone leaving the list stops being engaged in the ROW too. Replacing the whole list left a body
1051
+ // marked engaged from an earlier pull with nothing pointing at it. Only that flag resets: a corpse stays.
1052
+ const keep = new Set(resolved.map((e) => e.guid));
1053
+ for (const g of world.engagedGuids) {
1054
+ if (keep.has(g)) continue;
1055
+ const prev = world.entities.find((x) => x.guid === g);
1056
+ if (prev && prev.state === 'engaged') prev.state = 'alive';
1057
+ }
1058
+ for (const e of resolved) e.state = 'engaged';
1059
+ world.engagedGuids = resolved.map((e) => e.guid);
1060
+ return { ok: true, guids: world.engagedGuids.slice() };
1061
+ }
1062
+
1063
+ // Walk past without pull — no clear credit, entities stay alive or mark skipped. Product skip: player never
1064
+ // engaged; route progress does not clear them.
1065
+ export function skipEntities(
1066
+ world: ContinuousWorld,
1067
+ guids: readonly number[],
1068
+ ): { skipped: number[] } {
1069
+ const skipped: number[] = [];
1070
+ for (const g of guids) {
1071
+ const e = world.entities.find((x) => x.guid === g);
1072
+ if (!e || e.state === 'dead' || e.state === 'engaged') continue;
1073
+ e.state = 'skipped';
1074
+ dropFloorBody(world, g);
1075
+ skipped.push(g);
1076
+ }
1077
+ return { skipped };
1078
+ }
1079
+
1080
+ // Drop bodies from the roster and REBUILD the grid. The entity list is otherwise append-only and the
1081
+ // grid indexes only the tail, so shortening it by hand corrupts the index for the rest of the run.
1082
+ export function removeFloorEntities(
1083
+ world: ContinuousWorld,
1084
+ keep: (e: ContinuousEntity) => boolean,
1085
+ ): number {
1086
+ const before = world.entities.length;
1087
+ const kept = world.entities.filter(keep);
1088
+ if (kept.length === before) return 0;
1089
+ world.entities = kept;
1090
+ // The party index is filtered by the CALLER'S OWN predicate, so it can never name a row the roster
1091
+ // dropped. That is what makes it an index rather than a store that can disagree.
1092
+ if (world.partyBodies?.length) world.partyBodies = world.partyBodies.filter(keep);
1093
+ indexFloorGrid(world);
1094
+ return before - kept.length;
1095
+ }
1096
+
1097
+ // A body that LEFT the floor without being killed — a script's forced despawn. State plus the grid drop,
1098
+ // and deliberately not a clear: the player cleared nothing and the script owns whether it returns.
1099
+ export function despawnFloorBody(world: ContinuousWorld, guid: number): void {
1100
+ const e = world.entities.find((x) => x.guid === guid);
1101
+ // A skipped body owns its own list and its own drop, so leave it alone. Already-dead is NOT a reason
1102
+ // to return: the caller sets the state first, so the drop is the only thing left to do.
1103
+ if (!e || e.state === 'skipped') return;
1104
+ e.state = 'dead';
1105
+ dropFloorBody(world, guid);
1106
+ }
1107
+
1108
+ /** After a win: mark dead, grant clear credit, leave party where it stands. */
1109
+ export function resolveKill(
1110
+ world: ContinuousWorld,
1111
+ guids: readonly number[],
1112
+ ): void {
1113
+ for (const g of guids) {
1114
+ const e = world.entities.find((x) => x.guid === g);
1115
+ if (e) e.state = 'dead';
1116
+ dropFloorBody(world, g);
1117
+ if (!world.clearedGuids.includes(g)) world.clearedGuids.push(g);
1118
+ }
1119
+ world.engagedGuids = world.engagedGuids.filter((g) => !guids.includes(g));
1120
+ }
1121
+
1122
+ // Scaffolding only — marks hopUsed so probes/gates can reject hop success paths. Continuous product code
1123
+ // must not call this.
1124
+ export function markHopUsed(world: ContinuousWorld): void {
1125
+ world.hopUsed = true;
1126
+ }
1127
+
1128
+ /** World-space unit positions for createSession (party + engaged guids in place). */
1129
+ export function combatPositionsInPlace(
1130
+ world: ContinuousWorld,
1131
+ guids: readonly number[],
1132
+ ): Record<string, { x: number; y: number; z?: number }> {
1133
+ const positions: Record<string, { x: number; y: number; z?: number }> = {
1134
+ player: { x: world.party.x, y: world.party.y, z: world.party.z },
1135
+ };
1136
+ guids.forEach((g, i) => {
1137
+ const e = world.entities.find((x) => x.guid === g);
1138
+ if (!e) return;
1139
+ const side = i === 0 ? 'enemy' : `enemy_${i}`;
1140
+ // z carried, not dropped: the floor knows every body's storey and combat used to throw
1141
+ // it away at exactly this line.
1142
+ positions[side] = { x: e.x, y: e.y, z: e.z };
1143
+ });
1144
+ return positions;
1145
+ }
1146
+
1147
+ /** Nearest alive hostile — pull / skip target. Gossip flags do not exclude combat. */
1148
+ export function nearestAlive(world: ContinuousWorld): ContinuousEntity | null {
1149
+ let best: ContinuousEntity | null = null;
1150
+ let bestD = Infinity;
1151
+ for (const e of world.entities) {
1152
+ if (e.state !== 'alive') continue;
1153
+ if (!e.hostile) continue;
1154
+ const d = partyDistTo(world, e.x, e.y, e.z);
1155
+ if (d < bestD) {
1156
+ best = e;
1157
+ bestD = d;
1158
+ }
1159
+ }
1160
+ return best;
1161
+ }
1162
+
1163
+ /** Service NPCs still on the continuous floor (npcFlags ≠ 0). */
1164
+ export function floorNpcs(world: ContinuousWorld): ContinuousEntity[] {
1165
+ return world.entities.filter((e) => e.npcFlags !== 0 && e.state !== 'dead');
1166
+ }
1167
+
1168
+ // The nearest non-hostile service NPC within range, never hostile trash. The range matches the
1169
+ // interaction distance at the call site. Cite: Unit.h UNIT_NPC_FLAG_*; ObjectDefines.h.
1170
+ export function nearestTalkableNpc(
1171
+ world: ContinuousWorld,
1172
+ maxYd: number,
1173
+ ): ContinuousEntity | null {
1174
+ let best: ContinuousEntity | null = null;
1175
+ let bestD = Infinity;
1176
+ for (const e of world.entities) {
1177
+ if (e.npcFlags === 0 || e.state === 'dead' || e.hostile) continue;
1178
+ const d = partyDistTo(world, e.x, e.y, e.z);
1179
+ if (d > maxYd || d >= bestD) continue;
1180
+ best = e;
1181
+ bestD = d;
1182
+ }
1183
+ return best;
1184
+ }
1185
+
1186
+ // Continuous pull resolution (shipped controller path — probes drive these)
1187
+
1188
+ export type ContinuousEncounterRef = {
1189
+ id: string;
1190
+ name?: string;
1191
+ spawnGuids?: readonly number[];
1192
+ };
1193
+
1194
+ // Map floor guids → route encounter by spawnGuids overlap. null when no encounter owns any of the guids
1195
+ // (never invent next-route pack).
1196
+ export function encounterForSpawnGuids(
1197
+ encounters: readonly ContinuousEncounterRef[],
1198
+ guids: readonly number[],
1199
+ ): ContinuousEncounterRef | null {
1200
+ if (!guids.length) return null;
1201
+ const set = new Set(guids);
1202
+ let best: ContinuousEncounterRef | null = null;
1203
+ let bestN = 0;
1204
+ for (const e of encounters) {
1205
+ const sg = e.spawnGuids;
1206
+ if (!sg?.length) continue;
1207
+ let n = 0;
1208
+ for (const g of sg) if (set.has(g)) n++;
1209
+ if (n > bestN) {
1210
+ bestN = n;
1211
+ best = e;
1212
+ }
1213
+ }
1214
+ return bestN > 0 ? best : null;
1215
+ }
1216
+
1217
+ // Resolve which encounter a continuous pull may begin: it requires the guid-to-encounter map with no
1218
+ // substitute, refuses an already-defeated encounter, and does not check the sequential unlock.
1219
+ export function resolveContinuousPullEncounter(
1220
+ encounters: readonly ContinuousEncounterRef[],
1221
+ defeated: readonly string[],
1222
+ guids: readonly number[],
1223
+ ): { ok: true; encounter: ContinuousEncounterRef } | { ok: false; reason: string } {
1224
+ if (!guids.length) return { ok: false, reason: 'no guids' };
1225
+ const enc = encounterForSpawnGuids(encounters, guids);
1226
+ if (!enc) {
1227
+ return { ok: false, reason: 'unmapped guids - refuse nextEncounter substitute' };
1228
+ }
1229
+ if (defeated.includes(enc.id)) {
1230
+ return { ok: false, reason: `already defeated ${enc.id}` };
1231
+ }
1232
+ return { ok: true, encounter: enc };
1233
+ }
1234
+
1235
+ // Whether beginEncounter should be allowed for continuous floor product. continuousFloor=true → only block
1236
+ // if already defeated (not sequential path lock).
1237
+ export function continuousBeginAllowed(
1238
+ defeated: readonly string[],
1239
+ encounterId: string,
1240
+ opts: { continuousFloor: boolean; sequentialUnlocked: boolean },
1241
+ ): { ok: true } | { ok: false; reason: string } {
1242
+ if (defeated.includes(encounterId)) {
1243
+ return { ok: false, reason: 'Already defeated' };
1244
+ }
1245
+ if (!opts.continuousFloor && !opts.sequentialUnlocked) {
1246
+ return { ok: false, reason: 'Clear the path to it first' };
1247
+ }
1248
+ return { ok: true };
1249
+ }
1250
+