azeroth-shell 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +138 -2
- package/bin/azsh.mjs +19 -0
- package/docs/aifid/eventai-texts.json +4414 -0
- package/docs/dungeons/atlas/atlas-rows-dungeons.json +8989 -0
- package/docs/dungeons/survey/pack-id-migration.json +2418 -0
- package/package.json +26 -4
- package/src/autopilot/bossSkip.ts +26 -0
- package/src/autopilot/combatRotation.ts +824 -0
- package/src/autopilot/config.ts +533 -0
- package/src/autopilot/consumables.ts +58 -0
- package/src/autopilot/encounterStand.ts +121 -0
- package/src/autopilot/objectGatePlan.ts +53 -0
- package/src/autopilot/pathEngage.ts +229 -0
- package/src/autopilot/plan.ts +1643 -0
- package/src/autopilot/questPolicy.ts +274 -0
- package/src/autopilot/routeStep.ts +69 -0
- package/src/autopilot/sessionReport.ts +88 -0
- package/src/autopilot/topOffPower.ts +26 -0
- package/src/autopilot/view.ts +476 -0
- package/src/cli/bootCheck.mjs +34 -0
- package/src/cli/bootData.mjs +57 -0
- package/src/cli/combatLogFilter.ts +153 -0
- package/src/cli/combatLogFormat.ts +613 -0
- package/src/cli/fileRepository.mjs +105 -0
- package/src/cli/gzLoader.mjs +31 -0
- package/src/cli/liveGauntletEscort.ts +978 -0
- package/src/cli/liveStratUndead.ts +305 -0
- package/src/cli/macroHostCombat.ts +545 -0
- package/src/cli/macroHostWorld.ts +330 -0
- package/src/cli/prefs.mjs +31 -0
- package/src/cli/register.mjs +4 -0
- package/src/cli/repl.mjs +693 -0
- package/src/cli/rotationText.mjs +226 -0
- package/src/cli/squad.mjs +105 -0
- package/src/cli/term.mjs +126 -0
- package/src/cli/text.mjs +122 -0
- package/src/cli/tui.mjs +626 -0
- package/src/cli/tuiArena.mjs +109 -0
- package/src/cli/tuiAutopilotSettings.mjs +93 -0
- package/src/cli/tuiBags.mjs +180 -0
- package/src/cli/tuiBars.mjs +133 -0
- package/src/cli/tuiBg.mjs +243 -0
- package/src/cli/tuiBulk.mjs +162 -0
- package/src/cli/tuiCheck.mjs +1882 -0
- package/src/cli/tuiCity.mjs +396 -0
- package/src/cli/tuiCompanionKit.mjs +300 -0
- package/src/cli/tuiCompanions.mjs +471 -0
- package/src/cli/tuiDev.mjs +62 -0
- package/src/cli/tuiDungeon.mjs +606 -0
- package/src/cli/tuiEnchantTarget.mjs +120 -0
- package/src/cli/tuiFight.mjs +577 -0
- package/src/cli/tuiFightPanes.mjs +228 -0
- package/src/cli/tuiFloor.mjs +506 -0
- package/src/cli/tuiGear.mjs +158 -0
- package/src/cli/tuiHonor.mjs +74 -0
- package/src/cli/tuiLoot.mjs +97 -0
- package/src/cli/tuiMacros.mjs +144 -0
- package/src/cli/tuiOutfitter.mjs +115 -0
- package/src/cli/tuiPet.mjs +116 -0
- package/src/cli/tuiProfessions.mjs +800 -0
- package/src/cli/tuiRaid.mjs +127 -0
- package/src/cli/tuiRep.mjs +65 -0
- package/src/cli/tuiSaves.mjs +69 -0
- package/src/cli/tuiSearch.mjs +363 -0
- package/src/cli/tuiSettings.mjs +151 -0
- package/src/cli/tuiSimLab.mjs +80 -0
- package/src/cli/tuiTalents.mjs +60 -0
- package/src/cli/tuiViews.mjs +1178 -0
- package/src/cli/tuiWiki.mjs +181 -0
- package/src/cli/tuiWorld.mjs +361 -0
- package/src/cli/wikiIndex.ts +259 -0
- package/src/cli/wikiSources.ts +355 -0
- package/src/data/alteracValley.ts +176 -0
- package/src/data/appearanceOptions.ts +534 -0
- package/src/data/applyLootChanceSanity.ts +21 -0
- package/src/data/createFlavor.ts +96 -0
- package/src/data/customItems.ts +33 -0
- package/src/data/dataStore.ts +1904 -0
- package/src/data/dungeonGameObjects.ts +84 -0
- package/src/data/dungeonPlateCover.ts +66 -0
- package/src/data/dungeonSpawns.ts +294 -0
- package/src/data/dungeons/alterac-valley.ts +135 -0
- package/src/data/dungeons/apply-dungeon-rooms.ts +29 -0
- package/src/data/dungeons/apply-encounter-outdoors.ts +72 -0
- package/src/data/dungeons/apply-instance-geometry.ts +65 -0
- package/src/data/dungeons/apply-spawn-placement.ts +171 -0
- package/src/data/dungeons/blackfathom-deeps.ts +539 -0
- package/src/data/dungeons/blackrock-depths.ts +1410 -0
- package/src/data/dungeons/blackwing-lair.ts +129 -0
- package/src/data/dungeons/boss-eventai.ts +8 -0
- package/src/data/dungeons/deadmines.ts +410 -0
- package/src/data/dungeons/dire-maul-east.ts +980 -0
- package/src/data/dungeons/dire-maul-north.ts +661 -0
- package/src/data/dungeons/dire-maul-west.ts +785 -0
- package/src/data/dungeons/dungeon-rooms.json +5479 -0
- package/src/data/dungeons/encounter-outdoors.json +359 -0
- package/src/data/dungeons/eventai/blackfathom-deeps.ts +308 -0
- package/src/data/dungeons/eventai/blackrock-depths.ts +1257 -0
- package/src/data/dungeons/eventai/deadmines.ts +264 -0
- package/src/data/dungeons/eventai/dire-maul-east.ts +320 -0
- package/src/data/dungeons/eventai/gnomeregan.ts +213 -0
- package/src/data/dungeons/eventai/helpers.ts +79 -0
- package/src/data/dungeons/eventai/index.ts +133 -0
- package/src/data/dungeons/eventai/lbrs.ts +372 -0
- package/src/data/dungeons/eventai/maraudon.ts +323 -0
- package/src/data/dungeons/eventai/ragefire-chasm.ts +108 -0
- package/src/data/dungeons/eventai/razorfen-downs.ts +207 -0
- package/src/data/dungeons/eventai/razorfen-kraul.ts +326 -0
- package/src/data/dungeons/eventai/scholomance.ts +680 -0
- package/src/data/dungeons/eventai/shadowfang-keep.ts +230 -0
- package/src/data/dungeons/eventai/sm-cathedral.ts +75 -0
- package/src/data/dungeons/eventai/sm-graveyard.ts +150 -0
- package/src/data/dungeons/eventai/sm-library.ts +55 -0
- package/src/data/dungeons/eventai/stratholme-undead.ts +127 -0
- package/src/data/dungeons/eventai/sunken-temple.ts +582 -0
- package/src/data/dungeons/eventai/the-stockade.ts +228 -0
- package/src/data/dungeons/eventai/ubrs.ts +225 -0
- package/src/data/dungeons/eventai/uldaman.ts +355 -0
- package/src/data/dungeons/eventai/wailing-caverns.ts +396 -0
- package/src/data/dungeons/eventai/zul-farrak.ts +591 -0
- package/src/data/dungeons/gnomeregan.ts +909 -0
- package/src/data/dungeons/index.ts +126 -0
- package/src/data/dungeons/instance-geometry.json +5233 -0
- package/src/data/dungeons/key-sources.json +169 -0
- package/src/data/dungeons/lbrs.ts +996 -0
- package/src/data/dungeons/maraudon.ts +786 -0
- package/src/data/dungeons/molten-core.ts +194 -0
- package/src/data/dungeons/naxxramas.ts +173 -0
- package/src/data/dungeons/onyxias-lair.ts +71 -0
- package/src/data/dungeons/pack-from-clusters.ts +1256 -0
- package/src/data/dungeons/ragefire-chasm.ts +238 -0
- package/src/data/dungeons/razorfen-downs.ts +698 -0
- package/src/data/dungeons/razorfen-kraul.ts +766 -0
- package/src/data/dungeons/ruins-of-ahnqiraj.ts +121 -0
- package/src/data/dungeons/scholomance.ts +1076 -0
- package/src/data/dungeons/shadowfang-keep.ts +740 -0
- package/src/data/dungeons/sm-armory.ts +266 -0
- package/src/data/dungeons/sm-cathedral.ts +430 -0
- package/src/data/dungeons/sm-graveyard.ts +482 -0
- package/src/data/dungeons/sm-library.ts +337 -0
- package/src/data/dungeons/stratholme-live.ts +808 -0
- package/src/data/dungeons/stratholme-undead.ts +1164 -0
- package/src/data/dungeons/sunken-temple.ts +931 -0
- package/src/data/dungeons/temple-of-ahnqiraj.ts +119 -0
- package/src/data/dungeons/the-stockade.ts +282 -0
- package/src/data/dungeons/ubrs.ts +1286 -0
- package/src/data/dungeons/uldaman.ts +685 -0
- package/src/data/dungeons/wailing-caverns.ts +356 -0
- package/src/data/dungeons/zul-farrak.ts +686 -0
- package/src/data/dungeons/zul-gurub.ts +142 -0
- package/src/data/dungeons.ts +42 -0
- package/src/data/fixtures.ts +446 -0
- package/src/data/gameobject-data.json.gz +0 -0
- package/src/data/item-data.json.gz +0 -0
- package/src/data/loot-data.json.gz +0 -0
- package/src/data/maps/atlas-approach-maps.json +1425 -0
- package/src/data/maps/atlas-landmarks.json +1711 -0
- package/src/data/maps/dungeon-viewports.json +392 -0
- package/src/data/materializeModDamagePercentTaken.ts +70 -0
- package/src/data/materializeModHealthRegen.ts +89 -0
- package/src/data/materializeSpellReputation.ts +26 -0
- package/src/data/pageTexts.ts +19 -0
- package/src/data/profession-data.json.gz +0 -0
- package/src/data/raid-plans/blackfathom-deeps.json +86 -0
- package/src/data/raid-plans/blackrock-depths.json +419 -0
- package/src/data/raid-plans/blackwing-lair.json +328 -0
- package/src/data/raid-plans/deadmines.json +55 -0
- package/src/data/raid-plans/dire-maul-east.json +94 -0
- package/src/data/raid-plans/dire-maul-north.json +70 -0
- package/src/data/raid-plans/dire-maul-west.json +75 -0
- package/src/data/raid-plans/gnomeregan.json +131 -0
- package/src/data/raid-plans/lbrs.json +176 -0
- package/src/data/raid-plans/maraudon.json +102 -0
- package/src/data/raid-plans/molten-core.json +169 -0
- package/src/data/raid-plans/naxxramas.json +354 -0
- package/src/data/raid-plans/onyxias-lair.json +18 -0
- package/src/data/raid-plans/ragefire-chasm.json +30 -0
- package/src/data/raid-plans/razorfen-downs.json +75 -0
- package/src/data/raid-plans/razorfen-kraul.json +53 -0
- package/src/data/raid-plans/ruins-of-ahnqiraj.json +110 -0
- package/src/data/raid-plans/scholomance.json +170 -0
- package/src/data/raid-plans/shadowfang-keep.json +87 -0
- package/src/data/raid-plans/sm-armory.json +53 -0
- package/src/data/raid-plans/sm-cathedral.json +72 -0
- package/src/data/raid-plans/sm-graveyard.json +63 -0
- package/src/data/raid-plans/sm-library.json +23 -0
- package/src/data/raid-plans/stratholme-live.json +129 -0
- package/src/data/raid-plans/stratholme-undead.json +73 -0
- package/src/data/raid-plans/sunken-temple.json +159 -0
- package/src/data/raid-plans/temple-of-ahnqiraj.json +163 -0
- package/src/data/raid-plans/the-stockade.json +42 -0
- package/src/data/raid-plans/ubrs.json +53 -0
- package/src/data/raid-plans/uldaman.json +131 -0
- package/src/data/raid-plans/wailing-caverns.json +90 -0
- package/src/data/raid-plans/zul-farrak.json +156 -0
- package/src/data/raid-plans/zul-gurub.json +307 -0
- package/src/data/raidInstanceCreatures.mjs +473 -0
- package/src/data/rotations/index.ts +152 -0
- package/src/data/rotations/layout.mjs +72 -0
- package/src/data/rotations/pve/druid/balance.json +754 -0
- package/src/data/rotations/pve/druid/feral-tank.json +2448 -0
- package/src/data/rotations/pve/druid/feral.json +2660 -0
- package/src/data/rotations/pve/druid/restoration.json +424 -0
- package/src/data/rotations/pve/hunter/beast-mastery.json +1288 -0
- package/src/data/rotations/pve/hunter/marksmanship.json +1260 -0
- package/src/data/rotations/pve/hunter/survival.json +1373 -0
- package/src/data/rotations/pve/mage/arcane-leveling.json +1798 -0
- package/src/data/rotations/pve/mage/fire-leveling.json +2003 -0
- package/src/data/rotations/pve/mage/frost-leveling.json +1912 -0
- package/src/data/rotations/pve/paladin/holy.json +755 -0
- package/src/data/rotations/pve/paladin/protection.json +962 -0
- package/src/data/rotations/pve/paladin/retribution.json +924 -0
- package/src/data/rotations/pve/priest/discipline.json +772 -0
- package/src/data/rotations/pve/priest/holy.json +707 -0
- package/src/data/rotations/pve/priest/shadow.json +787 -0
- package/src/data/rotations/pve/rogue/assassination.json +2477 -0
- package/src/data/rotations/pve/rogue/combat.json +2483 -0
- package/src/data/rotations/pve/rogue/subtlety.json +2523 -0
- package/src/data/rotations/pve/shaman/elemental.json +1157 -0
- package/src/data/rotations/pve/shaman/enhancement.json +1085 -0
- package/src/data/rotations/pve/shaman/restoration.json +592 -0
- package/src/data/rotations/pve/warlock/affliction.json +1185 -0
- package/src/data/rotations/pve/warlock/demonology.json +1165 -0
- package/src/data/rotations/pve/warlock/destruction.json +1177 -0
- package/src/data/rotations/pve/warrior/arms.json +3020 -0
- package/src/data/rotations/pve/warrior/fury.json +2996 -0
- package/src/data/rotations/pve/warrior/protection.json +2509 -0
- package/src/data/rotations/pvp/druid/balance.json +593 -0
- package/src/data/rotations/pvp/druid/feral.json +3276 -0
- package/src/data/rotations/pvp/druid/restoration.json +662 -0
- package/src/data/rotations/pvp/hunter/beast-mastery.json +665 -0
- package/src/data/rotations/pvp/hunter/marksmanship.json +2406 -0
- package/src/data/rotations/pvp/hunter/survival.json +635 -0
- package/src/data/rotations/pvp/mage/arcane.json +574 -0
- package/src/data/rotations/pvp/mage/fire.json +570 -0
- package/src/data/rotations/pvp/mage/frost.json +4048 -0
- package/src/data/rotations/pvp/paladin/holy.json +1498 -0
- package/src/data/rotations/pvp/paladin/protection.json +567 -0
- package/src/data/rotations/pvp/paladin/retribution.json +1110 -0
- package/src/data/rotations/pvp/priest/discipline.json +1848 -0
- package/src/data/rotations/pvp/priest/holy.json +6340 -0
- package/src/data/rotations/pvp/priest/shadow.json +2329 -0
- package/src/data/rotations/pvp/rogue/assassination.json +1322 -0
- package/src/data/rotations/pvp/rogue/combat.json +5258 -0
- package/src/data/rotations/pvp/rogue/subtlety.json +586 -0
- package/src/data/rotations/pvp/shaman/elemental.json +1404 -0
- package/src/data/rotations/pvp/shaman/enhancement.json +1277 -0
- package/src/data/rotations/pvp/shaman/restoration.json +2490 -0
- package/src/data/rotations/pvp/warlock/affliction.json +1017 -0
- package/src/data/rotations/pvp/warlock/demonology.json +1503 -0
- package/src/data/rotations/pvp/warlock/destruction.json +638 -0
- package/src/data/rotations/pvp/warrior/arms.json +5665 -0
- package/src/data/rotations/pvp/warrior/fury.json +850 -0
- package/src/data/rotations/pvp/warrior/protection.json +777 -0
- package/src/data/schema/bundle.ts +511 -0
- package/src/data/schema/constants.ts +49 -0
- package/src/data/schema/creature.ts +454 -0
- package/src/data/schema/encounter.ts +155 -0
- package/src/data/schema/faction.ts +48 -0
- package/src/data/schema/item.ts +297 -0
- package/src/data/schema/itemEnchant.ts +105 -0
- package/src/data/schema/npc.ts +44 -0
- package/src/data/schema/primitives.ts +295 -0
- package/src/data/schema/profession.ts +226 -0
- package/src/data/schema/quest.ts +154 -0
- package/src/data/schema/spell.ts +1149 -0
- package/src/data/schema/talent.ts +74 -0
- package/src/data/schema/world.ts +124 -0
- package/src/data/schema.ts +19 -0
- package/src/data/skinNodeGapFill.ts +68 -0
- package/src/data/spell-data.json.gz +0 -0
- package/src/data/spell-script-targets.json +1 -0
- package/src/data/tables/ahItemValues.json.gz +0 -0
- package/src/data/tables/alteracValley.json.gz +0 -0
- package/src/data/tables/areatriggerTeleports.json.gz +0 -0
- package/src/data/tables/botNames.json.gz +0 -0
- package/src/data/tables/botPopulation.json.gz +0 -0
- package/src/data/tables/botSpecs.json.gz +0 -0
- package/src/data/tables/classLevelStats.json.gz +0 -0
- package/src/data/tables/combatConditions.json.gz +0 -0
- package/src/data/tables/combatSkillMeta.json.gz +0 -0
- package/src/data/tables/conditions.json.gz +0 -0
- package/src/data/tables/createInfo.json.gz +0 -0
- package/src/data/tables/creatureAggroGroups.json.gz +0 -0
- package/src/data/tables/creatureClassLevelStats.json.gz +0 -0
- package/src/data/tables/creaturePatrolPacks.json.gz +0 -0
- package/src/data/tables/creatureWeapons.json.gz +0 -0
- package/src/data/tables/creatures.json.gz +0 -0
- package/src/data/tables/dbScripts.json.gz +0 -0
- package/src/data/tables/dungeonAuthoredRoutes.json.gz +0 -0
- package/src/data/tables/dungeonCensus.json.gz +0 -0
- package/src/data/tables/dungeonGameObjects.json.gz +0 -0
- package/src/data/tables/dungeonPacks.json.gz +0 -0
- package/src/data/tables/dungeonPlateCover.json.gz +0 -0
- package/src/data/tables/dungeonSpawns.json.gz +0 -0
- package/src/data/tables/dungeonSurvey.json.gz +0 -0
- package/src/data/tables/durabilityCosts.json.gz +0 -0
- package/src/data/tables/durabilityQuality.json.gz +0 -0
- package/src/data/tables/enchantApplicators.json.gz +0 -0
- package/src/data/tables/entranceYards.json.gz +0 -0
- package/src/data/tables/explorationBasexp.json.gz +0 -0
- package/src/data/tables/factionTemplates.json.gz +0 -0
- package/src/data/tables/factions.json.gz +0 -0
- package/src/data/tables/gameEvents.json.gz +0 -0
- package/src/data/tables/gameObjects.json.gz +0 -0
- package/src/data/tables/gossipMenus.json.gz +0 -0
- package/src/data/tables/graveyards.json.gz +0 -0
- package/src/data/tables/instanceMaps.json.gz +0 -0
- package/src/data/tables/itemEnchantmentTemplates.json.gz +0 -0
- package/src/data/tables/itemEnchants.json.gz +0 -0
- package/src/data/tables/itemRandomProperties.json.gz +0 -0
- package/src/data/tables/itemSets.json.gz +0 -0
- package/src/data/tables/items.json.gz +0 -0
- package/src/data/tables/levelStats.json.gz +0 -0
- package/src/data/tables/locks.json.gz +0 -0
- package/src/data/tables/map-pin-overrides.json.gz +0 -0
- package/src/data/tables/nonCombatTrash.json.gz +0 -0
- package/src/data/tables/npcTexts.json.gz +0 -0
- package/src/data/tables/pageTexts.json.gz +0 -0
- package/src/data/tables/petAbilityTP.json.gz +0 -0
- package/src/data/tables/petGenericSpells.json.gz +0 -0
- package/src/data/tables/petLevelStats.json.gz +0 -0
- package/src/data/tables/playerbot-weightscales.json.gz +0 -0
- package/src/data/tables/pools.json.gz +0 -0
- package/src/data/tables/quests.json.gz +0 -0
- package/src/data/tables/races.json.gz +0 -0
- package/src/data/tables/reputationRanks.json.gz +0 -0
- package/src/data/tables/reputationRates.json.gz +0 -0
- package/src/data/tables/reputationSpillover.json.gz +0 -0
- package/src/data/tables/ridingSpells.json.gz +0 -0
- package/src/data/tables/scriptTexts.json.gz +0 -0
- package/src/data/tables/soundClipVolume.json.gz +0 -0
- package/src/data/tables/spellChain.json.gz +0 -0
- package/src/data/tables/spellTeleports.json.gz +0 -0
- package/src/data/tables/spells.json.gz +0 -0
- package/src/data/tables/talents.json.gz +0 -0
- package/src/data/tables/tavernTriggers.json.gz +0 -0
- package/src/data/tables/taxiNodes.json.gz +0 -0
- package/src/data/tables/taxiRoutes.json.gz +0 -0
- package/src/data/tables/trainers.json.gz +0 -0
- package/src/data/tables/transports.json.gz +0 -0
- package/src/data/tables/travelAnchors.json.gz +0 -0
- package/src/data/tables/travelEdges.json.gz +0 -0
- package/src/data/tables/unitConditions.json.gz +0 -0
- package/src/data/tables/vendors.json.gz +0 -0
- package/src/data/tables/weaponEnchantProcs.json.gz +0 -0
- package/src/data/tables/xp.json.gz +0 -0
- package/src/data/tables/zoneWeather.json.gz +0 -0
- package/src/data/tables/zones.json.gz +0 -0
- package/src/data/world-data.ts +56 -0
- package/src/data/zone-music-sets.json +2751 -0
- package/src/dev/etl/lib/loot-chance-sanity.mjs +180 -0
- package/src/domain/audioQuality.mjs +145 -0
- package/src/domain/bg/ab.ts +433 -0
- package/src/domain/bg/arenaComps.ts +644 -0
- package/src/domain/bg/arenaLab.ts +695 -0
- package/src/domain/bg/arenaPace.ts +31 -0
- package/src/domain/bg/arenaRating.ts +110 -0
- package/src/domain/bg/av.ts +758 -0
- package/src/domain/bg/avEnemyPush.ts +219 -0
- package/src/domain/bg/avField.ts +283 -0
- package/src/domain/bg/avInstanceNodes.ts +197 -0
- package/src/domain/bg/avInstanceScore.ts +123 -0
- package/src/domain/bg/avQuestItems.ts +55 -0
- package/src/domain/bg/avQuests.ts +210 -0
- package/src/domain/bg/avSession.ts +196 -0
- package/src/domain/bg/bgConsumes.ts +269 -0
- package/src/domain/bg/bgPrebuff.ts +153 -0
- package/src/domain/bg/bgRest.ts +91 -0
- package/src/domain/bg/bgRoster.ts +305 -0
- package/src/domain/bg/bgTier.ts +61 -0
- package/src/domain/bg/bgWorld.ts +862 -0
- package/src/domain/bg/match.ts +215 -0
- package/src/domain/bg/strategies.ts +552 -0
- package/src/domain/bg/types.ts +291 -0
- package/src/domain/bg/wsg.ts +264 -0
- package/src/domain/bots/actionProviderSpec.ts +38 -0
- package/src/domain/bots/autoConsumables.ts +285 -0
- package/src/domain/bots/betweenPullRest.ts +239 -0
- package/src/domain/bots/botGear.ts +248 -0
- package/src/domain/bots/botInventory.ts +486 -0
- package/src/domain/bots/botPet.ts +535 -0
- package/src/domain/bots/botPool.ts +291 -0
- package/src/domain/bots/botProfessions.ts +334 -0
- package/src/domain/bots/companionActionBar.ts +209 -0
- package/src/domain/bots/companionHireCost.ts +236 -0
- package/src/domain/bots/companionMissions.ts +582 -0
- package/src/domain/bots/companionPrep.ts +254 -0
- package/src/domain/bots/companionQuests.ts +270 -0
- package/src/domain/bots/companionRep.ts +75 -0
- package/src/domain/bots/companionRotation.ts +708 -0
- package/src/domain/bots/companionXp.ts +66 -0
- package/src/domain/bots/consumableShare.ts +811 -0
- package/src/domain/bots/dpsMate.ts +1072 -0
- package/src/domain/bots/groupCompReport.ts +132 -0
- package/src/domain/bots/healthstoneSupply.ts +198 -0
- package/src/domain/bots/outfitter.ts +1056 -0
- package/src/domain/bots/paladinPrePull.ts +231 -0
- package/src/domain/bots/partyRole.ts +40 -0
- package/src/domain/bots/playerbotEquipCache.ts +412 -0
- package/src/domain/bots/playerbotItemEligibility.ts +60 -0
- package/src/domain/bots/playerbotStatWeight.ts +853 -0
- package/src/domain/bots/playerbotUnavailableItems.ts +147 -0
- package/src/domain/bots/prePullBuffs.ts +219 -0
- package/src/domain/bots/prePullStealth.ts +82 -0
- package/src/domain/bots/runSupply.ts +251 -0
- package/src/domain/bots/runSupplyPrefs.ts +28 -0
- package/src/domain/bots/sendTradeGoods.ts +394 -0
- package/src/domain/bots/soulShardCap.ts +35 -0
- package/src/domain/bots/squad.ts +842 -0
- package/src/domain/bots/squadRun.ts +81 -0
- package/src/domain/character/actionbar.ts +346 -0
- package/src/domain/character/appearance.ts +165 -0
- package/src/domain/character/buildCombatant.ts +1726 -0
- package/src/domain/character/character.ts +356 -0
- package/src/domain/character/characterName.ts +43 -0
- package/src/domain/character/characterRatings.ts +424 -0
- package/src/domain/character/characterSpells.ts +282 -0
- package/src/domain/character/characterStats.ts +1559 -0
- package/src/domain/character/characterTalents.ts +398 -0
- package/src/domain/character/combatSkills.ts +994 -0
- package/src/domain/character/displayForm.ts +72 -0
- package/src/domain/character/formTalentAuras.ts +171 -0
- package/src/domain/character/forms.ts +499 -0
- package/src/domain/character/races.ts +40 -0
- package/src/domain/character/resurrectionSickness.ts +49 -0
- package/src/domain/character/spellbook.ts +169 -0
- package/src/domain/character/stanceBar.ts +354 -0
- package/src/domain/character/stancePrereq.ts +70 -0
- package/src/domain/character/talentBuilds.ts +63 -0
- package/src/domain/character/talentImport.ts +130 -0
- package/src/domain/character/talentLink.ts +123 -0
- package/src/domain/character/talents.ts +201 -0
- package/src/domain/core/conditionSnapshot.ts +92 -0
- package/src/domain/core/hover.ts +14 -0
- package/src/domain/core/ids.ts +58 -0
- package/src/domain/core/internalNameTags.ts +5 -0
- package/src/domain/core/runtimeDataPatches.ts +357 -0
- package/src/domain/creature/aiTargeting.ts +588 -0
- package/src/domain/creature/combatCondition.ts +157 -0
- package/src/domain/creature/creatureAggro.ts +804 -0
- package/src/domain/creature/creatureAi.ts +206 -0
- package/src/domain/creature/creatureAiConstants.ts +661 -0
- package/src/domain/creature/creatureCastList.ts +1007 -0
- package/src/domain/creature/creatureEventAi.ts +1409 -0
- package/src/domain/creature/creatureGroups.ts +144 -0
- package/src/domain/creature/creatureLinking.ts +333 -0
- package/src/domain/creature/creatureScaling.ts +320 -0
- package/src/domain/creature/creatureTrigger.ts +53 -0
- package/src/domain/creature/creatureWander.ts +74 -0
- package/src/domain/creature/eventAiTexts.ts +145 -0
- package/src/domain/creature/faction.ts +287 -0
- package/src/domain/creature/forcedReaction.ts +48 -0
- package/src/domain/creature/outdoorHuntable.ts +74 -0
- package/src/domain/creature/patrolPacks.ts +210 -0
- package/src/domain/creature/reputation.ts +967 -0
- package/src/domain/creature/unitFlags.ts +74 -0
- package/src/domain/creature/worldBosses.ts +393 -0
- package/src/domain/dungeonMusic.mjs +48 -0
- package/src/domain/economy/auction.ts +282 -0
- package/src/domain/economy/auctionBot.ts +1060 -0
- package/src/domain/economy/honorPrice.ts +100 -0
- package/src/domain/economy/mail.ts +958 -0
- package/src/domain/economy/money.ts +42 -0
- package/src/domain/economy/syntheticClassTrainers.ts +62 -0
- package/src/domain/economy/trading.ts +296 -0
- package/src/domain/economy/vendorSellAll.ts +252 -0
- package/src/domain/economy/vendorStock.ts +146 -0
- package/src/domain/items/ammo.ts +817 -0
- package/src/domain/items/bank.ts +162 -0
- package/src/domain/items/consumableFamily.ts +205 -0
- package/src/domain/items/craftUpgrades.ts +83 -0
- package/src/domain/items/createItem.ts +93 -0
- package/src/domain/items/durability.ts +581 -0
- package/src/domain/items/equipment.ts +441 -0
- package/src/domain/items/equipmentHelper.ts +767 -0
- package/src/domain/items/inventory.ts +561 -0
- package/src/domain/items/itemBonding.ts +93 -0
- package/src/domain/items/itemContainer.ts +245 -0
- package/src/domain/items/itemDisplayName.ts +33 -0
- package/src/domain/items/itemInstance.ts +181 -0
- package/src/domain/items/itemRandomEnchantOutcomes.ts +315 -0
- package/src/domain/items/itemRandomProps.ts +77 -0
- package/src/domain/items/itemRestrictions.ts +329 -0
- package/src/domain/items/itemTeaches.ts +82 -0
- package/src/domain/items/itemUseCooldown.ts +52 -0
- package/src/domain/items/itemUseTarget.ts +90 -0
- package/src/domain/items/junkCategories.ts +174 -0
- package/src/domain/items/junkFilter.ts +368 -0
- package/src/domain/items/keyring.ts +131 -0
- package/src/domain/items/loot.ts +221 -0
- package/src/domain/items/mounts.ts +190 -0
- package/src/domain/items/onUsePayload.ts +102 -0
- package/src/domain/items/pendingLoot.ts +107 -0
- package/src/domain/items/relic.ts +105 -0
- package/src/domain/items/rocketBoots.ts +36 -0
- package/src/domain/items/sortContainer.ts +139 -0
- package/src/domain/items/spareContainers.ts +71 -0
- package/src/domain/items/spellReagentIndex.ts +131 -0
- package/src/domain/items/staleConsumables.ts +66 -0
- package/src/domain/items/weaponSpender.ts +110 -0
- package/src/domain/listDungeonIds.mjs +28 -0
- package/src/domain/macro/compose.ts +239 -0
- package/src/domain/macro/conditions.ts +260 -0
- package/src/domain/macro/creatureTypes.ts +40 -0
- package/src/domain/macro/describe.ts +169 -0
- package/src/domain/macro/icon.ts +60 -0
- package/src/domain/macro/index.ts +20 -0
- package/src/domain/macro/normalize.ts +112 -0
- package/src/domain/macro/parse.ts +316 -0
- package/src/domain/macro/plan.ts +288 -0
- package/src/domain/macro/rotation.ts +590 -0
- package/src/domain/macro/rotationEnv.ts +173 -0
- package/src/domain/macro/slots.ts +101 -0
- package/src/domain/macro/snapshot.ts +114 -0
- package/src/domain/macro/templates.ts +446 -0
- package/src/domain/macro/types.ts +70 -0
- package/src/domain/macro/units.ts +93 -0
- package/src/domain/macro/weaponTypes.ts +83 -0
- package/src/domain/nav/cityTeleports.ts +10 -0
- package/src/domain/nav/mounting.ts +113 -0
- package/src/domain/nav/nav.ts +43 -0
- package/src/domain/nav/navCollision.ts +606 -0
- package/src/domain/nav/navOutdoors.ts +91 -0
- package/src/domain/nav/navRegistry.ts +179 -0
- package/src/domain/nav/navRoomGraph.ts +302 -0
- package/src/domain/nav/navTypes.ts +43 -0
- package/src/domain/nav/navmesh.ts +1715 -0
- package/src/domain/nav/speed.ts +200 -0
- package/src/domain/nav/storey.ts +10 -0
- package/src/domain/nav/travel.ts +725 -0
- package/src/domain/nav/travelTypes.ts +75 -0
- package/src/domain/pet/pet.ts +1150 -0
- package/src/domain/pet/petActionBar.ts +180 -0
- package/src/domain/pet/petSpellbook.ts +39 -0
- package/src/domain/pet/petStable.ts +81 -0
- package/src/domain/professions/autoDisenchant.ts +236 -0
- package/src/domain/professions/characterEnchants.ts +176 -0
- package/src/domain/professions/craftCooldown.ts +52 -0
- package/src/domain/professions/enchantApply.ts +62 -0
- package/src/domain/professions/enchantTargets.ts +114 -0
- package/src/domain/professions/enchanting.ts +236 -0
- package/src/domain/professions/gatherFilter.ts +149 -0
- package/src/domain/professions/gearEnchant.ts +137 -0
- package/src/domain/professions/heldTools.ts +29 -0
- package/src/domain/professions/learnAllRecipes.ts +146 -0
- package/src/domain/professions/miningHarvest.ts +69 -0
- package/src/domain/professions/partyDisenchant.ts +294 -0
- package/src/domain/professions/partyWork.ts +83 -0
- package/src/domain/professions/pickpocket.ts +172 -0
- package/src/domain/professions/poisons.ts +240 -0
- package/src/domain/professions/professions.ts +677 -0
- package/src/domain/professions/rareNodes.ts +45 -0
- package/src/domain/professions/skinLoot.ts +27 -0
- package/src/domain/professions/vendorReagents.ts +152 -0
- package/src/domain/professions/weaponImbueHand.ts +171 -0
- package/src/domain/questFarmFilter.mjs +42 -0
- package/src/domain/quests/doQuest.ts +1204 -0
- package/src/domain/quests/gossip.ts +308 -0
- package/src/domain/quests/gossipTalk.ts +298 -0
- package/src/domain/quests/interpreter/canComplete.ts +150 -0
- package/src/domain/quests/interpreter/claim.ts +137 -0
- package/src/domain/quests/interpreter/dbscript/handlers.ts +1371 -0
- package/src/domain/quests/interpreter/dbscript/handlersBatch.ts +1251 -0
- package/src/domain/quests/interpreter/dbscript/hooks.ts +331 -0
- package/src/domain/quests/interpreter/dbscript/index.ts +212 -0
- package/src/domain/quests/interpreter/dbscript/opcodes.ts +257 -0
- package/src/domain/quests/interpreter/dbscript/registry.ts +1194 -0
- package/src/domain/quests/interpreter/dbscript/registryAreatriggerScripts.ts +539 -0
- package/src/domain/quests/interpreter/dbscript/registryAshenvale.ts +553 -0
- package/src/domain/quests/interpreter/dbscript/registryAzshara.ts +272 -0
- package/src/domain/quests/interpreter/dbscript/registryDarkshore.ts +637 -0
- package/src/domain/quests/interpreter/dbscript/registryDesolace.ts +501 -0
- package/src/domain/quests/interpreter/dbscript/registryDustwallowMarsh.ts +735 -0
- package/src/domain/quests/interpreter/dbscript/registryFelwood.ts +493 -0
- package/src/domain/quests/interpreter/dbscript/registryFeralas.ts +485 -0
- package/src/domain/quests/interpreter/dbscript/registryGoScripts.ts +203 -0
- package/src/domain/quests/interpreter/dbscript/registryMoonglade.ts +288 -0
- package/src/domain/quests/interpreter/dbscript/registryNpcProfessions.ts +230 -0
- package/src/domain/quests/interpreter/dbscript/registryNpcsSpecial.ts +545 -0
- package/src/domain/quests/interpreter/dbscript/registryRazorfenDowns.ts +293 -0
- package/src/domain/quests/interpreter/dbscript/registryRazorfenKraul.ts +221 -0
- package/src/domain/quests/interpreter/dbscript/registryRedridge.ts +112 -0
- package/src/domain/quests/interpreter/dbscript/registrySearingGorge.ts +125 -0
- package/src/domain/quests/interpreter/dbscript/registrySiblings.ts +51 -0
- package/src/domain/quests/interpreter/dbscript/registrySilverpineForest.ts +172 -0
- package/src/domain/quests/interpreter/dbscript/registryStonetalonMountains.ts +180 -0
- package/src/domain/quests/interpreter/dbscript/registryStormwindCity.ts +369 -0
- package/src/domain/quests/interpreter/dbscript/registryStranglethornVale.ts +115 -0
- package/src/domain/quests/interpreter/dbscript/registryStratholme.ts +146 -0
- package/src/domain/quests/interpreter/dbscript/registrySunkenTemple.ts +149 -0
- package/src/domain/quests/interpreter/dbscript/registrySwampOfSorrows.ts +163 -0
- package/src/domain/quests/interpreter/dbscript/registryTanaris.ts +318 -0
- package/src/domain/quests/interpreter/dbscript/registryTeldrassil.ts +120 -0
- package/src/domain/quests/interpreter/dbscript/registryTheBarrens.ts +603 -0
- package/src/domain/quests/interpreter/dbscript/registryThousandNeedles.ts +499 -0
- package/src/domain/quests/interpreter/dbscript/registryTirisfalGlades.ts +222 -0
- package/src/domain/quests/interpreter/dbscript/registryUngoroCrater.ts +291 -0
- package/src/domain/quests/interpreter/dbscript/registryWarEffort.ts +773 -0
- package/src/domain/quests/interpreter/dbscript/registryWesternPlaguelands.ts +206 -0
- package/src/domain/quests/interpreter/dbscript/registryWestfall.ts +190 -0
- package/src/domain/quests/interpreter/dbscript/registryWetlands.ts +186 -0
- package/src/domain/quests/interpreter/dbscript/registryWinterspring.ts +235 -0
- package/src/domain/quests/interpreter/dbscript/types.ts +817 -0
- package/src/domain/quests/interpreter/dbscript/vm.ts +171 -0
- package/src/domain/quests/interpreter/diff.ts +349 -0
- package/src/domain/quests/interpreter/fixtures/oracle-questlog-qi2.json +2417 -0
- package/src/domain/quests/interpreter/flags.ts +101 -0
- package/src/domain/quests/interpreter/index.ts +113 -0
- package/src/domain/quests/interpreter/live.ts +178 -0
- package/src/domain/quests/interpreter/types.ts +81 -0
- package/src/domain/quests/interpreter/updaters.ts +412 -0
- package/src/domain/quests/questCorpseUse.ts +155 -0
- package/src/domain/quests/questDialog.ts +43 -0
- package/src/domain/quests/questFight.ts +34 -0
- package/src/domain/quests/questObjectiveLabel.ts +39 -0
- package/src/domain/quests/questRewardChoice.ts +85 -0
- package/src/domain/quests/questScriptCredit.ts +26 -0
- package/src/domain/quests/questScriptItemUse.ts +74 -0
- package/src/domain/quests/questTameRods.ts +79 -0
- package/src/domain/quests/questlog.ts +1545 -0
- package/src/domain/quests/talkDeliver.ts +170 -0
- package/src/domain/raid/globalActionBar.ts +195 -0
- package/src/domain/raid/instanceRoster.ts +194 -0
- package/src/domain/raid/partySummon.ts +198 -0
- package/src/domain/raid/partyVault.ts +320 -0
- package/src/domain/raid/raidBossAbilities.ts +268 -0
- package/src/domain/raid/raidComp.ts +335 -0
- package/src/domain/raid/raidCustomRows.ts +453 -0
- package/src/domain/raid/raidEncounterGear.ts +298 -0
- package/src/domain/raid/raidEncounterTactics.ts +412 -0
- package/src/domain/raid/raidPlan.ts +509 -0
- package/src/domain/raid/raidPlanEdits.ts +98 -0
- package/src/domain/raid/raidPlanPacks.ts +480 -0
- package/src/domain/raid/raidRecovery.ts +183 -0
- package/src/domain/raid/raidRosterTemplate.ts +138 -0
- package/src/domain/rotation/auraSide.ts +68 -0
- package/src/domain/rotation/build.ts +3031 -0
- package/src/domain/rotation/classes/druid.ts +58 -0
- package/src/domain/rotation/classes/hooks.ts +59 -0
- package/src/domain/rotation/classes/hunter.ts +156 -0
- package/src/domain/rotation/classes/index.ts +104 -0
- package/src/domain/rotation/classes/mage.ts +99 -0
- package/src/domain/rotation/classes/paladin.ts +296 -0
- package/src/domain/rotation/classes/priest.ts +94 -0
- package/src/domain/rotation/classes/pullOpener.ts +92 -0
- package/src/domain/rotation/classes/rogue.ts +69 -0
- package/src/domain/rotation/classes/shaman.ts +29 -0
- package/src/domain/rotation/classes/supportSpec.ts +94 -0
- package/src/domain/rotation/classes/warlock.ts +81 -0
- package/src/domain/rotation/classes/warrior.ts +402 -0
- package/src/domain/rotation/classify.ts +1381 -0
- package/src/domain/rotation/condMetricPicker.ts +379 -0
- package/src/domain/rotation/consumables.ts +242 -0
- package/src/domain/rotation/evaluate.ts +1115 -0
- package/src/domain/rotation/finisherLadder.ts +145 -0
- package/src/domain/rotation/invent.ts +938 -0
- package/src/domain/rotation/killOrder.ts +30 -0
- package/src/domain/rotation/openerForm.ts +22 -0
- package/src/domain/rotation/paladinBuffs.ts +568 -0
- package/src/domain/rotation/prebuff.ts +283 -0
- package/src/domain/rotation/raidRowTuning.ts +34 -0
- package/src/domain/rotation/rotation.ts +11 -0
- package/src/domain/rotation/rotationProfiles.ts +180 -0
- package/src/domain/rotation/rotationSuggestions.ts +851 -0
- package/src/domain/rotation/ruleAfterChain.ts +49 -0
- package/src/domain/rotation/spec.ts +70 -0
- package/src/domain/rotation/spellPicker.ts +140 -0
- package/src/domain/rotation/stand.ts +143 -0
- package/src/domain/rotation/types.ts +718 -0
- package/src/domain/run/battlegroundRun.ts +111 -0
- package/src/domain/run/canEnterContext.ts +32 -0
- package/src/domain/run/death.ts +561 -0
- package/src/domain/run/deathRecovery.ts +289 -0
- package/src/domain/run/duel.ts +141 -0
- package/src/domain/run/dungeonRun.ts +344 -0
- package/src/domain/run/floorRest.ts +159 -0
- package/src/domain/run/honor.ts +557 -0
- package/src/domain/run/honorWeek.ts +180 -0
- package/src/domain/run/whenMap.ts +977 -0
- package/src/domain/scriptdev/arathiHighlands.ts +445 -0
- package/src/domain/scriptdev/ashenvale.ts +635 -0
- package/src/domain/scriptdev/ashenvaleHelpers.ts +1215 -0
- package/src/domain/scriptdev/azshara.ts +892 -0
- package/src/domain/scriptdev/blackfathomDeeps.ts +212 -0
- package/src/domain/scriptdev/blackrockDepths.ts +1434 -0
- package/src/domain/scriptdev/blackrockSpire.ts +730 -0
- package/src/domain/scriptdev/blackwingLair.ts +521 -0
- package/src/domain/scriptdev/burningSteppes.ts +62 -0
- package/src/domain/scriptdev/classFilter.ts +43 -0
- package/src/domain/scriptdev/darkshore.ts +817 -0
- package/src/domain/scriptdev/darkshoreHelpers.ts +853 -0
- package/src/domain/scriptdev/deadmines.ts +331 -0
- package/src/domain/scriptdev/desolace.ts +1239 -0
- package/src/domain/scriptdev/direMaul.ts +859 -0
- package/src/domain/scriptdev/durotar.ts +532 -0
- package/src/domain/scriptdev/dustwallowMarsh.ts +758 -0
- package/src/domain/scriptdev/dustwallowMarshHelpers.ts +994 -0
- package/src/domain/scriptdev/easternPlaguelands.ts +21 -0
- package/src/domain/scriptdev/felwood.ts +1055 -0
- package/src/domain/scriptdev/feralas.ts +571 -0
- package/src/domain/scriptdev/feralasHelpers.ts +838 -0
- package/src/domain/scriptdev/gnomeregan.ts +466 -0
- package/src/domain/scriptdev/guards.ts +616 -0
- package/src/domain/scriptdev/hinterlands.ts +693 -0
- package/src/domain/scriptdev/host.ts +1134 -0
- package/src/domain/scriptdev/index.ts +123 -0
- package/src/domain/scriptdev/instanceRaids.ts +136 -0
- package/src/domain/scriptdev/itemScripts.ts +37 -0
- package/src/domain/scriptdev/lochModan.ts +283 -0
- package/src/domain/scriptdev/maraudon.ts +232 -0
- package/src/domain/scriptdev/moltenCore.ts +831 -0
- package/src/domain/scriptdev/moonglade.ts +659 -0
- package/src/domain/scriptdev/moongladeHelpers.ts +933 -0
- package/src/domain/scriptdev/naxxramas.ts +577 -0
- package/src/domain/scriptdev/naxxramasConstruct.ts +364 -0
- package/src/domain/scriptdev/naxxramasFrostwyrm.ts +378 -0
- package/src/domain/scriptdev/naxxramasMilitary.ts +276 -0
- package/src/domain/scriptdev/npcProfessions.ts +1025 -0
- package/src/domain/scriptdev/npcsSpecial.ts +1379 -0
- package/src/domain/scriptdev/onyxiasLair.ts +313 -0
- package/src/domain/scriptdev/orgrimmar.ts +147 -0
- package/src/domain/scriptdev/professionSpecConsumer.ts +481 -0
- package/src/domain/scriptdev/razorfenDowns.ts +468 -0
- package/src/domain/scriptdev/razorfenKraul.ts +410 -0
- package/src/domain/scriptdev/redridgeMountains.ts +163 -0
- package/src/domain/scriptdev/registry.ts +945 -0
- package/src/domain/scriptdev/ruinsOfAhnqiraj.ts +356 -0
- package/src/domain/scriptdev/scarletMonastery.ts +713 -0
- package/src/domain/scriptdev/scholomance.ts +682 -0
- package/src/domain/scriptdev/searingGorge.ts +295 -0
- package/src/domain/scriptdev/shadowfangKeep.ts +181 -0
- package/src/domain/scriptdev/silithus.ts +71 -0
- package/src/domain/scriptdev/silverpineForest.ts +662 -0
- package/src/domain/scriptdev/stonetalonMountains.ts +493 -0
- package/src/domain/scriptdev/stormwindCity.ts +1192 -0
- package/src/domain/scriptdev/stranglethornVale.ts +402 -0
- package/src/domain/scriptdev/stratholme.ts +650 -0
- package/src/domain/scriptdev/stratholmeScripts.ts +505 -0
- package/src/domain/scriptdev/sunkenTemple.ts +736 -0
- package/src/domain/scriptdev/swampOfSorrows.ts +22 -0
- package/src/domain/scriptdev/tanaris.ts +391 -0
- package/src/domain/scriptdev/tanarisHelpers.ts +661 -0
- package/src/domain/scriptdev/teldrassil.ts +143 -0
- package/src/domain/scriptdev/templeOfAhnqiraj.ts +1013 -0
- package/src/domain/scriptdev/theBarrens.ts +709 -0
- package/src/domain/scriptdev/theBarrensHelpers.ts +1026 -0
- package/src/domain/scriptdev/thousandNeedles.ts +426 -0
- package/src/domain/scriptdev/thousandNeedlesHelpers.ts +566 -0
- package/src/domain/scriptdev/tirisfalGlades.ts +533 -0
- package/src/domain/scriptdev/types.ts +1026 -0
- package/src/domain/scriptdev/uldaman.ts +437 -0
- package/src/domain/scriptdev/ungoroCrater.ts +549 -0
- package/src/domain/scriptdev/ungoroCraterHelpers.ts +1006 -0
- package/src/domain/scriptdev/wailingCaverns.ts +700 -0
- package/src/domain/scriptdev/warEffort.ts +371 -0
- package/src/domain/scriptdev/westernPlaguelands.ts +952 -0
- package/src/domain/scriptdev/westfall.ts +767 -0
- package/src/domain/scriptdev/wetlands.ts +660 -0
- package/src/domain/scriptdev/winterspring.ts +482 -0
- package/src/domain/scriptdev/winterspringHelpers.ts +801 -0
- package/src/domain/scriptdev/worldBosses.ts +605 -0
- package/src/domain/scriptdev/zulfarrak.ts +478 -0
- package/src/domain/scriptdev/zulgurub.ts +1152 -0
- package/src/domain/sim/dummySim.ts +408 -0
- package/src/domain/sim/targetDummy.ts +29 -0
- package/src/domain/social/guild.ts +148 -0
- package/src/domain/spells/areaAuraMembership.ts +93 -0
- package/src/domain/spells/breakableStunCc.ts +166 -0
- package/src/domain/spells/cancelAura.ts +80 -0
- package/src/domain/spells/diminishing.ts +167 -0
- package/src/domain/spells/dispel.ts +149 -0
- package/src/domain/spells/dispelMechanic.ts +105 -0
- package/src/domain/spells/equipSpells.ts +247 -0
- package/src/domain/spells/learnOnTargets.ts +260 -0
- package/src/domain/spells/mergeSchoolImmunityFromRaw.ts +66 -0
- package/src/domain/spells/resurrectSpell.ts +124 -0
- package/src/domain/spells/spellPushback.ts +39 -0
- package/src/domain/spells/spellReflect.ts +43 -0
- package/src/domain/spells/stealth.ts +183 -0
- package/src/domain/spells/totem.ts +394 -0
- package/src/domain/spells/worldCast.ts +187 -0
- package/src/domain/world/areaTriggerLocks.ts +177 -0
- package/src/domain/world/dungeonMusic.ts +108 -0
- package/src/domain/world/gameEvents.ts +119 -0
- package/src/domain/world/gameObjects.ts +1030 -0
- package/src/domain/world/goEventFire.ts +234 -0
- package/src/domain/world/goMoTransport.ts +74 -0
- package/src/domain/world/goTransport.ts +81 -0
- package/src/domain/world/hazards.ts +459 -0
- package/src/domain/world/openLock.ts +398 -0
- package/src/domain/world/pools.ts +470 -0
- package/src/domain/world/restArea.ts +37 -0
- package/src/domain/world/weather.ts +201 -0
- package/src/domain/zoneAmbience.mjs +87 -0
- package/src/domain/zoneMusic.mjs +62 -0
- package/src/domain/zoneMusicQueue.mjs +7 -0
- package/src/engine/combat/activeSeal.ts +39 -0
- package/src/engine/combat/aiTargetResolve.ts +64 -0
- package/src/engine/combat/aoeCast.ts +289 -0
- package/src/engine/combat/applyConsumeAura.ts +74 -0
- package/src/engine/combat/applyDemonicSacrifice.ts +70 -0
- package/src/engine/combat/applyDispelMechanic.ts +30 -0
- package/src/engine/combat/applyHealEffect.ts +301 -0
- package/src/engine/combat/applySchoolAbsorb.ts +114 -0
- package/src/engine/combat/applySpell.ts +3169 -0
- package/src/engine/combat/applySpellLate.ts +2026 -0
- package/src/engine/combat/applySpellLateBag.ts +144 -0
- package/src/engine/combat/areaAura.ts +283 -0
- package/src/engine/combat/attackTable.ts +508 -0
- package/src/engine/combat/battleRez.ts +87 -0
- package/src/engine/combat/castAction.ts +36 -0
- package/src/engine/combat/castTargetGates.ts +75 -0
- package/src/engine/combat/castableKit.ts +68 -0
- package/src/engine/combat/ccMirrorUpgrade.ts +39 -0
- package/src/engine/combat/chainFan.ts +210 -0
- package/src/engine/combat/channel.ts +423 -0
- package/src/engine/combat/chaseCloseness.ts +95 -0
- package/src/engine/combat/cmangosCastGates.ts +129 -0
- package/src/engine/combat/combatFlag.ts +77 -0
- package/src/engine/combat/combatGeometry.ts +1329 -0
- package/src/engine/combat/combustion.ts +68 -0
- package/src/engine/combat/context.ts +730 -0
- package/src/engine/combat/createSession.ts +1165 -0
- package/src/engine/combat/creatureLeash.ts +38 -0
- package/src/engine/combat/crowdControl.ts +1259 -0
- package/src/engine/combat/dispelDuty.ts +54 -0
- package/src/engine/combat/dispelReflect.ts +609 -0
- package/src/engine/combat/displaceFloor.ts +113 -0
- package/src/engine/combat/duelBounds.ts +47 -0
- package/src/engine/combat/equippedItemGate.ts +297 -0
- package/src/engine/combat/evadeLifecycle.ts +63 -0
- package/src/engine/combat/eventAi.ts +2220 -0
- package/src/engine/combat/facing.ts +74 -0
- package/src/engine/combat/fearFlee.ts +137 -0
- package/src/engine/combat/fighterFactory.ts +1144 -0
- package/src/engine/combat/forceDespawnAction.ts +51 -0
- package/src/engine/combat/formulas.ts +807 -0
- package/src/engine/combat/friendlyFan.ts +55 -0
- package/src/engine/combat/groundPoolTick.ts +210 -0
- package/src/engine/combat/hazards.ts +114 -0
- package/src/engine/combat/healTargets.ts +226 -0
- package/src/engine/combat/heartbeatResist.ts +49 -0
- package/src/engine/combat/hostileItemUse.ts +75 -0
- package/src/engine/combat/interruptAuras.ts +66 -0
- package/src/engine/combat/itemRescue.ts +49 -0
- package/src/engine/combat/itemUse.ts +260 -0
- package/src/engine/combat/kitById.ts +23 -0
- package/src/engine/combat/knockBack.ts +201 -0
- package/src/engine/combat/leap.ts +89 -0
- package/src/engine/combat/mitigation.ts +587 -0
- package/src/engine/combat/modTaunt.ts +43 -0
- package/src/engine/combat/motionClaim.ts +268 -0
- package/src/engine/combat/motionGate.ts +150 -0
- package/src/engine/combat/motionGenerator.ts +27 -0
- package/src/engine/combat/navSight.ts +138 -0
- package/src/engine/combat/perfSink.ts +28 -0
- package/src/engine/combat/periodicDue.ts +55 -0
- package/src/engine/combat/petAuras.ts +86 -0
- package/src/engine/combat/pickAction.ts +3449 -0
- package/src/engine/combat/powerForm.ts +735 -0
- package/src/engine/combat/powerPools.ts +49 -0
- package/src/engine/combat/predicates.ts +538 -0
- package/src/engine/combat/procsDamage.ts +1823 -0
- package/src/engine/combat/reactiveGates.ts +135 -0
- package/src/engine/combat/roles.ts +389 -0
- package/src/engine/combat/rotationSubject.ts +78 -0
- package/src/engine/combat/ruleAfter.ts +106 -0
- package/src/engine/combat/seedDisplayAuras.ts +203 -0
- package/src/engine/combat/seedOocEffects.ts +317 -0
- package/src/engine/combat/seedSchoolImmunities.ts +45 -0
- package/src/engine/combat/session-types.ts +458 -0
- package/src/engine/combat/sessionApi.ts +1785 -0
- package/src/engine/combat/sessionCharge.ts +124 -0
- package/src/engine/combat/sessionChase.ts +869 -0
- package/src/engine/combat/sessionDeaths.ts +469 -0
- package/src/engine/combat/sessionFocus.ts +506 -0
- package/src/engine/combat/sessionFollow.ts +167 -0
- package/src/engine/combat/sessionGeometry.ts +188 -0
- package/src/engine/combat/sessionHome.ts +75 -0
- package/src/engine/combat/sessionInject.ts +719 -0
- package/src/engine/combat/sessionMechanicMove.ts +555 -0
- package/src/engine/combat/sessionMotion.ts +1553 -0
- package/src/engine/combat/sessionMotionKit.ts +247 -0
- package/src/engine/combat/sessionMoveIntent.ts +49 -0
- package/src/engine/combat/sessionMoveOrder.ts +200 -0
- package/src/engine/combat/sessionPathTo.ts +657 -0
- package/src/engine/combat/sessionPools.ts +688 -0
- package/src/engine/combat/sessionSteer.ts +144 -0
- package/src/engine/combat/sessionStepBack.ts +151 -0
- package/src/engine/combat/sessionStepWrap.ts +116 -0
- package/src/engine/combat/sessionView.ts +442 -0
- package/src/engine/combat/simEffects.ts +32 -0
- package/src/engine/combat/simFacade.ts +620 -0
- package/src/engine/combat/simPump.ts +264 -0
- package/src/engine/combat/simSnapshot.ts +165 -0
- package/src/engine/combat/simThreadPool.ts +35 -0
- package/src/engine/combat/skeramImages.ts +57 -0
- package/src/engine/combat/slowUpdate.ts +178 -0
- package/src/engine/combat/snapToFloor.ts +42 -0
- package/src/engine/combat/speedAura.ts +29 -0
- package/src/engine/combat/spellReagents.ts +71 -0
- package/src/engine/combat/stealthDetect.ts +93 -0
- package/src/engine/combat/stepBackMotion.ts +171 -0
- package/src/engine/combat/stepSession.ts +3102 -0
- package/src/engine/combat/summonCast.ts +243 -0
- package/src/engine/combat/thaddiusPolarity.ts +97 -0
- package/src/engine/combat/threat.ts +388 -0
- package/src/engine/combat/threatOps.ts +272 -0
- package/src/engine/combat/tickWorkerBody.ts +211 -0
- package/src/engine/combat/totemAuras.ts +122 -0
- package/src/engine/combat/triggerPayload.ts +42 -0
- package/src/engine/combat/triggeredCompanion.ts +63 -0
- package/src/engine/combat/types.ts +1897 -0
- package/src/engine/combat/useObjectTrap.ts +140 -0
- package/src/engine/combat/walkSurface.ts +54 -0
- package/src/engine/combat/weapon.ts +1248 -0
- package/src/engine/combat/worldFrame.ts +43 -0
- package/src/engine/combat.solo-golden.json +2242 -0
- package/src/engine/combat.ts +84 -0
- package/src/engine/core/detMath.ts +289 -0
- package/src/engine/core/events.ts +357 -0
- package/src/engine/core/rng.ts +36 -0
- package/src/engine/game/actionBars.ts +124 -0
- package/src/engine/game/activateObjectFromSpell.ts +320 -0
- package/src/engine/game/applyActiveObjectFromDbScript.ts +98 -0
- package/src/engine/game/applyDeathAndSpellScripts.ts +268 -0
- package/src/engine/game/applyDoorFromDbScript.ts +388 -0
- package/src/engine/game/applyEscortFromDbScript.ts +290 -0
- package/src/engine/game/applyGoSpellcasterCast.ts +40 -0
- package/src/engine/game/applyHoverFromDbScript.ts +110 -0
- package/src/engine/game/applyOocResurrect.ts +71 -0
- package/src/engine/game/applySpellDurability.ts +115 -0
- package/src/engine/game/applyTailFromDbScript.ts +478 -0
- package/src/engine/game/applyTerminateFromDbScript.ts +95 -0
- package/src/engine/game/auctionMail.ts +269 -0
- package/src/engine/game/bagOverflow.ts +130 -0
- package/src/engine/game/bank.ts +110 -0
- package/src/engine/game/barAutofill.ts +26 -0
- package/src/engine/game/battleground.ts +369 -0
- package/src/engine/game/combatEnemySpec.ts +216 -0
- package/src/engine/game/combatObjectTraps.ts +167 -0
- package/src/engine/game/combatSeed.ts +320 -0
- package/src/engine/game/combatSession.ts +3241 -0
- package/src/engine/game/combatSessionClock.ts +62 -0
- package/src/engine/game/companionQuestActions.ts +242 -0
- package/src/engine/game/companionTraining.ts +40 -0
- package/src/engine/game/consumables.ts +624 -0
- package/src/engine/game/context.ts +53 -0
- package/src/engine/game/createHealthstone.ts +45 -0
- package/src/engine/game/deathFlow.ts +127 -0
- package/src/engine/game/devGrant.ts +117 -0
- package/src/engine/game/dynamicObject.ts +365 -0
- package/src/engine/game/enchantItem.ts +177 -0
- package/src/engine/game/equipmentHelper.ts +806 -0
- package/src/engine/game/factionState.ts +108 -0
- package/src/engine/game/garmentsOoc.ts +69 -0
- package/src/engine/game/globalActionBar.ts +179 -0
- package/src/engine/game/goInteractQuestCredit.ts +51 -0
- package/src/engine/game/goMoTransportUse.ts +61 -0
- package/src/engine/game/goTransportUse.ts +60 -0
- package/src/engine/game/healthstoneUpkeep.ts +59 -0
- package/src/engine/game/killSkin.ts +124 -0
- package/src/engine/game/learnFromItem.ts +118 -0
- package/src/engine/game/loadReconcile.ts +551 -0
- package/src/engine/game/loot.ts +294 -0
- package/src/engine/game/macros.ts +125 -0
- package/src/engine/game/mail.ts +293 -0
- package/src/engine/game/meetingStoneQueue.ts +75 -0
- package/src/engine/game/meetingStoneUse.ts +54 -0
- package/src/engine/game/newGameState.ts +363 -0
- package/src/engine/game/oocAuraInterrupt.ts +92 -0
- package/src/engine/game/oocCast.ts +241 -0
- package/src/engine/game/oocCastEffects.ts +803 -0
- package/src/engine/game/oocCastMethods.ts +1077 -0
- package/src/engine/game/openLockFromSpell.ts +174 -0
- package/src/engine/game/outdoorPvp.ts +187 -0
- package/src/engine/game/outfitter.ts +644 -0
- package/src/engine/game/paladinBoard.ts +393 -0
- package/src/engine/game/partyAuras.ts +121 -0
- package/src/engine/game/persistCombatAuras.ts +91 -0
- package/src/engine/game/pets.ts +459 -0
- package/src/engine/game/prePullHealthstones.ts +154 -0
- package/src/engine/game/professions.ts +2227 -0
- package/src/engine/game/pruneStaleRuntime.ts +39 -0
- package/src/engine/game/questFightCredit.ts +36 -0
- package/src/engine/game/questItemOnCorpse.ts +166 -0
- package/src/engine/game/questItemOnCreature.ts +103 -0
- package/src/engine/game/questLog.ts +879 -0
- package/src/engine/game/questSpellComplete.ts +21 -0
- package/src/engine/game/questTurnIn.ts +598 -0
- package/src/engine/game/raidParty.ts +32 -0
- package/src/engine/game/reagentBuyIn.ts +39 -0
- package/src/engine/game/regenRest.ts +186 -0
- package/src/engine/game/rotation.ts +425 -0
- package/src/engine/game/runFullDungeon.ts +611 -0
- package/src/engine/game/runSupply.ts +80 -0
- package/src/engine/game/sanitizeDriftedItems.ts +135 -0
- package/src/engine/game/scriptDevGoUse.ts +397 -0
- package/src/engine/game/scriptDevInnkeeper.ts +150 -0
- package/src/engine/game/scriptDevProfessionSpec.ts +99 -0
- package/src/engine/game/sendEventFromSpell.ts +87 -0
- package/src/engine/game/sortContainers.ts +85 -0
- package/src/engine/game/spellReputation.ts +69 -0
- package/src/engine/game/squad/squadDungeonSeating.ts +197 -0
- package/src/engine/game/squadDungeon.ts +4222 -0
- package/src/engine/game/squadQuestShare.ts +260 -0
- package/src/engine/game/summonObjectSlot.ts +69 -0
- package/src/engine/game/summonObjectWild.ts +73 -0
- package/src/engine/game/summoningRitualUse.ts +141 -0
- package/src/engine/game/talents.ts +356 -0
- package/src/engine/game/tamingRodUse.ts +66 -0
- package/src/engine/game/tempSpawnCreature.ts +136 -0
- package/src/engine/game/tickDungeonPatrolScripts.ts +205 -0
- package/src/engine/game/tickTimedQuests.ts +28 -0
- package/src/engine/game/trade.ts +586 -0
- package/src/engine/game/travel.ts +1155 -0
- package/src/engine/game/types.ts +1855 -0
- package/src/engine/game/vendorOffers.ts +244 -0
- package/src/engine/game/weaponImbueItem.ts +281 -0
- package/src/engine/game/worldSession.ts +183 -0
- package/src/engine/game/worldState.ts +166 -0
- package/src/engine/game.ts +968 -0
- package/src/engine/spells/GAP.md +67 -0
- package/src/engine/spells/absorbs.ts +376 -0
- package/src/engine/spells/addTargetTrigger.ts +53 -0
- package/src/engine/spells/auraPerSecondCost.ts +50 -0
- package/src/engine/spells/auraStacking.ts +497 -0
- package/src/engine/spells/cmangos-special-cases-combustion.ts +13 -0
- package/src/engine/spells/cmangos-special-cases-s18.ts +445 -0
- package/src/engine/spells/cmangos-special-cases-s19.ts +324 -0
- package/src/engine/spells/cmangos-special-cases-s20.ts +385 -0
- package/src/engine/spells/cmangos-special-cases-s21.ts +116 -0
- package/src/engine/spells/cmangos-special-cases-s22.ts +24 -0
- package/src/engine/spells/cmangos-special-cases-s23.ts +52 -0
- package/src/engine/spells/cmangos-special-cases.ts +1570 -0
- package/src/engine/spells/conditions.ts +718 -0
- package/src/engine/spells/effects.ts +203 -0
- package/src/engine/spells/fixtures/oracle-effects-lock9a.json +1 -0
- package/src/engine/spells/immunity.ts +942 -0
- package/src/engine/spells/intentEffects.ts +351 -0
- package/src/engine/spells/interpreter/GAPS.md +21 -0
- package/src/engine/spells/interpreter/amount.ts +109 -0
- package/src/engine/spells/interpreter/class-scripts-kit.ts +478 -0
- package/src/engine/spells/interpreter/diff.ts +246 -0
- package/src/engine/spells/interpreter/duration.ts +90 -0
- package/src/engine/spells/interpreter/form-attrs.json +1 -0
- package/src/engine/spells/interpreter/form-attrs.ts +95 -0
- package/src/engine/spells/interpreter/handlers/aura-remove.ts +113 -0
- package/src/engine/spells/interpreter/handlers/auras-control.ts +1547 -0
- package/src/engine/spells/interpreter/handlers/auras-core.ts +1583 -0
- package/src/engine/spells/interpreter/handlers/auras-misc.ts +1774 -0
- package/src/engine/spells/interpreter/handlers/effect-disenchant.ts +17 -0
- package/src/engine/spells/interpreter/handlers/effect-skinning.ts +20 -0
- package/src/engine/spells/interpreter/handlers/effects-action-utility.ts +1455 -0
- package/src/engine/spells/interpreter/handlers/effects-core.ts +432 -0
- package/src/engine/spells/interpreter/handlers/effects-remainder.ts +105 -0
- package/src/engine/spells/interpreter/handlers/effects-summon-item.ts +687 -0
- package/src/engine/spells/interpreter/handlers/mod-increase-energy-percent.ts +36 -0
- package/src/engine/spells/interpreter/handlers/mod-increase-energy.ts +36 -0
- package/src/engine/spells/interpreter/handlers/periodic-trigger-zero.ts +327 -0
- package/src/engine/spells/interpreter/handlers/procs.ts +131 -0
- package/src/engine/spells/interpreter/handlers/registry.ts +975 -0
- package/src/engine/spells/interpreter/handlers/shared.ts +667 -0
- package/src/engine/spells/interpreter/handlers.ts +9 -0
- package/src/engine/spells/interpreter/hunter-kit.ts +202 -0
- package/src/engine/spells/interpreter/index.ts +525 -0
- package/src/engine/spells/interpreter/item-triggers.ts +1121 -0
- package/src/engine/spells/interpreter/lift-consume-energy.ts +37 -0
- package/src/engine/spells/interpreter/mage-portals.ts +37 -0
- package/src/engine/spells/interpreter/materialize-charm.ts +88 -0
- package/src/engine/spells/interpreter/materialize-dispel-mechanic.ts +25 -0
- package/src/engine/spells/interpreter/materialize-rating-buffs.ts +81 -0
- package/src/engine/spells/interpreter/materialize-speed.ts +109 -0
- package/src/engine/spells/interpreter/materialize-spell-magnet.ts +22 -0
- package/src/engine/spells/interpreter/opcodes.ts +789 -0
- package/src/engine/spells/interpreter/paladin-kit.ts +95 -0
- package/src/engine/spells/interpreter/paladin-seals.ts +499 -0
- package/src/engine/spells/interpreter/priest-warlock-kit.ts +135 -0
- package/src/engine/spells/interpreter/proc.ts +443 -0
- package/src/engine/spells/interpreter/registry/helpers.ts +16 -0
- package/src/engine/spells/interpreter/registry/index.ts +216 -0
- package/src/engine/spells/interpreter/registry/packs/class-abilities.ts +304 -0
- package/src/engine/spells/interpreter/registry/packs/dire-maul.ts +44 -0
- package/src/engine/spells/interpreter/registry/packs/dummy-script-tail.ts +1065 -0
- package/src/engine/spells/interpreter/registry/packs/ex-wave-m.ts +70 -0
- package/src/engine/spells/interpreter/registry/packs/life-tap.ts +107 -0
- package/src/engine/spells/interpreter/registry/packs/paladin.ts +246 -0
- package/src/engine/spells/interpreter/registry/packs/raid-script-summons.ts +26 -0
- package/src/engine/spells/interpreter/registry/packs/raid-threat-wipe.ts +22 -0
- package/src/engine/spells/interpreter/registry/packs/shaman.ts +214 -0
- package/src/engine/spells/interpreter/registry/packs/si4-dummy-generic-a.ts +269 -0
- package/src/engine/spells/interpreter/registry/packs/si4-dummy-generic-b.ts +370 -0
- package/src/engine/spells/interpreter/registry/packs/si4-dummy-generic-c.ts +172 -0
- package/src/engine/spells/interpreter/registry/packs/si4-dummy-hunter.ts +60 -0
- package/src/engine/spells/interpreter/registry/packs/si4-dummy-warrior.ts +31 -0
- package/src/engine/spells/interpreter/registry/packs/si4-script-generic-a.ts +114 -0
- package/src/engine/spells/interpreter/registry/packs/si4-script-generic-b.ts +249 -0
- package/src/engine/spells/interpreter/registry/packs/si4-script-generic-c.ts +233 -0
- package/src/engine/spells/interpreter/registry/types.ts +48 -0
- package/src/engine/spells/interpreter/talent-scripted.ts +329 -0
- package/src/engine/spells/interpreter/targeting.ts +90 -0
- package/src/engine/spells/interpreter/types-intent.ts +1501 -0
- package/src/engine/spells/interpreter/types.ts +419 -0
- package/src/engine/spells/interpreter/warrior-druid-kit.ts +314 -0
- package/src/engine/spells/interpreter/weapon-imbue-kit.ts +384 -0
- package/src/engine/spells/interrupt.ts +217 -0
- package/src/engine/spells/meleeAttackReset.ts +60 -0
- package/src/engine/spells/oocTriggerSpell.ts +49 -0
- package/src/engine/spells/overrideClassScripts.ts +319 -0
- package/src/engine/spells/parryHaste.ts +20 -0
- package/src/engine/spells/procs.ts +300 -0
- package/src/engine/spells/recovery.ts +203 -0
- package/src/engine/spells/scriptTargetDest.ts +76 -0
- package/src/engine/spells/scriptTargets.ts +85 -0
- package/src/engine/spells/singleTargetAura.ts +82 -0
- package/src/engine/spells/specialCasePayloads.ts +57 -0
- package/src/engine/spells/spellAttributes.ts +249 -0
- package/src/engine/spells/spellBonus.ts +143 -0
- package/src/engine/spells/spellModIntents.ts +419 -0
- package/src/engine/spells/spellMods.ts +283 -0
- package/src/engine/spells/spellRadius.ts +15 -0
- package/src/engine/spells/trapObjects.ts +26 -0
- package/src/json.d.ts +7 -0
- package/src/persistence/memoryRepository.ts +23 -0
- package/src/persistence/saveBackups.ts +162 -0
- package/src/persistence/saveFile.ts +68 -0
- package/src/persistence/saveRepository.ts +11 -0
- package/src/persistence/saveShape.ts +668 -0
- package/src/progression/leveling.ts +89 -0
- package/src/progression/rest.ts +1434 -0
- package/src/progression/training.ts +226 -0
- package/src/progression/xpGain.ts +369 -0
- package/src/quests/quests.ts +1580 -0
- package/src/world/aoePull.ts +198 -0
- package/src/world/areaTableDbc.ts +39 -0
- package/src/world/areaTableMapIdPairs.ts +141 -0
- package/src/world/bakeSlug.ts +43 -0
- package/src/world/continuousDungeon.ts +1250 -0
- package/src/world/dungeonBakeProjection.ts +190 -0
- package/src/world/dungeonMapDensity.ts +342 -0
- package/src/world/dungeonMapProjection.ts +135 -0
- package/src/world/dungeonNav.ts +904 -0
- package/src/world/dungeonNpcSim.ts +147 -0
- package/src/world/dungeonObjectives.ts +234 -0
- package/src/world/dungeonPreset.ts +35 -0
- package/src/world/dungeonRoute.ts +311 -0
- package/src/world/dungeonRouteGeometry.ts +732 -0
- package/src/world/dungeonRouteOrder.ts +1037 -0
- package/src/world/dungeonWingRooms.ts +426 -0
- package/src/world/escort.ts +296 -0
- package/src/world/goPoolRoll.ts +75 -0
- package/src/world/instanceObjects.ts +785 -0
- package/src/world/instances.ts +1572 -0
- package/src/world/meetingStones.ts +56 -0
- package/src/world/navmeshFloors.ts +145 -0
- package/src/world/nearGrid.ts +167 -0
- package/src/world/packBudget.ts +613 -0
- package/src/world/rareRoll.ts +335 -0
- package/src/world/routeAuthoring.ts +132 -0
- package/src/world/routeEdit.ts +209 -0
- package/src/world/world.ts +812 -0
- package/src/world/zoneHazards.ts +47 -0
|
@@ -0,0 +1,708 @@
|
|
|
1
|
+
// Companion auto-combat is the SAME system as the player: shared packs, shared Rotation shape and
|
|
2
|
+
// shared chooseCombatAction. This module is role→band picks, the default seed and thin glue.
|
|
3
|
+
|
|
4
|
+
import type { DataStore } from '../../data/dataStore.ts';
|
|
5
|
+
import type { SpellDef } from '../../data/schema.ts';
|
|
6
|
+
import type { AllyActionProvider, AllyCombatAction, ProviderNeeds } from '../../engine/combat.ts';
|
|
7
|
+
import { resolveCombatSpell } from '../../engine/spells/interpreter/item-triggers.ts';
|
|
8
|
+
import { combatItems, type Character } from '../character/character.ts';
|
|
9
|
+
import { equippedEntries } from '../items/itemInstance.ts';
|
|
10
|
+
import type { Inventory } from '../items/inventory.ts';
|
|
11
|
+
import { imbueItemsIn } from './companionPrep.ts';
|
|
12
|
+
import { consumableFamilyKey } from '../items/consumableFamily.ts';
|
|
13
|
+
import { allEncounterTacticRules, encounterTacticRows } from '../raid/raidEncounterTactics.ts';
|
|
14
|
+
import {
|
|
15
|
+
CLASS_DEFAULT_SPEC,
|
|
16
|
+
getClassSuggestions,
|
|
17
|
+
selectBand,
|
|
18
|
+
suggestionClassKeyFromClassId,
|
|
19
|
+
} from '../rotation/rotationSuggestions.ts';
|
|
20
|
+
import type { SpellBook } from '../character/spellbook.ts';
|
|
21
|
+
import {
|
|
22
|
+
buildDefaultRotation,
|
|
23
|
+
ensureKnownDispelRows,
|
|
24
|
+
chooseCombatAction,
|
|
25
|
+
chooseOocAction,
|
|
26
|
+
defaultItemRuleConditions,
|
|
27
|
+
isRotationValid,
|
|
28
|
+
peekHaltDpsSchool,
|
|
29
|
+
primarySpec,
|
|
30
|
+
peekKillOrderEntries,
|
|
31
|
+
keepAuraIdsOf,
|
|
32
|
+
killOrderEntriesFromAction,
|
|
33
|
+
ROTATION_PHASES,
|
|
34
|
+
rotationSigDiffers,
|
|
35
|
+
type Rotation,
|
|
36
|
+
type RotationPhase,
|
|
37
|
+
type RotationRule,
|
|
38
|
+
type RotationSnapshot,
|
|
39
|
+
type RotationProfileId,
|
|
40
|
+
type RotationBandOptions,
|
|
41
|
+
type RuleAfter,
|
|
42
|
+
type RuleSpellTarget,
|
|
43
|
+
} from '../rotation/rotation.ts';
|
|
44
|
+
import { friendlyCastItemGate } from '../rotation/consumables.ts';
|
|
45
|
+
import {
|
|
46
|
+
companionCharacter,
|
|
47
|
+
companionLevel,
|
|
48
|
+
companionSpellbook,
|
|
49
|
+
decodeAoeMode,
|
|
50
|
+
encodeAoeMode,
|
|
51
|
+
resolveAoeMode,
|
|
52
|
+
resolveOffHeal,
|
|
53
|
+
type Companion,
|
|
54
|
+
type CompanionAoeMode,
|
|
55
|
+
type SquadRole,
|
|
56
|
+
} from './squad.ts';
|
|
57
|
+
|
|
58
|
+
// Suggestion-band override for a squad role so tank/healer do not seed Arms/Ret defaults. Matches
|
|
59
|
+
// CLASS_DEFAULT_SPEC role counterparts used by botSpecs + packs.
|
|
60
|
+
export function roleSpecOverride(cls: number, role: SquadRole): string | null {
|
|
61
|
+
if (role === 'dps') return null;
|
|
62
|
+
// CLASS ids: 1 warrior, 2 paladin, 3 hunter, 4 rogue, 5 priest, 7 shaman, 8 mage, 9 warlock, 11 druid
|
|
63
|
+
if (role === 'tank') {
|
|
64
|
+
if (cls === 1) return 'Protection';
|
|
65
|
+
if (cls === 2) return 'Protection';
|
|
66
|
+
if (cls === 11) return 'Feral tank';
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
// healer
|
|
70
|
+
if (cls === 2) return 'Holy';
|
|
71
|
+
if (cls === 5) return 'Holy';
|
|
72
|
+
if (cls === 7) return 'Restoration';
|
|
73
|
+
if (cls === 11) return 'Restoration';
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Tank / healer bands — the only characters offered a second DPS profile, since a DPS band's
|
|
78
|
+
// primary already is one. The same table partyRole.ts:51-55 reads, kept here for both sides.
|
|
79
|
+
export function isSupportRotationBand(cls: number, band: string | null | undefined): boolean {
|
|
80
|
+
if (!band) return false;
|
|
81
|
+
if (band === roleSpecOverride(cls, 'tank') || band === roleSpecOverride(cls, 'healer')) return true;
|
|
82
|
+
return cls === 5 && band === 'Discipline'; // Disc heals; the band table only names Holy
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Band the second profile builds on: the class's damage tree. Cite: domain/rotation/rotationSuggestions.ts
|
|
86
|
+
// CLASS_DEFAULT_SPEC.
|
|
87
|
+
export function dpsRotationBand(cls: number, supportBand?: string | null): string | undefined {
|
|
88
|
+
// Feral tank's damage half is the other side of the same tree, not the class default.
|
|
89
|
+
if (supportBand === 'Feral tank') return 'Feral';
|
|
90
|
+
const key = suggestionClassKeyFromClassId(cls);
|
|
91
|
+
return key ? CLASS_DEFAULT_SPEC[key] : undefined;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** First botSpecs index whose dungeon role matches (for hire / lazy talent stamp). */
|
|
95
|
+
export function botSpecIdxForRole(cls: number, role: SquadRole, ds: DataStore): number | undefined {
|
|
96
|
+
const specs = ds.botSpecs(cls);
|
|
97
|
+
const i = specs.findIndex((s) => s.role === role);
|
|
98
|
+
return i >= 0 ? i : undefined;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** Premade for a hire/resign role. Keeps `current` when that spec already plays `role`. */
|
|
102
|
+
export function specIdxForRole(
|
|
103
|
+
cls: number,
|
|
104
|
+
role: SquadRole,
|
|
105
|
+
current: number | undefined,
|
|
106
|
+
ds: DataStore,
|
|
107
|
+
): number | undefined {
|
|
108
|
+
if (current != null && ds.botSpecs(cls)[current]?.role === role) return current;
|
|
109
|
+
return botSpecIdxForRole(cls, role, ds) ?? current;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/** Assign role + matching premade. Drops a non-custom rotation so the next ensure rebuilds. */
|
|
113
|
+
export function applyCompanionRole(comp: Companion, role: SquadRole, ds: DataStore): void {
|
|
114
|
+
const idx = specIdxForRole(comp.cls, role, comp.specIdx, ds);
|
|
115
|
+
comp.role = role;
|
|
116
|
+
if (idx != null && comp.specIdx !== idx) {
|
|
117
|
+
comp.specIdx = idx;
|
|
118
|
+
if (comp.talentLink) delete comp.talentLink;
|
|
119
|
+
}
|
|
120
|
+
if (comp.rotation && !comp.rotation.custom) delete comp.rotation;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** Whether this companion's band is a tank/healer tree, i.e. it gets a second DPS profile. */
|
|
124
|
+
export function companionHasDpsProfile(comp: Companion): boolean {
|
|
125
|
+
return isSupportRotationBand(comp.cls, roleSpecOverride(comp.cls, comp.role));
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** The profile in force. 'dps' collapses to primary the moment the role stops being support. */
|
|
129
|
+
export function companionActiveProfile(comp: Companion): RotationProfileId {
|
|
130
|
+
return comp.rotationProfile === 'dps' && companionHasDpsProfile(comp) ? 'dps' : 'primary';
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/** The stored rotation in one profile slot. */
|
|
134
|
+
export function companionRotationSlot(comp: Companion, profile: RotationProfileId): Rotation | undefined {
|
|
135
|
+
return profile === 'dps' ? comp.rotationDps : comp.rotation;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/** Write one profile slot (mutates — callers already own the squad member). */
|
|
139
|
+
export function setCompanionRotationSlot(
|
|
140
|
+
comp: Companion,
|
|
141
|
+
profile: RotationProfileId,
|
|
142
|
+
rot: Rotation,
|
|
143
|
+
): void {
|
|
144
|
+
if (profile === 'dps') comp.rotationDps = rot;
|
|
145
|
+
else comp.rotation = rot;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// The exact (char, spellbook, band) triple a companion default is generated from. Shared so the
|
|
149
|
+
// sig test reads the same inputs the build stamps — drift between them would rebuild every read.
|
|
150
|
+
function companionRotationInputs(
|
|
151
|
+
comp: Companion,
|
|
152
|
+
level: number,
|
|
153
|
+
ds: DataStore,
|
|
154
|
+
profile: RotationProfileId,
|
|
155
|
+
): { char: Character; sb: SpellBook; bags: Inventory | undefined; specOver: string | null | undefined } {
|
|
156
|
+
const roleSpec = comp.specIdx == null ? botSpecIdxForRole(comp.cls, comp.role, ds) : undefined;
|
|
157
|
+
const stamped: Companion = roleSpec != null ? { ...comp, specIdx: roleSpec } : comp;
|
|
158
|
+
const roleBand = roleSpecOverride(comp.cls, comp.role);
|
|
159
|
+
return {
|
|
160
|
+
char: companionCharacter(stamped, level, ds),
|
|
161
|
+
sb: companionSpellbook(stamped, level, ds),
|
|
162
|
+
bags: comp.bags,
|
|
163
|
+
specOver: profile === 'dps' ? (dpsRotationBand(comp.cls, roleBand) ?? null) : roleBand,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// True when a stored companion default was built for a different level, spec or known-spell count
|
|
168
|
+
// than it has now. Ignores `custom`: the caller decides, exactly as on the player side.
|
|
169
|
+
export function companionRotationSigDiffers(
|
|
170
|
+
comp: Companion,
|
|
171
|
+
level: number,
|
|
172
|
+
ds: DataStore,
|
|
173
|
+
rot: Rotation,
|
|
174
|
+
profile: RotationProfileId = 'primary',
|
|
175
|
+
opts?: RotationBandOptions,
|
|
176
|
+
): boolean {
|
|
177
|
+
const { char, sb, specOver } = companionRotationInputs(comp, level, ds, profile);
|
|
178
|
+
return rotationSigDiffers(rot, char, sb, ds, specOver, opts);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// True when a pvp band really covers this body's level AND tree. `selectBand` falls back to the PvE
|
|
182
|
+
// ladder when it does not, so a list asked for as pvp would silently be the PvE one.
|
|
183
|
+
export function companionHasPvpBand(comp: Companion, level: number, ds: DataStore): boolean {
|
|
184
|
+
const key = suggestionClassKeyFromClassId(comp.cls);
|
|
185
|
+
if (!key) return false;
|
|
186
|
+
const { char, specOver } = companionRotationInputs(comp, level, ds, 'primary');
|
|
187
|
+
const spec = primarySpec(char, ds, specOver);
|
|
188
|
+
return selectBand(getClassSuggestions(key), level, spec, { mode: 'pvp' })?.mode === 'pvp';
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Role-adapted default: the same buildDefaultRotation the player gets, with the Protection / Holy
|
|
192
|
+
// / Resto band when the role asks. `profile: 'dps'` swaps that for the class damage band.
|
|
193
|
+
export function buildCompanionRotation(
|
|
194
|
+
comp: Companion,
|
|
195
|
+
level: number,
|
|
196
|
+
ds: DataStore,
|
|
197
|
+
profile: RotationProfileId = 'primary',
|
|
198
|
+
opts?: RotationBandOptions,
|
|
199
|
+
): Rotation {
|
|
200
|
+
const { char, sb, bags, specOver } = companionRotationInputs(comp, level, ds, profile);
|
|
201
|
+
// A known dispel no band authored. Memoized with the build, so BG and arena readers pay it once.
|
|
202
|
+
let base = ensureKnownDispelRows(buildDefaultRotation(char, sb, ds, bags, specOver, opts), sb, ds);
|
|
203
|
+
base = { ...base, profile };
|
|
204
|
+
if (base.autoSig) {
|
|
205
|
+
base = { ...base, autoSig: { ...base.autoSig, role: profile === 'dps' ? 'dps' : comp.role } };
|
|
206
|
+
}
|
|
207
|
+
return base;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// One built default per (companion, inputs) — a 40v40 gate asks per seat three times over. The
|
|
211
|
+
// key carries every input the build reads, so a drunk elixir or a respec honestly rebuilds.
|
|
212
|
+
const builtRotationMemo = new WeakMap<Companion, Map<string, Rotation>>();
|
|
213
|
+
|
|
214
|
+
function rotationBuildKey(
|
|
215
|
+
comp: Companion,
|
|
216
|
+
level: number,
|
|
217
|
+
profile: RotationProfileId,
|
|
218
|
+
opts?: RotationBandOptions,
|
|
219
|
+
): string {
|
|
220
|
+
const bags = comp.bags?.stacks.map((s) => `${s.item}:${s.count}`).join(',') ?? '';
|
|
221
|
+
const gear = Object.values(equippedEntries(comp.equipped)).join(',');
|
|
222
|
+
const auras = comp.prePullAuras?.map((a) => a.spellId).join(',') ?? '';
|
|
223
|
+
return `${profile}|${opts?.mode ?? ''}|${opts?.variant ?? ''}|${level}|${comp.specIdx ?? -1}`
|
|
224
|
+
+ `|${comp.talentLink ?? ''}|${comp.role}|${bags}|${gear}|${auras}`;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Stored rotation for a profile when valid for the class, else a fresh band default. `mode: 'pvp'`
|
|
228
|
+
// is the duel / BG request: a hand-edited list is never swapped, an untouched default rebuilds.
|
|
229
|
+
export function companionRotationOf(
|
|
230
|
+
comp: Companion,
|
|
231
|
+
playerLevel: number,
|
|
232
|
+
ds: DataStore,
|
|
233
|
+
profile: RotationProfileId = companionActiveProfile(comp),
|
|
234
|
+
opts?: RotationBandOptions,
|
|
235
|
+
): Rotation {
|
|
236
|
+
const stored = companionRotationSlot(comp, profile);
|
|
237
|
+
if (isRotationValid(stored, comp.cls)) {
|
|
238
|
+
const sameFight = (stored.autoSig?.mode ?? undefined) === (opts?.mode ?? undefined)
|
|
239
|
+
&& (stored.autoSig?.variant ?? undefined) === (opts?.variant ?? undefined);
|
|
240
|
+
if (stored.custom === true || sameFight) return stored;
|
|
241
|
+
}
|
|
242
|
+
const level = companionLevel(comp, playerLevel);
|
|
243
|
+
const key = rotationBuildKey(comp, level, profile, opts);
|
|
244
|
+
let perComp = builtRotationMemo.get(comp);
|
|
245
|
+
const hit = perComp?.get(key);
|
|
246
|
+
if (hit) return hit;
|
|
247
|
+
const built = buildCompanionRotation(comp, level, ds, profile, opts);
|
|
248
|
+
if (!perComp) { perComp = new Map(); builtRotationMemo.set(comp, perComp); }
|
|
249
|
+
perComp.set(key, built);
|
|
250
|
+
return built;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// `preferAoeRules` allocates two arrays and a rotation object, and ran per unit per tick in AoE
|
|
254
|
+
// mode. It is pure in (rotation, classifier), so one memo per rotation object is enough.
|
|
255
|
+
const aoeRotCache = new WeakMap<Rotation, Rotation>();
|
|
256
|
+
function aoeRotationOf(rot: Rotation, isMultiSpell: (spellId: number) => boolean): Rotation {
|
|
257
|
+
let hit = aoeRotCache.get(rot);
|
|
258
|
+
if (hit === undefined) {
|
|
259
|
+
hit = preferAoeRules(rot, isMultiSpell);
|
|
260
|
+
aoeRotCache.set(rot, hit);
|
|
261
|
+
}
|
|
262
|
+
return hit;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/** Reorder combat so multi-target spells are considered first (S4C aoe prefer). */
|
|
266
|
+
export function preferAoeRules(
|
|
267
|
+
rot: Rotation,
|
|
268
|
+
isMultiSpell: (spellId: number) => boolean,
|
|
269
|
+
): Rotation {
|
|
270
|
+
const multi: RotationRule[] = [];
|
|
271
|
+
const rest: RotationRule[] = [];
|
|
272
|
+
for (const r of rot.phases.combat) {
|
|
273
|
+
if (r.action.kind === 'spell' && isMultiSpell(r.action.spellId)) multi.push(r);
|
|
274
|
+
else rest.push(r);
|
|
275
|
+
}
|
|
276
|
+
if (multi.length === 0) return rot;
|
|
277
|
+
return { ...rot, phases: { ...rot.phases, combat: [...multi, ...rest] } };
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// Inject item rules for combat consumables currently in the companion's bags. Hire seeds once; gifts arrive
|
|
281
|
+
// later — idempotent on existing item-entry rules.
|
|
282
|
+
export function syncCompanionBagItemRules(
|
|
283
|
+
rot: Rotation,
|
|
284
|
+
char: Character,
|
|
285
|
+
bags: Inventory | undefined,
|
|
286
|
+
ds: DataStore,
|
|
287
|
+
): Rotation {
|
|
288
|
+
if (!bags?.stacks.length) return rot;
|
|
289
|
+
const items = combatItems(char, bags, ds);
|
|
290
|
+
// Weapon imbues are never CombatItems (out-of-combat only), so they need their own scan.
|
|
291
|
+
const imbues = imbueItemsIn(bags, ds);
|
|
292
|
+
if (!items.length && !imbues.length) return rot;
|
|
293
|
+
|
|
294
|
+
// Entries a seed may add but must never switch ON — see the `enabled` line below. A character
|
|
295
|
+
// seeded before that rule still carries the enabled row, so an existing one is flipped too.
|
|
296
|
+
const neverAutoOn = new Set<number>();
|
|
297
|
+
for (const it of items) {
|
|
298
|
+
if (it.reusable === true) continue;
|
|
299
|
+
if (it.effect.kind === 'hostile_cast') { neverAutoOn.add(it.entry); continue; }
|
|
300
|
+
if (it.effect.kind !== 'friendly_cast') continue;
|
|
301
|
+
const g = friendlyCastItemGate(it.effect.spell, it.effect.spellId, ds);
|
|
302
|
+
if (g.autoOff || g.neverAuto) neverAutoOn.add(it.entry);
|
|
303
|
+
}
|
|
304
|
+
const autoSeeded = (r: RotationRule): boolean =>
|
|
305
|
+
r.action.kind === 'item' && r.id === `g-item-${r.action.itemEntry}`
|
|
306
|
+
&& neverAutoOn.has(r.action.itemEntry);
|
|
307
|
+
|
|
308
|
+
const have = new Set<number>();
|
|
309
|
+
const haveFamilies = new Set<string>();
|
|
310
|
+
let flip = false;
|
|
311
|
+
for (const p of ROTATION_PHASES) {
|
|
312
|
+
for (const r of rot.phases[p] ?? []) {
|
|
313
|
+
if (r.action.kind !== 'item') continue;
|
|
314
|
+
have.add(r.action.itemEntry);
|
|
315
|
+
if (r.action.family) haveFamilies.add(r.action.family);
|
|
316
|
+
if (r.enabled && autoSeeded(r)) flip = true;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// Every CombatItem kind gets seeded. Before this only restore and apply_buff were handled, so
|
|
321
|
+
// all 28 grenades and the whole immunity kit sat in a companion's bags unusable.
|
|
322
|
+
const add: Record<RotationPhase, RotationRule[]> = {
|
|
323
|
+
prebuff: [], buffs: [], pull: [], combat: [], recovery: [],
|
|
324
|
+
};
|
|
325
|
+
for (const it of items) {
|
|
326
|
+
if (have.has(it.entry) || (it.family != null && haveFamilies.has(it.family))) continue;
|
|
327
|
+
const kind = it.effect.kind;
|
|
328
|
+
const buffSpellId = it.effect.kind === 'apply_buff' ? it.effect.spellId : undefined;
|
|
329
|
+
// A friendly_cast rides its whole SpellDef, and the gate is read off that payload — a Target
|
|
330
|
+
// Dummy and a Free Action Potion are not the same row (consumables.ts friendlyCastItemGate).
|
|
331
|
+
const payload = it.effect.kind === 'friendly_cast'
|
|
332
|
+
? { spell: it.effect.spell, spellId: it.effect.spellId, ds }
|
|
333
|
+
: {};
|
|
334
|
+
const { conditions, phase, autoOff, neverAuto } = defaultItemRuleConditions(kind, {
|
|
335
|
+
itemEntry: it.entry,
|
|
336
|
+
...(buffSpellId != null ? { buffSpellId } : {}),
|
|
337
|
+
...payload,
|
|
338
|
+
});
|
|
339
|
+
// A seeded hostile_cast carries `target.healthPct > 30` (build.ts:401), which is every mob on
|
|
340
|
+
// every pull — so a use that DESTROYS the item spends it with nobody asking. Seed it off.
|
|
341
|
+
// `neverAuto` is the worn self-harm case: reusable, and still never fired unasked.
|
|
342
|
+
const spendsTheItem = (kind === 'hostile_cast' || autoOff === true) && it.reusable !== true;
|
|
343
|
+
add[phase].push({
|
|
344
|
+
id: `g-item-${it.entry}`,
|
|
345
|
+
action: { kind: 'item', itemEntry: it.entry, ...(it.family ? { family: it.family } : {}) },
|
|
346
|
+
conditions,
|
|
347
|
+
enabled: !(spendsTheItem || neverAuto === true),
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
for (const im of imbues) {
|
|
351
|
+
const family = consumableFamilyKey(ds.item(im.entry), ds);
|
|
352
|
+
if (have.has(im.entry) || (family != null && haveFamilies.has(family))) continue;
|
|
353
|
+
const { conditions, phase } = defaultItemRuleConditions('weapon_imbue', { itemEntry: im.entry });
|
|
354
|
+
add[phase].push({
|
|
355
|
+
id: `g-item-${im.entry}`,
|
|
356
|
+
action: { kind: 'item', itemEntry: im.entry, ...(family ? { family } : {}) },
|
|
357
|
+
conditions,
|
|
358
|
+
enabled: true,
|
|
359
|
+
});
|
|
360
|
+
have.add(im.entry);
|
|
361
|
+
if (family) haveFamilies.add(family);
|
|
362
|
+
}
|
|
363
|
+
if (!flip && !ROTATION_PHASES.some((p) => add[p].length)) return rot;
|
|
364
|
+
const phases = { ...rot.phases };
|
|
365
|
+
for (const p of ROTATION_PHASES) {
|
|
366
|
+
const cur = rot.phases[p];
|
|
367
|
+
if (!cur?.length && !add[p].length) continue;
|
|
368
|
+
let list = cur ?? [];
|
|
369
|
+
if (flip) list = list.map((r) => (r.enabled && autoSeeded(r) ? { ...r, enabled: false } : r));
|
|
370
|
+
if (add[p].length) list = [...list, ...add[p]];
|
|
371
|
+
phases[p] = list;
|
|
372
|
+
}
|
|
373
|
+
return { ...rot, phases };
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
export interface CompanionActionKnobs {
|
|
377
|
+
companion?: Pick<Companion, 'aoeMode' | 'offHeal' | 'cls'>;
|
|
378
|
+
aoeMode?: CompanionAoeMode;
|
|
379
|
+
offHealAllowed?: boolean;
|
|
380
|
+
/** Combatant id of this unit's pet, so an item rule targeting 'pet' can resolve. */
|
|
381
|
+
petCombatantId?: string;
|
|
382
|
+
isMultiSpell?: (spellId: number) => boolean;
|
|
383
|
+
// Spell id → pure keep-up buff safe from buffs phase mid-session. Callers with DataStore: `(id) =>
|
|
384
|
+
// isCompanionKeepUpSpell(ds.spell(id))`.
|
|
385
|
+
isOocKeepUp?: (spellId: number) => boolean;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/** Combat ms one keep-up may block the combat phase before the provider stops offering it. */
|
|
389
|
+
const OOC_KEEPUP_YIELD_AFTER_MS = 10_000;
|
|
390
|
+
|
|
391
|
+
// Memoized because the resolve is 15% of live JS, and keyed on the def OBJECT so a talent-modded
|
|
392
|
+
// clone is asked separately from the bake row.
|
|
393
|
+
const keepUpMemo = new WeakMap<SpellDef, boolean>();
|
|
394
|
+
const keepUpDurMemo = new WeakMap<SpellDef, number>();
|
|
395
|
+
|
|
396
|
+
// What a keep-up LEAVES BEHIND. Every mage armor, aspect, Lightning Shield, Thorns and Retribution
|
|
397
|
+
// Aura carries a proc rider, so "every effect is buff or resist" refused 41 of the 51 packed rows.
|
|
398
|
+
const KEEP_UP_AURA_KINDS: ReadonlySet<string> = new Set([
|
|
399
|
+
'buff', 'resist', 'damage_shield', 'school_absorb', 'mana_shield', 'proc_trigger_spell',
|
|
400
|
+
'restore_power', 'restore_health', 'split_damage', 'split_damage_flat', 'blessing_of_light',
|
|
401
|
+
'threat_temporary', 'mod_unattackable', 'immunity',
|
|
402
|
+
]);
|
|
403
|
+
|
|
404
|
+
// The heavy business a buffs-phase row can also be — a rez, a conjure, a pet, a trap, a coat. None
|
|
405
|
+
// is an aura on a bar, none may be a free pre-pull stamp, none takes a mid-fight GCD (9d41d22d5).
|
|
406
|
+
const NOT_A_KEEP_UP_KINDS: ReadonlySet<string> = new Set([
|
|
407
|
+
'resurrect', 'conjure', 'summon_pet', 'summon_demon', 'revive_pet', 'summon_totem',
|
|
408
|
+
'summon_object_slot', 'shapeshift', 'weapon_imbue', 'learn_spell', 'teleport', 'teleport_hearth',
|
|
409
|
+
'stealth', 'next_cast_mod', 'reset_cooldowns',
|
|
410
|
+
]);
|
|
411
|
+
|
|
412
|
+
export function isCompanionKeepUpSpell(s: SpellDef | undefined): boolean {
|
|
413
|
+
if (!s) return false;
|
|
414
|
+
const hit = keepUpMemo.get(s);
|
|
415
|
+
if (hit !== undefined) return hit;
|
|
416
|
+
const resolved = resolveCombatSpell(s);
|
|
417
|
+
const effects = resolved.effects ?? [];
|
|
418
|
+
const yes = effects.length > 0
|
|
419
|
+
&& !resolved.outOfCombatOnly
|
|
420
|
+
&& (resolved.channelMs ?? 0) <= 0
|
|
421
|
+
&& effects.some((e) => KEEP_UP_AURA_KINDS.has(e.kind))
|
|
422
|
+
&& effects.every(
|
|
423
|
+
(e) => !NOT_A_KEEP_UP_KINDS.has(e.kind) && !(e.kind === 'buff' && e.hostile === true),
|
|
424
|
+
);
|
|
425
|
+
keepUpMemo.set(s, yes);
|
|
426
|
+
return yes;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
/** Longest resolved aura duration of a keep-up buff (0 = permanent-until-cancelled). */
|
|
430
|
+
export function keepUpAuraDurationMs(s: SpellDef): number {
|
|
431
|
+
const hit = keepUpDurMemo.get(s);
|
|
432
|
+
if (hit !== undefined) return hit;
|
|
433
|
+
let max = 0;
|
|
434
|
+
for (const e of resolveCombatSpell(s).effects ?? []) {
|
|
435
|
+
if (e.kind !== 'buff' && e.kind !== 'resist') continue;
|
|
436
|
+
const d = (e as { durationMs?: number }).durationMs ?? 0;
|
|
437
|
+
if (d > max) max = d;
|
|
438
|
+
}
|
|
439
|
+
keepUpDurMemo.set(s, max);
|
|
440
|
+
return max;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
// Engine-facing brain: a pure closure over one unit's Rotation, running the same evaluator as the
|
|
444
|
+
// player autopilot. Named for its first caller — the PLAYER uses it too for engine-driven ticks.
|
|
445
|
+
export function companionActionProvider(
|
|
446
|
+
rot: Rotation,
|
|
447
|
+
targetEntry?: number,
|
|
448
|
+
knobs?: CompanionActionKnobs,
|
|
449
|
+
): AllyActionProvider {
|
|
450
|
+
// An OOC keep-up whose aura never registers under the id the check below reads was returned every
|
|
451
|
+
// decision forever, so chooseCombatAction never ran and the unit buffed instead of fighting
|
|
452
|
+
// (KI-1078). Same yield an unachieved move order takes: pickAction.ts:695 RUNOUT_YIELD_AFTER_MS.
|
|
453
|
+
const oocSince = new Map<number, number>();
|
|
454
|
+
const oocGaveUp = new Set<number>();
|
|
455
|
+
const provider: AllyActionProvider = (snap) => {
|
|
456
|
+
// The ENGINE stamps these when the session supplies `SimTickInputs.companionKnobs`, which is what
|
|
457
|
+
// lets this provider be rebuilt from plain data instead of a live companion ref (S6b). Nothing
|
|
458
|
+
// supplying them keeps the old reads, so a session without the channel is unchanged.
|
|
459
|
+
const stamped = snap.aoeMode != null;
|
|
460
|
+
const mode: CompanionAoeMode = stamped
|
|
461
|
+
? decodeAoeMode(snap.aoeMode)
|
|
462
|
+
: (knobs?.companion ? resolveAoeMode(knobs.companion) : (knobs?.aoeMode ?? 'auto'));
|
|
463
|
+
const offHealOn = stamped
|
|
464
|
+
? snap.offHealAllowed === 1
|
|
465
|
+
: (knobs?.companion ? resolveOffHeal(knobs.companion) : (knobs?.offHealAllowed ?? false));
|
|
466
|
+
const aoeCode = encodeAoeMode(mode);
|
|
467
|
+
const baseUsable = snap.usableSpell;
|
|
468
|
+
const isMulti = knobs?.isMultiSpell;
|
|
469
|
+
// Stamped in place, not spread. The engine builds a fresh snapshot per call and drops it, and
|
|
470
|
+
// `{...snap}` copied ~25 fields per unit per tick — 40 clones a tick at 40 units.
|
|
471
|
+
const enriched = snap as RotationSnapshot;
|
|
472
|
+
enriched.aoeMode = aoeCode;
|
|
473
|
+
enriched.offHealAllowed = offHealOn ? 1 : 0;
|
|
474
|
+
// Checkbox off: drop healerPowerPcts so those rows cannot fire (evaluate.ts returns null).
|
|
475
|
+
const offHealSupplied = stamped || knobs?.companion != null || knobs?.offHealAllowed != null;
|
|
476
|
+
if (offHealSupplied && !offHealOn) enriched.healerPowerPcts = undefined;
|
|
477
|
+
enriched.usableSpell = (id) => {
|
|
478
|
+
if (!baseUsable(id)) return false;
|
|
479
|
+
if (mode === 'single' && isMulti?.(id)) return false;
|
|
480
|
+
return true;
|
|
481
|
+
};
|
|
482
|
+
const useRot =
|
|
483
|
+
mode === 'aoe' && enriched.enemyCount >= 2 && isMulti
|
|
484
|
+
? aoeRotationOf(rot, isMulti)
|
|
485
|
+
: rot;
|
|
486
|
+
// A keep-up that HAS registered is working: clear its clock so the next expiry gets a fresh
|
|
487
|
+
// window, and only a buff that never lands at all can reach the give-up below.
|
|
488
|
+
for (const id of oocSince.keys()) {
|
|
489
|
+
if (enriched.self.buffs.has(id) || enriched.auraCovered?.(enriched.self.buffs, id)) {
|
|
490
|
+
oocSince.delete(id); oocGaveUp.delete(id);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
// Both guards below protect a MID-FIGHT GCD, so both are in-combat rules: the shape gate blocked
|
|
494
|
+
// 41 of 51 packed rows, and the give-up is a yield inside one fight, not a session-long ban.
|
|
495
|
+
const outOfFight = enriched.inCombat === false;
|
|
496
|
+
if (outOfFight && oocGaveUp.size > 0) { oocGaveUp.clear(); oocSince.clear(); }
|
|
497
|
+
// One spell action -> one provider pick. The OOC branch returned a bare id and dropped the
|
|
498
|
+
// row's target with it, so a `{ allyMissingAura }` party keep-up cast on the caster instead.
|
|
499
|
+
const spellPick = (a: { spellId: number; target?: RuleSpellTarget; after?: RuleAfter }): AllyCombatAction => {
|
|
500
|
+
const t = a.target;
|
|
501
|
+
const offTarget = t === 'other';
|
|
502
|
+
const obj = t && typeof t === 'object' ? t : undefined;
|
|
503
|
+
const creatureEntry = obj && 'creatureEntry' in obj ? obj.creatureEntry : undefined;
|
|
504
|
+
const role = obj && 'role' in obj ? obj.role : undefined;
|
|
505
|
+
const priority = obj && 'priority' in obj ? obj.priority : undefined;
|
|
506
|
+
const allyMissingAura = obj && 'allyMissingAura' in obj ? obj.allyMissingAura : undefined;
|
|
507
|
+
const lowestHp = obj && 'lowestHp' in obj && obj.lowestHp === true;
|
|
508
|
+
// Both aimed forms carry the same narrowing field, and dropping it on the party keep-up let a
|
|
509
|
+
// paladin bless a class its PallyPower column never named.
|
|
510
|
+
const among = (lowestHp || allyMissingAura != null) && obj && 'among' in obj
|
|
511
|
+
? obj.among : undefined;
|
|
512
|
+
if (a.after || offTarget || creatureEntry != null || role != null || priority != null
|
|
513
|
+
|| allyMissingAura != null || lowestHp) {
|
|
514
|
+
return {
|
|
515
|
+
spell: a.spellId,
|
|
516
|
+
...(a.after ? { after: a.after } : {}),
|
|
517
|
+
...(offTarget ? { offTarget: true } : {}),
|
|
518
|
+
...(creatureEntry != null ? { creatureEntry } : {}),
|
|
519
|
+
...(role != null ? { role } : {}),
|
|
520
|
+
...(priority != null ? { priority } : {}),
|
|
521
|
+
...(allyMissingAura != null ? { allyMissingAura } : {}),
|
|
522
|
+
...(lowestHp ? { lowestAlly: true } : {}),
|
|
523
|
+
...(among ? { among } : {}),
|
|
524
|
+
};
|
|
525
|
+
}
|
|
526
|
+
return a.spellId;
|
|
527
|
+
};
|
|
528
|
+
const ooc = chooseOocAction(useRot, enriched);
|
|
529
|
+
// "I already have it" answers a SELF keep-up only. A party row is about somebody else's bar, and
|
|
530
|
+
// this guard killed it the moment the caster buffed itself — the first body a party row reaches.
|
|
531
|
+
const aimsAtAlly = ooc?.kind === 'spell' && ooc.target != null
|
|
532
|
+
&& typeof ooc.target === 'object' && 'allyMissingAura' in ooc.target;
|
|
533
|
+
const selfHas = (id: number): boolean =>
|
|
534
|
+
enriched.self.buffs.has(id) || enriched.auraCovered?.(enriched.self.buffs, id) === true;
|
|
535
|
+
if (ooc && ooc.kind === 'spell'
|
|
536
|
+
&& (aimsAtAlly || !selfHas(ooc.spellId))
|
|
537
|
+
&& !oocGaveUp.has(ooc.spellId)
|
|
538
|
+
&& (outOfFight || (knobs?.isOocKeepUp?.(ooc.spellId) ?? true))) {
|
|
539
|
+
// The give-up clock reads "never registers", on a bar it cannot see. `actionUsable` owns this row.
|
|
540
|
+
if (aimsAtAlly) return spellPick(ooc);
|
|
541
|
+
const since = oocSince.get(ooc.spellId);
|
|
542
|
+
if (since == null || enriched.combatTimeMs < since) oocSince.set(ooc.spellId, enriched.combatTimeMs);
|
|
543
|
+
else if (enriched.combatTimeMs - since > OOC_KEEPUP_YIELD_AFTER_MS) oocGaveUp.add(ooc.spellId);
|
|
544
|
+
if (!oocGaveUp.has(ooc.spellId)) return spellPick(ooc);
|
|
545
|
+
}
|
|
546
|
+
const action = chooseCombatAction(useRot, enriched, targetEntry);
|
|
547
|
+
if (!action) return null;
|
|
548
|
+
if (action.kind === 'move') {
|
|
549
|
+
// A run-out does not silence an instant: only a cast with time left is cancelled by movement,
|
|
550
|
+
// and Burning Adrenaline is a nuke window the holder spends walking. 4 of 5 windows cast 0.
|
|
551
|
+
const alt = chooseCombatAction(useRot, enriched, targetEntry, { skipMove: true });
|
|
552
|
+
return alt?.kind === 'spell'
|
|
553
|
+
? { move: action.move, altSpell: alt.spellId }
|
|
554
|
+
: { move: action.move };
|
|
555
|
+
}
|
|
556
|
+
if (action.kind === 'halt_dps') {
|
|
557
|
+
return { haltDps: true, school: action.school ?? 'all', entries: action.entries };
|
|
558
|
+
}
|
|
559
|
+
if (action.kind === 'kill_order' || action.kind === 'keep_aura') return null;
|
|
560
|
+
if (action.kind === 'use_object') return { useObject: action.goEntry };
|
|
561
|
+
if (action.kind === 'spell') {
|
|
562
|
+
return spellPick(action);
|
|
563
|
+
}
|
|
564
|
+
// Compiled away before the evaluator runs (macro/rotation.ts) and refused by actionUsable if
|
|
565
|
+
// not, so chooseCombatAction never hands back a macro action.
|
|
566
|
+
if (action.kind !== 'item') return null;
|
|
567
|
+
const sel = action.target ?? 'self';
|
|
568
|
+
if (sel === 'lowest_ally') {
|
|
569
|
+
return { item: action.itemEntry, lowestAlly: true };
|
|
570
|
+
}
|
|
571
|
+
// 'pet' used to drop the rule entirely even though the editor offers the option.
|
|
572
|
+
if (sel === 'pet') {
|
|
573
|
+
const petId = knobs?.petCombatantId;
|
|
574
|
+
if (!petId) return null;
|
|
575
|
+
return { item: action.itemEntry, target: petId };
|
|
576
|
+
}
|
|
577
|
+
return { item: action.itemEntry };
|
|
578
|
+
};
|
|
579
|
+
provider.needs = rotationNeeds(rot, targetEntry);
|
|
580
|
+
// Arm school halt before evaluate (pickAction sets f.haltDpsSchool from this).
|
|
581
|
+
provider.peekHalt = (snap) => peekHaltDpsSchool(rot, snap, targetEntry);
|
|
582
|
+
provider.peekKillOrder = (snap) => peekKillOrderEntries(rot, snap, targetEntry);
|
|
583
|
+
provider.keepAuraIds = keepAuraIdsOf(rot);
|
|
584
|
+
return provider;
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
// Which O(roster) snapshot fields this rotation's rules can observe, scanned over every phase and
|
|
588
|
+
// override. Exported only for the capability row that proves an opt-in metric stays opt-in.
|
|
589
|
+
export function rotationNeedsForCapability(rot: Rotation): ProviderNeeds {
|
|
590
|
+
return rotationNeeds(rot);
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
function rotationNeeds(rot: Rotation, targetEntry?: number): ProviderNeeds {
|
|
594
|
+
const needs: ProviderNeeds = {
|
|
595
|
+
allyDistHp: false,
|
|
596
|
+
allyTriageBuffs: false,
|
|
597
|
+
allySubject: false,
|
|
598
|
+
charmedHostileCount: false,
|
|
599
|
+
enemyDistsFromTarget: false,
|
|
600
|
+
enemyDists: false,
|
|
601
|
+
enemyHealerDists: false,
|
|
602
|
+
hasAggro: false,
|
|
603
|
+
enemyCastingOnAlly: false,
|
|
604
|
+
enemyCastingOnSelf: false,
|
|
605
|
+
items: false,
|
|
606
|
+
groundPools: false,
|
|
607
|
+
targetCone: false,
|
|
608
|
+
hostileCreatureEntries: false,
|
|
609
|
+
spellCosts: false,
|
|
610
|
+
dispellablePresent: false,
|
|
611
|
+
kickableCastPresent: false,
|
|
612
|
+
aggroHolder: false,
|
|
613
|
+
};
|
|
614
|
+
const scan = (rules: readonly RotationRule[] | undefined): void => {
|
|
615
|
+
for (const r of rules ?? []) {
|
|
616
|
+
if (r.action.kind === 'item') needs.items = true;
|
|
617
|
+
if (r.action.kind === 'kill_order' || killOrderEntriesFromAction(r.action)) {
|
|
618
|
+
needs.hostileCreatureEntries = true;
|
|
619
|
+
}
|
|
620
|
+
if (r.action.kind === 'spell' && r.action.target
|
|
621
|
+
&& typeof r.action.target === 'object' && 'creatureEntry' in r.action.target) {
|
|
622
|
+
needs.hostileCreatureEntries = true;
|
|
623
|
+
}
|
|
624
|
+
// A follow-up step's own gate reads the same snapshot fields as the row's, so it advertises
|
|
625
|
+
// the same needs; scanning the row alone left an ally-gated step reading null.
|
|
626
|
+
const conds = [...r.conditions];
|
|
627
|
+
const after = 'after' in r.action ? r.action.after : undefined;
|
|
628
|
+
for (const s of after?.steps ?? []) if (s.conditions) conds.push(...s.conditions);
|
|
629
|
+
for (const c of conds) {
|
|
630
|
+
// A subject, not a metric: every SUBJECT metric can name an ally, so this is checked first
|
|
631
|
+
// and does not join the metric chain below.
|
|
632
|
+
if (c.subject === 'ally') needs.allySubject = true;
|
|
633
|
+
if (c.metric === 'nearbyAlliesBelowHpCount'
|
|
634
|
+
|| c.metric === 'alliesWithinYd'
|
|
635
|
+
|| c.metric === 'healersWithinYd') {
|
|
636
|
+
needs.allyDistHp = true;
|
|
637
|
+
}
|
|
638
|
+
else if (c.metric === 'allyLowestBuffPresent') needs.allyTriageBuffs = true;
|
|
639
|
+
else if (c.metric === 'charmedHostileCount') needs.charmedHostileCount = true;
|
|
640
|
+
else if (c.metric === 'hasAggro' || c.metric === 'allyHasAggro') needs.hasAggro = true;
|
|
641
|
+
else if (c.metric === 'enemyCastingOnAlly') needs.enemyCastingOnAlly = true;
|
|
642
|
+
else if (c.metric === 'enemyCastingOnSelf') needs.enemyCastingOnSelf = true;
|
|
643
|
+
else if (c.metric === 'enemiesWithinYd' && c.subject === 'target') needs.enemyDistsFromTarget = true;
|
|
644
|
+
else if (c.metric === 'enemiesWithinYd') needs.enemyDists = true;
|
|
645
|
+
else if (c.metric === 'enemyHealersWithinYd') needs.enemyHealerDists = true;
|
|
646
|
+
else if (c.metric === 'hazardProximityYd') needs.groundPools = true;
|
|
647
|
+
else if (c.metric === 'inTargetCone') needs.targetCone = true;
|
|
648
|
+
else if (c.metric === 'canAfford') needs.spellCosts = true;
|
|
649
|
+
else if (c.metric === 'dispellablePresent') needs.dispellablePresent = true;
|
|
650
|
+
else if (c.metric === 'castingPresent' && c.subject === 'target') needs.kickableCastPresent = true;
|
|
651
|
+
else if (c.metric === 'aggroHolderDebuffPresent' || c.metric === 'aggroHolderDebuffStacks') needs.aggroHolder = true;
|
|
652
|
+
else if (c.metric === 'itemCount') needs.items = true;
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
};
|
|
656
|
+
for (const phase of ROTATION_PHASES) scan(rot.phases[phase] ?? []);
|
|
657
|
+
for (const list of Object.values(rot.overrides ?? {})) scan(list);
|
|
658
|
+
// Per-fight tactic rows are prepended by the evaluator, not stored on the rotation, so a scan
|
|
659
|
+
// that skipped them left their metric unfilled and the row could never fire.
|
|
660
|
+
if (targetEntry != null) scan(encounterTacticRows(targetEntry));
|
|
661
|
+
scan(allEncounterTacticRules());
|
|
662
|
+
return needs;
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
/** Same brain, said out loud for non-companion callers (the player's engine-driven ticks). */
|
|
666
|
+
export const rotationActionProvider = companionActionProvider;
|
|
667
|
+
|
|
668
|
+
export type CompanionRotationFlag = 'NO-HEALS' | 'no-taunt' | 'EMPTY-COMBAT';
|
|
669
|
+
|
|
670
|
+
/** Audit a companion rotation for role/kit gaps (editor banner + CLI). */
|
|
671
|
+
export function auditCompanionRotation(
|
|
672
|
+
rot: Rotation,
|
|
673
|
+
role: SquadRole,
|
|
674
|
+
ds: DataStore,
|
|
675
|
+
): CompanionRotationFlag[] {
|
|
676
|
+
const all = ROTATION_PHASES.flatMap((p) => rot.phases[p] ?? []);
|
|
677
|
+
const spellOf = (r: RotationRule) => (r.action.kind === 'spell' ? ds.spell(r.action.spellId) : null);
|
|
678
|
+
const triageHeals = all.filter((r) =>
|
|
679
|
+
spellOf(r)?.effects.some((e) => e.kind === 'heal')
|
|
680
|
+
&& r.conditions.some((c) => c.metric === 'allyLowestHpPct')).length;
|
|
681
|
+
const hasTaunt = all.some((r) => spellOf(r)?.effects.some((e) => e.kind === 'taunt'));
|
|
682
|
+
const flags: CompanionRotationFlag[] = [];
|
|
683
|
+
if (role === 'healer' && triageHeals === 0) flags.push('NO-HEALS');
|
|
684
|
+
if (role === 'tank' && !hasTaunt) flags.push('no-taunt');
|
|
685
|
+
if (rot.phases.combat.length === 0) flags.push('EMPTY-COMBAT');
|
|
686
|
+
return flags;
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
export function companionRotationWarning(flag: CompanionRotationFlag): string {
|
|
690
|
+
switch (flag) {
|
|
691
|
+
case 'NO-HEALS': return 'This healer knows no heals - visit a trainer';
|
|
692
|
+
case 'no-taunt': return 'This tank has no taunt in its rotation';
|
|
693
|
+
case 'EMPTY-COMBAT': return 'Combat phase is empty - this companion will only auto-attack';
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
/** True when the spell is a party-healing cast (direct, HoT, LoH, Holy Shock). */
|
|
698
|
+
export function spellIsHeal(spell: {
|
|
699
|
+
effects?: ReadonlyArray<{ kind: string }> | null;
|
|
700
|
+
} | null | undefined): boolean {
|
|
701
|
+
return !!spell?.effects?.some(
|
|
702
|
+
(e) =>
|
|
703
|
+
e.kind === 'heal'
|
|
704
|
+
|| e.kind === 'restore_health'
|
|
705
|
+
|| e.kind === 'heal_max_health'
|
|
706
|
+
|| e.kind === 'holy_shock',
|
|
707
|
+
);
|
|
708
|
+
}
|