azeroth-shell 0.0.0-stage → 0.1.0

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 +26 -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 +126 -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,842 @@
1
+ // AI squad companions: FREE composition, persistent characters you gear from your own bags, built
2
+ // through the SAME paths as the player. Pure — no DOM, clock or rng; names come from seeds.
3
+
4
+ import type { DataStore } from '../../data/dataStore.ts';
5
+ import { CLASS, SHAPESHIFT_FORM } from '../../data/schema.ts';
6
+ import type { SkillLine } from '../../data/schema.ts';
7
+ import type { ActiveAura, Character, EquippedMap, PetState, TempEnchantMap } from '../character/character.ts';
8
+ import { maxHealth, maxPower, powerType, buildCombatant, combatItems } from '../character/character.ts';
9
+ import type { DurabilityMap } from '../items/durability.ts';
10
+ import type { SpellBook } from '../character/spellbook.ts';
11
+ import { resolveSpellId } from '../character/spellbook.ts';
12
+ import type { CombatantSpec } from '../../engine/combat.ts';
13
+ import type { Rotation, RotationProfileId } from '../rotation/rotation.ts';
14
+ import type { RotationProfile } from '../rotation/rotationProfiles.ts';
15
+ import type { Inventory } from '../items/inventory.ts';
16
+ import type { QuestLog } from '../quests/questlog.ts';
17
+ import { countItem, emptyInventory } from '../items/inventory.ts';
18
+ import { equippedEntry } from '../items/itemInstance.ts';
19
+ import { bestAmmoForWeapon, checkAmmoCompatibility } from '../items/ammo.ts';
20
+ import type { BankBags } from '../items/bank.ts';
21
+ import { factionOf } from '../character/races.ts';
22
+ import { talentsForSpec, talentsFromLink } from '../character/talentLink.ts';
23
+ import { talentGrantedSpellIds } from '../character/talents.ts';
24
+ import { buildPet } from '../pet/pet.ts';
25
+ import { syntheticClassTrainerEntry } from '../economy/syntheticClassTrainers.ts';
26
+ import {
27
+ isSpellFitByClassAndRace,
28
+ raceClassMaskMatches,
29
+ grantMaxedCombatSkillsForRaceClass,
30
+ } from '../character/combatSkills.ts';
31
+ import { isRaidGearProfile, type GearProfile } from './botGear.ts';
32
+ import {
33
+ applyTrainedCaps,
34
+ companionProfessionSkills,
35
+ companionSkillCap,
36
+ companionTrainedRank,
37
+ professionSkillCap,
38
+ } from './botProfessions.ts';
39
+ import type { CompanionMission, CompanionProfessionMap } from './companionMissions.ts';
40
+ import { deterministicAppearance } from '../character/appearance.ts';
41
+ import { stampStandYards } from '../rotation/stand.ts';
42
+ import { firstOffensiveRotationRangeYd } from '../../autopilot/config.ts';
43
+ import { seedPrePullStealth } from './prePullStealth.ts';
44
+ import { seedReagentBagCounts } from '../../engine/combat/spellReagents.ts';
45
+
46
+ export type SquadRole = 'tank' | 'healer' | 'dps';
47
+
48
+ /** All signed dungeon roles — recruitCompanion / setSquadRole / setCompanionRole reject anything else. */
49
+ export const SQUAD_ROLES: readonly SquadRole[] = ['tank', 'healer', 'dps'] as const;
50
+
51
+ export function isSquadRole(v: unknown): v is SquadRole {
52
+ return v === 'tank' || v === 'healer' || v === 'dps';
53
+ }
54
+
55
+ // S4C companion AoE knob: 'auto' keeps the default multi gates, 'aoe' prefers aoe-flagged spells
56
+ // at two or more enemies, and 'single' suppresses them.
57
+ export type CompanionAoeMode = 'auto' | 'aoe' | 'single';
58
+
59
+ /** Numeric encoding of CompanionAoeMode for rotation metric `aoeMode` (S4C). */
60
+ export const AOE_MODE_CODE = { auto: 0, aoe: 1, single: 2 } as const;
61
+
62
+ /** Active party size in the world and any 5-man. The 4 that walk a dungeon with you. */
63
+ export const MAX_COMPANIONS = 4;
64
+
65
+ // Companions that walk THIS instance with you — the sourced size minus the player, from
66
+ // instance_template.maxPlayers alone: 40, 20, 10 or 5. Cite: docs/archive/raids/PLAN.md §1.
67
+ export function maxCompanionsFor(maxPlayers: number | undefined): number {
68
+ const n = (maxPlayers ?? MAX_COMPANIONS + 1) | 0;
69
+ return Math.max(1, n - 1);
70
+ }
71
+
72
+ // Roster size — every companion you own, active or benched. 80 is two full AV teams, the largest
73
+ // thing a BG can ask for. Hiring past MAX_COMPANIONS benches rather than failing.
74
+ export const MAX_ROSTER = 80;
75
+
76
+ // D3 strategy toggles, the rest axis of the three DR knobs: careful rests to 95% before every pull,
77
+ // aggressive chains at 60%, and sip barely recovers at ~40%. Never HP multipliers.
78
+ export type SquadStrategy = 'careful' | 'aggressive' | 'sip';
79
+
80
+ export const SQUAD_PACING: Record<SquadStrategy, { restTo: number; healerBudgetFactor: number }> = {
81
+ careful: { restTo: 0.95, healerBudgetFactor: 0.95 },
82
+ aggressive: { restTo: 0.6, healerBudgetFactor: 0.6 },
83
+ /** §8b.5 Sip ≈0.40 — "keep pulling, barely recover". */
84
+ sip: { restTo: 0.4, healerBudgetFactor: 0.4 },
85
+ };
86
+
87
+ export interface Companion {
88
+ id: string;
89
+ name: string;
90
+ race: number;
91
+ cls: number;
92
+ /** 0 = male, 1 = female (ai_playerbot_names convention). Optional: pre-D3.5 saves lack it. */
93
+ gender?: 0 | 1;
94
+ role: SquadRole;
95
+ /** Deterministic per-companion stream seed (mini-sims, flavor). */
96
+ seed: number;
97
+ /** Gear the bot wears — spawn gear from its playerbot template plus what you've given. */
98
+ equipped: EquippedMap;
99
+ // Per-slot durability on the companion's paperdoll, the same DurabilityMap as Character. Absent
100
+ // or empty means full; combat wear applies after each group fight and Repair all restores it.
101
+ durability?: DurabilityMap;
102
+ // TEMP_ENCHANTMENT_SLOT on the companion's hands — poison, oil, stone or imbue. Same shape as
103
+ // Character.tempEnchants, cleared on weapon swap like the player's.
104
+ tempEnchants?: TempEnchantMap;
105
+ // D4 world-pool fields; absent on a pre-pool save, where the companion level-syncs to the player
106
+ // until its first dungeon run. `level` is the bot's OWN level, grown by party XP, capped at 60.
107
+ level?: number;
108
+ /** XP into the current level (real player curve via progression/leveling). */
109
+ xp?: number;
110
+ // This companion's own faction standings (Faction.dbc id → absolute standing), sparse and the
111
+ // same shape as Character.reputations. Absent means base standing per race and class.
112
+ reputations?: Record<number, number>;
113
+ // Per-faction FactionState flags for this companion (VISIBLE / AT_WAR / …). Same shape as
114
+ // Character.factionFlags. Optional — pre-companion-rep saves omit it.
115
+ factionFlags?: Record<number, number>;
116
+ /** Premade playerbot spec index into ds.botSpecs(cls) — talents derive from it. */
117
+ specIdx?: number;
118
+ // Classic talent string from a named wiki loadout. When set, companionTalents spends this instead of
119
+ // specIdx. Cleared by a premade spec or role restamp.
120
+ talentLink?: string;
121
+ // The bot's own bags and bank — THEIR loot, not yours: nothing here reaches a vendor or sell
122
+ // path, which read the player's inventory only. Conjured items are the one take-back exception.
123
+ bags?: Inventory;
124
+ bank?: Inventory;
125
+ bankBags?: BankBags;
126
+ // Active pet (hunter beast / warlock demon) from playerbot InitPet. Absent on non-pet classes and pre-kit
127
+ // hires.
128
+ pet?: PetState;
129
+ // Character-wide pet ability ranks (warlock grimoires / hunter training repertoire). Fed into buildPet
130
+ // via a Character shell — same field as Character.petSpells.
131
+ petSpells?: number[];
132
+ // This companion's editable combat rotation, the same Rotation shape the player edits, driving
133
+ // it as a real `ally_N` combatant. Absent lazily seeds the role-adapted class default.
134
+ rotation?: Rotation;
135
+ // Second rotation for a tank or healer companion — exactly the player's `rotationDps`, same
136
+ // shape and builder. A pure-DPS companion has no second profile because its primary is one.
137
+ rotationDps?: Rotation;
138
+ /** Which of the two slots drives this companion. Absent → 'primary'. */
139
+ rotationProfile?: RotationProfileId;
140
+ /** Named rotation lists for this companion — same list the player owns, same rules. */
141
+ rotationProfiles?: RotationProfile[];
142
+ /** Which named profile drives this companion. Absent → the first. */
143
+ activeRotationProfileId?: string;
144
+ // Configured action bars for party takeover, the same ActionBar shape as the player's. Absent
145
+ // seeds lazily. Keybinds at fight time overlay the PLAYER's bar keys by slot index.
146
+ actionBars?: import('../character/actionbar.ts').ActionBar[];
147
+ // This companion's Outfitter sets (same shape as GameState.outfitter). Absent ⇒ seeded on first open from
148
+ // their current gear.
149
+ outfitter?: import('./outfitter.ts').OutfitterState;
150
+ // Pre-pull party buff auras this companion carries into each pull, so buffed stats flow through
151
+ // companionCharacter. Transient run state, set fresh each run and pruned by wall-clock expiry.
152
+ prePullAuras?: ActiveAura[];
153
+ // This companion's own cooldowns as world-clock readyAt, exactly the shape the player's take.
154
+ // Without it a companion re-fired every long CD on each mob. Absent or expired means ready.
155
+ spellCooldowns?: Record<number, number>;
156
+ categoryCooldowns?: Record<number, number>;
157
+ // S4C (COMBAT-INTERACTION-V2): AoE ↔ single-target preference. Optional — pre-S4C saves omit it → {@link
158
+ // resolveAoeMode} treats as `'auto'`.
159
+ aoeMode?: CompanionAoeMode;
160
+ // S4C: allow emergency off-heals for hybrid DPS/tank (has a heal, role ≠ healer). Optional — pre-S4C
161
+ // saves omit it → {@link resolveOffHeal} uses class-appropriate default.
162
+ offHeal?: boolean;
163
+ // ICH1 kit tier at hire: naked, shabby, field, twink or one of the raid tiers. Spawn gear is
164
+ // frozen into `equipped` at hire, so this stamp is for the badge, the hire cost and the XP lock.
165
+ gearProfile?: GearProfile;
166
+ // ICH4 XP lock. Missing or false levels normally; true makes every companion XP grant a no-op.
167
+ // Hire defaults it on for twink and the raid tiers, off otherwise.
168
+ xpLocked?: boolean;
169
+ // Player-assigned trade skills, skill line → current value. Absent falls back to the
170
+ // seed-derived set, which is what every pre-existing save and every fresh hire has.
171
+ professions?: CompanionProfessionMap;
172
+ // Trainer ranks this body holds, skill line → rank number (1 Apprentice … 4 Artisan). The cap is
173
+ // derived from skill + level either way; this stamp only decides which rank-ups get announced.
174
+ professionRanks?: Partial<Record<SkillLine, number>>;
175
+ // Recipe ids this companion knows (trainer/vendor auto-catalog + recipes learned from items). Absent ⇒
176
+ // empty until first syncCompanionProfessionCatalog. Optional on pre-craft saves.
177
+ knownRecipes?: number[];
178
+ // Enchant formula ids this companion knows (same catalog rules as knownRecipes). Optional on pre-craft
179
+ // saves.
180
+ knownEnchants?: number[];
181
+ // Spells a book or tome taught THIS companion. Everything else in the kit derives from race,
182
+ // class, level and spec, so these are the only spells that have to be stored.
183
+ taughtSpells?: number[];
184
+ // THIS companion's own quest log, same QuestLog shape as the player's. Status is per body, so a
185
+ // quest you already turned in is still offerable to a companion who has not. Absent ⇒ empty.
186
+ questLog?: QuestLog;
187
+ // Send-out zone mission in flight, resolved by wall clock exactly like Character.journey, so it
188
+ // closes correctly across a reload. Energy is shared on GameState.companionEnergy.
189
+ mission?: CompanionMission;
190
+ /** @deprecated Pre-revamp per-body energy, ignored — the party pool is GameState.companionEnergy. */
191
+ energy?: number;
192
+ /** @deprecated See energy. */
193
+ energyAt?: number;
194
+ }
195
+
196
+ /** Effective AoE mode (legacy / unset → auto). */
197
+ export function resolveAoeMode(comp: Pick<Companion, 'aoeMode'>): CompanionAoeMode {
198
+ return comp.aoeMode === 'aoe' || comp.aoeMode === 'single' ? comp.aoeMode : 'auto';
199
+ }
200
+
201
+ // ICH4: effective XP lock (missing → unlocked / false). Cite: docs/archive/INN-COMPANION-HIRE-DESIGN.md
202
+ // §4.2.
203
+ export function isXpLocked(comp: Pick<Companion, 'xpLocked'>): boolean {
204
+ return comp.xpLocked === true;
205
+ }
206
+
207
+ // ICH4 hire default for `xpLocked` by kit profile. twink + raid-* → true; naked / shabby / field / unknown
208
+ // → false. Cite: docs/archive/INN-COMPANION-HIRE-DESIGN.md §4.3.
209
+ export function defaultXpLocked(profile: GearProfile | undefined): boolean {
210
+ if (!profile) return false;
211
+ return profile === 'twink' || isRaidGearProfile(profile);
212
+ }
213
+
214
+ // Class-appropriate default for the off-heal knob: true for the Classic hybrid healers, who keep
215
+ // heals while playing DPS or tank, false for pure DPS. Used only when Companion.offHeal is absent.
216
+ export function defaultOffHealForClass(cls: number): boolean {
217
+ return (
218
+ cls === CLASS.PALADIN
219
+ || cls === CLASS.PRIEST
220
+ || cls === CLASS.SHAMAN
221
+ || cls === CLASS.DRUID
222
+ );
223
+ }
224
+
225
+ /** Effective off-heal toggle (legacy / unset → class default). */
226
+ export function resolveOffHeal(comp: Pick<Companion, 'offHeal' | 'cls'>): boolean {
227
+ return comp.offHeal ?? defaultOffHealForClass(comp.cls);
228
+ }
229
+
230
+ /** Rotation metric encoding of an AoE mode (0=auto, 1=aoe, 2=single). */
231
+ export function encodeAoeMode(mode: CompanionAoeMode): number {
232
+ return AOE_MODE_CODE[mode];
233
+ }
234
+
235
+ // The inverse, for a provider rebuilt off-thread: the knob arrives as the code on the snapshot rather
236
+ // than as a live companion the worker cannot hold. Cite: PERF-RUNSHEET S6b.
237
+ export function decodeAoeMode(code: number | undefined): CompanionAoeMode {
238
+ return code === 1 ? 'aoe' : code === 2 ? 'single' : 'auto';
239
+ }
240
+
241
+ /** A companion's effective level: its own, else legacy player-sync. */
242
+ export function companionLevel(comp: Companion, playerLevel: number): number {
243
+ return Math.max(1, Math.min(60, comp.level ?? playerLevel));
244
+ }
245
+
246
+ // Companion names come from the playerbot name pool, the same list random bots on a playerbot
247
+ // server draw from. Deterministic by seed; a duplicate in the roster steps to the next name.
248
+ export interface BotNamePool { male: readonly string[]; female: readonly string[] }
249
+
250
+ const FALLBACK_NAMES: BotNamePool = {
251
+ male: ['Bramwell', 'Dorn', 'Halric', 'Torvald', 'Aldwin', 'Garruk', 'Osmund', 'Cedric'],
252
+ female: ['Kessa', 'Yvette', 'Mira', 'Senna', 'Petra', 'Liette', 'Runa', 'Wren'],
253
+ };
254
+
255
+ export function companionGender(seed: number): 0 | 1 {
256
+ return (Math.abs(seed) >>> 3) % 2 === 0 ? 0 : 1;
257
+ }
258
+
259
+ export function companionName(pool: BotNamePool, seed: number, gender: 0 | 1, taken: readonly string[]): string {
260
+ let list = gender === 1 ? pool.female : pool.male;
261
+ if (list.length === 0) list = gender === 1 ? FALLBACK_NAMES.female : FALLBACK_NAMES.male;
262
+ const start = Math.abs(seed) % list.length;
263
+ for (let i = 0; i < list.length; i++) {
264
+ const name = list[(start + i) % list.length]!;
265
+ if (!taken.includes(name)) return name;
266
+ }
267
+ return `${list[start]!} II`;
268
+ }
269
+
270
+ export function addCompanion(squad: readonly Companion[], comp: Companion): Companion[] {
271
+ if (squad.length >= MAX_COMPANIONS) return [...squad];
272
+ if (squad.some((c) => c.id === comp.id)) return [...squad];
273
+ return [...squad, comp];
274
+ }
275
+
276
+ /** How many companions you own in total — active party plus bench. */
277
+ export function rosterSize(
278
+ squad: readonly Companion[] | undefined,
279
+ roster: Readonly<Record<string, Companion>> | undefined,
280
+ ): number {
281
+ return (squad?.length ?? 0) + Object.keys(roster ?? {}).length;
282
+ }
283
+
284
+ // Place a hire: the active party when there is room, otherwise the bench. A hire that "succeeds"
285
+ // and changes nothing was the bug. `full` is returned only at MAX_ROSTER, which is a real refusal.
286
+ export function placeHire(
287
+ squad: readonly Companion[],
288
+ roster: Readonly<Record<string, Companion>> | undefined,
289
+ comp: Companion,
290
+ ): {
291
+ squad: Companion[];
292
+ roster: Record<string, Companion>;
293
+ where: 'party' | 'roster' | 'duplicate' | 'full';
294
+ } {
295
+ const bench = { ...(roster ?? {}) };
296
+ if (squad.some((c) => c.id === comp.id) || bench[comp.id]) {
297
+ return { squad: [...squad], roster: bench, where: 'duplicate' };
298
+ }
299
+ if (rosterSize(squad, bench) >= MAX_ROSTER) {
300
+ return { squad: [...squad], roster: bench, where: 'full' };
301
+ }
302
+ if (squad.length < MAX_COMPANIONS) {
303
+ return { squad: [...squad, comp], roster: bench, where: 'party' };
304
+ }
305
+ bench[comp.id] = comp;
306
+ return { squad: [...squad], roster: bench, where: 'roster' };
307
+ }
308
+
309
+ export function removeCompanion(squad: readonly Companion[], id: string): Companion[] {
310
+ return squad.filter((c) => c.id !== id);
311
+ }
312
+
313
+ // Pick a race for a new companion: the first race of the player's faction whose create-info allows
314
+ // this class, data-driven and never hardcoded. Undefined when no faction race can play it.
315
+ export function companionRaceFor(ds: DataStore, playerRace: number, cls: number): number | undefined {
316
+ return companionRacesFor(ds, playerRace, cls)[0];
317
+ }
318
+
319
+ // All races of the player's faction that can play `cls` (create-info matrix). Order follows the baked race
320
+ // table — never a hardcoded race/class list.
321
+ export function companionRacesFor(ds: DataStore, playerRace: number, cls: number): number[] {
322
+ const team = factionOf(ds, playerRace);
323
+ return ds.races()
324
+ .filter((r) => factionOf(ds, r.id) === team && ds.createInfo(r.id, cls))
325
+ .map((r) => r.id);
326
+ }
327
+
328
+ // Class ids the player's faction can field as companions: every class that at least one same-faction race
329
+ // has create-info for (data-driven matrix).
330
+ export function factionPlayableClasses(ds: DataStore, playerRace: number): number[] {
331
+ const team = factionOf(ds, playerRace);
332
+ const out: number[] = [];
333
+ const seen = new Set<number>();
334
+ for (const r of ds.races()) {
335
+ if (factionOf(ds, r.id) !== team) continue;
336
+ for (const cls of r.classes) {
337
+ if (seen.has(cls)) continue;
338
+ if (ds.createInfo(r.id, cls)) {
339
+ seen.add(cls);
340
+ out.push(cls);
341
+ }
342
+ }
343
+ }
344
+ return out;
345
+ }
346
+
347
+ /** Stable 32-bit FNV-1a over a zone id (same zone → same candidates). */
348
+ export function stableIdHash(id: string): number {
349
+ let h = 2166136261;
350
+ for (let i = 0; i < id.length; i++) {
351
+ h ^= id.charCodeAt(i);
352
+ h = Math.imul(h, 16777619);
353
+ }
354
+ return h >>> 0;
355
+ }
356
+
357
+ // The seed-derived trade skills of a body that is not hired yet — an inn slate candidate. The same
358
+ // call the hired companion makes, so the hire preview cannot drift from what the player buys.
359
+ export function hireSkillMap(
360
+ seed: number,
361
+ level: number,
362
+ gearProfile: GearProfile | undefined,
363
+ ): Character['skills'] {
364
+ return applyTrainedCaps(
365
+ companionProfessionSkills(seed, level, {
366
+ maxed: gearProfile === 'twink' || isRaidGearProfile(gearProfile ?? 'field'),
367
+ }),
368
+ level,
369
+ );
370
+ }
371
+
372
+ // The companion's trade skills: what the player assigned (`{}` = all unlearned), else the seed-derived
373
+ // set. The cap is the trainer rank they reached, so a line just taken up sits at 75 until skill 50.
374
+ export function companionSkillMap(comp: Companion, level: number): Character['skills'] {
375
+ const assigned = comp.professions;
376
+ if (assigned == null) {
377
+ return hireSkillMap(comp.seed, level, comp.gearProfile);
378
+ }
379
+ const levelCap = professionSkillCap(level);
380
+ const out: Character['skills'] = {};
381
+ for (const [line, value] of Object.entries(assigned) as Array<[keyof Character['skills'], number]>) {
382
+ const cur = Math.max(1, Math.min(levelCap, value | 0));
383
+ const cap = companionSkillCap(line, cur, level);
384
+ if (cap <= 0) continue;
385
+ out[line] = { current: Math.min(cap, cur), max: cap };
386
+ }
387
+ return out;
388
+ }
389
+
390
+ /** A rank a companion just trained, for the log line. */
391
+ export interface CompanionRankTrained {
392
+ line: SkillLine;
393
+ rank: number;
394
+ name: string;
395
+ cap: number;
396
+ }
397
+
398
+ // Stamp the trainer ranks this body holds and report the new ones. A save with no stamp yet records
399
+ // what it had without announcing it, so an old roster does not spam the feed.
400
+ export function trainCompanionProfessionRanks(
401
+ comp: Companion,
402
+ level: number,
403
+ ): CompanionRankTrained[] {
404
+ const had = comp.professionRanks;
405
+ const next: Partial<Record<SkillLine, number>> = {};
406
+ const learned: CompanionRankTrained[] = [];
407
+ for (const [line, cur] of Object.entries(companionSkillMap(comp, level)) as Array<
408
+ [SkillLine, { current: number; max: number }]
409
+ >) {
410
+ if (line === 'poisons') continue;
411
+ const rank = companionTrainedRank(line, cur.current, level);
412
+ if (!rank) continue;
413
+ next[line] = rank.rank;
414
+ if (had && (had[line] ?? 0) < rank.rank) {
415
+ learned.push({ line, rank: rank.rank, name: rank.name, cap: rank.cap });
416
+ }
417
+ }
418
+ comp.professionRanks = next;
419
+ return learned;
420
+ }
421
+
422
+ // Talent map this companion fights with: a saved wiki string when stamped, else the premade specIdx link,
423
+ // else nothing.
424
+ export function companionTalents(
425
+ comp: Companion,
426
+ level: number,
427
+ ds: DataStore,
428
+ ): Record<number, number> | undefined {
429
+ const lvl = Math.max(1, level);
430
+ if (comp.talentLink) {
431
+ const fromLink = talentsFromLink(comp.talentLink, comp.cls, lvl, ds);
432
+ if (Object.values(fromLink).some((n) => n > 0)) return fromLink;
433
+ }
434
+ const spec = comp.specIdx != null ? ds.botSpecs(comp.cls)[comp.specIdx] : undefined;
435
+ return spec ? talentsForSpec(spec, comp.cls, lvl, ds) : undefined;
436
+ }
437
+
438
+ export function companionCharacter(comp: Companion, level: number, ds: DataStore): Character {
439
+ // TEMP_ENCHANTMENT_SLOT plus oil equip auras (TYPE_EQUIP_SPELL) ride into the combat build,
440
+ // mirroring the player path: the apply-spell chip and the equip aura share expiresAt.
441
+ const tempEnchants = comp.tempEnchants
442
+ ? {
443
+ ...(comp.tempEnchants.mainhand ? { mainhand: { ...comp.tempEnchants.mainhand } } : {}),
444
+ ...(comp.tempEnchants.offhand ? { offhand: { ...comp.tempEnchants.offhand } } : {}),
445
+ }
446
+ : undefined;
447
+ const now = Date.now();
448
+ const seedAuras: ActiveAura[] = comp.prePullAuras ? comp.prePullAuras.map((a) => ({ ...a })) : [];
449
+ if (tempEnchants) {
450
+ for (const hand of ['mainhand', 'offhand'] as const) {
451
+ const te = tempEnchants[hand];
452
+ if (!te) continue;
453
+ if (te.expiresAt != null && te.expiresAt <= now) continue;
454
+ seedAuras.push({ spellId: te.spellId, expiresAt: te.expiresAt });
455
+ if (te.equipSpellId != null && te.equipSpellId > 0) {
456
+ seedAuras.push({ spellId: te.equipSpellId, expiresAt: te.expiresAt });
457
+ }
458
+ }
459
+ }
460
+ const gender = comp.gender === 1 ? 1 : 0;
461
+ const lvl = Math.max(1, level);
462
+ const combatSkills = grantMaxedCombatSkillsForRaceClass(
463
+ lvl,
464
+ ds.combatSkillMeta?.(),
465
+ comp.race,
466
+ comp.cls,
467
+ );
468
+ const talents = companionTalents(comp, lvl, ds);
469
+ const char: Character = {
470
+ name: comp.name,
471
+ race: comp.race,
472
+ gender,
473
+ // Same deterministic-by-name look as pool bots / paperdoll — never all-zero
474
+ // DEFAULT_APPEARANCE (bald/hornless). Cite: domain/character/appearance.ts Wave R.
475
+ appearance: deterministicAppearance(comp.name, comp.race, gender),
476
+ cls: comp.cls,
477
+ level: lvl,
478
+ xp: comp.xp ?? 0,
479
+ gold: 0,
480
+ zoneId: '',
481
+ health: 1,
482
+ power: 0,
483
+ equipped: { ...comp.equipped },
484
+ ...(comp.durability ? { durability: { ...comp.durability } } : {}),
485
+ activeBuffs: [],
486
+ // Pre-pull party buffs ride along so buffed stats flow into maxHealth and buildCombatant.
487
+ // Expiry is pruned by wall clock at read time, and temp-enchant equip auras seed here too.
488
+ activeAuras: seedAuras,
489
+ ...(tempEnchants && (tempEnchants.mainhand || tempEnchants.offhand) ? { tempEnchants } : {}),
490
+ // W4: companions had `skills: {}`, so every item use-gate passed vacuously. Skills only — no
491
+ // recipes or tools — because this runs on every rotation build. Twink and raid tiers max lines.
492
+ skills: companionSkillMap(comp, lvl),
493
+ knownRecipes: [],
494
+ combatSkills,
495
+ ...(talents ? { talents } : {}),
496
+ ...(comp.reputations ? { reputations: { ...comp.reputations } } : {}),
497
+ ...(comp.factionFlags ? { factionFlags: { ...comp.factionFlags } } : {}),
498
+ };
499
+ // A generated body never buys arrows, so nothing set `ammoItem` and buildCombatant's ammo gate
500
+ // zeroed ranged damage for every companion hunter. Cite: Player.cpp:7591–7621.
501
+ //
502
+ // SHOOT WHAT THE BAGS HOLD. `generateSpawnInventory` stocks arrows with `getAmmo` (quality 1, the
503
+ // highest requiredLevel that fits) and this line picked with `bestAmmoForWeapon` (best DPS) - two
504
+ // selectors for one fact, and when they disagreed the quiver held one arrow and `ammoItem` named
505
+ // another, so a real count read 0.
506
+ {
507
+ const rangedEntry = equippedEntry(char.equipped.ranged);
508
+ const rangedItem = rangedEntry != null ? ds.item(rangedEntry) : undefined;
509
+ const wanted = bestAmmoForWeapon(ds, rangedItem, lvl);
510
+ const carried = (comp.bags?.stacks ?? [])
511
+ .map((s) => s.item)
512
+ .find((entry) => entry != null && ds.item(entry)?.ammoDps != null
513
+ && checkAmmoCompatibility(rangedItem, ds.item(entry)));
514
+ const ammo = carried ?? wanted;
515
+ if (ammo != null) char.ammoItem = ammo;
516
+ }
517
+ char.health = maxHealth(char, ds);
518
+ const pt = powerType(char);
519
+ char.power = pt === 'rage' ? 0 : maxPower(char, ds);
520
+ return char;
521
+ }
522
+
523
+ /** Per-DataStore memo: kit walks were O(zones+quests) per companionSpellbook call. */
524
+ type SpellbookMemo = {
525
+ trainersByCls: Map<number, number[]>;
526
+ talentOnlyByCls: Map<number, Set<number>>;
527
+ classQuest: Map<string, number[]>;
528
+ pending: Map<string, number[]>;
529
+ book: Map<string, number[]>;
530
+ };
531
+ const spellbookMemo = new WeakMap<DataStore, SpellbookMemo>();
532
+
533
+ function memoFor(ds: DataStore): SpellbookMemo {
534
+ let m = spellbookMemo.get(ds);
535
+ if (!m) {
536
+ m = {
537
+ trainersByCls: new Map(),
538
+ talentOnlyByCls: new Map(),
539
+ classQuest: new Map(),
540
+ pending: new Map(),
541
+ book: new Map(),
542
+ };
543
+ spellbookMemo.set(ds, m);
544
+ }
545
+ return m;
546
+ }
547
+
548
+ function trainerEntriesForClass(ds: DataStore, cls: number): number[] {
549
+ const m = memoFor(ds);
550
+ const hit = m.trainersByCls.get(cls);
551
+ if (hit) return hit;
552
+ const entries = new Set<number>();
553
+ for (const z of ds.zones()) {
554
+ for (const t of z.trainers) if (t.cls === cls) entries.add(t.entry);
555
+ }
556
+ const synthetic = syntheticClassTrainerEntry(cls);
557
+ if (ds.trainer(synthetic)?.spells?.length) entries.add(synthetic);
558
+ const list = [...entries];
559
+ m.trainersByCls.set(cls, list);
560
+ return list;
561
+ }
562
+
563
+ function talentOnlyForClass(ds: DataStore, cls: number): Set<number> {
564
+ const m = memoFor(ds);
565
+ const hit = m.talentOnlyByCls.get(cls);
566
+ if (hit) return hit;
567
+ const talentOnly = new Set<number>();
568
+ for (const tree of ds.talentTrees(cls) ?? []) {
569
+ for (const tal of tree.talents ?? []) {
570
+ for (const rank of tal.ranks ?? []) {
571
+ if (rank.spellId) talentOnly.add(rank.spellId);
572
+ for (const e of rank.effects ?? []) {
573
+ if (e.kind === 'grant_spell' && typeof (e as { spellId?: number }).spellId === 'number') {
574
+ talentOnly.add((e as { spellId: number }).spellId);
575
+ }
576
+ }
577
+ }
578
+ }
579
+ }
580
+ m.talentOnlyByCls.set(cls, talentOnly);
581
+ return talentOnly;
582
+ }
583
+
584
+ function pendingTrainerSpells(
585
+ ds: DataStore,
586
+ race: number,
587
+ cls: number,
588
+ level: number,
589
+ ): number[] {
590
+ const key = `${race}|${cls}|${level}`;
591
+ const m = memoFor(ds);
592
+ const hit = m.pending.get(key);
593
+ if (hit) return hit;
594
+ const meta = ds.combatSkillMeta?.();
595
+ const talentOnly = talentOnlyForClass(ds, cls);
596
+ const pending: number[] = [];
597
+ for (const entry of trainerEntriesForClass(ds, cls)) {
598
+ for (const ts of ds.trainer(entry)?.spells ?? []) {
599
+ if (ts.reqLevel > level) continue;
600
+ const sid = resolveSpellId(ts.spell, ds);
601
+ if (!ds.spell(sid)) continue;
602
+ if (meta && !isSpellFitByClassAndRace(sid, race, cls, meta, level)) continue;
603
+ if (talentOnly.has(sid)) continue;
604
+ pending.push(sid);
605
+ }
606
+ }
607
+ m.pending.set(key, pending);
608
+ return pending;
609
+ }
610
+
611
+ function sweepTrainerRanks(
612
+ known: Set<number>,
613
+ pending: number[],
614
+ ds: DataStore,
615
+ ): void {
616
+ for (;;) {
617
+ let added = 0;
618
+ for (let i = 0; i < pending.length; i++) {
619
+ const sid = pending[i]!;
620
+ if (sid < 0 || known.has(sid)) continue;
621
+ const node = ds.spellChain?.(sid);
622
+ if (node && ((node.prev && !known.has(node.prev)) || (node.req && !known.has(node.req)))) {
623
+ continue;
624
+ }
625
+ known.add(sid);
626
+ pending[i] = -1;
627
+ added++;
628
+ }
629
+ if (!added) break;
630
+ }
631
+ }
632
+
633
+ // Class-quest reward spells available at `level` for this race and class — vanilla teaches several
634
+ // kit spells only by quest. PLAYER characters must not use this free-grant; they earn on turn-in.
635
+ export function classQuestSpellsFor(
636
+ race: number,
637
+ cls: number,
638
+ level: number,
639
+ ds: DataStore,
640
+ ): number[] {
641
+ const lvl = Math.max(1, level);
642
+ const ck = `${race}|${cls}|${lvl}`;
643
+ const cached = memoFor(ds).classQuest.get(ck);
644
+ if (cached) return cached;
645
+ const out: number[] = [];
646
+ const seen = new Set<number>();
647
+ for (const q of ds.quests()) {
648
+ const rew = q.rewSpells;
649
+ if (!rew?.length) continue;
650
+ if ((q.minLevel || 0) > lvl) continue;
651
+ // Class gate: reqClass (single) or reqClassMask (multi-bit, KI-519).
652
+ if (q.reqClass != null && q.reqClass !== cls) continue;
653
+ if (q.reqClassMask != null && q.reqClassMask !== 0 && !raceClassMaskMatches(q.reqClassMask, cls)) {
654
+ continue;
655
+ }
656
+ // Unclassed rewSpells quests are not auto-granted to bots (open-world rewards).
657
+ if (q.reqClass == null && (q.reqClassMask == null || q.reqClassMask === 0)) continue;
658
+ if (q.reqRaceMask != null && q.reqRaceMask !== 0 && !raceClassMaskMatches(q.reqRaceMask, race)) {
659
+ continue;
660
+ }
661
+ for (const sid of rew) {
662
+ if (seen.has(sid) || !ds.spell(sid)) continue;
663
+ seen.add(sid);
664
+ out.push(sid);
665
+ }
666
+ }
667
+ memoFor(ds).classQuest.set(ck, out);
668
+ return out;
669
+ }
670
+
671
+ // A companion's spellbook: create-info spells, everything the class trainers teach up to `level`,
672
+ // talent grants, class-quest rewSpells and `taughtSpells`, all under the race/class fit gate.
673
+ export function companionSpellbook(comp: Companion, level: number, ds: DataStore): SpellBook {
674
+ const lvl = Math.max(1, level);
675
+ const specIdx = comp.specIdx ?? -1;
676
+ // Book-taught ranks are per-BODY, so they are part of the memo key — the rest of the key
677
+ // (race/class/level/spec) is shared by every companion of that shape.
678
+ const taught = comp.taughtSpells?.length ? [...new Set(comp.taughtSpells)].sort((a, b) => a - b) : [];
679
+ const linkKey = comp.talentLink ?? '';
680
+ const bookKey = `${comp.race}|${comp.cls}|${lvl}|${specIdx}|${linkKey}|${taught.join(',')}`;
681
+ const memo = memoFor(ds);
682
+ const hit = memo.book.get(bookKey);
683
+ if (hit) return { known: hit.slice() };
684
+
685
+ const known = new Set<number>(ds.createInfo(comp.race, comp.cls)?.spells ?? []);
686
+ // Class-quest kit (stances, Taunt, pets, forms…) — before trainer sweep so
687
+ // chain-gated trainer ranks that require a quest-taught root can open.
688
+ for (const sid of classQuestSpellsFor(comp.race, comp.cls, lvl, ds)) known.add(sid);
689
+ // Tomes / books / codices read on this body, seeded before the sweep for the same reason.
690
+ for (const sid of taught) if (ds.spell(sid)) known.add(sid);
691
+
692
+ // Slice: sweepTrainerRanks tombstones in place. Cite: Player.cpp:3974–3982 GetTrainerSpellState.
693
+ const pending = pendingTrainerSpells(ds, comp.race, comp.cls, lvl).slice();
694
+ sweepTrainerRanks(known, pending, ds);
695
+
696
+ // Talent-granted actives (Inner Focus, etc.) — wiki string when stamped, else premade spec.
697
+ // Cite: Player::LearnTalent → learnSpell.
698
+ const talents = companionTalents(comp, lvl, ds);
699
+ if (talents) {
700
+ for (const sid of talentGrantedSpellIds({ talents } as Character, ds)) {
701
+ if (ds.spell(sid)) known.add(sid);
702
+ }
703
+ sweepTrainerRanks(known, pending, ds);
704
+ }
705
+
706
+ const book = [...known].sort((a, b) => a - b);
707
+ memo.book.set(bookKey, book);
708
+ return { known: book.slice() };
709
+ }
710
+
711
+ /** Warrior stance spell ids (spell_template 1.12). */
712
+ const BATTLE_STANCE_SPELL = 2457;
713
+ const DEFENSIVE_STANCE_SPELL = 71;
714
+ const BERSERKER_STANCE_SPELL = 2458;
715
+
716
+ // Default stance for a warrior companion: tanks prefer Defensive when known; everyone else Battle; fall
717
+ // back to whichever stance they know. Classic warriors are never formless once a stance is known.
718
+ function companionWarriorForm(
719
+ role: SquadRole,
720
+ known: readonly number[],
721
+ ): number | undefined {
722
+ const has = (id: number) => known.includes(id);
723
+ if (role === 'tank' && has(DEFENSIVE_STANCE_SPELL)) return SHAPESHIFT_FORM.DEFENSIVESTANCE;
724
+ if (has(BATTLE_STANCE_SPELL)) return SHAPESHIFT_FORM.BATTLESTANCE;
725
+ if (has(DEFENSIVE_STANCE_SPELL)) return SHAPESHIFT_FORM.DEFENSIVESTANCE;
726
+ if (has(BERSERKER_STANCE_SPELL)) return SHAPESHIFT_FORM.BERSERKERSTANCE;
727
+ return undefined;
728
+ }
729
+
730
+ // Full combat spec via the shared player derivation. `stealthForPull` is the party's engage moment
731
+ // and is off by default; `spellCooldowns` is the world clock, so a chain-pull arrives unstealthed.
732
+ export function companionSpec(
733
+ comp: Companion,
734
+ level: number,
735
+ ds: DataStore,
736
+ opts?: {
737
+ stealthForPull?: boolean;
738
+ spellCooldowns?: Record<number, number>;
739
+ now?: number;
740
+ /** formId read off this seat's own pull phase (`openerFormOf`, arenaLab.ts). */
741
+ openerForm?: number;
742
+ },
743
+ ): CombatantSpec {
744
+ const char = companionCharacter(comp, level, ds);
745
+ const sb = companionSpellbook(comp, level, ds);
746
+ // Warriors always need a stance in Classic; tanks start in Defensive when known.
747
+ if (comp.cls === CLASS.WARRIOR && !((char.form ?? 0) | 0)) {
748
+ const form = companionWarriorForm(comp.role, sb.known);
749
+ if (form != null) char.form = form;
750
+ }
751
+ // Open IN the form the list opens with instead of spending the first GCD entering it. The form
752
+ // package rides spec.form already (fighterFactory.ts:794); the caller derives the id, never a default.
753
+ if (opts?.openerForm && !((char.form ?? 0) | 0)) char.form = opts.openerForm | 0;
754
+ // Seeded as an aura, not as spec.stealth: buildCombatant's activeStealthAura already derives
755
+ // strength / level bonus / break flags, and the same read puts the chip on the party frame.
756
+ if (opts?.stealthForPull) {
757
+ seedPrePullStealth(char, sb, ds, { spellCooldowns: opts.spellCooldowns, now: opts.now });
758
+ }
759
+ // WITH the bags, because ammo is counted out of them: without an inventory buildCombatant takes
760
+ // its "no inv -> assume present for unit tests" fallback of ONE arrow, and every companion hunter
761
+ // fired once and then read `no ammo` for the rest of the fight. `generateSpawnInventory` already
762
+ // stocks 5 + level/10 stacks of 200 (InitAmmo, botInventory.ts:401-416); nothing was reading them.
763
+ const spec = buildCombatant(char, sb, ds, comp.bags ?? emptyInventory());
764
+ // S4C single-target knob also suppresses the motion PBAoE pack walk-in.
765
+ spec.packClose = resolveAoeMode(comp) !== 'single';
766
+ spec.groupRole = comp.role === 'dps' ? 'damage' : comp.role;
767
+ {
768
+ const rot = comp.rotation;
769
+ const bot = comp.specIdx != null ? ds.botSpecs(comp.cls)[comp.specIdx] : undefined;
770
+ stampStandYards(spec, {
771
+ explicit: rot?.standYards,
772
+ specName: rot?.autoSig?.spec ?? bot?.name,
773
+ offenseYd: rot ? firstOffensiveRotationRangeYd(rot, (id) => ds.spell(id)) : null,
774
+ });
775
+ }
776
+ // Consumables in the companion's own bags enter the fight, and equipped on-use gear does too so
777
+ // takeover bar slots can fire it — its count is high because personal CD is the real gate.
778
+ const bags = comp.bags ?? emptyInventory();
779
+ const bagItems = combatItems(char, bags, ds);
780
+ const byEntry = new Map(bagItems.map((it) => [it.entry, it]));
781
+ for (const slot of Object.keys(char.equipped) as Array<keyof typeof char.equipped>) {
782
+ const entry = equippedEntry(char.equipped[slot]);
783
+ if (entry == null || byEntry.has(entry)) continue;
784
+ const it = ds.item(entry);
785
+ if (!it || !(it.useInCombat || it.useBuff || it.useSpell != null)) continue;
786
+ // Reuse combatItems' classification via a one-stack bag shell.
787
+ const synthetic = combatItems(char, { stacks: [{ item: entry, count: 1 }] }, ds);
788
+ const row = synthetic.find((x) => x.entry === entry);
789
+ if (row) byEntry.set(entry, { ...row, count: 99 });
790
+ }
791
+ const items = [...byEntry.values()];
792
+ if (items.length > 0) spec.items = items;
793
+ // CheckItems / TakeReagents snapshot, the same seed the player gets at combatSession.ts:779. Without
794
+ // it a companion's reagent spells were free: `canPaySpellReagents` allows anyone with no bag counts.
795
+ {
796
+ const bag = seedReagentBagCounts(spec.spells, (item) => countItem(bags, item));
797
+ if (bag) spec.bagItemCounts = bag;
798
+ }
799
+ return spec;
800
+ }
801
+
802
+ // CombatantSpec for a companion's active pet, or null. Uses the same buildPet path as the player,
803
+ // and is appended after the human allies so ally_0..n-1 stay index-aligned with state.squad.
804
+ export function companionPetSpec(comp: Companion, level: number, ds: DataStore): CombatantSpec | null {
805
+ if (!comp.pet || comp.pet.health <= 0) return null;
806
+ const char: Character = {
807
+ ...companionCharacter(comp, level, ds),
808
+ pet: comp.pet,
809
+ petSpells: comp.petSpells ?? [],
810
+ };
811
+ const pet = buildPet(char, ds);
812
+ if (!pet) return null;
813
+ // Pets fight as damage allies (factory autocasts offensive pet spells).
814
+ pet.groupRole = 'damage';
815
+ return pet;
816
+ }
817
+
818
+ // Healer throughput from the spec's REAL heal spells: best direct heal by average, HPS over its
819
+ // cast time, and total healing the mana pool can pay for. A healer with no heals reports zeros.
820
+ export function healerThroughput(spec: CombatantSpec): {
821
+ hps: number;
822
+ healingBudget: number;
823
+ healName?: string;
824
+ } {
825
+ let best: { avg: number; castMs: number; cost: number; name: string } | undefined;
826
+ for (const s of spec.spells) {
827
+ for (const e of s.effects) {
828
+ if (e.kind !== 'heal') continue;
829
+ const heal = e as { min?: number; max?: number };
830
+ const avg = ((heal.min ?? 0) + (heal.max ?? heal.min ?? 0)) / 2;
831
+ if (avg <= 0) continue;
832
+ if (!best || avg > best.avg) {
833
+ best = { avg, castMs: Math.max(s.castTimeMs || 0, 1500), cost: Math.max(0, s.cost), name: s.name };
834
+ }
835
+ }
836
+ }
837
+ if (!best) return { hps: 0, healingBudget: 0 };
838
+ const hps = best.avg / (best.castMs / 1000);
839
+ const casts = best.cost > 0 ? Math.floor(spec.maxPower / best.cost) : Number.POSITIVE_INFINITY;
840
+ const healingBudget = Number.isFinite(casts) ? casts * best.avg : Number.POSITIVE_INFINITY;
841
+ return { hps, healingBudget, healName: best.name };
842
+ }