azeroth-shell 0.0.0-stage → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1163) hide show
  1. package/README.md +138 -2
  2. package/bin/azsh.mjs +19 -0
  3. package/docs/aifid/eventai-texts.json +4414 -0
  4. package/docs/dungeons/atlas/atlas-rows-dungeons.json +8989 -0
  5. package/docs/dungeons/survey/pack-id-migration.json +2418 -0
  6. package/package.json +35 -4
  7. package/src/autopilot/bossSkip.ts +26 -0
  8. package/src/autopilot/combatRotation.ts +824 -0
  9. package/src/autopilot/config.ts +533 -0
  10. package/src/autopilot/consumables.ts +58 -0
  11. package/src/autopilot/encounterStand.ts +121 -0
  12. package/src/autopilot/objectGatePlan.ts +53 -0
  13. package/src/autopilot/pathEngage.ts +229 -0
  14. package/src/autopilot/plan.ts +1643 -0
  15. package/src/autopilot/questPolicy.ts +274 -0
  16. package/src/autopilot/routeStep.ts +69 -0
  17. package/src/autopilot/sessionReport.ts +88 -0
  18. package/src/autopilot/topOffPower.ts +26 -0
  19. package/src/autopilot/view.ts +476 -0
  20. package/src/cli/bootCheck.mjs +34 -0
  21. package/src/cli/bootData.mjs +57 -0
  22. package/src/cli/combatLogFilter.ts +153 -0
  23. package/src/cli/combatLogFormat.ts +613 -0
  24. package/src/cli/fileRepository.mjs +105 -0
  25. package/src/cli/gzLoader.mjs +31 -0
  26. package/src/cli/liveGauntletEscort.ts +978 -0
  27. package/src/cli/liveStratUndead.ts +305 -0
  28. package/src/cli/macroHostCombat.ts +545 -0
  29. package/src/cli/macroHostWorld.ts +330 -0
  30. package/src/cli/prefs.mjs +31 -0
  31. package/src/cli/register.mjs +4 -0
  32. package/src/cli/repl.mjs +693 -0
  33. package/src/cli/rotationText.mjs +226 -0
  34. package/src/cli/squad.mjs +105 -0
  35. package/src/cli/term.mjs +144 -0
  36. package/src/cli/text.mjs +122 -0
  37. package/src/cli/tui.mjs +626 -0
  38. package/src/cli/tuiArena.mjs +109 -0
  39. package/src/cli/tuiAutopilotSettings.mjs +93 -0
  40. package/src/cli/tuiBags.mjs +180 -0
  41. package/src/cli/tuiBars.mjs +133 -0
  42. package/src/cli/tuiBg.mjs +243 -0
  43. package/src/cli/tuiBulk.mjs +162 -0
  44. package/src/cli/tuiCheck.mjs +1882 -0
  45. package/src/cli/tuiCity.mjs +396 -0
  46. package/src/cli/tuiCompanionKit.mjs +300 -0
  47. package/src/cli/tuiCompanions.mjs +471 -0
  48. package/src/cli/tuiDev.mjs +62 -0
  49. package/src/cli/tuiDungeon.mjs +606 -0
  50. package/src/cli/tuiEnchantTarget.mjs +120 -0
  51. package/src/cli/tuiFight.mjs +577 -0
  52. package/src/cli/tuiFightPanes.mjs +228 -0
  53. package/src/cli/tuiFloor.mjs +506 -0
  54. package/src/cli/tuiGear.mjs +158 -0
  55. package/src/cli/tuiHonor.mjs +74 -0
  56. package/src/cli/tuiLoot.mjs +97 -0
  57. package/src/cli/tuiMacros.mjs +144 -0
  58. package/src/cli/tuiOutfitter.mjs +115 -0
  59. package/src/cli/tuiPet.mjs +116 -0
  60. package/src/cli/tuiProfessions.mjs +800 -0
  61. package/src/cli/tuiRaid.mjs +127 -0
  62. package/src/cli/tuiRep.mjs +65 -0
  63. package/src/cli/tuiSaves.mjs +69 -0
  64. package/src/cli/tuiSearch.mjs +363 -0
  65. package/src/cli/tuiSettings.mjs +151 -0
  66. package/src/cli/tuiSimLab.mjs +80 -0
  67. package/src/cli/tuiTalents.mjs +60 -0
  68. package/src/cli/tuiViews.mjs +1178 -0
  69. package/src/cli/tuiWiki.mjs +181 -0
  70. package/src/cli/tuiWorld.mjs +361 -0
  71. package/src/cli/wikiIndex.ts +259 -0
  72. package/src/cli/wikiSources.ts +355 -0
  73. package/src/data/alteracValley.ts +176 -0
  74. package/src/data/appearanceOptions.ts +534 -0
  75. package/src/data/applyLootChanceSanity.ts +21 -0
  76. package/src/data/createFlavor.ts +96 -0
  77. package/src/data/customItems.ts +33 -0
  78. package/src/data/dataStore.ts +1904 -0
  79. package/src/data/dungeonGameObjects.ts +84 -0
  80. package/src/data/dungeonPlateCover.ts +66 -0
  81. package/src/data/dungeonSpawns.ts +294 -0
  82. package/src/data/dungeons/alterac-valley.ts +135 -0
  83. package/src/data/dungeons/apply-dungeon-rooms.ts +29 -0
  84. package/src/data/dungeons/apply-encounter-outdoors.ts +72 -0
  85. package/src/data/dungeons/apply-instance-geometry.ts +65 -0
  86. package/src/data/dungeons/apply-spawn-placement.ts +171 -0
  87. package/src/data/dungeons/blackfathom-deeps.ts +539 -0
  88. package/src/data/dungeons/blackrock-depths.ts +1410 -0
  89. package/src/data/dungeons/blackwing-lair.ts +129 -0
  90. package/src/data/dungeons/boss-eventai.ts +8 -0
  91. package/src/data/dungeons/deadmines.ts +410 -0
  92. package/src/data/dungeons/dire-maul-east.ts +980 -0
  93. package/src/data/dungeons/dire-maul-north.ts +661 -0
  94. package/src/data/dungeons/dire-maul-west.ts +785 -0
  95. package/src/data/dungeons/dungeon-rooms.json +5479 -0
  96. package/src/data/dungeons/encounter-outdoors.json +359 -0
  97. package/src/data/dungeons/eventai/blackfathom-deeps.ts +308 -0
  98. package/src/data/dungeons/eventai/blackrock-depths.ts +1257 -0
  99. package/src/data/dungeons/eventai/deadmines.ts +264 -0
  100. package/src/data/dungeons/eventai/dire-maul-east.ts +320 -0
  101. package/src/data/dungeons/eventai/gnomeregan.ts +213 -0
  102. package/src/data/dungeons/eventai/helpers.ts +79 -0
  103. package/src/data/dungeons/eventai/index.ts +133 -0
  104. package/src/data/dungeons/eventai/lbrs.ts +372 -0
  105. package/src/data/dungeons/eventai/maraudon.ts +323 -0
  106. package/src/data/dungeons/eventai/ragefire-chasm.ts +108 -0
  107. package/src/data/dungeons/eventai/razorfen-downs.ts +207 -0
  108. package/src/data/dungeons/eventai/razorfen-kraul.ts +326 -0
  109. package/src/data/dungeons/eventai/scholomance.ts +680 -0
  110. package/src/data/dungeons/eventai/shadowfang-keep.ts +230 -0
  111. package/src/data/dungeons/eventai/sm-cathedral.ts +75 -0
  112. package/src/data/dungeons/eventai/sm-graveyard.ts +150 -0
  113. package/src/data/dungeons/eventai/sm-library.ts +55 -0
  114. package/src/data/dungeons/eventai/stratholme-undead.ts +127 -0
  115. package/src/data/dungeons/eventai/sunken-temple.ts +582 -0
  116. package/src/data/dungeons/eventai/the-stockade.ts +228 -0
  117. package/src/data/dungeons/eventai/ubrs.ts +225 -0
  118. package/src/data/dungeons/eventai/uldaman.ts +355 -0
  119. package/src/data/dungeons/eventai/wailing-caverns.ts +396 -0
  120. package/src/data/dungeons/eventai/zul-farrak.ts +591 -0
  121. package/src/data/dungeons/gnomeregan.ts +909 -0
  122. package/src/data/dungeons/index.ts +126 -0
  123. package/src/data/dungeons/instance-geometry.json +5233 -0
  124. package/src/data/dungeons/key-sources.json +169 -0
  125. package/src/data/dungeons/lbrs.ts +996 -0
  126. package/src/data/dungeons/maraudon.ts +786 -0
  127. package/src/data/dungeons/molten-core.ts +194 -0
  128. package/src/data/dungeons/naxxramas.ts +173 -0
  129. package/src/data/dungeons/onyxias-lair.ts +71 -0
  130. package/src/data/dungeons/pack-from-clusters.ts +1256 -0
  131. package/src/data/dungeons/ragefire-chasm.ts +238 -0
  132. package/src/data/dungeons/razorfen-downs.ts +698 -0
  133. package/src/data/dungeons/razorfen-kraul.ts +766 -0
  134. package/src/data/dungeons/ruins-of-ahnqiraj.ts +121 -0
  135. package/src/data/dungeons/scholomance.ts +1076 -0
  136. package/src/data/dungeons/shadowfang-keep.ts +740 -0
  137. package/src/data/dungeons/sm-armory.ts +266 -0
  138. package/src/data/dungeons/sm-cathedral.ts +430 -0
  139. package/src/data/dungeons/sm-graveyard.ts +482 -0
  140. package/src/data/dungeons/sm-library.ts +337 -0
  141. package/src/data/dungeons/stratholme-live.ts +808 -0
  142. package/src/data/dungeons/stratholme-undead.ts +1164 -0
  143. package/src/data/dungeons/sunken-temple.ts +931 -0
  144. package/src/data/dungeons/temple-of-ahnqiraj.ts +119 -0
  145. package/src/data/dungeons/the-stockade.ts +282 -0
  146. package/src/data/dungeons/ubrs.ts +1286 -0
  147. package/src/data/dungeons/uldaman.ts +685 -0
  148. package/src/data/dungeons/wailing-caverns.ts +356 -0
  149. package/src/data/dungeons/zul-farrak.ts +686 -0
  150. package/src/data/dungeons/zul-gurub.ts +142 -0
  151. package/src/data/dungeons.ts +42 -0
  152. package/src/data/fixtures.ts +446 -0
  153. package/src/data/gameobject-data.json.gz +0 -0
  154. package/src/data/item-data.json.gz +0 -0
  155. package/src/data/loot-data.json.gz +0 -0
  156. package/src/data/maps/atlas-approach-maps.json +1425 -0
  157. package/src/data/maps/atlas-landmarks.json +1711 -0
  158. package/src/data/maps/dungeon-viewports.json +392 -0
  159. package/src/data/materializeModDamagePercentTaken.ts +70 -0
  160. package/src/data/materializeModHealthRegen.ts +89 -0
  161. package/src/data/materializeSpellReputation.ts +26 -0
  162. package/src/data/pageTexts.ts +19 -0
  163. package/src/data/profession-data.json.gz +0 -0
  164. package/src/data/raid-plans/blackfathom-deeps.json +86 -0
  165. package/src/data/raid-plans/blackrock-depths.json +419 -0
  166. package/src/data/raid-plans/blackwing-lair.json +328 -0
  167. package/src/data/raid-plans/deadmines.json +55 -0
  168. package/src/data/raid-plans/dire-maul-east.json +94 -0
  169. package/src/data/raid-plans/dire-maul-north.json +70 -0
  170. package/src/data/raid-plans/dire-maul-west.json +75 -0
  171. package/src/data/raid-plans/gnomeregan.json +131 -0
  172. package/src/data/raid-plans/lbrs.json +176 -0
  173. package/src/data/raid-plans/maraudon.json +102 -0
  174. package/src/data/raid-plans/molten-core.json +169 -0
  175. package/src/data/raid-plans/naxxramas.json +354 -0
  176. package/src/data/raid-plans/onyxias-lair.json +18 -0
  177. package/src/data/raid-plans/ragefire-chasm.json +30 -0
  178. package/src/data/raid-plans/razorfen-downs.json +75 -0
  179. package/src/data/raid-plans/razorfen-kraul.json +53 -0
  180. package/src/data/raid-plans/ruins-of-ahnqiraj.json +110 -0
  181. package/src/data/raid-plans/scholomance.json +170 -0
  182. package/src/data/raid-plans/shadowfang-keep.json +87 -0
  183. package/src/data/raid-plans/sm-armory.json +53 -0
  184. package/src/data/raid-plans/sm-cathedral.json +72 -0
  185. package/src/data/raid-plans/sm-graveyard.json +63 -0
  186. package/src/data/raid-plans/sm-library.json +23 -0
  187. package/src/data/raid-plans/stratholme-live.json +129 -0
  188. package/src/data/raid-plans/stratholme-undead.json +73 -0
  189. package/src/data/raid-plans/sunken-temple.json +159 -0
  190. package/src/data/raid-plans/temple-of-ahnqiraj.json +163 -0
  191. package/src/data/raid-plans/the-stockade.json +42 -0
  192. package/src/data/raid-plans/ubrs.json +53 -0
  193. package/src/data/raid-plans/uldaman.json +131 -0
  194. package/src/data/raid-plans/wailing-caverns.json +90 -0
  195. package/src/data/raid-plans/zul-farrak.json +156 -0
  196. package/src/data/raid-plans/zul-gurub.json +307 -0
  197. package/src/data/raidInstanceCreatures.mjs +473 -0
  198. package/src/data/rotations/index.ts +152 -0
  199. package/src/data/rotations/layout.mjs +72 -0
  200. package/src/data/rotations/pve/druid/balance.json +754 -0
  201. package/src/data/rotations/pve/druid/feral-tank.json +2448 -0
  202. package/src/data/rotations/pve/druid/feral.json +2660 -0
  203. package/src/data/rotations/pve/druid/restoration.json +424 -0
  204. package/src/data/rotations/pve/hunter/beast-mastery.json +1288 -0
  205. package/src/data/rotations/pve/hunter/marksmanship.json +1260 -0
  206. package/src/data/rotations/pve/hunter/survival.json +1373 -0
  207. package/src/data/rotations/pve/mage/arcane-leveling.json +1798 -0
  208. package/src/data/rotations/pve/mage/fire-leveling.json +2003 -0
  209. package/src/data/rotations/pve/mage/frost-leveling.json +1912 -0
  210. package/src/data/rotations/pve/paladin/holy.json +755 -0
  211. package/src/data/rotations/pve/paladin/protection.json +962 -0
  212. package/src/data/rotations/pve/paladin/retribution.json +924 -0
  213. package/src/data/rotations/pve/priest/discipline.json +772 -0
  214. package/src/data/rotations/pve/priest/holy.json +707 -0
  215. package/src/data/rotations/pve/priest/shadow.json +787 -0
  216. package/src/data/rotations/pve/rogue/assassination.json +2477 -0
  217. package/src/data/rotations/pve/rogue/combat.json +2483 -0
  218. package/src/data/rotations/pve/rogue/subtlety.json +2523 -0
  219. package/src/data/rotations/pve/shaman/elemental.json +1157 -0
  220. package/src/data/rotations/pve/shaman/enhancement.json +1085 -0
  221. package/src/data/rotations/pve/shaman/restoration.json +592 -0
  222. package/src/data/rotations/pve/warlock/affliction.json +1185 -0
  223. package/src/data/rotations/pve/warlock/demonology.json +1165 -0
  224. package/src/data/rotations/pve/warlock/destruction.json +1177 -0
  225. package/src/data/rotations/pve/warrior/arms.json +3020 -0
  226. package/src/data/rotations/pve/warrior/fury.json +2996 -0
  227. package/src/data/rotations/pve/warrior/protection.json +2509 -0
  228. package/src/data/rotations/pvp/druid/balance.json +593 -0
  229. package/src/data/rotations/pvp/druid/feral.json +3276 -0
  230. package/src/data/rotations/pvp/druid/restoration.json +662 -0
  231. package/src/data/rotations/pvp/hunter/beast-mastery.json +665 -0
  232. package/src/data/rotations/pvp/hunter/marksmanship.json +2406 -0
  233. package/src/data/rotations/pvp/hunter/survival.json +635 -0
  234. package/src/data/rotations/pvp/mage/arcane.json +574 -0
  235. package/src/data/rotations/pvp/mage/fire.json +570 -0
  236. package/src/data/rotations/pvp/mage/frost.json +4048 -0
  237. package/src/data/rotations/pvp/paladin/holy.json +1498 -0
  238. package/src/data/rotations/pvp/paladin/protection.json +567 -0
  239. package/src/data/rotations/pvp/paladin/retribution.json +1110 -0
  240. package/src/data/rotations/pvp/priest/discipline.json +1848 -0
  241. package/src/data/rotations/pvp/priest/holy.json +6340 -0
  242. package/src/data/rotations/pvp/priest/shadow.json +2329 -0
  243. package/src/data/rotations/pvp/rogue/assassination.json +1322 -0
  244. package/src/data/rotations/pvp/rogue/combat.json +5258 -0
  245. package/src/data/rotations/pvp/rogue/subtlety.json +586 -0
  246. package/src/data/rotations/pvp/shaman/elemental.json +1404 -0
  247. package/src/data/rotations/pvp/shaman/enhancement.json +1277 -0
  248. package/src/data/rotations/pvp/shaman/restoration.json +2490 -0
  249. package/src/data/rotations/pvp/warlock/affliction.json +1017 -0
  250. package/src/data/rotations/pvp/warlock/demonology.json +1503 -0
  251. package/src/data/rotations/pvp/warlock/destruction.json +638 -0
  252. package/src/data/rotations/pvp/warrior/arms.json +5665 -0
  253. package/src/data/rotations/pvp/warrior/fury.json +850 -0
  254. package/src/data/rotations/pvp/warrior/protection.json +777 -0
  255. package/src/data/schema/bundle.ts +511 -0
  256. package/src/data/schema/constants.ts +49 -0
  257. package/src/data/schema/creature.ts +454 -0
  258. package/src/data/schema/encounter.ts +155 -0
  259. package/src/data/schema/faction.ts +48 -0
  260. package/src/data/schema/item.ts +297 -0
  261. package/src/data/schema/itemEnchant.ts +105 -0
  262. package/src/data/schema/npc.ts +44 -0
  263. package/src/data/schema/primitives.ts +295 -0
  264. package/src/data/schema/profession.ts +226 -0
  265. package/src/data/schema/quest.ts +154 -0
  266. package/src/data/schema/spell.ts +1149 -0
  267. package/src/data/schema/talent.ts +74 -0
  268. package/src/data/schema/world.ts +124 -0
  269. package/src/data/schema.ts +19 -0
  270. package/src/data/skinNodeGapFill.ts +68 -0
  271. package/src/data/spell-data.json.gz +0 -0
  272. package/src/data/spell-script-targets.json +1 -0
  273. package/src/data/tables/ahItemValues.json.gz +0 -0
  274. package/src/data/tables/alteracValley.json.gz +0 -0
  275. package/src/data/tables/areatriggerTeleports.json.gz +0 -0
  276. package/src/data/tables/botNames.json.gz +0 -0
  277. package/src/data/tables/botPopulation.json.gz +0 -0
  278. package/src/data/tables/botSpecs.json.gz +0 -0
  279. package/src/data/tables/classLevelStats.json.gz +0 -0
  280. package/src/data/tables/combatConditions.json.gz +0 -0
  281. package/src/data/tables/combatSkillMeta.json.gz +0 -0
  282. package/src/data/tables/conditions.json.gz +0 -0
  283. package/src/data/tables/createInfo.json.gz +0 -0
  284. package/src/data/tables/creatureAggroGroups.json.gz +0 -0
  285. package/src/data/tables/creatureClassLevelStats.json.gz +0 -0
  286. package/src/data/tables/creaturePatrolPacks.json.gz +0 -0
  287. package/src/data/tables/creatureWeapons.json.gz +0 -0
  288. package/src/data/tables/creatures.json.gz +0 -0
  289. package/src/data/tables/dbScripts.json.gz +0 -0
  290. package/src/data/tables/dungeonAuthoredRoutes.json.gz +0 -0
  291. package/src/data/tables/dungeonCensus.json.gz +0 -0
  292. package/src/data/tables/dungeonGameObjects.json.gz +0 -0
  293. package/src/data/tables/dungeonPacks.json.gz +0 -0
  294. package/src/data/tables/dungeonPlateCover.json.gz +0 -0
  295. package/src/data/tables/dungeonSpawns.json.gz +0 -0
  296. package/src/data/tables/dungeonSurvey.json.gz +0 -0
  297. package/src/data/tables/durabilityCosts.json.gz +0 -0
  298. package/src/data/tables/durabilityQuality.json.gz +0 -0
  299. package/src/data/tables/enchantApplicators.json.gz +0 -0
  300. package/src/data/tables/entranceYards.json.gz +0 -0
  301. package/src/data/tables/explorationBasexp.json.gz +0 -0
  302. package/src/data/tables/factionTemplates.json.gz +0 -0
  303. package/src/data/tables/factions.json.gz +0 -0
  304. package/src/data/tables/gameEvents.json.gz +0 -0
  305. package/src/data/tables/gameObjects.json.gz +0 -0
  306. package/src/data/tables/gossipMenus.json.gz +0 -0
  307. package/src/data/tables/graveyards.json.gz +0 -0
  308. package/src/data/tables/instanceMaps.json.gz +0 -0
  309. package/src/data/tables/itemEnchantmentTemplates.json.gz +0 -0
  310. package/src/data/tables/itemEnchants.json.gz +0 -0
  311. package/src/data/tables/itemRandomProperties.json.gz +0 -0
  312. package/src/data/tables/itemSets.json.gz +0 -0
  313. package/src/data/tables/items.json.gz +0 -0
  314. package/src/data/tables/levelStats.json.gz +0 -0
  315. package/src/data/tables/locks.json.gz +0 -0
  316. package/src/data/tables/map-pin-overrides.json.gz +0 -0
  317. package/src/data/tables/nonCombatTrash.json.gz +0 -0
  318. package/src/data/tables/npcTexts.json.gz +0 -0
  319. package/src/data/tables/pageTexts.json.gz +0 -0
  320. package/src/data/tables/petAbilityTP.json.gz +0 -0
  321. package/src/data/tables/petGenericSpells.json.gz +0 -0
  322. package/src/data/tables/petLevelStats.json.gz +0 -0
  323. package/src/data/tables/playerbot-weightscales.json.gz +0 -0
  324. package/src/data/tables/pools.json.gz +0 -0
  325. package/src/data/tables/quests.json.gz +0 -0
  326. package/src/data/tables/races.json.gz +0 -0
  327. package/src/data/tables/reputationRanks.json.gz +0 -0
  328. package/src/data/tables/reputationRates.json.gz +0 -0
  329. package/src/data/tables/reputationSpillover.json.gz +0 -0
  330. package/src/data/tables/ridingSpells.json.gz +0 -0
  331. package/src/data/tables/scriptTexts.json.gz +0 -0
  332. package/src/data/tables/soundClipVolume.json.gz +0 -0
  333. package/src/data/tables/spellChain.json.gz +0 -0
  334. package/src/data/tables/spellTeleports.json.gz +0 -0
  335. package/src/data/tables/spells.json.gz +0 -0
  336. package/src/data/tables/talents.json.gz +0 -0
  337. package/src/data/tables/tavernTriggers.json.gz +0 -0
  338. package/src/data/tables/taxiNodes.json.gz +0 -0
  339. package/src/data/tables/taxiRoutes.json.gz +0 -0
  340. package/src/data/tables/trainers.json.gz +0 -0
  341. package/src/data/tables/transports.json.gz +0 -0
  342. package/src/data/tables/travelAnchors.json.gz +0 -0
  343. package/src/data/tables/travelEdges.json.gz +0 -0
  344. package/src/data/tables/unitConditions.json.gz +0 -0
  345. package/src/data/tables/vendors.json.gz +0 -0
  346. package/src/data/tables/weaponEnchantProcs.json.gz +0 -0
  347. package/src/data/tables/xp.json.gz +0 -0
  348. package/src/data/tables/zoneWeather.json.gz +0 -0
  349. package/src/data/tables/zones.json.gz +0 -0
  350. package/src/data/world-data.ts +56 -0
  351. package/src/data/zone-music-sets.json +2751 -0
  352. package/src/dev/etl/lib/loot-chance-sanity.mjs +180 -0
  353. package/src/domain/audioQuality.mjs +145 -0
  354. package/src/domain/bg/ab.ts +433 -0
  355. package/src/domain/bg/arenaComps.ts +644 -0
  356. package/src/domain/bg/arenaLab.ts +695 -0
  357. package/src/domain/bg/arenaPace.ts +31 -0
  358. package/src/domain/bg/arenaRating.ts +110 -0
  359. package/src/domain/bg/av.ts +758 -0
  360. package/src/domain/bg/avEnemyPush.ts +219 -0
  361. package/src/domain/bg/avField.ts +283 -0
  362. package/src/domain/bg/avInstanceNodes.ts +197 -0
  363. package/src/domain/bg/avInstanceScore.ts +123 -0
  364. package/src/domain/bg/avQuestItems.ts +55 -0
  365. package/src/domain/bg/avQuests.ts +210 -0
  366. package/src/domain/bg/avSession.ts +196 -0
  367. package/src/domain/bg/bgConsumes.ts +269 -0
  368. package/src/domain/bg/bgPrebuff.ts +153 -0
  369. package/src/domain/bg/bgRest.ts +91 -0
  370. package/src/domain/bg/bgRoster.ts +305 -0
  371. package/src/domain/bg/bgTier.ts +61 -0
  372. package/src/domain/bg/bgWorld.ts +862 -0
  373. package/src/domain/bg/match.ts +215 -0
  374. package/src/domain/bg/strategies.ts +552 -0
  375. package/src/domain/bg/types.ts +291 -0
  376. package/src/domain/bg/wsg.ts +264 -0
  377. package/src/domain/bots/actionProviderSpec.ts +38 -0
  378. package/src/domain/bots/autoConsumables.ts +285 -0
  379. package/src/domain/bots/betweenPullRest.ts +239 -0
  380. package/src/domain/bots/botGear.ts +248 -0
  381. package/src/domain/bots/botInventory.ts +486 -0
  382. package/src/domain/bots/botPet.ts +535 -0
  383. package/src/domain/bots/botPool.ts +291 -0
  384. package/src/domain/bots/botProfessions.ts +334 -0
  385. package/src/domain/bots/companionActionBar.ts +209 -0
  386. package/src/domain/bots/companionHireCost.ts +236 -0
  387. package/src/domain/bots/companionMissions.ts +582 -0
  388. package/src/domain/bots/companionPrep.ts +254 -0
  389. package/src/domain/bots/companionQuests.ts +270 -0
  390. package/src/domain/bots/companionRep.ts +75 -0
  391. package/src/domain/bots/companionRotation.ts +708 -0
  392. package/src/domain/bots/companionXp.ts +66 -0
  393. package/src/domain/bots/consumableShare.ts +811 -0
  394. package/src/domain/bots/dpsMate.ts +1072 -0
  395. package/src/domain/bots/groupCompReport.ts +132 -0
  396. package/src/domain/bots/healthstoneSupply.ts +198 -0
  397. package/src/domain/bots/outfitter.ts +1056 -0
  398. package/src/domain/bots/paladinPrePull.ts +231 -0
  399. package/src/domain/bots/partyRole.ts +40 -0
  400. package/src/domain/bots/playerbotEquipCache.ts +412 -0
  401. package/src/domain/bots/playerbotItemEligibility.ts +60 -0
  402. package/src/domain/bots/playerbotStatWeight.ts +853 -0
  403. package/src/domain/bots/playerbotUnavailableItems.ts +147 -0
  404. package/src/domain/bots/prePullBuffs.ts +219 -0
  405. package/src/domain/bots/prePullStealth.ts +82 -0
  406. package/src/domain/bots/runSupply.ts +251 -0
  407. package/src/domain/bots/runSupplyPrefs.ts +28 -0
  408. package/src/domain/bots/sendTradeGoods.ts +394 -0
  409. package/src/domain/bots/soulShardCap.ts +35 -0
  410. package/src/domain/bots/squad.ts +842 -0
  411. package/src/domain/bots/squadRun.ts +81 -0
  412. package/src/domain/character/actionbar.ts +346 -0
  413. package/src/domain/character/appearance.ts +165 -0
  414. package/src/domain/character/buildCombatant.ts +1726 -0
  415. package/src/domain/character/character.ts +356 -0
  416. package/src/domain/character/characterName.ts +43 -0
  417. package/src/domain/character/characterRatings.ts +424 -0
  418. package/src/domain/character/characterSpells.ts +282 -0
  419. package/src/domain/character/characterStats.ts +1559 -0
  420. package/src/domain/character/characterTalents.ts +398 -0
  421. package/src/domain/character/combatSkills.ts +994 -0
  422. package/src/domain/character/displayForm.ts +72 -0
  423. package/src/domain/character/formTalentAuras.ts +171 -0
  424. package/src/domain/character/forms.ts +499 -0
  425. package/src/domain/character/races.ts +40 -0
  426. package/src/domain/character/resurrectionSickness.ts +49 -0
  427. package/src/domain/character/spellbook.ts +169 -0
  428. package/src/domain/character/stanceBar.ts +354 -0
  429. package/src/domain/character/stancePrereq.ts +70 -0
  430. package/src/domain/character/talentBuilds.ts +63 -0
  431. package/src/domain/character/talentImport.ts +130 -0
  432. package/src/domain/character/talentLink.ts +123 -0
  433. package/src/domain/character/talents.ts +201 -0
  434. package/src/domain/core/conditionSnapshot.ts +92 -0
  435. package/src/domain/core/hover.ts +14 -0
  436. package/src/domain/core/ids.ts +58 -0
  437. package/src/domain/core/internalNameTags.ts +5 -0
  438. package/src/domain/core/runtimeDataPatches.ts +357 -0
  439. package/src/domain/creature/aiTargeting.ts +588 -0
  440. package/src/domain/creature/combatCondition.ts +157 -0
  441. package/src/domain/creature/creatureAggro.ts +804 -0
  442. package/src/domain/creature/creatureAi.ts +206 -0
  443. package/src/domain/creature/creatureAiConstants.ts +661 -0
  444. package/src/domain/creature/creatureCastList.ts +1007 -0
  445. package/src/domain/creature/creatureEventAi.ts +1409 -0
  446. package/src/domain/creature/creatureGroups.ts +144 -0
  447. package/src/domain/creature/creatureLinking.ts +333 -0
  448. package/src/domain/creature/creatureScaling.ts +320 -0
  449. package/src/domain/creature/creatureTrigger.ts +53 -0
  450. package/src/domain/creature/creatureWander.ts +74 -0
  451. package/src/domain/creature/eventAiTexts.ts +145 -0
  452. package/src/domain/creature/faction.ts +287 -0
  453. package/src/domain/creature/forcedReaction.ts +48 -0
  454. package/src/domain/creature/outdoorHuntable.ts +74 -0
  455. package/src/domain/creature/patrolPacks.ts +210 -0
  456. package/src/domain/creature/reputation.ts +967 -0
  457. package/src/domain/creature/unitFlags.ts +74 -0
  458. package/src/domain/creature/worldBosses.ts +393 -0
  459. package/src/domain/dungeonMusic.mjs +48 -0
  460. package/src/domain/economy/auction.ts +282 -0
  461. package/src/domain/economy/auctionBot.ts +1060 -0
  462. package/src/domain/economy/honorPrice.ts +100 -0
  463. package/src/domain/economy/mail.ts +958 -0
  464. package/src/domain/economy/money.ts +42 -0
  465. package/src/domain/economy/syntheticClassTrainers.ts +62 -0
  466. package/src/domain/economy/trading.ts +296 -0
  467. package/src/domain/economy/vendorSellAll.ts +252 -0
  468. package/src/domain/economy/vendorStock.ts +146 -0
  469. package/src/domain/items/ammo.ts +817 -0
  470. package/src/domain/items/bank.ts +162 -0
  471. package/src/domain/items/consumableFamily.ts +205 -0
  472. package/src/domain/items/craftUpgrades.ts +83 -0
  473. package/src/domain/items/createItem.ts +93 -0
  474. package/src/domain/items/durability.ts +581 -0
  475. package/src/domain/items/equipment.ts +441 -0
  476. package/src/domain/items/equipmentHelper.ts +767 -0
  477. package/src/domain/items/inventory.ts +561 -0
  478. package/src/domain/items/itemBonding.ts +93 -0
  479. package/src/domain/items/itemContainer.ts +245 -0
  480. package/src/domain/items/itemDisplayName.ts +33 -0
  481. package/src/domain/items/itemInstance.ts +181 -0
  482. package/src/domain/items/itemRandomEnchantOutcomes.ts +315 -0
  483. package/src/domain/items/itemRandomProps.ts +77 -0
  484. package/src/domain/items/itemRestrictions.ts +329 -0
  485. package/src/domain/items/itemTeaches.ts +82 -0
  486. package/src/domain/items/itemUseCooldown.ts +52 -0
  487. package/src/domain/items/itemUseTarget.ts +90 -0
  488. package/src/domain/items/junkCategories.ts +174 -0
  489. package/src/domain/items/junkFilter.ts +368 -0
  490. package/src/domain/items/keyring.ts +131 -0
  491. package/src/domain/items/loot.ts +221 -0
  492. package/src/domain/items/mounts.ts +190 -0
  493. package/src/domain/items/onUsePayload.ts +102 -0
  494. package/src/domain/items/pendingLoot.ts +107 -0
  495. package/src/domain/items/relic.ts +105 -0
  496. package/src/domain/items/rocketBoots.ts +36 -0
  497. package/src/domain/items/sortContainer.ts +139 -0
  498. package/src/domain/items/spareContainers.ts +71 -0
  499. package/src/domain/items/spellReagentIndex.ts +131 -0
  500. package/src/domain/items/staleConsumables.ts +66 -0
  501. package/src/domain/items/weaponSpender.ts +110 -0
  502. package/src/domain/listDungeonIds.mjs +28 -0
  503. package/src/domain/macro/compose.ts +239 -0
  504. package/src/domain/macro/conditions.ts +260 -0
  505. package/src/domain/macro/creatureTypes.ts +40 -0
  506. package/src/domain/macro/describe.ts +169 -0
  507. package/src/domain/macro/icon.ts +60 -0
  508. package/src/domain/macro/index.ts +20 -0
  509. package/src/domain/macro/normalize.ts +112 -0
  510. package/src/domain/macro/parse.ts +316 -0
  511. package/src/domain/macro/plan.ts +288 -0
  512. package/src/domain/macro/rotation.ts +590 -0
  513. package/src/domain/macro/rotationEnv.ts +173 -0
  514. package/src/domain/macro/slots.ts +101 -0
  515. package/src/domain/macro/snapshot.ts +114 -0
  516. package/src/domain/macro/templates.ts +446 -0
  517. package/src/domain/macro/types.ts +70 -0
  518. package/src/domain/macro/units.ts +93 -0
  519. package/src/domain/macro/weaponTypes.ts +83 -0
  520. package/src/domain/nav/cityTeleports.ts +10 -0
  521. package/src/domain/nav/mounting.ts +113 -0
  522. package/src/domain/nav/nav.ts +43 -0
  523. package/src/domain/nav/navCollision.ts +606 -0
  524. package/src/domain/nav/navOutdoors.ts +91 -0
  525. package/src/domain/nav/navRegistry.ts +179 -0
  526. package/src/domain/nav/navRoomGraph.ts +302 -0
  527. package/src/domain/nav/navTypes.ts +43 -0
  528. package/src/domain/nav/navmesh.ts +1715 -0
  529. package/src/domain/nav/speed.ts +200 -0
  530. package/src/domain/nav/storey.ts +10 -0
  531. package/src/domain/nav/travel.ts +725 -0
  532. package/src/domain/nav/travelTypes.ts +75 -0
  533. package/src/domain/pet/pet.ts +1150 -0
  534. package/src/domain/pet/petActionBar.ts +180 -0
  535. package/src/domain/pet/petSpellbook.ts +39 -0
  536. package/src/domain/pet/petStable.ts +81 -0
  537. package/src/domain/professions/autoDisenchant.ts +236 -0
  538. package/src/domain/professions/characterEnchants.ts +176 -0
  539. package/src/domain/professions/craftCooldown.ts +52 -0
  540. package/src/domain/professions/enchantApply.ts +62 -0
  541. package/src/domain/professions/enchantTargets.ts +114 -0
  542. package/src/domain/professions/enchanting.ts +236 -0
  543. package/src/domain/professions/gatherFilter.ts +149 -0
  544. package/src/domain/professions/gearEnchant.ts +137 -0
  545. package/src/domain/professions/heldTools.ts +29 -0
  546. package/src/domain/professions/learnAllRecipes.ts +146 -0
  547. package/src/domain/professions/miningHarvest.ts +69 -0
  548. package/src/domain/professions/partyDisenchant.ts +294 -0
  549. package/src/domain/professions/partyWork.ts +83 -0
  550. package/src/domain/professions/pickpocket.ts +172 -0
  551. package/src/domain/professions/poisons.ts +240 -0
  552. package/src/domain/professions/professions.ts +677 -0
  553. package/src/domain/professions/rareNodes.ts +45 -0
  554. package/src/domain/professions/skinLoot.ts +27 -0
  555. package/src/domain/professions/vendorReagents.ts +152 -0
  556. package/src/domain/professions/weaponImbueHand.ts +171 -0
  557. package/src/domain/questFarmFilter.mjs +42 -0
  558. package/src/domain/quests/doQuest.ts +1204 -0
  559. package/src/domain/quests/gossip.ts +308 -0
  560. package/src/domain/quests/gossipTalk.ts +298 -0
  561. package/src/domain/quests/interpreter/canComplete.ts +150 -0
  562. package/src/domain/quests/interpreter/claim.ts +137 -0
  563. package/src/domain/quests/interpreter/dbscript/handlers.ts +1371 -0
  564. package/src/domain/quests/interpreter/dbscript/handlersBatch.ts +1251 -0
  565. package/src/domain/quests/interpreter/dbscript/hooks.ts +331 -0
  566. package/src/domain/quests/interpreter/dbscript/index.ts +212 -0
  567. package/src/domain/quests/interpreter/dbscript/opcodes.ts +257 -0
  568. package/src/domain/quests/interpreter/dbscript/registry.ts +1194 -0
  569. package/src/domain/quests/interpreter/dbscript/registryAreatriggerScripts.ts +539 -0
  570. package/src/domain/quests/interpreter/dbscript/registryAshenvale.ts +553 -0
  571. package/src/domain/quests/interpreter/dbscript/registryAzshara.ts +272 -0
  572. package/src/domain/quests/interpreter/dbscript/registryDarkshore.ts +637 -0
  573. package/src/domain/quests/interpreter/dbscript/registryDesolace.ts +501 -0
  574. package/src/domain/quests/interpreter/dbscript/registryDustwallowMarsh.ts +735 -0
  575. package/src/domain/quests/interpreter/dbscript/registryFelwood.ts +493 -0
  576. package/src/domain/quests/interpreter/dbscript/registryFeralas.ts +485 -0
  577. package/src/domain/quests/interpreter/dbscript/registryGoScripts.ts +203 -0
  578. package/src/domain/quests/interpreter/dbscript/registryMoonglade.ts +288 -0
  579. package/src/domain/quests/interpreter/dbscript/registryNpcProfessions.ts +230 -0
  580. package/src/domain/quests/interpreter/dbscript/registryNpcsSpecial.ts +545 -0
  581. package/src/domain/quests/interpreter/dbscript/registryRazorfenDowns.ts +293 -0
  582. package/src/domain/quests/interpreter/dbscript/registryRazorfenKraul.ts +221 -0
  583. package/src/domain/quests/interpreter/dbscript/registryRedridge.ts +112 -0
  584. package/src/domain/quests/interpreter/dbscript/registrySearingGorge.ts +125 -0
  585. package/src/domain/quests/interpreter/dbscript/registrySiblings.ts +51 -0
  586. package/src/domain/quests/interpreter/dbscript/registrySilverpineForest.ts +172 -0
  587. package/src/domain/quests/interpreter/dbscript/registryStonetalonMountains.ts +180 -0
  588. package/src/domain/quests/interpreter/dbscript/registryStormwindCity.ts +369 -0
  589. package/src/domain/quests/interpreter/dbscript/registryStranglethornVale.ts +115 -0
  590. package/src/domain/quests/interpreter/dbscript/registryStratholme.ts +146 -0
  591. package/src/domain/quests/interpreter/dbscript/registrySunkenTemple.ts +149 -0
  592. package/src/domain/quests/interpreter/dbscript/registrySwampOfSorrows.ts +163 -0
  593. package/src/domain/quests/interpreter/dbscript/registryTanaris.ts +318 -0
  594. package/src/domain/quests/interpreter/dbscript/registryTeldrassil.ts +120 -0
  595. package/src/domain/quests/interpreter/dbscript/registryTheBarrens.ts +603 -0
  596. package/src/domain/quests/interpreter/dbscript/registryThousandNeedles.ts +499 -0
  597. package/src/domain/quests/interpreter/dbscript/registryTirisfalGlades.ts +222 -0
  598. package/src/domain/quests/interpreter/dbscript/registryUngoroCrater.ts +291 -0
  599. package/src/domain/quests/interpreter/dbscript/registryWarEffort.ts +773 -0
  600. package/src/domain/quests/interpreter/dbscript/registryWesternPlaguelands.ts +206 -0
  601. package/src/domain/quests/interpreter/dbscript/registryWestfall.ts +190 -0
  602. package/src/domain/quests/interpreter/dbscript/registryWetlands.ts +186 -0
  603. package/src/domain/quests/interpreter/dbscript/registryWinterspring.ts +235 -0
  604. package/src/domain/quests/interpreter/dbscript/types.ts +817 -0
  605. package/src/domain/quests/interpreter/dbscript/vm.ts +171 -0
  606. package/src/domain/quests/interpreter/diff.ts +349 -0
  607. package/src/domain/quests/interpreter/fixtures/oracle-questlog-qi2.json +2417 -0
  608. package/src/domain/quests/interpreter/flags.ts +101 -0
  609. package/src/domain/quests/interpreter/index.ts +113 -0
  610. package/src/domain/quests/interpreter/live.ts +178 -0
  611. package/src/domain/quests/interpreter/types.ts +81 -0
  612. package/src/domain/quests/interpreter/updaters.ts +412 -0
  613. package/src/domain/quests/questCorpseUse.ts +155 -0
  614. package/src/domain/quests/questDialog.ts +43 -0
  615. package/src/domain/quests/questFight.ts +34 -0
  616. package/src/domain/quests/questObjectiveLabel.ts +39 -0
  617. package/src/domain/quests/questRewardChoice.ts +85 -0
  618. package/src/domain/quests/questScriptCredit.ts +26 -0
  619. package/src/domain/quests/questScriptItemUse.ts +74 -0
  620. package/src/domain/quests/questTameRods.ts +79 -0
  621. package/src/domain/quests/questlog.ts +1545 -0
  622. package/src/domain/quests/talkDeliver.ts +170 -0
  623. package/src/domain/raid/globalActionBar.ts +195 -0
  624. package/src/domain/raid/instanceRoster.ts +194 -0
  625. package/src/domain/raid/partySummon.ts +198 -0
  626. package/src/domain/raid/partyVault.ts +320 -0
  627. package/src/domain/raid/raidBossAbilities.ts +268 -0
  628. package/src/domain/raid/raidComp.ts +335 -0
  629. package/src/domain/raid/raidCustomRows.ts +453 -0
  630. package/src/domain/raid/raidEncounterGear.ts +298 -0
  631. package/src/domain/raid/raidEncounterTactics.ts +412 -0
  632. package/src/domain/raid/raidPlan.ts +509 -0
  633. package/src/domain/raid/raidPlanEdits.ts +98 -0
  634. package/src/domain/raid/raidPlanPacks.ts +480 -0
  635. package/src/domain/raid/raidRecovery.ts +183 -0
  636. package/src/domain/raid/raidRosterTemplate.ts +138 -0
  637. package/src/domain/rotation/auraSide.ts +68 -0
  638. package/src/domain/rotation/build.ts +3031 -0
  639. package/src/domain/rotation/classes/druid.ts +58 -0
  640. package/src/domain/rotation/classes/hooks.ts +59 -0
  641. package/src/domain/rotation/classes/hunter.ts +156 -0
  642. package/src/domain/rotation/classes/index.ts +104 -0
  643. package/src/domain/rotation/classes/mage.ts +99 -0
  644. package/src/domain/rotation/classes/paladin.ts +296 -0
  645. package/src/domain/rotation/classes/priest.ts +94 -0
  646. package/src/domain/rotation/classes/pullOpener.ts +92 -0
  647. package/src/domain/rotation/classes/rogue.ts +69 -0
  648. package/src/domain/rotation/classes/shaman.ts +29 -0
  649. package/src/domain/rotation/classes/supportSpec.ts +94 -0
  650. package/src/domain/rotation/classes/warlock.ts +81 -0
  651. package/src/domain/rotation/classes/warrior.ts +402 -0
  652. package/src/domain/rotation/classify.ts +1381 -0
  653. package/src/domain/rotation/condMetricPicker.ts +379 -0
  654. package/src/domain/rotation/consumables.ts +242 -0
  655. package/src/domain/rotation/evaluate.ts +1115 -0
  656. package/src/domain/rotation/finisherLadder.ts +145 -0
  657. package/src/domain/rotation/invent.ts +938 -0
  658. package/src/domain/rotation/killOrder.ts +30 -0
  659. package/src/domain/rotation/openerForm.ts +22 -0
  660. package/src/domain/rotation/paladinBuffs.ts +568 -0
  661. package/src/domain/rotation/prebuff.ts +283 -0
  662. package/src/domain/rotation/raidRowTuning.ts +34 -0
  663. package/src/domain/rotation/rotation.ts +11 -0
  664. package/src/domain/rotation/rotationProfiles.ts +180 -0
  665. package/src/domain/rotation/rotationSuggestions.ts +851 -0
  666. package/src/domain/rotation/ruleAfterChain.ts +49 -0
  667. package/src/domain/rotation/spec.ts +70 -0
  668. package/src/domain/rotation/spellPicker.ts +140 -0
  669. package/src/domain/rotation/stand.ts +143 -0
  670. package/src/domain/rotation/types.ts +718 -0
  671. package/src/domain/run/battlegroundRun.ts +111 -0
  672. package/src/domain/run/canEnterContext.ts +32 -0
  673. package/src/domain/run/death.ts +561 -0
  674. package/src/domain/run/deathRecovery.ts +289 -0
  675. package/src/domain/run/duel.ts +141 -0
  676. package/src/domain/run/dungeonRun.ts +344 -0
  677. package/src/domain/run/floorRest.ts +159 -0
  678. package/src/domain/run/honor.ts +557 -0
  679. package/src/domain/run/honorWeek.ts +180 -0
  680. package/src/domain/run/whenMap.ts +977 -0
  681. package/src/domain/scriptdev/arathiHighlands.ts +445 -0
  682. package/src/domain/scriptdev/ashenvale.ts +635 -0
  683. package/src/domain/scriptdev/ashenvaleHelpers.ts +1215 -0
  684. package/src/domain/scriptdev/azshara.ts +892 -0
  685. package/src/domain/scriptdev/blackfathomDeeps.ts +212 -0
  686. package/src/domain/scriptdev/blackrockDepths.ts +1434 -0
  687. package/src/domain/scriptdev/blackrockSpire.ts +730 -0
  688. package/src/domain/scriptdev/blackwingLair.ts +521 -0
  689. package/src/domain/scriptdev/burningSteppes.ts +62 -0
  690. package/src/domain/scriptdev/classFilter.ts +43 -0
  691. package/src/domain/scriptdev/darkshore.ts +817 -0
  692. package/src/domain/scriptdev/darkshoreHelpers.ts +853 -0
  693. package/src/domain/scriptdev/deadmines.ts +331 -0
  694. package/src/domain/scriptdev/desolace.ts +1239 -0
  695. package/src/domain/scriptdev/direMaul.ts +859 -0
  696. package/src/domain/scriptdev/durotar.ts +532 -0
  697. package/src/domain/scriptdev/dustwallowMarsh.ts +758 -0
  698. package/src/domain/scriptdev/dustwallowMarshHelpers.ts +994 -0
  699. package/src/domain/scriptdev/easternPlaguelands.ts +21 -0
  700. package/src/domain/scriptdev/felwood.ts +1055 -0
  701. package/src/domain/scriptdev/feralas.ts +571 -0
  702. package/src/domain/scriptdev/feralasHelpers.ts +838 -0
  703. package/src/domain/scriptdev/gnomeregan.ts +466 -0
  704. package/src/domain/scriptdev/guards.ts +616 -0
  705. package/src/domain/scriptdev/hinterlands.ts +693 -0
  706. package/src/domain/scriptdev/host.ts +1134 -0
  707. package/src/domain/scriptdev/index.ts +123 -0
  708. package/src/domain/scriptdev/instanceRaids.ts +136 -0
  709. package/src/domain/scriptdev/itemScripts.ts +37 -0
  710. package/src/domain/scriptdev/lochModan.ts +283 -0
  711. package/src/domain/scriptdev/maraudon.ts +232 -0
  712. package/src/domain/scriptdev/moltenCore.ts +831 -0
  713. package/src/domain/scriptdev/moonglade.ts +659 -0
  714. package/src/domain/scriptdev/moongladeHelpers.ts +933 -0
  715. package/src/domain/scriptdev/naxxramas.ts +577 -0
  716. package/src/domain/scriptdev/naxxramasConstruct.ts +364 -0
  717. package/src/domain/scriptdev/naxxramasFrostwyrm.ts +378 -0
  718. package/src/domain/scriptdev/naxxramasMilitary.ts +276 -0
  719. package/src/domain/scriptdev/npcProfessions.ts +1025 -0
  720. package/src/domain/scriptdev/npcsSpecial.ts +1379 -0
  721. package/src/domain/scriptdev/onyxiasLair.ts +313 -0
  722. package/src/domain/scriptdev/orgrimmar.ts +147 -0
  723. package/src/domain/scriptdev/professionSpecConsumer.ts +481 -0
  724. package/src/domain/scriptdev/razorfenDowns.ts +468 -0
  725. package/src/domain/scriptdev/razorfenKraul.ts +410 -0
  726. package/src/domain/scriptdev/redridgeMountains.ts +163 -0
  727. package/src/domain/scriptdev/registry.ts +945 -0
  728. package/src/domain/scriptdev/ruinsOfAhnqiraj.ts +356 -0
  729. package/src/domain/scriptdev/scarletMonastery.ts +713 -0
  730. package/src/domain/scriptdev/scholomance.ts +682 -0
  731. package/src/domain/scriptdev/searingGorge.ts +295 -0
  732. package/src/domain/scriptdev/shadowfangKeep.ts +181 -0
  733. package/src/domain/scriptdev/silithus.ts +71 -0
  734. package/src/domain/scriptdev/silverpineForest.ts +662 -0
  735. package/src/domain/scriptdev/stonetalonMountains.ts +493 -0
  736. package/src/domain/scriptdev/stormwindCity.ts +1192 -0
  737. package/src/domain/scriptdev/stranglethornVale.ts +402 -0
  738. package/src/domain/scriptdev/stratholme.ts +650 -0
  739. package/src/domain/scriptdev/stratholmeScripts.ts +505 -0
  740. package/src/domain/scriptdev/sunkenTemple.ts +736 -0
  741. package/src/domain/scriptdev/swampOfSorrows.ts +22 -0
  742. package/src/domain/scriptdev/tanaris.ts +391 -0
  743. package/src/domain/scriptdev/tanarisHelpers.ts +661 -0
  744. package/src/domain/scriptdev/teldrassil.ts +143 -0
  745. package/src/domain/scriptdev/templeOfAhnqiraj.ts +1013 -0
  746. package/src/domain/scriptdev/theBarrens.ts +709 -0
  747. package/src/domain/scriptdev/theBarrensHelpers.ts +1026 -0
  748. package/src/domain/scriptdev/thousandNeedles.ts +426 -0
  749. package/src/domain/scriptdev/thousandNeedlesHelpers.ts +566 -0
  750. package/src/domain/scriptdev/tirisfalGlades.ts +533 -0
  751. package/src/domain/scriptdev/types.ts +1026 -0
  752. package/src/domain/scriptdev/uldaman.ts +437 -0
  753. package/src/domain/scriptdev/ungoroCrater.ts +549 -0
  754. package/src/domain/scriptdev/ungoroCraterHelpers.ts +1006 -0
  755. package/src/domain/scriptdev/wailingCaverns.ts +700 -0
  756. package/src/domain/scriptdev/warEffort.ts +371 -0
  757. package/src/domain/scriptdev/westernPlaguelands.ts +952 -0
  758. package/src/domain/scriptdev/westfall.ts +767 -0
  759. package/src/domain/scriptdev/wetlands.ts +660 -0
  760. package/src/domain/scriptdev/winterspring.ts +482 -0
  761. package/src/domain/scriptdev/winterspringHelpers.ts +801 -0
  762. package/src/domain/scriptdev/worldBosses.ts +605 -0
  763. package/src/domain/scriptdev/zulfarrak.ts +478 -0
  764. package/src/domain/scriptdev/zulgurub.ts +1152 -0
  765. package/src/domain/sim/dummySim.ts +408 -0
  766. package/src/domain/sim/targetDummy.ts +29 -0
  767. package/src/domain/social/guild.ts +148 -0
  768. package/src/domain/spells/areaAuraMembership.ts +93 -0
  769. package/src/domain/spells/breakableStunCc.ts +166 -0
  770. package/src/domain/spells/cancelAura.ts +80 -0
  771. package/src/domain/spells/diminishing.ts +167 -0
  772. package/src/domain/spells/dispel.ts +149 -0
  773. package/src/domain/spells/dispelMechanic.ts +105 -0
  774. package/src/domain/spells/equipSpells.ts +247 -0
  775. package/src/domain/spells/learnOnTargets.ts +260 -0
  776. package/src/domain/spells/mergeSchoolImmunityFromRaw.ts +66 -0
  777. package/src/domain/spells/resurrectSpell.ts +124 -0
  778. package/src/domain/spells/spellPushback.ts +39 -0
  779. package/src/domain/spells/spellReflect.ts +43 -0
  780. package/src/domain/spells/stealth.ts +183 -0
  781. package/src/domain/spells/totem.ts +394 -0
  782. package/src/domain/spells/worldCast.ts +187 -0
  783. package/src/domain/world/areaTriggerLocks.ts +177 -0
  784. package/src/domain/world/dungeonMusic.ts +108 -0
  785. package/src/domain/world/gameEvents.ts +119 -0
  786. package/src/domain/world/gameObjects.ts +1030 -0
  787. package/src/domain/world/goEventFire.ts +234 -0
  788. package/src/domain/world/goMoTransport.ts +74 -0
  789. package/src/domain/world/goTransport.ts +81 -0
  790. package/src/domain/world/hazards.ts +459 -0
  791. package/src/domain/world/openLock.ts +398 -0
  792. package/src/domain/world/pools.ts +470 -0
  793. package/src/domain/world/restArea.ts +37 -0
  794. package/src/domain/world/weather.ts +201 -0
  795. package/src/domain/zoneAmbience.mjs +87 -0
  796. package/src/domain/zoneMusic.mjs +62 -0
  797. package/src/domain/zoneMusicQueue.mjs +7 -0
  798. package/src/engine/combat/activeSeal.ts +39 -0
  799. package/src/engine/combat/aiTargetResolve.ts +64 -0
  800. package/src/engine/combat/aoeCast.ts +289 -0
  801. package/src/engine/combat/applyConsumeAura.ts +74 -0
  802. package/src/engine/combat/applyDemonicSacrifice.ts +70 -0
  803. package/src/engine/combat/applyDispelMechanic.ts +30 -0
  804. package/src/engine/combat/applyHealEffect.ts +301 -0
  805. package/src/engine/combat/applySchoolAbsorb.ts +114 -0
  806. package/src/engine/combat/applySpell.ts +3169 -0
  807. package/src/engine/combat/applySpellLate.ts +2026 -0
  808. package/src/engine/combat/applySpellLateBag.ts +144 -0
  809. package/src/engine/combat/areaAura.ts +283 -0
  810. package/src/engine/combat/attackTable.ts +508 -0
  811. package/src/engine/combat/battleRez.ts +87 -0
  812. package/src/engine/combat/castAction.ts +36 -0
  813. package/src/engine/combat/castTargetGates.ts +75 -0
  814. package/src/engine/combat/castableKit.ts +68 -0
  815. package/src/engine/combat/ccMirrorUpgrade.ts +39 -0
  816. package/src/engine/combat/chainFan.ts +210 -0
  817. package/src/engine/combat/channel.ts +423 -0
  818. package/src/engine/combat/chaseCloseness.ts +95 -0
  819. package/src/engine/combat/cmangosCastGates.ts +129 -0
  820. package/src/engine/combat/combatFlag.ts +77 -0
  821. package/src/engine/combat/combatGeometry.ts +1329 -0
  822. package/src/engine/combat/combustion.ts +68 -0
  823. package/src/engine/combat/context.ts +730 -0
  824. package/src/engine/combat/createSession.ts +1165 -0
  825. package/src/engine/combat/creatureLeash.ts +38 -0
  826. package/src/engine/combat/crowdControl.ts +1259 -0
  827. package/src/engine/combat/dispelDuty.ts +54 -0
  828. package/src/engine/combat/dispelReflect.ts +609 -0
  829. package/src/engine/combat/displaceFloor.ts +113 -0
  830. package/src/engine/combat/duelBounds.ts +47 -0
  831. package/src/engine/combat/equippedItemGate.ts +297 -0
  832. package/src/engine/combat/evadeLifecycle.ts +63 -0
  833. package/src/engine/combat/eventAi.ts +2220 -0
  834. package/src/engine/combat/facing.ts +74 -0
  835. package/src/engine/combat/fearFlee.ts +137 -0
  836. package/src/engine/combat/fighterFactory.ts +1144 -0
  837. package/src/engine/combat/forceDespawnAction.ts +51 -0
  838. package/src/engine/combat/formulas.ts +807 -0
  839. package/src/engine/combat/friendlyFan.ts +55 -0
  840. package/src/engine/combat/groundPoolTick.ts +210 -0
  841. package/src/engine/combat/hazards.ts +114 -0
  842. package/src/engine/combat/healTargets.ts +226 -0
  843. package/src/engine/combat/heartbeatResist.ts +49 -0
  844. package/src/engine/combat/hostileItemUse.ts +75 -0
  845. package/src/engine/combat/interruptAuras.ts +66 -0
  846. package/src/engine/combat/itemRescue.ts +49 -0
  847. package/src/engine/combat/itemUse.ts +260 -0
  848. package/src/engine/combat/kitById.ts +23 -0
  849. package/src/engine/combat/knockBack.ts +201 -0
  850. package/src/engine/combat/leap.ts +89 -0
  851. package/src/engine/combat/mitigation.ts +587 -0
  852. package/src/engine/combat/modTaunt.ts +43 -0
  853. package/src/engine/combat/motionClaim.ts +268 -0
  854. package/src/engine/combat/motionGate.ts +150 -0
  855. package/src/engine/combat/motionGenerator.ts +27 -0
  856. package/src/engine/combat/navSight.ts +138 -0
  857. package/src/engine/combat/perfSink.ts +28 -0
  858. package/src/engine/combat/periodicDue.ts +55 -0
  859. package/src/engine/combat/petAuras.ts +86 -0
  860. package/src/engine/combat/pickAction.ts +3449 -0
  861. package/src/engine/combat/powerForm.ts +735 -0
  862. package/src/engine/combat/powerPools.ts +49 -0
  863. package/src/engine/combat/predicates.ts +538 -0
  864. package/src/engine/combat/procsDamage.ts +1823 -0
  865. package/src/engine/combat/reactiveGates.ts +135 -0
  866. package/src/engine/combat/roles.ts +389 -0
  867. package/src/engine/combat/rotationSubject.ts +78 -0
  868. package/src/engine/combat/ruleAfter.ts +106 -0
  869. package/src/engine/combat/seedDisplayAuras.ts +203 -0
  870. package/src/engine/combat/seedOocEffects.ts +317 -0
  871. package/src/engine/combat/seedSchoolImmunities.ts +45 -0
  872. package/src/engine/combat/session-types.ts +458 -0
  873. package/src/engine/combat/sessionApi.ts +1785 -0
  874. package/src/engine/combat/sessionCharge.ts +124 -0
  875. package/src/engine/combat/sessionChase.ts +869 -0
  876. package/src/engine/combat/sessionDeaths.ts +469 -0
  877. package/src/engine/combat/sessionFocus.ts +506 -0
  878. package/src/engine/combat/sessionFollow.ts +167 -0
  879. package/src/engine/combat/sessionGeometry.ts +188 -0
  880. package/src/engine/combat/sessionHome.ts +75 -0
  881. package/src/engine/combat/sessionInject.ts +719 -0
  882. package/src/engine/combat/sessionMechanicMove.ts +555 -0
  883. package/src/engine/combat/sessionMotion.ts +1553 -0
  884. package/src/engine/combat/sessionMotionKit.ts +247 -0
  885. package/src/engine/combat/sessionMoveIntent.ts +49 -0
  886. package/src/engine/combat/sessionMoveOrder.ts +200 -0
  887. package/src/engine/combat/sessionPathTo.ts +657 -0
  888. package/src/engine/combat/sessionPools.ts +688 -0
  889. package/src/engine/combat/sessionSteer.ts +144 -0
  890. package/src/engine/combat/sessionStepBack.ts +151 -0
  891. package/src/engine/combat/sessionStepWrap.ts +116 -0
  892. package/src/engine/combat/sessionView.ts +442 -0
  893. package/src/engine/combat/simEffects.ts +32 -0
  894. package/src/engine/combat/simFacade.ts +620 -0
  895. package/src/engine/combat/simPump.ts +264 -0
  896. package/src/engine/combat/simSnapshot.ts +165 -0
  897. package/src/engine/combat/simThreadPool.ts +35 -0
  898. package/src/engine/combat/skeramImages.ts +57 -0
  899. package/src/engine/combat/slowUpdate.ts +178 -0
  900. package/src/engine/combat/snapToFloor.ts +42 -0
  901. package/src/engine/combat/speedAura.ts +29 -0
  902. package/src/engine/combat/spellReagents.ts +71 -0
  903. package/src/engine/combat/stealthDetect.ts +93 -0
  904. package/src/engine/combat/stepBackMotion.ts +171 -0
  905. package/src/engine/combat/stepSession.ts +3102 -0
  906. package/src/engine/combat/summonCast.ts +243 -0
  907. package/src/engine/combat/thaddiusPolarity.ts +97 -0
  908. package/src/engine/combat/threat.ts +388 -0
  909. package/src/engine/combat/threatOps.ts +272 -0
  910. package/src/engine/combat/tickWorkerBody.ts +211 -0
  911. package/src/engine/combat/totemAuras.ts +122 -0
  912. package/src/engine/combat/triggerPayload.ts +42 -0
  913. package/src/engine/combat/triggeredCompanion.ts +63 -0
  914. package/src/engine/combat/types.ts +1897 -0
  915. package/src/engine/combat/useObjectTrap.ts +140 -0
  916. package/src/engine/combat/walkSurface.ts +54 -0
  917. package/src/engine/combat/weapon.ts +1248 -0
  918. package/src/engine/combat/worldFrame.ts +43 -0
  919. package/src/engine/combat.solo-golden.json +2242 -0
  920. package/src/engine/combat.ts +84 -0
  921. package/src/engine/core/detMath.ts +289 -0
  922. package/src/engine/core/events.ts +357 -0
  923. package/src/engine/core/rng.ts +36 -0
  924. package/src/engine/game/actionBars.ts +124 -0
  925. package/src/engine/game/activateObjectFromSpell.ts +320 -0
  926. package/src/engine/game/applyActiveObjectFromDbScript.ts +98 -0
  927. package/src/engine/game/applyDeathAndSpellScripts.ts +268 -0
  928. package/src/engine/game/applyDoorFromDbScript.ts +388 -0
  929. package/src/engine/game/applyEscortFromDbScript.ts +290 -0
  930. package/src/engine/game/applyGoSpellcasterCast.ts +40 -0
  931. package/src/engine/game/applyHoverFromDbScript.ts +110 -0
  932. package/src/engine/game/applyOocResurrect.ts +71 -0
  933. package/src/engine/game/applySpellDurability.ts +115 -0
  934. package/src/engine/game/applyTailFromDbScript.ts +478 -0
  935. package/src/engine/game/applyTerminateFromDbScript.ts +95 -0
  936. package/src/engine/game/auctionMail.ts +269 -0
  937. package/src/engine/game/bagOverflow.ts +130 -0
  938. package/src/engine/game/bank.ts +110 -0
  939. package/src/engine/game/barAutofill.ts +26 -0
  940. package/src/engine/game/battleground.ts +369 -0
  941. package/src/engine/game/combatEnemySpec.ts +216 -0
  942. package/src/engine/game/combatObjectTraps.ts +167 -0
  943. package/src/engine/game/combatSeed.ts +320 -0
  944. package/src/engine/game/combatSession.ts +3241 -0
  945. package/src/engine/game/combatSessionClock.ts +62 -0
  946. package/src/engine/game/companionQuestActions.ts +242 -0
  947. package/src/engine/game/companionTraining.ts +40 -0
  948. package/src/engine/game/consumables.ts +624 -0
  949. package/src/engine/game/context.ts +53 -0
  950. package/src/engine/game/createHealthstone.ts +45 -0
  951. package/src/engine/game/deathFlow.ts +127 -0
  952. package/src/engine/game/devGrant.ts +117 -0
  953. package/src/engine/game/dynamicObject.ts +365 -0
  954. package/src/engine/game/enchantItem.ts +177 -0
  955. package/src/engine/game/equipmentHelper.ts +806 -0
  956. package/src/engine/game/factionState.ts +108 -0
  957. package/src/engine/game/garmentsOoc.ts +69 -0
  958. package/src/engine/game/globalActionBar.ts +179 -0
  959. package/src/engine/game/goInteractQuestCredit.ts +51 -0
  960. package/src/engine/game/goMoTransportUse.ts +61 -0
  961. package/src/engine/game/goTransportUse.ts +60 -0
  962. package/src/engine/game/healthstoneUpkeep.ts +59 -0
  963. package/src/engine/game/killSkin.ts +124 -0
  964. package/src/engine/game/learnFromItem.ts +118 -0
  965. package/src/engine/game/loadReconcile.ts +551 -0
  966. package/src/engine/game/loot.ts +294 -0
  967. package/src/engine/game/macros.ts +125 -0
  968. package/src/engine/game/mail.ts +293 -0
  969. package/src/engine/game/meetingStoneQueue.ts +75 -0
  970. package/src/engine/game/meetingStoneUse.ts +54 -0
  971. package/src/engine/game/newGameState.ts +363 -0
  972. package/src/engine/game/oocAuraInterrupt.ts +92 -0
  973. package/src/engine/game/oocCast.ts +241 -0
  974. package/src/engine/game/oocCastEffects.ts +803 -0
  975. package/src/engine/game/oocCastMethods.ts +1077 -0
  976. package/src/engine/game/openLockFromSpell.ts +174 -0
  977. package/src/engine/game/outdoorPvp.ts +187 -0
  978. package/src/engine/game/outfitter.ts +644 -0
  979. package/src/engine/game/paladinBoard.ts +393 -0
  980. package/src/engine/game/partyAuras.ts +121 -0
  981. package/src/engine/game/persistCombatAuras.ts +91 -0
  982. package/src/engine/game/pets.ts +459 -0
  983. package/src/engine/game/prePullHealthstones.ts +154 -0
  984. package/src/engine/game/professions.ts +2227 -0
  985. package/src/engine/game/pruneStaleRuntime.ts +39 -0
  986. package/src/engine/game/questFightCredit.ts +36 -0
  987. package/src/engine/game/questItemOnCorpse.ts +166 -0
  988. package/src/engine/game/questItemOnCreature.ts +103 -0
  989. package/src/engine/game/questLog.ts +879 -0
  990. package/src/engine/game/questSpellComplete.ts +21 -0
  991. package/src/engine/game/questTurnIn.ts +598 -0
  992. package/src/engine/game/raidParty.ts +32 -0
  993. package/src/engine/game/reagentBuyIn.ts +39 -0
  994. package/src/engine/game/regenRest.ts +186 -0
  995. package/src/engine/game/rotation.ts +425 -0
  996. package/src/engine/game/runFullDungeon.ts +611 -0
  997. package/src/engine/game/runSupply.ts +80 -0
  998. package/src/engine/game/sanitizeDriftedItems.ts +135 -0
  999. package/src/engine/game/scriptDevGoUse.ts +397 -0
  1000. package/src/engine/game/scriptDevInnkeeper.ts +150 -0
  1001. package/src/engine/game/scriptDevProfessionSpec.ts +99 -0
  1002. package/src/engine/game/sendEventFromSpell.ts +87 -0
  1003. package/src/engine/game/sortContainers.ts +85 -0
  1004. package/src/engine/game/spellReputation.ts +69 -0
  1005. package/src/engine/game/squad/squadDungeonSeating.ts +197 -0
  1006. package/src/engine/game/squadDungeon.ts +4222 -0
  1007. package/src/engine/game/squadQuestShare.ts +260 -0
  1008. package/src/engine/game/summonObjectSlot.ts +69 -0
  1009. package/src/engine/game/summonObjectWild.ts +73 -0
  1010. package/src/engine/game/summoningRitualUse.ts +141 -0
  1011. package/src/engine/game/talents.ts +356 -0
  1012. package/src/engine/game/tamingRodUse.ts +66 -0
  1013. package/src/engine/game/tempSpawnCreature.ts +136 -0
  1014. package/src/engine/game/tickDungeonPatrolScripts.ts +205 -0
  1015. package/src/engine/game/tickTimedQuests.ts +28 -0
  1016. package/src/engine/game/trade.ts +586 -0
  1017. package/src/engine/game/travel.ts +1155 -0
  1018. package/src/engine/game/types.ts +1855 -0
  1019. package/src/engine/game/vendorOffers.ts +244 -0
  1020. package/src/engine/game/weaponImbueItem.ts +281 -0
  1021. package/src/engine/game/worldSession.ts +183 -0
  1022. package/src/engine/game/worldState.ts +166 -0
  1023. package/src/engine/game.ts +968 -0
  1024. package/src/engine/spells/GAP.md +67 -0
  1025. package/src/engine/spells/absorbs.ts +376 -0
  1026. package/src/engine/spells/addTargetTrigger.ts +53 -0
  1027. package/src/engine/spells/auraPerSecondCost.ts +50 -0
  1028. package/src/engine/spells/auraStacking.ts +497 -0
  1029. package/src/engine/spells/cmangos-special-cases-combustion.ts +13 -0
  1030. package/src/engine/spells/cmangos-special-cases-s18.ts +445 -0
  1031. package/src/engine/spells/cmangos-special-cases-s19.ts +324 -0
  1032. package/src/engine/spells/cmangos-special-cases-s20.ts +385 -0
  1033. package/src/engine/spells/cmangos-special-cases-s21.ts +116 -0
  1034. package/src/engine/spells/cmangos-special-cases-s22.ts +24 -0
  1035. package/src/engine/spells/cmangos-special-cases-s23.ts +52 -0
  1036. package/src/engine/spells/cmangos-special-cases.ts +1570 -0
  1037. package/src/engine/spells/conditions.ts +718 -0
  1038. package/src/engine/spells/effects.ts +203 -0
  1039. package/src/engine/spells/fixtures/oracle-effects-lock9a.json +1 -0
  1040. package/src/engine/spells/immunity.ts +942 -0
  1041. package/src/engine/spells/intentEffects.ts +351 -0
  1042. package/src/engine/spells/interpreter/GAPS.md +21 -0
  1043. package/src/engine/spells/interpreter/amount.ts +109 -0
  1044. package/src/engine/spells/interpreter/class-scripts-kit.ts +478 -0
  1045. package/src/engine/spells/interpreter/diff.ts +246 -0
  1046. package/src/engine/spells/interpreter/duration.ts +90 -0
  1047. package/src/engine/spells/interpreter/form-attrs.json +1 -0
  1048. package/src/engine/spells/interpreter/form-attrs.ts +95 -0
  1049. package/src/engine/spells/interpreter/handlers/aura-remove.ts +113 -0
  1050. package/src/engine/spells/interpreter/handlers/auras-control.ts +1547 -0
  1051. package/src/engine/spells/interpreter/handlers/auras-core.ts +1583 -0
  1052. package/src/engine/spells/interpreter/handlers/auras-misc.ts +1774 -0
  1053. package/src/engine/spells/interpreter/handlers/effect-disenchant.ts +17 -0
  1054. package/src/engine/spells/interpreter/handlers/effect-skinning.ts +20 -0
  1055. package/src/engine/spells/interpreter/handlers/effects-action-utility.ts +1455 -0
  1056. package/src/engine/spells/interpreter/handlers/effects-core.ts +432 -0
  1057. package/src/engine/spells/interpreter/handlers/effects-remainder.ts +105 -0
  1058. package/src/engine/spells/interpreter/handlers/effects-summon-item.ts +687 -0
  1059. package/src/engine/spells/interpreter/handlers/mod-increase-energy-percent.ts +36 -0
  1060. package/src/engine/spells/interpreter/handlers/mod-increase-energy.ts +36 -0
  1061. package/src/engine/spells/interpreter/handlers/periodic-trigger-zero.ts +327 -0
  1062. package/src/engine/spells/interpreter/handlers/procs.ts +131 -0
  1063. package/src/engine/spells/interpreter/handlers/registry.ts +975 -0
  1064. package/src/engine/spells/interpreter/handlers/shared.ts +667 -0
  1065. package/src/engine/spells/interpreter/handlers.ts +9 -0
  1066. package/src/engine/spells/interpreter/hunter-kit.ts +202 -0
  1067. package/src/engine/spells/interpreter/index.ts +525 -0
  1068. package/src/engine/spells/interpreter/item-triggers.ts +1121 -0
  1069. package/src/engine/spells/interpreter/lift-consume-energy.ts +37 -0
  1070. package/src/engine/spells/interpreter/mage-portals.ts +37 -0
  1071. package/src/engine/spells/interpreter/materialize-charm.ts +88 -0
  1072. package/src/engine/spells/interpreter/materialize-dispel-mechanic.ts +25 -0
  1073. package/src/engine/spells/interpreter/materialize-rating-buffs.ts +81 -0
  1074. package/src/engine/spells/interpreter/materialize-speed.ts +109 -0
  1075. package/src/engine/spells/interpreter/materialize-spell-magnet.ts +22 -0
  1076. package/src/engine/spells/interpreter/opcodes.ts +789 -0
  1077. package/src/engine/spells/interpreter/paladin-kit.ts +95 -0
  1078. package/src/engine/spells/interpreter/paladin-seals.ts +499 -0
  1079. package/src/engine/spells/interpreter/priest-warlock-kit.ts +135 -0
  1080. package/src/engine/spells/interpreter/proc.ts +443 -0
  1081. package/src/engine/spells/interpreter/registry/helpers.ts +16 -0
  1082. package/src/engine/spells/interpreter/registry/index.ts +216 -0
  1083. package/src/engine/spells/interpreter/registry/packs/class-abilities.ts +304 -0
  1084. package/src/engine/spells/interpreter/registry/packs/dire-maul.ts +44 -0
  1085. package/src/engine/spells/interpreter/registry/packs/dummy-script-tail.ts +1065 -0
  1086. package/src/engine/spells/interpreter/registry/packs/ex-wave-m.ts +70 -0
  1087. package/src/engine/spells/interpreter/registry/packs/life-tap.ts +107 -0
  1088. package/src/engine/spells/interpreter/registry/packs/paladin.ts +246 -0
  1089. package/src/engine/spells/interpreter/registry/packs/raid-script-summons.ts +26 -0
  1090. package/src/engine/spells/interpreter/registry/packs/raid-threat-wipe.ts +22 -0
  1091. package/src/engine/spells/interpreter/registry/packs/shaman.ts +214 -0
  1092. package/src/engine/spells/interpreter/registry/packs/si4-dummy-generic-a.ts +269 -0
  1093. package/src/engine/spells/interpreter/registry/packs/si4-dummy-generic-b.ts +370 -0
  1094. package/src/engine/spells/interpreter/registry/packs/si4-dummy-generic-c.ts +172 -0
  1095. package/src/engine/spells/interpreter/registry/packs/si4-dummy-hunter.ts +60 -0
  1096. package/src/engine/spells/interpreter/registry/packs/si4-dummy-warrior.ts +31 -0
  1097. package/src/engine/spells/interpreter/registry/packs/si4-script-generic-a.ts +114 -0
  1098. package/src/engine/spells/interpreter/registry/packs/si4-script-generic-b.ts +249 -0
  1099. package/src/engine/spells/interpreter/registry/packs/si4-script-generic-c.ts +233 -0
  1100. package/src/engine/spells/interpreter/registry/types.ts +48 -0
  1101. package/src/engine/spells/interpreter/talent-scripted.ts +329 -0
  1102. package/src/engine/spells/interpreter/targeting.ts +90 -0
  1103. package/src/engine/spells/interpreter/types-intent.ts +1501 -0
  1104. package/src/engine/spells/interpreter/types.ts +419 -0
  1105. package/src/engine/spells/interpreter/warrior-druid-kit.ts +314 -0
  1106. package/src/engine/spells/interpreter/weapon-imbue-kit.ts +384 -0
  1107. package/src/engine/spells/interrupt.ts +217 -0
  1108. package/src/engine/spells/meleeAttackReset.ts +60 -0
  1109. package/src/engine/spells/oocTriggerSpell.ts +49 -0
  1110. package/src/engine/spells/overrideClassScripts.ts +319 -0
  1111. package/src/engine/spells/parryHaste.ts +20 -0
  1112. package/src/engine/spells/procs.ts +300 -0
  1113. package/src/engine/spells/recovery.ts +203 -0
  1114. package/src/engine/spells/scriptTargetDest.ts +76 -0
  1115. package/src/engine/spells/scriptTargets.ts +85 -0
  1116. package/src/engine/spells/singleTargetAura.ts +82 -0
  1117. package/src/engine/spells/specialCasePayloads.ts +57 -0
  1118. package/src/engine/spells/spellAttributes.ts +249 -0
  1119. package/src/engine/spells/spellBonus.ts +143 -0
  1120. package/src/engine/spells/spellModIntents.ts +419 -0
  1121. package/src/engine/spells/spellMods.ts +283 -0
  1122. package/src/engine/spells/spellRadius.ts +15 -0
  1123. package/src/engine/spells/trapObjects.ts +26 -0
  1124. package/src/json.d.ts +7 -0
  1125. package/src/persistence/memoryRepository.ts +23 -0
  1126. package/src/persistence/saveBackups.ts +162 -0
  1127. package/src/persistence/saveFile.ts +68 -0
  1128. package/src/persistence/saveRepository.ts +11 -0
  1129. package/src/persistence/saveShape.ts +668 -0
  1130. package/src/progression/leveling.ts +89 -0
  1131. package/src/progression/rest.ts +1434 -0
  1132. package/src/progression/training.ts +226 -0
  1133. package/src/progression/xpGain.ts +369 -0
  1134. package/src/quests/quests.ts +1580 -0
  1135. package/src/world/aoePull.ts +198 -0
  1136. package/src/world/areaTableDbc.ts +39 -0
  1137. package/src/world/areaTableMapIdPairs.ts +141 -0
  1138. package/src/world/bakeSlug.ts +43 -0
  1139. package/src/world/continuousDungeon.ts +1250 -0
  1140. package/src/world/dungeonBakeProjection.ts +190 -0
  1141. package/src/world/dungeonMapDensity.ts +342 -0
  1142. package/src/world/dungeonMapProjection.ts +135 -0
  1143. package/src/world/dungeonNav.ts +904 -0
  1144. package/src/world/dungeonNpcSim.ts +147 -0
  1145. package/src/world/dungeonObjectives.ts +234 -0
  1146. package/src/world/dungeonPreset.ts +35 -0
  1147. package/src/world/dungeonRoute.ts +311 -0
  1148. package/src/world/dungeonRouteGeometry.ts +732 -0
  1149. package/src/world/dungeonRouteOrder.ts +1037 -0
  1150. package/src/world/dungeonWingRooms.ts +426 -0
  1151. package/src/world/escort.ts +296 -0
  1152. package/src/world/goPoolRoll.ts +75 -0
  1153. package/src/world/instanceObjects.ts +785 -0
  1154. package/src/world/instances.ts +1572 -0
  1155. package/src/world/meetingStones.ts +56 -0
  1156. package/src/world/navmeshFloors.ts +145 -0
  1157. package/src/world/nearGrid.ts +167 -0
  1158. package/src/world/packBudget.ts +613 -0
  1159. package/src/world/rareRoll.ts +335 -0
  1160. package/src/world/routeAuthoring.ts +132 -0
  1161. package/src/world/routeEdit.ts +209 -0
  1162. package/src/world/world.ts +812 -0
  1163. package/src/world/zoneHazards.ts +47 -0
@@ -0,0 +1,1150 @@
1
+ // Pure pet selectors: PetState plus DataStore into a combat-ready spec, with stats from
2
+ // pet_levelstats and loyalty, happiness and TP per Pet.cpp. Imported by game.ts, never the engine.
3
+
4
+ import type { DataStore } from '../../data/dataStore.ts';
5
+ import type { CreatureDef, ItemDef, PowerType, School, SpellDef } from '../../data/schema.ts';
6
+ import type { Character, PetState } from '../character/character.ts';
7
+ import { applyAura, getActiveBuffIds, maxHealth } from '../character/character.ts';
8
+ import { pruneExpiredAuras } from '../character/characterStats.ts';
9
+ import type { CombatantSpec } from '../../engine/combat.ts';
10
+ import type { Rng } from '../../engine/core/rng.ts';
11
+ import { TUNING } from '../../engine/combat/formulas.ts';
12
+ import { getDamageMod } from '../creature/creatureScaling.ts';
13
+ import { resolveCombatSpell } from '../../engine/spells/interpreter/item-triggers.ts';
14
+ import { racialSpells } from '../character/races.ts';
15
+ import { resolveSpellId, type SpellLookup } from '../character/spellbook.ts';
16
+
17
+ const BEAST = 1; // CreatureType: hunter-tameable beasts
18
+ const FOCUS_MAX = 100; // hunter pet Focus pool (SharedDefines POWER_FOCUS practice)
19
+ /** All hunter pets look up pet_levelstats creature_entry=1. Cite: Pet.cpp ~1263. */
20
+ export const HUNTER_PET_LEVELSTATS_ENTRY = 1;
21
+ /** Imp template entry — special AP formula (str-10). Cite: StatSystem.cpp ~905–908. */
22
+ const IMP_ENTRY = 416;
23
+
24
+ // ── Loyalty / happiness (CMaNGOS Pet.cpp) ───────────────────────────────────
25
+ /** REBELLIOUS=1 … BEST_FRIEND=6. Cite: Pet.cpp loyalty enum. */
26
+ export const LOYALTY_REBELLIOUS = 1;
27
+ export const LOYALTY_BEST_FRIEND = 6;
28
+ /** Points to exceed for loyalty level-up, index loyalty-1. Cite: Pet.cpp LevelUpLoyalty. */
29
+ export const LEVEL_UP_LOYALTY = [5500, 11500, 17000, 23500, 31000, 39500] as const;
30
+ /** Points set when entering a loyalty level, index loyalty-1. Cite: Pet.cpp LevelStartLoyalty. */
31
+ export const LEVEL_START_LOYALTY = [2000, 4500, 7000, 10000, 13500, 17500] as const;
32
+ /** Display names for loyalty 1..6. */
33
+ export const LOYALTY_NAMES = [
34
+ '', 'Rebellious', 'Unruly', 'Submissive', 'Dependable', 'Faithful', 'Best Friend',
35
+ ] as const;
36
+ // Happiness bar range. Vanilla stores POWER_HAPPINESS on a raw 0..1,050,000 scale; we mirror the
37
+ // client's ÷1000 display, so a feed is +35 a bite and a mood band is 333.
38
+ export const HAPPINESS_MAX = 1000;
39
+ // Raw UNIT_FIELD_POWER5 units per display point. Dismiss Pet 2641 drains 50000 raw → 50 display,
40
+ // "reduce its happiness by 50". Cite: Pet.h HAPPINESS_LEVEL_SIZE 333000.
41
+ export const HAPPINESS_RAW_PER_DISPLAY = 1000;
42
+ /** One mood band = HAPPINESS_LEVEL_SIZE (333000 raw ÷1000). Thresholds sit at 333 / 666. */
43
+ export const HAPPINESS_LEVEL_SIZE = 333;
44
+ /** Death happiness loss = one full band (−HAPPINESS_LEVEL_SIZE). Cite: Pet.cpp ~618. */
45
+ export const HAPPINESS_DEATH_LOSS = HAPPINESS_LEVEL_SIZE;
46
+ /** LooseHappiness period (seconds). Cite: Pet.cpp ~731. */
47
+ const HAPPINESS_DECAY_PERIOD_S = 7.5;
48
+ /** TickLoyaltyChange period (seconds). Cite: Pet.cpp ~839. */
49
+ const LOYALTY_TICK_PERIOD_S = 12;
50
+
51
+ // Happiness damage mult from Pet::GetConditionalTotalPhysicalDamageModifier. We store 0..1000, so
52
+ // the CMaNGOS 333k / 666k thresholds are 333 and 666. Cite: Pet.cpp GetHappinessState ~863.
53
+ export function happinessDamageMult(happiness: number): number {
54
+ const h = Math.max(0, Math.min(HAPPINESS_MAX, happiness));
55
+ if (h < HAPPINESS_LEVEL_SIZE) return 0.75; // UNHAPPY (< 333)
56
+ if (h >= HAPPINESS_LEVEL_SIZE * 2) return 1.25; // HAPPY (>= 666)
57
+ return 1.0; // CONTENT
58
+ }
59
+
60
+ /** GetHappinessState on the 0..1000 scale (thresholds 333 / 666). Cite: Pet.cpp GetHappinessState ~863. */
61
+ export function happinessState(happiness: number): 'unhappy' | 'content' | 'happy' {
62
+ const h = Math.max(0, Math.min(HAPPINESS_MAX, happiness));
63
+ if (h < HAPPINESS_LEVEL_SIZE) return 'unhappy';
64
+ if (h >= HAPPINESS_LEVEL_SIZE * 2) return 'happy';
65
+ return 'content';
66
+ }
67
+
68
+ /** Whether this pet uses happiness (hunter beasts). Warlock demons do not. */
69
+ export function petHasHappiness(cdef: CreatureDef): boolean {
70
+ return cdef.creatureType === BEAST || !!cdef.tameable;
71
+ }
72
+
73
+ // Apply POWER_DRAIN with POWER_HAPPINESS to a pet's display-scale bar, as ModifyPower does before
74
+ // EffectDismissPet unsummons. Amounts arrive already ÷1000. Cite: SpellEffects.cpp:1750.
75
+ export function applyPetHappinessPowerDrains(
76
+ pet: PetState,
77
+ effects: ReadonlyArray<{ kind: string; powerType?: number; min?: number; max?: number }>,
78
+ ): PetState {
79
+ let h = pet.happiness;
80
+ let changed = false;
81
+ for (const e of effects) {
82
+ if (e.kind !== 'power_drain' || ((e.powerType ?? 0) | 0) !== 4) continue;
83
+ // Fixed DBC range (min==max for 2641); take max of the rolled range.
84
+ const amount = Math.max(0, Math.trunc(Math.max(e.min ?? 0, e.max ?? 0)));
85
+ if (amount <= 0) continue;
86
+ h = Math.max(0, Math.min(HAPPINESS_MAX, h - amount));
87
+ changed = true;
88
+ }
89
+ return changed ? { ...pet, happiness: h } : pet;
90
+ }
91
+
92
+ // LooseHappiness on the ÷1000 scale: (140>>loyalty)*0.125 per 7.5s; ×1.5 in combat. Cite: Pet.cpp
93
+ // LooseHappiness ~731 ((140>>L)*125 raw ÷1000).
94
+ export function decayHappiness(
95
+ happiness: number,
96
+ loyalty: number,
97
+ seconds: number,
98
+ inCombat: boolean,
99
+ ): number {
100
+ if (seconds <= 0) return Math.max(0, Math.min(HAPPINESS_MAX, happiness));
101
+ const L = Math.max(LOYALTY_REBELLIOUS, Math.min(LOYALTY_BEST_FRIEND, loyalty | 0));
102
+ // Per 7.5s on the ÷1000 scale: (140 >> L) * 125 / 1000 = (140 >> L) * 0.125
103
+ let perPeriod = (140 >> L) * 0.125;
104
+ if (inCombat) perPeriod *= 1.5;
105
+ const loss = (perPeriod / HAPPINESS_DECAY_PERIOD_S) * seconds;
106
+ return Math.max(0, Math.min(HAPPINESS_MAX, happiness - loss));
107
+ }
108
+
109
+ // Owner XP required to clear the loyalty level-up gate: GetXPForLevel * 5/100. Returns undefined when the
110
+ // XP table has no row (do not invent). Cite: Pet.cpp ~742.
111
+ export function loyaltyXpForOwnerLevel(ownerLevel: number, ds: DataStore): number | undefined {
112
+ const xp = ds.xpToNext(ownerLevel);
113
+ if (!Number.isFinite(xp)) return undefined;
114
+ return Math.floor((xp * 5) / 100);
115
+ }
116
+
117
+ /** KillLoyaltyBonus(level): ((100-level)/10) + (6-loyalty), integer. Cite: Pet.cpp ~853. */
118
+ export function killLoyaltyBonus(petLevel: number, loyalty: number): number {
119
+ const level = Math.max(1, Math.min(100, petLevel | 0));
120
+ const L = Math.max(LOYALTY_REBELLIOUS, Math.min(LOYALTY_BEST_FRIEND, loyalty | 0));
121
+ return Math.floor((100 - level) / 10) + (6 - L);
122
+ }
123
+
124
+ // ModifyLoyalty: add points, then level up or down with TP ± petLevel and a start-points reset.
125
+ // Rebellion clamps points at 0 — there is no abandon AI. Cite: Pet.cpp ~766.
126
+ export function modifyLoyalty(
127
+ pet: PetState,
128
+ delta: number,
129
+ petLevel: number,
130
+ ownerXpForLevel?: number,
131
+ ): PetState {
132
+ let loyalty = Math.max(LOYALTY_REBELLIOUS, Math.min(LOYALTY_BEST_FRIEND, (pet.loyalty ?? LOYALTY_REBELLIOUS) | 0));
133
+ let points = (pet.loyaltyPoints ?? 0) + delta;
134
+ let tp = pet.trainingPoints ?? 0;
135
+ let xpReq = pet.loyaltyXpRequired;
136
+
137
+ const setRequiredXp = (): number | undefined => {
138
+ if (ownerXpForLevel != null && Number.isFinite(ownerXpForLevel)) {
139
+ return Math.floor((ownerXpForLevel * 5) / 100);
140
+ }
141
+ return 0; // table missing: do not invent XP; unlock gate so points-only progress still works
142
+ };
143
+
144
+ if (points < 0) {
145
+ if (loyalty > LOYALTY_REBELLIOUS) {
146
+ loyalty -= 1;
147
+ points = LEVEL_START_LOYALTY[loyalty - 1]!;
148
+ tp = tp - petLevel; // SetTP is signed — tame debt persists. Cite: Pet.cpp:788/:976.
149
+ xpReq = setRequiredXp();
150
+ } else {
151
+ // Minimal rebellion: clamp at 0; full abandon/aggressive AI is out of scope.
152
+ points = 0;
153
+ }
154
+ } else if (
155
+ loyalty < LOYALTY_BEST_FRIEND
156
+ && points > LEVEL_UP_LOYALTY[loyalty - 1]!
157
+ && (xpReq ?? 0) <= 0
158
+ ) {
159
+ loyalty += 1;
160
+ points = LEVEL_START_LOYALTY[loyalty - 1]!;
161
+ tp = tp + petLevel;
162
+ xpReq = setRequiredXp();
163
+ }
164
+
165
+ return {
166
+ ...pet,
167
+ loyalty,
168
+ loyaltyPoints: points,
169
+ trainingPoints: tp,
170
+ loyaltyXpRequired: xpReq,
171
+ };
172
+ }
173
+
174
+ // TickLoyaltyChange over `seconds` (out-of-combat regen). Amount per 12s from happiness state: HAPPY +20,
175
+ // CONTENT +10, UNHAPPY −20. Fractional ticks: amount * seconds/12. Cite: Pet.cpp TickLoyaltyChange ~839.
176
+ export function tickLoyalty(
177
+ pet: PetState,
178
+ seconds: number,
179
+ petLevel: number,
180
+ ownerXpForLevel?: number,
181
+ ): PetState {
182
+ if (seconds <= 0) return pet;
183
+ const st = happinessState(pet.happiness);
184
+ const perTick = st === 'happy' ? 20 : st === 'content' ? 10 : -20;
185
+ const delta = (perTick * seconds) / LOYALTY_TICK_PERIOD_S;
186
+ return modifyLoyalty(pet, delta, petLevel, ownerXpForLevel);
187
+ }
188
+
189
+ // Apply kill XP toward the loyalty-XP gate, then KillLoyaltyBonus. Cite: Pet.cpp GivePetXP ~1087;
190
+ // UpdateRequireXpForNextLoyaltyLevel ~758.
191
+ export function applyKillLoyalty(
192
+ pet: PetState,
193
+ killXp: number,
194
+ petLevel: number,
195
+ ownerXpForLevel?: number,
196
+ ): PetState {
197
+ const xp = Math.max(0, Math.round(killXp));
198
+ const req = Math.max(0, (pet.loyaltyXpRequired ?? 0) - xp);
199
+ const withXp: PetState = { ...pet, loyaltyXpRequired: req };
200
+ const bonus = killLoyaltyBonus(petLevel, withXp.loyalty ?? LOYALTY_REBELLIOUS);
201
+ return modifyLoyalty(withXp, bonus, petLevel, ownerXpForLevel);
202
+ }
203
+
204
+ // GetTPForSpell: basetrainp − max already-spent TP in the same name chain. Cite: Pet.cpp GetTPForSpell
205
+ // ~916.
206
+ export function tpForSpell(spellId: number, knownPetSpellIds: readonly number[], ds: DataStore): number {
207
+ const base = ds.petAbilityTP(spellId);
208
+ if (base === 0) return 0;
209
+ const target = ds.spell(spellId);
210
+ if (!target) return base;
211
+ let spent = 0;
212
+ for (const id of knownPetSpellIds) {
213
+ const s = ds.spell(id);
214
+ if (!s || s.name !== target.name) continue;
215
+ const tp = ds.petAbilityTP(id);
216
+ if (tp > spent) spent = tp;
217
+ }
218
+ return base - spent;
219
+ }
220
+
221
+ // Cumulative TP a known set has consumed: the chain max per name, since GetTPForSpell charges
222
+ // base(rank) − spent(chain). Cite: Pet.cpp GetTPForSpell ~916; InitPetCreateSpells ~1990.
223
+ export function tpSpentOnKnown(ids: readonly number[], ds: DataStore): number {
224
+ const byName = new Map<string, number>();
225
+ for (const id of ids) {
226
+ const tp = ds.petAbilityTP(id);
227
+ if (tp <= 0) continue;
228
+ const name = ds.spell(id)?.name ?? `#${id}`;
229
+ if (tp > (byName.get(name) ?? 0)) byName.set(name, tp);
230
+ }
231
+ let sum = 0;
232
+ for (const v of byName.values()) sum += v;
233
+ return sum;
234
+ }
235
+
236
+ // True when `repertoire` already holds `spellId` or its LEARN_PET_SPELL / LEARN_SPELL live rank.
237
+ // CheckLearning rolls urand(0,100) < 10 per pet cast for the owner to learn it. Cite: Pet.cpp:2001.
238
+ export function petRepertoireHas(
239
+ repertoire: readonly number[],
240
+ spellId: number,
241
+ ds: SpellLookup,
242
+ ): boolean {
243
+ const live = resolveSpellId(spellId, ds);
244
+ return repertoire.some((id) => id === spellId || id === live || resolveSpellId(id, ds) === live);
245
+ }
246
+
247
+ export function checkPetLearning(
248
+ pet: PetState,
249
+ repertoire: readonly number[],
250
+ petCastIds: readonly number[],
251
+ rng: Rng,
252
+ ds: DataStore,
253
+ ): { pet: PetState; learnedIds: number[] } {
254
+ const queue = pet.teachSpells;
255
+ if (!queue || queue.length === 0 || petCastIds.length === 0) return { pet, learnedIds: [] };
256
+ const remaining = [...queue];
257
+ const known = new Set(repertoire);
258
+ const learnedIds: number[] = [];
259
+ for (const cast of petCastIds) {
260
+ const live = resolveSpellId(cast, ds);
261
+ const i = remaining.findIndex((id) => id === cast || resolveSpellId(id, ds) === live);
262
+ if (i < 0) continue;
263
+ if (known.has(cast) || known.has(live) || petRepertoireHas([...known], live, ds)) {
264
+ remaining.splice(i, 1);
265
+ continue;
266
+ }
267
+ if (rng.int(0, 100) >= 10) continue;
268
+ remaining.splice(i, 1);
269
+ known.add(live);
270
+ if (ds.spell(live)) learnedIds.push(live);
271
+ }
272
+ if (remaining.length === queue.length) return { pet, learnedIds };
273
+ return {
274
+ pet: { ...pet, teachSpells: remaining.length ? remaining : undefined },
275
+ learnedIds,
276
+ };
277
+ }
278
+
279
+ // HasTPForSpell. Cite: Pet.cpp HasTPForSpell ~916. True when need==0 or (need>=0 and trainingPoints >=
280
+ // need).
281
+ export function hasTpForSpell(
282
+ pet: PetState,
283
+ spellId: number,
284
+ knownPetSpellIds: readonly number[],
285
+ ds: DataStore,
286
+ ): boolean {
287
+ const need = tpForSpell(spellId, knownPetSpellIds, ds);
288
+ return !(((pet.trainingPoints ?? 0) - need < 0 || need < 0) && need !== 0);
289
+ }
290
+
291
+ // SPELL_EFFECT_LEARN_PET_SPELL (57): SetTP(GetTPForSpell) then store the live rank in petSpells. Cite:
292
+ // SpellEffects.cpp:3386–3404 EffectLearnPetSpell; Pet.cpp GetTPForSpell ~916.
293
+ export function applyLearnPetSpellCast(
294
+ char: Character,
295
+ spellId: number,
296
+ ds: DataStore,
297
+ ): { ok: true; char: Character; needTp: number; spell: SpellDef; liveId: number } | { ok: false; reason: string } {
298
+ const pet = char.pet;
299
+ if (!pet) return { ok: false, reason: 'You have no pet' };
300
+ if (pet.health <= 0) return { ok: false, reason: 'Your pet is dead' };
301
+ const liveId = resolveSpellId(spellId, ds);
302
+ const spell = ds.spell(liveId);
303
+ if (!spell) return { ok: false, reason: 'Unknown ability' };
304
+
305
+ const known = char.petSpells ?? [];
306
+ if (petRepertoireHas(known, liveId, ds)) {
307
+ return { ok: true, char, needTp: 0, spell, liveId };
308
+ }
309
+
310
+ const petDef = ds.creature(pet.creature);
311
+ const taught = petDef ? petTaughtIds(char, petDef) : known;
312
+ const needTp = tpForSpell(liveId, taught, ds);
313
+ return {
314
+ ok: true,
315
+ needTp,
316
+ spell,
317
+ liveId,
318
+ char: {
319
+ ...char,
320
+ pet: {
321
+ ...pet,
322
+ // Signed like SetTP — a 0-clamp would erase innate tame debt on a free teach.
323
+ trainingPoints: (pet.trainingPoints ?? 0) - needTp,
324
+ },
325
+ petSpells: [...known, liveId],
326
+ },
327
+ };
328
+ }
329
+
330
+ /** FoodType display names, index foodType-1. Cite: SharedDefines.h PetDiet / item FoodType. */
331
+ export const FOOD_TYPE_NAMES = [
332
+ 'Meat', 'Fish', 'Cheese', 'Bread', 'Fungus', 'Fruit', 'Raw Meat', 'Raw Fish',
333
+ ] as const;
334
+
335
+ // Anything a pet could conceivably be fed: the canonical item_template.FoodType marker (enrich-pet-diet),
336
+ // with the legacy consumable shape as fixture/seed fallback.
337
+ export function isPetFood(itemDef: ItemDef): boolean {
338
+ return (itemDef.foodType ?? 0) > 0 || itemDef.consumable?.effect === 'food';
339
+ }
340
+
341
+ // HaveInDiet: family PetFoodMask & (1<<(FoodType-1)). Cite: Pet.cpp HaveInDiet ~1424. When the creature has
342
+ // no baked mask (fixtures / pre-diet bakes), any pet food passes.
343
+ export function petDiet(cdef: CreatureDef, itemDef: ItemDef): boolean {
344
+ const mask = cdef.petFoodMask;
345
+ if (mask != null && mask > 0) {
346
+ const ft = itemDef.foodType ?? 0;
347
+ return ft > 0 && (mask & (1 << (ft - 1))) !== 0;
348
+ }
349
+ return isPetFood(itemDef);
350
+ }
351
+
352
+ /** The food-type names a pet's family eats (["Meat", "Fish"]), for the Feed UI. */
353
+ export function petDietNames(cdef: CreatureDef): string[] {
354
+ const mask = cdef.petFoodMask ?? 0;
355
+ if (mask <= 0) return [];
356
+ return FOOD_TYPE_NAMES.filter((_, i) => (mask & (1 << i)) !== 0);
357
+ }
358
+
359
+ // GetCurrentFoodBenefitLevel on the ÷1000 scale (35000/17000/8000 → 35/17/8) — the PER-TICK (per-bite)
360
+ // happiness a feeding energizes. Cite: Pet.cpp GetCurrentFoodBenefitLevel ~1442.
361
+ export function foodBenefit(petLevel: number, foodItemLevel: number): number {
362
+ if (petLevel <= foodItemLevel + 5) return 35;
363
+ if (petLevel <= foodItemLevel + 10) return 17;
364
+ if (petLevel <= foodItemLevel + 14) return 8;
365
+ return 0;
366
+ }
367
+
368
+ // Feed Pet 1539 ticks: 20000 ms duration over a 2000 ms amplitude, energizing happiness by the
369
+ // food benefit each tick. Cite: SpellEffects.cpp EffectFeedPet ~4699; spell_template 1539.
370
+ export const FEED_PET_TICKS = 10;
371
+ /** The eat lasts 20s; PetState.feedRemaining is absorbed at gain/20 per second OOC. */
372
+ export const FEED_PET_DURATION_S = 20;
373
+
374
+ /** Total happiness one feeding restores (350 / 170 / 80 = per-bite benefit × 10 bites). */
375
+ export function feedPetHappinessGain(petLevel: number, foodItemLevel: number): number {
376
+ return foodBenefit(petLevel, foodItemLevel) * FEED_PET_TICKS;
377
+ }
378
+
379
+ // Auto-feed tops happiness back up to this level. A feeding restores exactly `gain`, so we hold
380
+ // off until happiness has dropped by that much and the food lands with no overcap waste.
381
+ export const AUTO_FEED_TARGET = 980;
382
+
383
+ // The happiness at or below which auto-feed should fire for a food worth `gain`: target − gain,
384
+ // clamped to [0, target]. The "should I fire" decision lives in game.ts.
385
+ export function autoFeedThreshold(gain: number, target = AUTO_FEED_TARGET): number {
386
+ if (gain <= 0) return 0;
387
+ return Math.max(0, Math.min(target, target - gain));
388
+ }
389
+
390
+ // Absorb an in-progress feeding over `seconds`, returning the pet unchanged when it is not eating.
391
+ // Eating is OOC-only: spell 1539's AuraInterruptFlags cancel it, and game.ts clears the fields.
392
+ export function tickFeeding(pet: PetState, seconds: number): PetState {
393
+ const rem = pet.feedRemaining ?? 0;
394
+ if (rem <= 0 || seconds <= 0) return pet;
395
+ const perSec = pet.feedPerSec ?? rem / FEED_PET_DURATION_S;
396
+ const eaten = Math.min(rem, perSec * seconds);
397
+ const left = rem - eaten;
398
+ return {
399
+ ...pet,
400
+ happiness: Math.min(HAPPINESS_MAX, pet.happiness + eaten),
401
+ feedRemaining: left > 1e-9 ? left : undefined,
402
+ feedPerSec: left > 1e-9 ? pet.feedPerSec : undefined,
403
+ };
404
+ }
405
+
406
+ // Sourced combat profile from Pet::InitStatsForLevel when pet_levelstats is present. Family scale
407
+ // is visual only, never applied to HP or damage. Cite: Pet.cpp InitStatsForLevel ~1199–1398.
408
+ export interface PetInitStats {
409
+ maxHealth: number;
410
+ armor: number;
411
+ /** Base weapon min (before happiness total mult). */
412
+ weaponMin: number;
413
+ weaponMax: number;
414
+ attackPower: number;
415
+ powerType: PowerType;
416
+ maxPower: number;
417
+ attackTimeMs: number;
418
+ /** pet_levelstats base stamina (sourced only) — the knee for stamina-buff HP folds. */
419
+ stamina?: number;
420
+ /** pet_levelstats intellect (for OCT mana regen / weapon skill bonuses). */
421
+ intellect?: number;
422
+ /** pet_levelstats spirit (for OCTRegenMPPerSpirit mana regen). */
423
+ spirit?: number;
424
+ /** creature UnitClass / classId for OCTRegenMPPerSpirit. */
425
+ classId?: number;
426
+ /** True when numbers came from pet_levelstats + InitStats formulas. */
427
+ sourced: boolean;
428
+ }
429
+
430
+ // Melee AP for hunter/summon pets after create stats are set. Imp: str−10; all other pets: 2×str−20. Cite:
431
+ // StatSystem.cpp Pet::UpdateAttackPowerAndDamage ~905–908.
432
+ export function petMeleeAttackPower(strength: number, creatureEntry: number): number {
433
+ if (creatureEntry === IMP_ENTRY) return strength - 10;
434
+ return 2 * strength - 20;
435
+ }
436
+
437
+ // Hunter base weapon damage before AP layer / happiness. mDmg = (attackTimeMs * petlevel) / 2000; min =
438
+ // mDmg − mDmg/4; max = min×1.5. Cite: Pet.cpp ~1272–1277.
439
+ export function hunterPetBaseWeaponDamage(attackTimeMs: number, petLevel: number): { min: number; max: number } {
440
+ const mDmg = (attackTimeMs * petLevel) / 2000;
441
+ const min = mDmg - mDmg / 4;
442
+ return { min, max: min * 1.5 };
443
+ }
444
+
445
+ // Summon pet base weapon damage from CLS + template multipliers, or Min/Max template interp. Cite: Pet.cpp
446
+ // ~1312–1332.
447
+ export function summonPetBaseWeaponDamage(
448
+ cdef: CreatureDef,
449
+ petLevel: number,
450
+ ds: DataStore,
451
+ ): { min: number; max: number } {
452
+ const sc = cdef.scaling;
453
+ const unitClass = sc?.unitClass ?? 1;
454
+ const cls = ds.creatureClassLvlStats(petLevel, unitClass);
455
+ const atkMs = (sc?.meleeBaseAttackTime || cdef.attackTimeMs || 2000);
456
+ if (cls) {
457
+ const variance = sc?.damageVariance ?? 1;
458
+ const dmgMult = sc?.damageMultiplier ?? 1;
459
+ const rank = sc?.rank ?? 0;
460
+ let minDmg =
461
+ (cls.baseDamage * variance + (cls.baseMeleeAttackPower / 14) * (atkMs / 1000)) * dmgMult;
462
+ minDmg *= getDamageMod(rank);
463
+ return { min: minDmg, max: minDmg * 1.5 };
464
+ }
465
+ // Template fallback when CLS missing for UnitClass/level.
466
+ const minLevel = Math.max(1, sc?.minLevel ?? cdef.level ?? 1);
467
+ const maxLevel = Math.max(minLevel, sc?.maxLevel ?? cdef.level ?? minLevel);
468
+ const minMelee = sc?.minMeleeDmg ?? cdef.dmgMin;
469
+ const maxMelee = sc?.maxMeleeDmg ?? cdef.dmgMax;
470
+ const dMinLevel = minMelee / minLevel;
471
+ const dMaxLevel = maxMelee / maxLevel;
472
+ const mDmg = (dMaxLevel - (dMaxLevel - dMinLevel) / 2) * petLevel;
473
+ const min = mDmg - mDmg / 4;
474
+ return { min, max: min * 1.5 };
475
+ }
476
+
477
+ // Pet::InitStatsForLevel for the active owner level. Returns sourced stats when pet_levelstats is in the
478
+ // bundle; otherwise a legacy fallback (fixtures / pre-3A saves).
479
+ export function petInitStats(char: Character, cdef: CreatureDef, ds: DataStore): PetInitStats {
480
+ const petLevel = Math.max(1, Math.min(60, char.level | 0));
481
+ const attackTimeMs = (cdef.attackTimeMs || cdef.scaling?.meleeBaseAttackTime || 2000);
482
+ const hunter = petHasHappiness(cdef);
483
+
484
+ if (hunter) {
485
+ const info = ds.petLevelStats(HUNTER_PET_LEVELSTATS_ENTRY, petLevel);
486
+ if (info) {
487
+ const wpn = hunterPetBaseWeaponDamage(attackTimeMs, petLevel);
488
+ const ap = petMeleeAttackPower(info.str, HUNTER_PET_LEVELSTATS_ENTRY);
489
+ return {
490
+ maxHealth: Math.max(1, info.hp),
491
+ armor: info.armor,
492
+ weaponMin: wpn.min,
493
+ weaponMax: wpn.max,
494
+ attackPower: Math.max(0, ap),
495
+ powerType: 'focus',
496
+ maxPower: FOCUS_MAX,
497
+ attackTimeMs,
498
+ stamina: info.sta,
499
+ intellect: info.inte,
500
+ spirit: info.spi,
501
+ classId: cdef.scaling?.unitClass ?? 1,
502
+ sourced: true,
503
+ };
504
+ }
505
+ } else {
506
+ // SUMMON_PET path — warlock demons etc. Cite: Pet.cpp ~1297–1350.
507
+ const info = ds.petLevelStats(cdef.entry, petLevel);
508
+ if (info) {
509
+ const wpn = summonPetBaseWeaponDamage(cdef, petLevel, ds);
510
+ const ap = petMeleeAttackPower(info.str, cdef.entry);
511
+ const mana = Math.max(0, info.mana);
512
+ return {
513
+ maxHealth: Math.max(1, info.hp),
514
+ armor: info.armor,
515
+ weaponMin: wpn.min,
516
+ weaponMax: wpn.max,
517
+ attackPower: Math.max(0, ap),
518
+ powerType: mana > 0 ? 'mana' : (cdef.creatureType === BEAST || cdef.tameable ? 'focus' : 'mana'),
519
+ maxPower: mana > 0 ? mana : (cdef.creatureType === BEAST || cdef.tameable ? FOCUS_MAX : 0),
520
+ attackTimeMs,
521
+ stamina: info.sta,
522
+ intellect: info.inte,
523
+ spirit: info.spi,
524
+ classId: cdef.scaling?.unitClass ?? (mana > 0 ? 8 : 1),
525
+ sourced: true,
526
+ };
527
+ }
528
+ }
529
+
530
+ // Legacy fallback when pet_levelstats absent (fixtures / pre-enrich bakes).
531
+ // Do not invent DB rows — keep prior owner-fraction + template dmg behaviour.
532
+ return legacyPetInitStats(char, cdef, ds, attackTimeMs);
533
+ }
534
+
535
+ function legacyPetInitStats(
536
+ char: Character,
537
+ cdef: CreatureDef,
538
+ ds: DataStore,
539
+ attackTimeMs: number,
540
+ ): PetInitStats {
541
+ const maxHp = Math.max(1, Math.round(maxHealth(char, ds) * TUNING.petHealthFrac));
542
+ const hunter = petHasHappiness(cdef);
543
+ if (cdef.mana && cdef.mana > 0) {
544
+ const maxPower = cdef.mana + Math.max(0, char.level - 1) * TUNING.petManaPerLevel;
545
+ return {
546
+ maxHealth: maxHp,
547
+ armor: cdef.armor,
548
+ weaponMin: cdef.dmgMin,
549
+ weaponMax: cdef.dmgMax,
550
+ attackPower: 0,
551
+ powerType: 'mana',
552
+ maxPower,
553
+ attackTimeMs,
554
+ intellect: 20,
555
+ spirit: 20,
556
+ classId: cdef.scaling?.unitClass ?? 8,
557
+ sourced: false,
558
+ };
559
+ }
560
+ if (hunter) {
561
+ return {
562
+ maxHealth: maxHp,
563
+ armor: cdef.armor,
564
+ weaponMin: cdef.dmgMin,
565
+ weaponMax: cdef.dmgMax,
566
+ attackPower: 0,
567
+ powerType: 'focus',
568
+ maxPower: FOCUS_MAX,
569
+ attackTimeMs,
570
+ sourced: false,
571
+ };
572
+ }
573
+ return {
574
+ maxHealth: maxHp,
575
+ armor: cdef.armor,
576
+ weaponMin: cdef.dmgMin,
577
+ weaponMax: cdef.dmgMax,
578
+ attackPower: 0,
579
+ powerType: 'mana',
580
+ maxPower: 0,
581
+ attackTimeMs,
582
+ sourced: false,
583
+ };
584
+ }
585
+
586
+ // A pet's maximum health for OOC clamp and heal paths: InitStats create HP plus family and taught
587
+ // passives. Without the fold, Call Pet clipped a trained pet to base HP (KI-488).
588
+ export function petMaxHealth(char: Character, ds: DataStore): number {
589
+ // Active pet preferred; dismissed pet still has a real max for Call Pet / revive clamps.
590
+ const pet = char.pet ?? char.storedPet;
591
+ if (!pet) {
592
+ // No pet at all — legacy fallback for callers that pass a hypothetical owner.
593
+ return Math.max(1, Math.round(maxHealth(char, ds) * TUNING.petHealthFrac));
594
+ }
595
+ const cdef = ds.creature(pet.creature);
596
+ if (!cdef) return Math.max(1, Math.round(maxHealth(char, ds) * TUNING.petHealthFrac));
597
+ // petTaughtIds / petLearnedGenericPassives read char.pet; when only storedPet is set,
598
+ // present a view so taught Great Stamina / Hardiness still fold into max HP.
599
+ const view: Character = char.pet ? char : { ...char, pet };
600
+ const init = petInitStats(view, cdef, ds);
601
+ // Same fold order as buildPet (family first, then taught generics). Attack power is
602
+ // pass-through for maxHealth; happiness only scales weapon/AP, not HP.
603
+ const familyFold = applyPetFamilyPassives(
604
+ { maxHealth: init.maxHealth, armor: init.armor, attackPower: init.attackPower },
605
+ cdef,
606
+ ds,
607
+ init.stamina,
608
+ );
609
+ const passive = applyPetPassiveEffects(
610
+ familyFold,
611
+ petLearnedGenericPassives(view, cdef, ds),
612
+ init.stamina,
613
+ );
614
+ return passive.maxHealth;
615
+ }
616
+
617
+ // A pet's resource type + max for THIS owner (InitStats mana / fixed focus). `petPowerSpec` is the
618
+ // creature-only view; this is level-aware.
619
+ export function petPowerSpec(cdef: CreatureDef): { powerType: PowerType; maxPower: number } {
620
+ if (cdef.mana && cdef.mana > 0) return { powerType: 'mana', maxPower: cdef.mana };
621
+ if (cdef.creatureType === BEAST || cdef.tameable) return { powerType: 'focus', maxPower: FOCUS_MAX };
622
+ return { powerType: 'mana', maxPower: 0 };
623
+ }
624
+
625
+ export function petMaxPower(char: Character, cdef: CreatureDef, ds?: DataStore): { powerType: PowerType; maxPower: number } {
626
+ if (ds) {
627
+ const init = petInitStats(char, cdef, ds);
628
+ return { powerType: init.powerType, maxPower: init.maxPower };
629
+ }
630
+ // Legacy path for tests that omit DataStore levelstats.
631
+ const spec = petPowerSpec(cdef);
632
+ if (spec.powerType === 'mana' && spec.maxPower > 0) {
633
+ return { powerType: 'mana', maxPower: spec.maxPower + Math.max(0, char.level - 1) * TUNING.petManaPerLevel };
634
+ }
635
+ return spec;
636
+ }
637
+
638
+ /** The active pet's resource (type + max), or null when there's no living pet — for the HUD. */
639
+ export function petPower(char: Character, ds: DataStore): { powerType: PowerType; maxPower: number; power: number } | null {
640
+ const pet = char.pet;
641
+ if (!pet || pet.health <= 0) return null;
642
+ const cdef = ds.creature(pet.creature);
643
+ if (!cdef) return null;
644
+ const { powerType, maxPower } = petMaxPower(char, cdef, ds);
645
+ const power = pet.power != null ? Math.max(0, Math.min(maxPower, pet.power)) : maxPower;
646
+ return { powerType, maxPower, power };
647
+ }
648
+
649
+ // The ability ids feeding a pet's kit, per the vanilla split: a hunter pet's own taughtSpells,
650
+ // a demon's character-wide petSpells. A beast that is not this character's pet was taught nothing.
651
+ export function petTaughtIds(char: Character, cdef: CreatureDef): readonly number[] {
652
+ if (!petHasHappiness(cdef)) return char.petSpells ?? [];
653
+ const pet = char.pet;
654
+ if (!pet || pet.creature !== cdef.entry) return [];
655
+ return pet.taughtSpells ?? char.petSpells ?? [];
656
+ }
657
+
658
+ // GivePetLevel's training-point grant, once per pet level: SetTP(m_TP + loyalty − 1). Pet level
659
+ // tracks owner level here. Hunter pets only — demons have no TP. Cite: Pet.cpp:1128–1141.
660
+ export function grantPetLevelTrainingPoints(
661
+ pet: PetState | undefined,
662
+ levels: number,
663
+ ): PetState | undefined {
664
+ if (!pet || levels <= 0 || pet.loyalty == null) return pet;
665
+ const gain = Math.max(0, pet.loyalty - 1) * levels;
666
+ if (gain === 0) return pet;
667
+ return { ...pet, trainingPoints: (pet.trainingPoints ?? 0) + gain };
668
+ }
669
+
670
+ // Abilities the active pet can cast: the innate kit plus taught ranks, intersected with the
671
+ // creature's petSpells, highest LEVEL-ELIGIBLE rank per name. Generic-line passives are excluded.
672
+ export function petKnownSpells(char: Character, cdef: CreatureDef, ds: DataStore): SpellDef[] {
673
+ const familyIds = new Set(cdef.petSpells ?? []);
674
+ const generic = petHasHappiness(cdef) ? (ds.petGenericSpells?.() ?? []).map((g) => g.id) : [];
675
+ const usable = [...familyIds, ...generic];
676
+ if (usable.length === 0) return [];
677
+ const known = new Set([...(cdef.petDefaultSpells ?? []), ...petTaughtIds(char, cdef)]);
678
+ // LEARN_PET_SPELL stubs (7886 Firebolt R1) hop to the live rank 3110, so a repertoire still
679
+ // holding the stub id matches the family catalog. Cite: SpellEffects.cpp:3386–3404.
680
+ const knownLive = new Set<number>();
681
+ for (const id of known) {
682
+ knownLive.add(id);
683
+ knownLive.add(resolveSpellId(id, ds));
684
+ }
685
+ // Hunter tames only: demon create-spells are added regardless of owner level, so a reqLevel
686
+ // floor there empties Felhunter and Succubus at L10. Cite: Pet.cpp InitPetCreateSpells.
687
+ const petLevel = petHasHappiness(cdef) ? Math.max(1, char.level | 0) : Infinity;
688
+ const byName = new Map<string, SpellDef>();
689
+ for (const rawId of usable) {
690
+ const id = resolveSpellId(rawId, ds);
691
+ if (!knownLive.has(rawId) && !knownLive.has(id)) continue;
692
+ const s = ds.spell(id);
693
+ if (!s) continue;
694
+ // Trust family catalog over a lone ATTR_PASSIVE bit; drop generic-line passives only.
695
+ if (s.passive && !familyIds.has(id) && !familyIds.has(rawId)) continue;
696
+ // Same floor as teachPetSpell — unusable ranks stay out of kit and rank pick.
697
+ if ((s.reqLevel ?? 0) > petLevel) continue;
698
+ const prev = byName.get(s.name);
699
+ if (!prev || s.rank > prev.rank) byName.set(s.name, s);
700
+ }
701
+ return [...byName.values()];
702
+ }
703
+
704
+ // Taught Pet-Generic PASSIVES (Great Stamina, Natural Armor, resistances): taught ids ∩
705
+ // petGenericSpells that are passive, highest rank per name. They fold into InitStats, not casts.
706
+ export function petLearnedGenericPassives(char: Character, cdef: CreatureDef, ds: DataStore): SpellDef[] {
707
+ if (!petHasHappiness(cdef)) return [];
708
+ const learned = new Set(petTaughtIds(char, cdef));
709
+ if (learned.size === 0) return [];
710
+ const byName = new Map<string, SpellDef>();
711
+ for (const g of ds.petGenericSpells?.() ?? []) {
712
+ const live = resolveSpellId(g.id, ds);
713
+ if (!learned.has(g.id) && !learned.has(live)) continue;
714
+ const s = ds.spell(live);
715
+ if (!s?.passive) continue;
716
+ const prev = byName.get(s.name);
717
+ if (!prev || s.rank > prev.rank) byName.set(s.name, s);
718
+ }
719
+ return [...byName.values()];
720
+ }
721
+
722
+ // Autocast: a pet ability is on unless any rank of its name chain is in autocastOff, so learning
723
+ // a new rank keeps the toggle. Mirrors PetSpellMap ACT_ENABLED / ACT_DISABLED.
724
+ export function petAutocastOn(pet: PetState, spell: SpellDef, ds: DataStore): boolean {
725
+ const off = pet.autocastOff;
726
+ if (!off || off.length === 0) return true;
727
+ if (off.includes(spell.id)) return false;
728
+ return !off.some((id) => ds.spell(id)?.name === spell.name);
729
+ }
730
+
731
+ // Append TRIGGER_SPELL and aura-42 companions that known pet abilities fire. Outside name-rank
732
+ // dedup: Spell Lock's silence 24259 shares the name at rank 0 and would lose to r1.
733
+ export function petSpellsWithTriggers(known: SpellDef[], ds: DataStore): SpellDef[] {
734
+ if (known.length === 0) return known;
735
+ const have = new Set(known.map((s) => s.id));
736
+ const extra: SpellDef[] = [];
737
+ for (const s of known) {
738
+ for (const e of s.effects) {
739
+ let tid: number | undefined;
740
+ if (e.kind === 'trigger_spell') tid = e.spellId;
741
+ else if (e.kind === 'proc_trigger_spell') tid = e.triggerSpellId;
742
+ if (tid == null || have.has(tid)) continue;
743
+ const t = ds.spell(tid);
744
+ if (!t) continue;
745
+ extra.push(t);
746
+ have.add(tid);
747
+ }
748
+ }
749
+ return extra.length === 0 ? known : [...known, ...extra];
750
+ }
751
+
752
+ // Unit::GetHealthBonusFromStamina: first 20 stamina give 1 HP each, the rest 10 HP each. Cite:
753
+ // StatSystem.cpp ~144–150.
754
+ export function healthBonusFromStamina(stamina: number): number {
755
+ const baseStam = Math.min(stamina, 20);
756
+ return baseStam + (stamina - baseStam) * 10;
757
+ }
758
+
759
+ interface PetPassiveBase {
760
+ maxHealth: number;
761
+ armor: number;
762
+ attackPower: number;
763
+ resistances?: Partial<Record<School, number>>;
764
+ mp5?: number;
765
+ }
766
+
767
+ // Fold passive SpellDefs' stat effects into base InitStats; empty or non-stat effects are skipped.
768
+ // Stamina buffs convert via GetHealthBonusFromStamina on top of the pet_levelstats base. Pure.
769
+ export function applyPetPassiveEffects(
770
+ base: PetPassiveBase,
771
+ spells: readonly SpellDef[],
772
+ staBase?: number,
773
+ ): PetPassiveBase {
774
+ if (spells.length === 0) return base;
775
+
776
+ let maxHealth = base.maxHealth;
777
+ let armor = base.armor;
778
+ let attackPower = base.attackPower;
779
+ let resistances = base.resistances ? { ...base.resistances } : undefined;
780
+ let mp5 = base.mp5;
781
+ let sta = staBase ?? 20; // unknown base: all bonus stamina is past the 20-point knee
782
+
783
+ for (const s of spells) {
784
+ for (const e of s.effects) {
785
+ if (e.kind === 'buff') {
786
+ // Only mods with a direct CombatantSpec surface. STR/INT curves are not invented here.
787
+ const amt = e.amount ?? 0;
788
+ if (amt === 0) continue;
789
+ if (e.mod === 'armor') armor += amt;
790
+ else if (e.mod === 'attack_power') attackPower += amt;
791
+ else if (e.mod === 'mp5') mp5 = (mp5 ?? 0) + amt;
792
+ else if (e.mod === 'stamina') {
793
+ maxHealth += healthBonusFromStamina(sta + amt) - healthBonusFromStamina(sta);
794
+ sta += amt;
795
+ }
796
+ } else if (e.kind === 'resist') {
797
+ const amt = e.amount ?? 0;
798
+ if (amt === 0) continue;
799
+ resistances = resistances ?? {};
800
+ resistances[e.school] = (resistances[e.school] ?? 0) + amt;
801
+ }
802
+ // Empty effects, proc_trigger_spell, unmapped stat_mod — skip (do not fabricate).
803
+ }
804
+ }
805
+
806
+ return {
807
+ maxHealth: Math.max(1, Math.round(maxHealth)),
808
+ armor,
809
+ attackPower: Math.max(0, attackPower),
810
+ ...(resistances && Object.keys(resistances).length > 0 ? { resistances } : {}),
811
+ ...(mp5 != null && mp5 !== 0 ? { mp5 } : {}),
812
+ };
813
+ }
814
+
815
+ /** Fold CreatureDef.petFamilyPassives’ stat-affecting effects into base InitStats. */
816
+ export function applyPetFamilyPassives(
817
+ base: PetPassiveBase,
818
+ cdef: CreatureDef,
819
+ ds: DataStore,
820
+ staBase?: number,
821
+ ): PetPassiveBase {
822
+ const ids = cdef.petFamilyPassives;
823
+ if (!ids || ids.length === 0) return base;
824
+ const defs: SpellDef[] = [];
825
+ for (const id of ids) {
826
+ const s = ds.spell(id);
827
+ if (s) defs.push(s);
828
+ }
829
+ return applyPetPassiveEffects(base, defs, staBase);
830
+ }
831
+
832
+ // Fresh full-health PetState from a creature, with power full and hunter loyalty/TP defaults.
833
+ // Happiness starts at HAPPINESS_MAX for playability — a deliberate deviation from the 166k tame.
834
+ export function newPet(creature: number, ds: DataStore, char: Character): PetState | null {
835
+ const cdef = ds.creature(creature);
836
+ if (!cdef) return null;
837
+ const init = petInitStats(char, cdef, ds);
838
+ const base: PetState = {
839
+ creature,
840
+ name: cdef.name,
841
+ health: init.maxHealth,
842
+ // CMaNGOS hunter tame: 166500/1e6 ≈ 166 UNHAPPY — we keep HAPPINESS_MAX for playability.
843
+ happiness: HAPPINESS_MAX,
844
+ power: init.maxPower,
845
+ };
846
+ if (!petHasHappiness(cdef)) return base;
847
+ const xpReq = loyaltyXpForOwnerLevel(char.level, ds);
848
+ // InitPetCreateSpells: the innate kit charges its reqtrainpoints, so TP starts in debt, and
849
+ // innate actives the owner has not learned queue as teachable. Cite: Pet.cpp:1955–1998.
850
+ const innate = cdef.petDefaultSpells ?? [];
851
+ const known = new Set(char.petSpells ?? []);
852
+ const teachSpells = innate.filter((id) => {
853
+ const s = ds.spell(id);
854
+ return !!s && !s.passive && !known.has(id) && !known.has(resolveSpellId(id, ds));
855
+ });
856
+ return {
857
+ ...base,
858
+ loyalty: LOYALTY_REBELLIOUS,
859
+ loyaltyPoints: 1000,
860
+ trainingPoints: -tpSpentOnKnown(innate, ds),
861
+ loyaltyXpRequired: xpReq ?? 0,
862
+ // Fresh tames know only their innate kit — abilities from the character's Beast
863
+ // Training repertoire are taught per-pet for TP (game.teachPetSpell).
864
+ taughtSpells: [],
865
+ teachSpells,
866
+ };
867
+ }
868
+
869
+ /** Command racial ids: Warlock 20575 / Hunter 20576. Cite: playercreateinfo_spell. */
870
+ const ORC_COMMAND_SPELL_IDS = new Set([20575, 20576]);
871
+
872
+ // Owner permanent +% pet damage from Command racial (applyTo pet, duration 0). Race list shows 20575;
873
+ // createInfo grants 20575 (warlock) / 20576 (hunter). Cite: spell_template; races.json orc racials; KI-824.
874
+ function ownerCommandPetDamagePct(char: Character, ds: DataStore): number {
875
+ if (char.race !== 2) return 0; // Orc only
876
+ let best = 0;
877
+ for (const id of ORC_COMMAND_SPELL_IDS) {
878
+ const raw = ds.spell(id);
879
+ if (!raw) continue;
880
+ const sp = resolveCombatSpell(raw, { unitTargetIsPlayer: true });
881
+ for (const e of sp.effects ?? []) {
882
+ if (e.kind === 'buff' && e.mod === 'damage_done_pct' && e.applyTo === 'pet') {
883
+ best = Math.max(best, e.amount | 0);
884
+ }
885
+ }
886
+ }
887
+ // Also fold display racial row (same effect) if not already covered.
888
+ for (const s of racialSpells(ds, char.race)) {
889
+ if (!ORC_COMMAND_SPELL_IDS.has(s.id)) continue;
890
+ const sp = resolveCombatSpell(s, { unitTargetIsPlayer: true });
891
+ for (const e of sp.effects ?? []) {
892
+ if (e.kind === 'buff' && e.mod === 'damage_done_pct' && e.applyTo === 'pet') {
893
+ best = Math.max(best, e.amount | 0);
894
+ }
895
+ }
896
+ }
897
+ return best;
898
+ }
899
+
900
+ // Party buffs the pet carries into this pull. A pet has no character sheet to fold them into, so each
901
+ // mod seeds as a live row (applyBuffMod) and resistances, which have no live row, go on the spec.
902
+ function carriedPetAuras(
903
+ pet: PetState,
904
+ level: number,
905
+ ds: DataStore,
906
+ now: number,
907
+ ): {
908
+ display: NonNullable<CombatantSpec['startDisplayAuras']>;
909
+ resistances: Partial<Record<School, number>>;
910
+ } {
911
+ const display: NonNullable<CombatantSpec['startDisplayAuras']> = [];
912
+ const resistances: Partial<Record<School, number>> = {};
913
+ for (const a of pruneExpiredAuras(pet.prePullAuras, now)) {
914
+ const raw = ds.spell(a.spellId);
915
+ if (!raw) continue;
916
+ const sp = resolveCombatSpell(raw, { casterLevel: level });
917
+ const liveBuffs: NonNullable<NonNullable<CombatantSpec['startDisplayAuras']>[number]['liveBuffs']> = [];
918
+ for (const e of sp.effects) {
919
+ if (e.kind === 'buff' && e.mod && !e.hostile && (e.amount ?? 0) !== 0) {
920
+ liveBuffs.push({ mod: e.mod, amount: e.amount, ...(e.school ? { school: e.school } : {}) });
921
+ } else if (e.kind === 'resist' && (e.amount ?? 0) !== 0) {
922
+ resistances[e.school] = (resistances[e.school] ?? 0) + e.amount;
923
+ }
924
+ }
925
+ const permanent = a.expiresAt == null;
926
+ display.push({
927
+ spellId: sp.id,
928
+ name: sp.name,
929
+ ...(permanent ? { permanent: true } : { remainingMs: Math.max(0, a.expiresAt! - now) }),
930
+ ...(liveBuffs.length > 0 ? { liveBuffs } : {}),
931
+ });
932
+ }
933
+ return { display, resistances };
934
+ }
935
+
936
+ // Combat-ready spec for the living pet, or null. Level follows the owner, HP and damage come from
937
+ // InitStats, and happiness applies 0.75 / 1 / 1.25 to physical damage. Power persists between fights.
938
+ export function buildPet(char: Character, ds: DataStore): CombatantSpec | null {
939
+ const pet = char.pet;
940
+ if (!pet || pet.health <= 0) return null;
941
+ const cdef = ds.creature(pet.creature);
942
+ if (!cdef) return null;
943
+ const init = petInitStats(char, cdef, ds);
944
+ const happy = petHasHappiness(cdef) ? happinessDamageMult(pet.happiness ?? HAPPINESS_MAX) : 1;
945
+ // Happiness multiplies total physical (weapon + AP). Cite: StatSystem.cpp ~930–951.
946
+ const happyAp = Math.max(0, Math.round(init.attackPower * happy));
947
+ const familyFold = applyPetFamilyPassives(
948
+ { maxHealth: init.maxHealth, armor: init.armor, attackPower: happyAp },
949
+ cdef,
950
+ ds,
951
+ init.stamina,
952
+ );
953
+ // Trainer-taught generic passives (Pet Hardiness → HP via stamina, Pet Resistance → armor…)
954
+ // stack on the family fold; stamina knee advances past any family stamina already applied.
955
+ const passive = applyPetPassiveEffects(
956
+ familyFold,
957
+ petLearnedGenericPassives(char, cdef, ds),
958
+ init.stamina,
959
+ );
960
+ // Party buffs the pet is carrying in from the last pull / the zone-in "Buff up".
961
+ const carried = carriedPetAuras(pet, char.level, ds, Date.now());
962
+ const petResists = { ...(passive.resistances ?? {}) };
963
+ for (const [school, amt] of Object.entries(carried.resistances)) {
964
+ petResists[school as School] = (petResists[school as School] ?? 0) + (amt ?? 0);
965
+ }
966
+ const startPower =
967
+ pet.power != null
968
+ ? Math.max(0, Math.min(init.maxPower, pet.power))
969
+ : init.maxPower;
970
+ // Autocast: right-click-disabled abilities stay learned but the AI never picks them. The full kit
971
+ // rides along so the bar can flip one on mid-fight without rebuilding the spec.
972
+ const fullKit = petKnownSpells(char, cdef, ds);
973
+ const known = fullKit.filter((s) => petAutocastOn(pet, s, ds));
974
+ // Owner Command racial (+5% pet damage). Cite: spell_template 20575/20576; KI-824.
975
+ const ownerPetDmgPct = ownerCommandPetDamagePct(char, ds);
976
+ return {
977
+ name: pet.name,
978
+ petFullKit: fullKit,
979
+ // Player-controlled, same as its owner. Cite: the field's own contract, types.ts:311.
980
+ isPlayerOrPet: true,
981
+ level: char.level,
982
+ maxHealth: passive.maxHealth,
983
+ startHealth: Math.min(pet.health, passive.maxHealth),
984
+ powerType: init.powerType,
985
+ maxPower: init.maxPower,
986
+ startPower,
987
+ armor: passive.armor,
988
+ weapon: {
989
+ dmgMin: Math.max(1, Math.round(init.weaponMin * happy)),
990
+ dmgMax: Math.max(2, Math.round(init.weaponMax * happy)),
991
+ speedMs: init.attackTimeMs,
992
+ school: 'physical',
993
+ },
994
+ attackPower: passive.attackPower,
995
+ critChance: TUNING.baseCritChance,
996
+ hitChance: TUNING.meleeHitChance,
997
+ haste: 0,
998
+ canParry: false,
999
+ canBlock: false,
1000
+ ...(init.intellect != null ? { intellect: init.intellect } : {}),
1001
+ ...(init.spirit != null ? { spirit: init.spirit } : {}),
1002
+ ...(init.classId != null ? { classId: init.classId } : {}),
1003
+ // Carry the creature identity so scripted effects can key off it — CC immunity (creatureType)
1004
+ // and warlock Demonic Sacrifice's per-demon buff (creatureEntry: Imp 416 / Succubus 1863 / …).
1005
+ ...(cdef.creatureType != null ? { creatureType: cdef.creatureType } : {}),
1006
+ creatureEntry: pet.creature,
1007
+ ...(Object.keys(petResists).length > 0 ? { resistances: petResists } : {}),
1008
+ ...(passive.mp5 != null ? { mp5: passive.mp5 } : {}),
1009
+ ...(ownerPetDmgPct
1010
+ ? { damagePctBySchool: { physical: ownerPetDmgPct, holy: ownerPetDmgPct, fire: ownerPetDmgPct, nature: ownerPetDmgPct, frost: ownerPetDmgPct, shadow: ownerPetDmgPct, arcane: ownerPetDmgPct } }
1011
+ : {}),
1012
+ // Pet bar state the fight opens with (the session owns it from here; 'attack' is a
1013
+ // one-shot order and never persists). Cite: Unit.h CommandStates / UnitAI.h ReactStates.
1014
+ petCommand: pet.command ?? 'follow',
1015
+ petReact: pet.react ?? 'defensive',
1016
+ // Triggers appended by id (outside name-rank dedup) so Spell Lock → 24259 silence works.
1017
+ spells: petSpellsWithTriggers(known, ds),
1018
+ ...(carried.display.length > 0 ? { startDisplayAuras: carried.display } : {}),
1019
+ };
1020
+ }
1021
+
1022
+ /** True when a spell effect is APPLY_AREA_AURA_PARTY (baked applyTo:'party', non-hostile). */
1023
+ function isPartyAreaBuffSpell(sp: SpellDef | undefined): boolean {
1024
+ return !!sp?.effects.some((e) => e.kind === 'buff' && e.applyTo === 'party' && !e.hostile);
1025
+ }
1026
+
1027
+ // APPLY_AREA_AURA_PARTY spells on the living pet's autocast kit (Blood Pact, Furious Howl), which
1028
+ // are permanent while it is out. Returns [] when the pet is absent or dead.
1029
+ export function petPartyAuraSpellIds(char: Character, ds: DataStore): number[] {
1030
+ const built = buildPet(char, ds);
1031
+ if (!built) return [];
1032
+ const out: number[] = [];
1033
+ for (const sp of built.spells) {
1034
+ if (isPartyAreaBuffSpell(sp)) out.push(sp.id);
1035
+ }
1036
+ return out;
1037
+ }
1038
+
1039
+ // Pet-repertoire party aura ids, used to strip orphan owner copies after an Imp→Voidwalker swap
1040
+ // or after death, when buildPet is already null. Player party buffs are never in petSpells.
1041
+ export function petRepertoirePartyAuraIds(char: Character, ds: DataStore): number[] {
1042
+ const seen = new Set<number>();
1043
+ const out: number[] = [];
1044
+ const consider = (id: number) => {
1045
+ if (seen.has(id)) return;
1046
+ if (!isPartyAreaBuffSpell(ds.spell(id))) return;
1047
+ seen.add(id);
1048
+ out.push(id);
1049
+ };
1050
+ for (const id of char.petSpells ?? []) consider(id);
1051
+ for (const id of char.pet?.taughtSpells ?? []) consider(id);
1052
+ return out;
1053
+ }
1054
+
1055
+ // Grant the owner permanent chips for pet party auras while the pet is out, so sheet maxHealth
1056
+ // includes the +sta before the next pull (KI-066). Cite: AreaAura::Update party copies.
1057
+ export function applyPetPartyAuras(char: Character, ds: DataStore, now: number = Date.now()): Character {
1058
+ if (!char.pet || char.pet.health <= 0) return char;
1059
+ const ids = petPartyAuraSpellIds(char, ds);
1060
+ if (ids.length === 0) return char;
1061
+ const beforeMax = maxHealth(char, ds);
1062
+ let next = char;
1063
+ for (const id of ids) {
1064
+ // durationMs undefined → permanent until dismiss/death (matches durationMs 0 combat path).
1065
+ next = applyAura(next, id, undefined, now, ds);
1066
+ }
1067
+ const afterMax = maxHealth(next, ds);
1068
+ // Stamina buffs raise current HP by the same delta (combat applyBuffMod stamina does this).
1069
+ if (afterMax > beforeMax) {
1070
+ next = { ...next, health: Math.min(afterMax, next.health + (afterMax - beforeMax)) };
1071
+ }
1072
+ return next;
1073
+ }
1074
+
1075
+ // Drop owner auras that were pet party copies. Call while the pet is still on `char` so the kit is
1076
+ // known, or pass explicit ids; a dead pet falls back to the repertoire auras still on the owner.
1077
+ export function stripPetPartyAuras(
1078
+ char: Character,
1079
+ ds: DataStore,
1080
+ partySpellIds?: readonly number[],
1081
+ now: number = Date.now(),
1082
+ ): Character {
1083
+ let ids: number[];
1084
+ if (partySpellIds != null) {
1085
+ ids = [...partySpellIds];
1086
+ } else {
1087
+ const fromKit = petPartyAuraSpellIds(char, ds);
1088
+ // Dead/absent pet → kit empty; still drop repertoire orphans (Blood Pact after Imp death).
1089
+ ids = fromKit.length > 0 ? fromKit : petRepertoirePartyAuraIds(char, ds);
1090
+ }
1091
+ if (ids.length === 0) return char;
1092
+ const names = new Set<string>();
1093
+ for (const id of ids) {
1094
+ const n = ds.spell(id)?.name;
1095
+ if (n) names.add(n);
1096
+ }
1097
+ const drop = (spellId: number): boolean => {
1098
+ if (ids.includes(spellId)) return true;
1099
+ const sp = ds.spell(spellId);
1100
+ return !!(sp?.name && names.has(sp.name));
1101
+ };
1102
+ const prevAuras = char.activeAuras;
1103
+ const auras = (prevAuras ?? []).filter((a) => !drop(a.spellId));
1104
+ const legacyBuffs = (char.activeBuffs ?? []).filter((id) => !drop(id));
1105
+ if (
1106
+ auras.length === (prevAuras ?? []).length
1107
+ && legacyBuffs.length === (char.activeBuffs ?? []).length
1108
+ ) {
1109
+ return char;
1110
+ }
1111
+ const next: Character = {
1112
+ ...char,
1113
+ activeAuras: prevAuras !== undefined ? auras : undefined,
1114
+ activeBuffs: prevAuras !== undefined
1115
+ ? getActiveBuffIds({ ...char, activeAuras: auras }, now, ds)
1116
+ : legacyBuffs,
1117
+ };
1118
+ const cap = maxHealth(next, ds);
1119
+ if (next.health > cap) return { ...next, health: cap };
1120
+ return next;
1121
+ }
1122
+
1123
+ // Align owner party-aura copies with the living pet's kit: strip what the current kit does not
1124
+ // provide, apply what it does. A dead or absent pet strips them all. Cite: KI-555 / KI-589.
1125
+ export function reconcilePetPartyAuras(
1126
+ char: Character,
1127
+ ds: DataStore,
1128
+ now: number = Date.now(),
1129
+ ): Character {
1130
+ const provide = petPartyAuraSpellIds(char, ds);
1131
+ const provideIds = new Set(provide);
1132
+ const provideNames = new Set<string>();
1133
+ for (const id of provide) {
1134
+ const n = ds.spell(id)?.name;
1135
+ if (n) provideNames.add(n);
1136
+ }
1137
+ // Repertoire party auras the living pet does not currently provide.
1138
+ const toStrip: number[] = [];
1139
+ for (const id of petRepertoirePartyAuraIds(char, ds)) {
1140
+ if (provideIds.has(id)) continue;
1141
+ const n = ds.spell(id)?.name;
1142
+ if (n && provideNames.has(n)) continue;
1143
+ toStrip.push(id);
1144
+ }
1145
+ let next = toStrip.length > 0 ? stripPetPartyAuras(char, ds, toStrip, now) : char;
1146
+ if (char.pet && char.pet.health > 0) {
1147
+ next = applyPetPartyAuras(next, ds, now);
1148
+ }
1149
+ return next;
1150
+ }