azeroth-shell 0.0.0-stage → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +35 -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 +144 -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,977 @@
|
|
|
1
|
+
// Pure "when" string to Condition mapper for rotation suggestions. Suggestions are free text and
|
|
2
|
+
// runtime rules are numeric refs, so this maps to a symbolic shape that materializes to DB ids.
|
|
3
|
+
|
|
4
|
+
import type { CondMetric, CondOp, CondSubject, Condition } from '../rotation/rotation.ts';
|
|
5
|
+
import { SOUL_SHARD_ITEM } from '../core/ids.ts';
|
|
6
|
+
import { SHAPESHIFT_FORM, type TotemSlot } from '../../data/schema.ts';
|
|
7
|
+
import { totemSlotIndex } from '../spells/totem.ts';
|
|
8
|
+
import { SCHOOL_INDEX } from '../creature/creatureAi.ts';
|
|
9
|
+
|
|
10
|
+
// ---- Named debuff / item constants (Wave 1C) ------------------------------
|
|
11
|
+
|
|
12
|
+
// High-traffic named debuffs suggestions refer to by name rather than action spell id. Judgement of
|
|
13
|
+
// Light and Wisdom stay out: debuffPresent matches an EXACT id, so one key would gate a wrong rank.
|
|
14
|
+
export const NAMED_DEBUFF_SPELL_IDS = {
|
|
15
|
+
/** Classic Power Word: Shield anti-stack debuff. */
|
|
16
|
+
WEAKENED_SOUL: 6788,
|
|
17
|
+
} as const;
|
|
18
|
+
|
|
19
|
+
export type NamedDebuffKey = keyof typeof NAMED_DEBUFF_SPELL_IDS;
|
|
20
|
+
|
|
21
|
+
/** Classic Power Word: Shield anti-stack debuff (spell-data id). */
|
|
22
|
+
export const WEAKENED_SOUL_SPELL_ID = NAMED_DEBUFF_SPELL_IDS.WEAKENED_SOUL;
|
|
23
|
+
|
|
24
|
+
// Retired: `debuffStacks` now exists, so an authored low-stacks phrase maps to debuffStacks under the
|
|
25
|
+
// cap — reapply until the stack cap, as with Sunder at five.
|
|
26
|
+
export const DEBUFF_LOW_STACKS_SIMPLIFIED_TO_ABSENT = false;
|
|
27
|
+
|
|
28
|
+
// Sentinel `value` for stack conditions: replaced at materialize time by the action spell's own StackAmount
|
|
29
|
+
// (5 for Sunder). Falls back to {@link DEFAULT_STACK_CAP}.
|
|
30
|
+
export const ACTION_STACK_CAP = -1;
|
|
31
|
+
export const DEFAULT_STACK_CAP = 5;
|
|
32
|
+
|
|
33
|
+
/** Soul Shard item entry - same as domain/ids SOUL_SHARD_ITEM. */
|
|
34
|
+
export const SOUL_SHARD_ITEM_REF = SOUL_SHARD_ITEM;
|
|
35
|
+
|
|
36
|
+
// ---- Intermediate condition shape -----------------------------------------
|
|
37
|
+
|
|
38
|
+
// Placeholder refs until the suggestion rule's spell/item id is known. Numeric refs are already final (e.g.
|
|
39
|
+
// soul shard, Weakened Soul).
|
|
40
|
+
export type WhenRefPlaceholder = 'ACTION_SPELL' | 'ITEM' | 'TOTEM_SLOT' | NamedDebuffKey;
|
|
41
|
+
|
|
42
|
+
export type WhenRef = number | WhenRefPlaceholder;
|
|
43
|
+
|
|
44
|
+
/** One guard produced by mapWhen - same fields as Condition, with symbolic ref. */
|
|
45
|
+
export interface WhenCondition {
|
|
46
|
+
subject: CondSubject;
|
|
47
|
+
metric: CondMetric;
|
|
48
|
+
op: CondOp;
|
|
49
|
+
value: number;
|
|
50
|
+
ref?: WhenRef;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export type WhenMapStatus = 'mapped' | 'partial' | 'unmapped' | 'always' | 'noop';
|
|
54
|
+
|
|
55
|
+
/** Engine / policy flags surfaced for audit and class agents. */
|
|
56
|
+
export type WhenMapFlag =
|
|
57
|
+
| 'totem'
|
|
58
|
+
| 'form-or-stance'
|
|
59
|
+
| 'weapon-imbue'
|
|
60
|
+
| 'multi-target'
|
|
61
|
+
| 'talent-gated'
|
|
62
|
+
| 'positional'
|
|
63
|
+
| 'stacks'
|
|
64
|
+
| 'combo-points'
|
|
65
|
+
| 'or-condition'
|
|
66
|
+
| 'needs-debuff-id';
|
|
67
|
+
|
|
68
|
+
export interface WhenMapResult {
|
|
69
|
+
status: WhenMapStatus;
|
|
70
|
+
conditions: WhenCondition[];
|
|
71
|
+
reason?: string;
|
|
72
|
+
flags: WhenMapFlag[];
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Flags that force partial or unmapped until engine metrics land. Multi-target, form, totem, weapon
|
|
76
|
+
// imbue and stacks are no longer gaps: they still flag for audit but do not block mapping.
|
|
77
|
+
export const ENGINE_GAP_FLAGS: readonly WhenMapFlag[] = [
|
|
78
|
+
'combo-points',
|
|
79
|
+
'positional',
|
|
80
|
+
] as const;
|
|
81
|
+
|
|
82
|
+
// ---- Form / stance label → formId (Wave 1A) --------------------------------
|
|
83
|
+
|
|
84
|
+
// Resolve a spell label or "in … Form/Stance" fragment to a shapeshift form id. Order matters: "dire bear"
|
|
85
|
+
// before "bear". Returns null when unknown.
|
|
86
|
+
export function formIdFromLabel(label: string): number | null {
|
|
87
|
+
const s = String(label || '').toLowerCase().trim();
|
|
88
|
+
if (!s) return null;
|
|
89
|
+
// Dire before bare bear
|
|
90
|
+
if (/\bdire\s*bear\b/.test(s)) return SHAPESHIFT_FORM.DIREBEAR;
|
|
91
|
+
if (/\bbear(?:\s*form)?\b/.test(s)) return SHAPESHIFT_FORM.BEAR;
|
|
92
|
+
if (/\bcat(?:\s*form)?\b/.test(s)) return SHAPESHIFT_FORM.CAT;
|
|
93
|
+
if (/\btravel(?:\s*form)?\b/.test(s)) return SHAPESHIFT_FORM.TRAVEL;
|
|
94
|
+
if (/\baquatic(?:\s*form)?\b/.test(s)) return SHAPESHIFT_FORM.AQUA;
|
|
95
|
+
if (/\bmoonkin(?:\s*form)?\b/.test(s)) return SHAPESHIFT_FORM.MOONKIN;
|
|
96
|
+
if (/\btree(?:\s*of\s*life)?\b/.test(s)) return SHAPESHIFT_FORM.TREE;
|
|
97
|
+
// Single-word "Shadowform" (no space before form) - priest Wave 2.
|
|
98
|
+
if (/\bshadowform\b/.test(s)) return SHAPESHIFT_FORM.SHADOWFORM;
|
|
99
|
+
if (/\bbattle\s*stance\b/.test(s)) return SHAPESHIFT_FORM.BATTLESTANCE;
|
|
100
|
+
if (/\bdefensive\s*stance\b/.test(s)) return SHAPESHIFT_FORM.DEFENSIVESTANCE;
|
|
101
|
+
if (/\bberserker\s*stance\b/.test(s)) return SHAPESHIFT_FORM.BERSERKERSTANCE;
|
|
102
|
+
if (/\b(?:stealth|prowl)\b/.test(s)) return SHAPESHIFT_FORM.STEALTH;
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// True when the spell label is a known form/stance enter ability. Any label that resolves via
|
|
107
|
+
// formIdFromLabel (including single-word Shadowform).
|
|
108
|
+
export function isFormOrStanceSpellLabel(spellLabel: string): boolean {
|
|
109
|
+
return formIdFromLabel(spellLabel) != null;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/** Suggestion `(multi)` → living enemies >= 2. Subject ignored by evaluator. */
|
|
113
|
+
export const MULTI_ENEMY_COUNT_COND: WhenCondition = {
|
|
114
|
+
subject: 'self',
|
|
115
|
+
metric: 'enemyCount',
|
|
116
|
+
op: '>=',
|
|
117
|
+
value: 2,
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
/** Suggestion `(single)` → living enemies < 2 (bosses / hard ST). Subject ignored. */
|
|
121
|
+
export const SINGLE_ENEMY_COUNT_COND: WhenCondition = {
|
|
122
|
+
subject: 'self',
|
|
123
|
+
metric: 'enemyCount',
|
|
124
|
+
op: '<',
|
|
125
|
+
value: 2,
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
function pushMultiGate(conditions: WhenCondition[], flags: WhenMapFlag[]): void {
|
|
129
|
+
pushUniqueFlag(flags, 'multi-target');
|
|
130
|
+
if (!conditions.some((c) => c.metric === 'enemyCount')) {
|
|
131
|
+
conditions.push({ ...MULTI_ENEMY_COUNT_COND });
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function pushSingleGate(conditions: WhenCondition[], flags: WhenMapFlag[]): void {
|
|
136
|
+
// Trace-only: single is the inverse of multi, not a separate engine gap.
|
|
137
|
+
if (!conditions.some((c) => c.metric === 'enemyCount')) {
|
|
138
|
+
conditions.push({ ...SINGLE_ENEMY_COUNT_COND });
|
|
139
|
+
}
|
|
140
|
+
// Keep multi-target flag out so audits do not treat ST gates as pack tools.
|
|
141
|
+
void flags;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// ---- Helpers --------------------------------------------------------------
|
|
145
|
+
|
|
146
|
+
function isCondOp(s: string): s is CondOp {
|
|
147
|
+
return s === '<' || s === '<=' || s === '>' || s === '>=' || s === '==' || s === '!=';
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function pushUniqueFlag(flags: WhenMapFlag[], f: WhenMapFlag): void {
|
|
151
|
+
if (!flags.includes(f)) flags.push(f);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Weapon imbue and poison apply spells, excluding totem names — a Flametongue Totem is not an imbue.
|
|
155
|
+
// Gates use weaponImbuePresent at ref 2, open eligible hands, not the apply spell's own buff.
|
|
156
|
+
export function isWeaponImbueSpellLabel(spellLabel: string): boolean {
|
|
157
|
+
const s = String(spellLabel || '').toLowerCase();
|
|
158
|
+
if (!s || /\btotem\b/.test(s)) return false;
|
|
159
|
+
// Rogue poisons (items or apply spells)
|
|
160
|
+
if (/\b(instant|deadly|crippling|mind-numbing|wound)\s+poison\b/.test(s)) return true;
|
|
161
|
+
// Authored rank shorthand without the word "poison" (e.g. "Instant VI / Deadly V")
|
|
162
|
+
if (/\binstant\b/.test(s) && /\bdeadly\b/.test(s)) return true;
|
|
163
|
+
if (/^instant\s+(vi|v|iv|iii|ii|i)\b/.test(s)) return true;
|
|
164
|
+
if (/^deadly\s+(vi|v|iv|iii|ii|i)\b/.test(s)) return true;
|
|
165
|
+
// Shaman weapon imbues
|
|
166
|
+
if (/\brockbiter\b/.test(s)) return true;
|
|
167
|
+
if (/\bwindfury weapon\b/.test(s)) return true;
|
|
168
|
+
if (/\bflametongue weapon\b/.test(s)) return true;
|
|
169
|
+
if (/\bfrostbrand weapon\b/.test(s)) return true;
|
|
170
|
+
// Slash alt: "Windfury Weapon or Flametongue" (second label omits "Weapon")
|
|
171
|
+
if (/\b(or flametongue|flametongue or)\b/.test(s)) return true;
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/** True when the spell label is a totem summon (name contains "totem"). */
|
|
176
|
+
export function isTotemSpellLabel(spellLabel: string): boolean {
|
|
177
|
+
return /\btotem\b/i.test(String(spellLabel || ''));
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Defense-react spenders (vanilla Revenge): only usable after the caster dodge/parry/blocks. Bare
|
|
181
|
+
// "usable"/"always" on these labels must not become unconditional filler.
|
|
182
|
+
export function isDefenseReactSpellLabel(spellLabel: string): boolean {
|
|
183
|
+
return /\brevenge\b/i.test(String(spellLabel || ''));
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/** Self.defenseReactRecently == 1 — Revenge / block-parry-dodge react gate. */
|
|
187
|
+
export const DEFENSE_REACT_COND: WhenCondition = {
|
|
188
|
+
subject: 'self',
|
|
189
|
+
metric: 'defenseReactRecently',
|
|
190
|
+
op: '==',
|
|
191
|
+
value: 1,
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
/** Self.inMelee == 1 — Raptor Strike / melee-only spenders while in melee range. */
|
|
195
|
+
export const IN_MELEE_COND: WhenCondition = {
|
|
196
|
+
subject: 'self',
|
|
197
|
+
metric: 'inMelee',
|
|
198
|
+
op: '==',
|
|
199
|
+
value: 1,
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
function spellGapFlags(spellLabel: string, flags: WhenMapFlag[]): void {
|
|
203
|
+
const spellL = String(spellLabel || '').toLowerCase();
|
|
204
|
+
if (/totem/.test(spellL)) pushUniqueFlag(flags, 'totem');
|
|
205
|
+
if (
|
|
206
|
+
/\b(cat form|bear form|dire bear|travel form|aquatic form|moonkin(?:\s*form)?|tree(?:\s*of\s*life)?|shadowform|battle stance|defensive stance|berserker stance|prowl|stealth)\b/.test(
|
|
207
|
+
spellL,
|
|
208
|
+
)
|
|
209
|
+
) {
|
|
210
|
+
pushUniqueFlag(flags, 'form-or-stance');
|
|
211
|
+
}
|
|
212
|
+
if (isWeaponImbueSpellLabel(spellLabel)) {
|
|
213
|
+
pushUniqueFlag(flags, 'weapon-imbue');
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/** "debuff absent/low stacks" - reapply until the stack cap (Sunder x5). */
|
|
218
|
+
function isLowStacksWhen(when: string): boolean {
|
|
219
|
+
return /absent\s*\/\s*low\s+stacks|low\s+stacks/.test(when);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function whenGapFlags(when: string, flags: WhenMapFlag[]): void {
|
|
223
|
+
if (/\bmulti\b/.test(when)) pushUniqueFlag(flags, 'multi-target');
|
|
224
|
+
if (/if talented|if dipped|if available/.test(when)) pushUniqueFlag(flags, 'talent-gated');
|
|
225
|
+
if (/from behind|positional|backstab from/.test(when)) pushUniqueFlag(flags, 'positional');
|
|
226
|
+
// stacks: trace-only since the debuffStacks metric landed (no longer an engine gap)
|
|
227
|
+
if (/stacks?/.test(when)) pushUniqueFlag(flags, 'stacks');
|
|
228
|
+
if (/combo|finish|cp\b|points?/.test(when)) pushUniqueFlag(flags, 'combo-points');
|
|
229
|
+
if (/form|shapeshift|cat form|bear form|stance/.test(when)) pushUniqueFlag(flags, 'form-or-stance');
|
|
230
|
+
if (/totem/.test(when)) pushUniqueFlag(flags, 'totem');
|
|
231
|
+
// "or" inside armor phrases (Demon Skin/Armor) is not an OR-condition
|
|
232
|
+
if (/\bor\b/.test(when) && !/armor/.test(when)) pushUniqueFlag(flags, 'or-condition');
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function gapReason(flags: WhenMapFlag[]): string {
|
|
236
|
+
const bits = flags.filter((f) => (ENGINE_GAP_FLAGS as readonly string[]).includes(f) || f === 'or-condition');
|
|
237
|
+
return bits.length ? `engine gap: ${bits.join(', ')}` : 'OR: took primary clause only (no full OR DSL)';
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Bare session-gate clauses meaning "always when usable". When any OR branch is one of these, keep
|
|
241
|
+
// empty conditions rather than a restrictive primary, which would drop the filler branch.
|
|
242
|
+
function isSessionAlwaysOrClause(clause: string): boolean {
|
|
243
|
+
const c = clause.trim();
|
|
244
|
+
if (!c) return true;
|
|
245
|
+
if (
|
|
246
|
+
c === 'always' ||
|
|
247
|
+
c === 'usable' ||
|
|
248
|
+
c === 'opener' ||
|
|
249
|
+
c === 'filler' ||
|
|
250
|
+
c === 'fallback' ||
|
|
251
|
+
c === 'lower priority' ||
|
|
252
|
+
c === 'off cd' ||
|
|
253
|
+
c === 'off cooldown'
|
|
254
|
+
) {
|
|
255
|
+
return true;
|
|
256
|
+
}
|
|
257
|
+
// "always (highest rank)" etc. — still session-only unless multi-gated
|
|
258
|
+
if (/^always\b/.test(c) && !/\bmulti\b/.test(c)) return true;
|
|
259
|
+
return false;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
function alwaysOrPartial(
|
|
263
|
+
flags: WhenMapFlag[],
|
|
264
|
+
reason?: string,
|
|
265
|
+
): WhenMapResult {
|
|
266
|
+
const blocked = flags.length > 0;
|
|
267
|
+
return {
|
|
268
|
+
status: blocked ? 'partial' : 'always',
|
|
269
|
+
conditions: [],
|
|
270
|
+
flags,
|
|
271
|
+
reason: blocked ? reason ?? `spell/when needs engine: ${flags.join(', ')}` : reason,
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// Result after attaching multi (or other) conditions on an "always-style" when. Remaining ENGINE_GAP_FLAGS
|
|
276
|
+
// / OR / talent-gated keep status partial; multi alone is mapped.
|
|
277
|
+
function multiAwareResult(
|
|
278
|
+
conditions: WhenCondition[],
|
|
279
|
+
flags: WhenMapFlag[],
|
|
280
|
+
reason?: string,
|
|
281
|
+
): WhenMapResult {
|
|
282
|
+
const hasGap = flags.some((f) => (ENGINE_GAP_FLAGS as readonly string[]).includes(f));
|
|
283
|
+
const softPartial = flags.includes('or-condition') || flags.includes('talent-gated') || flags.includes('needs-debuff-id');
|
|
284
|
+
if (hasGap || softPartial) {
|
|
285
|
+
return {
|
|
286
|
+
status: conditions.length ? 'partial' : 'unmapped',
|
|
287
|
+
conditions,
|
|
288
|
+
flags,
|
|
289
|
+
reason: reason ?? gapReason(flags),
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
return {
|
|
293
|
+
status: conditions.length ? 'mapped' : 'always',
|
|
294
|
+
conditions,
|
|
295
|
+
flags,
|
|
296
|
+
reason,
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// ---- Core mapper ----------------------------------------------------------
|
|
301
|
+
|
|
302
|
+
// Map a free-text suggestion `when` clause to structured conditions plus an audit status. The spell
|
|
303
|
+
// label is used only for the engine-gap flags.
|
|
304
|
+
export function mapWhen(whenRaw: string | undefined | null, spellLabel = ''): WhenMapResult {
|
|
305
|
+
const when = String(whenRaw || '')
|
|
306
|
+
.trim()
|
|
307
|
+
.toLowerCase();
|
|
308
|
+
const flags: WhenMapFlag[] = [];
|
|
309
|
+
spellGapFlags(spellLabel, flags);
|
|
310
|
+
|
|
311
|
+
// Intentional no-op row
|
|
312
|
+
if (when === 'n/a') return { status: 'noop', conditions: [], flags };
|
|
313
|
+
|
|
314
|
+
// Tank taunt peel: target is on someone else (targetAttackingMe == 0).
|
|
315
|
+
// Phrases used by Feral tank / Prot suggestion packs and the rotation editor preset.
|
|
316
|
+
if (
|
|
317
|
+
/target\s+not\s+attacking\s+me|not\s+attacking\s+me|target\s+attacking\s+someone\s+else|your\s+target\s+is\s+attacking\s+someone\s+else|off[\s-]?target|lost\s+aggro|target\s+not\s+on\s+me/.test(
|
|
318
|
+
when,
|
|
319
|
+
)
|
|
320
|
+
) {
|
|
321
|
+
return {
|
|
322
|
+
status: 'mapped',
|
|
323
|
+
conditions: [{ subject: 'self', metric: 'targetAttackingMe', op: '==', value: 0 }],
|
|
324
|
+
flags,
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// Threat DUMP: the target is on ME — Feint, Cower, Disengage. The inverse of the taunt peel above,
|
|
329
|
+
// and it had no mapping, so the prose the materializer emits could not be read back.
|
|
330
|
+
if (
|
|
331
|
+
/your\s+target\s+is\s+attacking\s+you|target\s+is\s+attacking\s+me|target\s+attacking\s+me|target\s+is\s+on\s+me/.test(
|
|
332
|
+
when,
|
|
333
|
+
)
|
|
334
|
+
) {
|
|
335
|
+
return {
|
|
336
|
+
status: 'mapped',
|
|
337
|
+
conditions: [{ subject: 'self', metric: 'targetAttackingMe', op: '==', value: 1 }],
|
|
338
|
+
flags,
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// Dodge-reactive abilities: the engine remembers the target's last dodge for 5 s, so "after target
|
|
343
|
+
// dodges" is a real gate. Without it Overpower spam torched the rage bar — 61 casts, 0 kills.
|
|
344
|
+
if (/after\s+(?:target\s+)?dodges?|on\s+dodge/.test(when) && !/parry|block/.test(when)) {
|
|
345
|
+
return {
|
|
346
|
+
status: 'mapped',
|
|
347
|
+
conditions: [{ subject: 'target', metric: 'dodgedRecently', op: '==', value: 1 }],
|
|
348
|
+
flags,
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
// Defense reacts (Revenge): self dodge/parry/block within 5s. Phrases like
|
|
352
|
+
// "after a block or parry", "after dodge/parry/block", "on react".
|
|
353
|
+
if (
|
|
354
|
+
/after\s+(?:a\s+)?block|after\s+(?:a\s+)?parry|after\s+(?:a\s+)?dodge|on\s+react|block\s+or\s+parry|dodge.*parry|parry.*block/.test(
|
|
355
|
+
when,
|
|
356
|
+
)
|
|
357
|
+
) {
|
|
358
|
+
return {
|
|
359
|
+
status: 'mapped',
|
|
360
|
+
conditions: [{ ...DEFENSE_REACT_COND }],
|
|
361
|
+
flags,
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// "always on self" = keep buff up (buff absent)
|
|
366
|
+
// Form/stance enter spells: modal formId, not buffPresent (recast toggles form off).
|
|
367
|
+
if (when === 'always on self') {
|
|
368
|
+
const formOfSpell = formIdFromLabel(spellLabel);
|
|
369
|
+
if (formOfSpell != null && isFormOrStanceSpellLabel(spellLabel)) {
|
|
370
|
+
return {
|
|
371
|
+
status: 'mapped',
|
|
372
|
+
conditions: [{ subject: 'self', metric: 'formId', op: '!=', value: formOfSpell }],
|
|
373
|
+
flags,
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
return {
|
|
377
|
+
status: flags.length ? 'partial' : 'mapped',
|
|
378
|
+
conditions: [{ subject: 'self', metric: 'buffPresent', op: '==', value: 0, ref: 'ACTION_SPELL' }],
|
|
379
|
+
flags,
|
|
380
|
+
reason: flags.length ? `spell needs engine: ${flags.join(', ')}` : undefined,
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// Soft always with prose tags
|
|
385
|
+
if (when === 'opener/slow' || when === 'multi/burst') {
|
|
386
|
+
if (/\bsingle\b/.test(when) && !/\bmulti\b/.test(when)) {
|
|
387
|
+
const conditions: WhenCondition[] = [];
|
|
388
|
+
pushSingleGate(conditions, flags);
|
|
389
|
+
return multiAwareResult(conditions, flags, when);
|
|
390
|
+
}
|
|
391
|
+
if (/multi/.test(when)) {
|
|
392
|
+
const conditions: WhenCondition[] = [];
|
|
393
|
+
pushMultiGate(conditions, flags);
|
|
394
|
+
return multiAwareResult(conditions, flags, when);
|
|
395
|
+
}
|
|
396
|
+
// Form enter still needs formId even on soft-always prose (toggle thrash).
|
|
397
|
+
const formSoft = formIdFromLabel(spellLabel);
|
|
398
|
+
if (formSoft != null && isFormOrStanceSpellLabel(spellLabel)) {
|
|
399
|
+
return {
|
|
400
|
+
status: 'mapped',
|
|
401
|
+
conditions: [{ subject: 'self', metric: 'formId', op: '!=', value: formSoft }],
|
|
402
|
+
flags,
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
return alwaysOrPartial(flags, when);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// "usable or …" takes the primary usable, session gates only. Never promote the secondary clause
|
|
409
|
+
// alone: Eviscerate's "usable or target under 40%" must not become execute-only.
|
|
410
|
+
if (/^usable\s+or\b/.test(when)) {
|
|
411
|
+
pushUniqueFlag(flags, 'or-condition');
|
|
412
|
+
const formUsableOr = formIdFromLabel(spellLabel);
|
|
413
|
+
if (formUsableOr != null && isFormOrStanceSpellLabel(spellLabel)) {
|
|
414
|
+
const conditions: WhenCondition[] = [
|
|
415
|
+
{ subject: 'self', metric: 'formId', op: '!=', value: formUsableOr },
|
|
416
|
+
];
|
|
417
|
+
if (/\bmulti\b/.test(when)) pushMultiGate(conditions, flags);
|
|
418
|
+
return multiAwareResult(conditions, flags, 'OR: form enter + primary usable');
|
|
419
|
+
}
|
|
420
|
+
if (/\bmulti\b/.test(when)) {
|
|
421
|
+
const conditions: WhenCondition[] = [];
|
|
422
|
+
pushMultiGate(conditions, flags);
|
|
423
|
+
return multiAwareResult(conditions, flags, 'OR: took primary usable');
|
|
424
|
+
}
|
|
425
|
+
return {
|
|
426
|
+
status: 'partial',
|
|
427
|
+
conditions: [],
|
|
428
|
+
flags,
|
|
429
|
+
reason: 'OR: took primary usable (session gate only)',
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// "always", "always (multi)", plain usable, opener and filler. NOTE: "usable in melee" and
|
|
434
|
+
// "usable (…)" are NOT bare usable — they fall through so the intent is not dropped to ALWAYS.
|
|
435
|
+
if (
|
|
436
|
+
!when ||
|
|
437
|
+
when === 'always' ||
|
|
438
|
+
when === 'usable' ||
|
|
439
|
+
when === 'opener' ||
|
|
440
|
+
when === 'filler' ||
|
|
441
|
+
when === 'fallback' ||
|
|
442
|
+
when === 'lower priority' ||
|
|
443
|
+
/^always\b/.test(when)
|
|
444
|
+
) {
|
|
445
|
+
if (/if talented|if dipped|if available/.test(when)) pushUniqueFlag(flags, 'talent-gated');
|
|
446
|
+
// `(single)` / "always (single)" — bosses only (Sunder-class ST keep-ups).
|
|
447
|
+
if (/\bsingle\b/.test(when) && !/\bmulti\b/.test(when)) {
|
|
448
|
+
const conditions: WhenCondition[] = [];
|
|
449
|
+
pushSingleGate(conditions, flags);
|
|
450
|
+
return multiAwareResult(conditions, flags);
|
|
451
|
+
}
|
|
452
|
+
if (/\bmulti\b/.test(when)) {
|
|
453
|
+
const conditions: WhenCondition[] = [];
|
|
454
|
+
pushMultiGate(conditions, flags);
|
|
455
|
+
return multiAwareResult(conditions, flags);
|
|
456
|
+
}
|
|
457
|
+
// Wave 1D: totem summons with bare "always"/"usable" still gate on empty element slot
|
|
458
|
+
// so role/suggestion lists never thrash a full slot.
|
|
459
|
+
if (isTotemSpellLabel(spellLabel)) {
|
|
460
|
+
const conditions: WhenCondition[] = [
|
|
461
|
+
{ subject: 'self', metric: 'totemPresent', op: '==', value: 0, ref: 'TOTEM_SLOT' },
|
|
462
|
+
];
|
|
463
|
+
return multiAwareResult(conditions, flags);
|
|
464
|
+
}
|
|
465
|
+
// Weapon imbue: keep up while any eligible weapon hand is open (ref 2).
|
|
466
|
+
if (isWeaponImbueSpellLabel(spellLabel)) {
|
|
467
|
+
const conditions: WhenCondition[] = [
|
|
468
|
+
{ subject: 'self', metric: 'weaponImbuePresent', op: '==', value: 0, ref: 2 },
|
|
469
|
+
];
|
|
470
|
+
return multiAwareResult(conditions, flags);
|
|
471
|
+
}
|
|
472
|
+
// Form/stance enter: gate on formId != form so "always" / empty when never toggle-thrashes
|
|
473
|
+
// (recasting Cat Form while already in Cat leaves form — Classic toggle).
|
|
474
|
+
const formOfAlways = formIdFromLabel(spellLabel);
|
|
475
|
+
if (formOfAlways != null && isFormOrStanceSpellLabel(spellLabel)) {
|
|
476
|
+
const conditions: WhenCondition[] = [
|
|
477
|
+
{ subject: 'self', metric: 'formId', op: '!=', value: formOfAlways },
|
|
478
|
+
];
|
|
479
|
+
return multiAwareResult(conditions, flags);
|
|
480
|
+
}
|
|
481
|
+
// Revenge et al.: bare "usable"/"always" is still a react ability, not free filler.
|
|
482
|
+
if (isDefenseReactSpellLabel(spellLabel)) {
|
|
483
|
+
return {
|
|
484
|
+
status: 'mapped',
|
|
485
|
+
conditions: [{ ...DEFENSE_REACT_COND }],
|
|
486
|
+
flags,
|
|
487
|
+
reason: 'defense-react spell (Revenge) requires dodge/parry/block react',
|
|
488
|
+
};
|
|
489
|
+
}
|
|
490
|
+
return alwaysOrPartial(flags);
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
const conditions: WhenCondition[] = [];
|
|
494
|
+
whenGapFlags(when, flags);
|
|
495
|
+
|
|
496
|
+
// OR policy, with no full OR DSL: never AND conditions from distinct OR sides, since the runtime
|
|
497
|
+
// ANDs them. A filler branch empties the conditions; otherwise map the primary clause only.
|
|
498
|
+
if (flags.includes('or-condition')) {
|
|
499
|
+
// An "or" inside a parenthetical qualifier is not a top-level OR of clauses, so let it fall
|
|
500
|
+
// through to normal handling rather than dropping the reapply gate to an empty ALWAYS.
|
|
501
|
+
const orOutsideParens = /\bor\b/.test(when.replace(/\([^)]*\)/g, ''));
|
|
502
|
+
const orParts = when.split(/\s+or\s+/).map((p) => p.trim()).filter(Boolean);
|
|
503
|
+
if (orOutsideParens && orParts.length >= 2) {
|
|
504
|
+
if (orParts.some(isSessionAlwaysOrClause)) {
|
|
505
|
+
return {
|
|
506
|
+
status: 'partial',
|
|
507
|
+
conditions: [],
|
|
508
|
+
flags,
|
|
509
|
+
reason: 'OR: took always/filler/usable branch (session gate only)',
|
|
510
|
+
};
|
|
511
|
+
}
|
|
512
|
+
const primary = orParts[0]!;
|
|
513
|
+
const primaryResult = mapWhen(primary, spellLabel);
|
|
514
|
+
const outFlags = [...primaryResult.flags];
|
|
515
|
+
pushUniqueFlag(outFlags, 'or-condition');
|
|
516
|
+
// Keep other audit flags from the full phrase, but do not import multi-target from a
|
|
517
|
+
// secondary-only "… or multi" (that would re-AND the multi gate onto the primary).
|
|
518
|
+
for (const f of flags) {
|
|
519
|
+
if (f === 'or-condition') continue;
|
|
520
|
+
if (f === 'multi-target' && !/\bmulti\b/.test(primary)) continue;
|
|
521
|
+
pushUniqueFlag(outFlags, f);
|
|
522
|
+
}
|
|
523
|
+
if (primaryResult.status === 'noop') {
|
|
524
|
+
return { status: 'noop', conditions: [], flags: outFlags, reason: primaryResult.reason };
|
|
525
|
+
}
|
|
526
|
+
const reason =
|
|
527
|
+
primaryResult.reason && !/or-condition|OR:/.test(primaryResult.reason)
|
|
528
|
+
? `OR primary: ${primaryResult.reason}`
|
|
529
|
+
: 'OR: took primary clause only (no full OR DSL)';
|
|
530
|
+
return {
|
|
531
|
+
// Authoring still had OR — always partial so audits see the gap, even when the
|
|
532
|
+
// primary clause mapped cleanly on its own.
|
|
533
|
+
status: 'partial',
|
|
534
|
+
conditions: primaryResult.conditions,
|
|
535
|
+
flags: outFlags,
|
|
536
|
+
reason,
|
|
537
|
+
};
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
// Wave 1B: multi is a real gate, not only a gap flag.
|
|
542
|
+
if (flags.includes('multi-target')) {
|
|
543
|
+
if (!conditions.some((c) => c.metric === 'enemyCount')) {
|
|
544
|
+
conditions.push({ ...MULTI_ENEMY_COUNT_COND });
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
// `(single)` / "single target" — ST-only (Sunder on bosses, not trash packs).
|
|
548
|
+
// Prefer multi when both appear (authored "(multi)" should win).
|
|
549
|
+
if (
|
|
550
|
+
!conditions.some((c) => c.metric === 'enemyCount')
|
|
551
|
+
&& /\bsingle\b/.test(when)
|
|
552
|
+
&& !/\bmulti\b/.test(when)
|
|
553
|
+
) {
|
|
554
|
+
conditions.push({ ...SINGLE_ENEMY_COUNT_COND });
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
// pet happiness
|
|
558
|
+
const petHappy =
|
|
559
|
+
when.match(/pethappiness\s*([<>]=?)\s*(\d+)/) || when.match(/happiness\s*([<>]=?)\s*(\d+)/);
|
|
560
|
+
if (petHappy && isCondOp(petHappy[1]!)) {
|
|
561
|
+
conditions.push({
|
|
562
|
+
subject: 'pet',
|
|
563
|
+
metric: 'petHappiness',
|
|
564
|
+
op: petHappy[1]!,
|
|
565
|
+
value: +petHappy[2]!,
|
|
566
|
+
});
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
// pet not alive / pet alive
|
|
570
|
+
if (/pet\s+(not\s+)?alive|no\s+pet|pet\s+missing|pet\s+dead/.test(when)) {
|
|
571
|
+
const alive = /not|no |missing|dead/.test(when) ? 0 : 1;
|
|
572
|
+
conditions.push({ subject: 'pet', metric: 'alive', op: '==', value: alive });
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
// has aggro (any enemy on you) — Feign Death dump. Distinct from "lost aggro" (taunt).
|
|
576
|
+
if (/\bhas\s+aggro\b|\ban\s+enemy\s+is\s+(on|attacking)\s+you\b/.test(when)) {
|
|
577
|
+
if (!conditions.some((c) => c.metric === 'hasAggro')) {
|
|
578
|
+
conditions.push({ subject: 'self', metric: 'hasAggro', op: '==', value: 1 });
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
// Buff missing, absent or not active. Form and stance enter use formId rather than buffPresent,
|
|
583
|
+
// since forms are modal and a recast toggles off; totem summons use the empty element slot.
|
|
584
|
+
if (
|
|
585
|
+
(/buff\s+(missing|absent)|buff absent|if not active|not active|missing on self|buff missing/.test(when) ||
|
|
586
|
+
when === 'if not active') &&
|
|
587
|
+
!/debuff/.test(when)
|
|
588
|
+
) {
|
|
589
|
+
const formOfSpell = formIdFromLabel(spellLabel);
|
|
590
|
+
if (formOfSpell != null && isFormOrStanceSpellLabel(spellLabel)) {
|
|
591
|
+
conditions.push({ subject: 'self', metric: 'formId', op: '!=', value: formOfSpell });
|
|
592
|
+
} else if (isTotemSpellLabel(spellLabel)) {
|
|
593
|
+
conditions.push({
|
|
594
|
+
subject: 'self',
|
|
595
|
+
metric: 'totemPresent',
|
|
596
|
+
op: '==',
|
|
597
|
+
value: 0,
|
|
598
|
+
ref: 'TOTEM_SLOT',
|
|
599
|
+
});
|
|
600
|
+
} else if (isWeaponImbueSpellLabel(spellLabel)) {
|
|
601
|
+
// Open eligible hands (ref 2) — dual-wield fills MH then OH; both coated stops thrash.
|
|
602
|
+
conditions.push({
|
|
603
|
+
subject: 'self',
|
|
604
|
+
metric: 'weaponImbuePresent',
|
|
605
|
+
op: '==',
|
|
606
|
+
value: 0,
|
|
607
|
+
ref: 2,
|
|
608
|
+
});
|
|
609
|
+
} else {
|
|
610
|
+
conditions.push({ subject: 'self', metric: 'buffPresent', op: '==', value: 0, ref: 'ACTION_SPELL' });
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
// "in Bear Form" / "in Cat Form" / "in Battle Stance" (Wave 1A formId == id)
|
|
615
|
+
// Prefer explicit "in …" phrases over bare form names in free prose.
|
|
616
|
+
const inFormMatch = when.match(
|
|
617
|
+
/\bin\s+((?:dire\s+)?bear(?:\s+form)?|cat(?:\s+form)?|travel(?:\s+form)?|aquatic(?:\s+form)?|moonkin(?:\s+form)?|tree(?:\s+of\s+life)?|shadowform|battle\s+stance|defensive\s+stance|berserker\s+stance|stealth|prowl)\b/,
|
|
618
|
+
);
|
|
619
|
+
if (inFormMatch) {
|
|
620
|
+
const fid = formIdFromLabel(inFormMatch[1]!);
|
|
621
|
+
if (fid != null && !conditions.some((c) => c.metric === 'formId' && c.op === '==')) {
|
|
622
|
+
conditions.push({ subject: 'self', metric: 'formId', op: '==', value: fid });
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
// Group composition — "2+ melee in party". Air-slot buff totems only pay off with melee
|
|
627
|
+
// beneficiaries, and it is evaluated per snapshot so a composition change needs no rebuild.
|
|
628
|
+
const meleeParty = when.match(/(\d+)\+?\s*melee(?:\s+allies)?\s+in\s+(?:the\s+)?party/)
|
|
629
|
+
?? (/\bmelee in party\b/.test(when) ? ([, '1'] as unknown as RegExpMatchArray) : null);
|
|
630
|
+
if (meleeParty) {
|
|
631
|
+
conditions.push({
|
|
632
|
+
subject: 'self',
|
|
633
|
+
metric: 'meleeAllyCount',
|
|
634
|
+
op: '>=',
|
|
635
|
+
value: Math.max(1, parseInt(meleeParty[1] ?? '1', 10) || 1),
|
|
636
|
+
});
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
// Named self-debuffs first (Wave 1C) - must not also match generic target debuff-absent.
|
|
640
|
+
// Weakened Soul: Power Word: Shield anti-stack on self; id is fixed in NAMED_DEBUFF_SPELL_IDS.
|
|
641
|
+
const namedSelfDebuff = /weakened soul/.test(when);
|
|
642
|
+
if (namedSelfDebuff) {
|
|
643
|
+
conditions.push({
|
|
644
|
+
subject: 'self',
|
|
645
|
+
metric: 'debuffPresent',
|
|
646
|
+
op: '==',
|
|
647
|
+
value: 0,
|
|
648
|
+
ref: 'WEAKENED_SOUL',
|
|
649
|
+
});
|
|
650
|
+
// Id is known - no needs-debuff-id flag (Wave 1C resolves Wave 0 placeholder).
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
// "debuff absent/low stacks" → reapply until the action spell's stack cap (Sunder x5).
|
|
654
|
+
// ACTION_STACK_CAP is replaced by the spell's own StackAmount at materialize time.
|
|
655
|
+
if (!namedSelfDebuff && isLowStacksWhen(when)) {
|
|
656
|
+
conditions.push({
|
|
657
|
+
subject: 'target',
|
|
658
|
+
metric: 'debuffStacks',
|
|
659
|
+
op: '<',
|
|
660
|
+
value: ACTION_STACK_CAP,
|
|
661
|
+
ref: 'ACTION_SPELL',
|
|
662
|
+
});
|
|
663
|
+
} else if (
|
|
664
|
+
// debuff not present on target (action spell). Skip named self-debuff clauses.
|
|
665
|
+
!namedSelfDebuff &&
|
|
666
|
+
/debuff\s+(not\s+present|absent)|not on target|not present on target|debuff absent/.test(when)
|
|
667
|
+
) {
|
|
668
|
+
conditions.push({
|
|
669
|
+
subject: 'target',
|
|
670
|
+
metric: 'debuffPresent',
|
|
671
|
+
op: '==',
|
|
672
|
+
value: 0,
|
|
673
|
+
ref: 'ACTION_SPELL',
|
|
674
|
+
});
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
// Explicit stack thresholds: "stacks < 5", "stacks >= 3", "at 5 stacks" (>=).
|
|
678
|
+
// Refers to the action spell's own debuff on the target (Sunder, Expose Armor …).
|
|
679
|
+
if (!conditions.some((c) => c.metric === 'debuffStacks')) {
|
|
680
|
+
const stOp = when.match(/stacks?\s*(<=|>=|==|!=|<|>)\s*(\d+)/);
|
|
681
|
+
const stAt = when.match(/(?:at\s+)?(\d+)\s+stacks?/);
|
|
682
|
+
if (stOp && isCondOp(stOp[1]!)) {
|
|
683
|
+
conditions.push({ subject: 'target', metric: 'debuffStacks', op: stOp[1]!, value: +stOp[2]!, ref: 'ACTION_SPELL' });
|
|
684
|
+
} else if (stAt) {
|
|
685
|
+
conditions.push({ subject: 'target', metric: 'debuffStacks', op: '>=', value: +stAt[1]!, ref: 'ACTION_SPELL' });
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
// Interrupt gates: "enemy/target (is) casting", "to interrupt", "while casting".
|
|
690
|
+
// Optional flavor: "casting a heal" and "casting <school>" narrow the gate.
|
|
691
|
+
if (/(?:enemy|target)\s+(?:is\s+)?casting|\bto\s+interrupt\b|\binterrupt\b|\bwhile\s+casting\b/.test(when)) {
|
|
692
|
+
conditions.push({ subject: 'target', metric: 'castingPresent', op: '==', value: 1 });
|
|
693
|
+
if (/casting\s+(?:a\s+)?heal|\bheal\s+cast/.test(when)) {
|
|
694
|
+
conditions.push({ subject: 'target', metric: 'castingIsHeal', op: '==', value: 1 });
|
|
695
|
+
}
|
|
696
|
+
const school = when.match(/casting\s+(physical|holy|fire|nature|frost|shadow|arcane)/);
|
|
697
|
+
if (school) {
|
|
698
|
+
conditions.push({
|
|
699
|
+
subject: 'target',
|
|
700
|
+
metric: 'castingSchool',
|
|
701
|
+
op: '==',
|
|
702
|
+
value: SCHOOL_INDEX[school[1] as keyof typeof SCHOOL_INDEX],
|
|
703
|
+
});
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
// Melee gate: "usable in melee", "in melee", "melee range" (Raptor Strike, etc.).
|
|
708
|
+
// Snapshot: pairwise band vs the acting unit (self = pile, target = this enemy on you).
|
|
709
|
+
if (/\bin\s+melee\b|\bmelee\s+range\b/.test(when)) {
|
|
710
|
+
if (!conditions.some((c) => c.metric === 'inMelee')) {
|
|
711
|
+
conditions.push({ ...IN_MELEE_COND });
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
// "high value" / keep-up prose inside usable parentheticals (Devouring Plague, etc.):
|
|
716
|
+
// re-apply only when the action debuff is absent — never free on-GCD spam.
|
|
717
|
+
if (/\bhigh\s*value\b|\bkeep\s*up\b/.test(when)) {
|
|
718
|
+
if (!conditions.some((c) => c.metric === 'debuffPresent' && c.ref === 'ACTION_SPELL')) {
|
|
719
|
+
conditions.push({
|
|
720
|
+
subject: 'target',
|
|
721
|
+
metric: 'debuffPresent',
|
|
722
|
+
op: '==',
|
|
723
|
+
value: 0,
|
|
724
|
+
ref: 'ACTION_SPELL',
|
|
725
|
+
});
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
// Defense-react spell label still needs the react gate when when-string is free prose.
|
|
730
|
+
if (isDefenseReactSpellLabel(spellLabel) && !conditions.some((c) => c.metric === 'defenseReactRecently')) {
|
|
731
|
+
conditions.push({ ...DEFENSE_REACT_COND });
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
// health / power thresholds (self)
|
|
735
|
+
const selfHp =
|
|
736
|
+
when.match(/self\s+health(?:pct)?\s*([<>]=?)\s*(\d+)/) || when.match(/health\s*([<>]=?)\s*(\d+)\s*%/);
|
|
737
|
+
if (selfHp && isCondOp(selfHp[1]!)) {
|
|
738
|
+
conditions.push({ subject: 'self', metric: 'healthPct', op: selfHp[1]!, value: +selfHp[2]! });
|
|
739
|
+
}
|
|
740
|
+
// pet power before bare "power" so Dark Pact "pet powerPct > 50% AND self powerPct < 40%" keeps both
|
|
741
|
+
const petPow = when.match(/pet\s+power(?:pct)?\s*([<>]=?)\s*(\d+)/);
|
|
742
|
+
if (petPow && isCondOp(petPow[1]!)) {
|
|
743
|
+
conditions.push({ subject: 'pet', metric: 'powerPct', op: petPow[1]!, value: +petPow[2]! });
|
|
744
|
+
}
|
|
745
|
+
// Prefer `self power…`; bare mana/power only when no pet-power clause stole the word "power"
|
|
746
|
+
const powAlt =
|
|
747
|
+
when.match(/self\s+power(?:pct)?\s*([<>]=?)\s*(\d+)/) ||
|
|
748
|
+
(!petPow ? when.match(/(?:mana|power)\s*([<>]=?)\s*(\d+)\s*%/) : null);
|
|
749
|
+
if (powAlt && isCondOp(powAlt[1]!)) {
|
|
750
|
+
conditions.push({ subject: 'self', metric: 'powerPct', op: powAlt[1]!, value: +powAlt[2]! });
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
// target health
|
|
754
|
+
const tarHp = when.match(/target\s+health(?:pct)?\s*([<>]=?)\s*(\d+)/);
|
|
755
|
+
if (tarHp && isCondOp(tarHp[1]!)) {
|
|
756
|
+
conditions.push({ subject: 'target', metric: 'healthPct', op: tarHp[1]!, value: +tarHp[2]! });
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
// pet health
|
|
760
|
+
const petHp = when.match(/pet\s+health(?:pct)?\s*([<>]=?)\s*(\d+)/);
|
|
761
|
+
if (petHp && isCondOp(petHp[1]!)) {
|
|
762
|
+
conditions.push({ subject: 'pet', metric: 'healthPct', op: petHp[1]!, value: +petHp[2]! });
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
// itemCount - named items (Soul Shard) resolve to fixed entry; others keep ITEM placeholder
|
|
766
|
+
const ic =
|
|
767
|
+
when.match(/itemcount\s*(?:\(\s*['"]?([^'")]+)['"]?\s*\))?\s*([<>]=?)\s*(\d+)/i) ||
|
|
768
|
+
when.match(/itemcount\s*([<>]=?)\s*(\d+)/i);
|
|
769
|
+
if (ic) {
|
|
770
|
+
if (ic.length === 4 && ic[1] && Number.isNaN(+ic[1])) {
|
|
771
|
+
// named item in parens - Soul Shard is a known entry; Healthstone stays ITEM (often missing in bake)
|
|
772
|
+
if (isCondOp(ic[2]!)) {
|
|
773
|
+
const name = String(ic[1]).toLowerCase().trim();
|
|
774
|
+
const ref: WhenRef = /soul\s*shard/.test(name) ? SOUL_SHARD_ITEM_REF : 'ITEM';
|
|
775
|
+
conditions.push({
|
|
776
|
+
subject: 'self',
|
|
777
|
+
metric: 'itemCount',
|
|
778
|
+
op: ic[2]!,
|
|
779
|
+
value: +ic[3]!,
|
|
780
|
+
ref,
|
|
781
|
+
});
|
|
782
|
+
}
|
|
783
|
+
} else if (ic.length === 3 && isCondOp(ic[1]!)) {
|
|
784
|
+
conditions.push({
|
|
785
|
+
subject: 'self',
|
|
786
|
+
metric: 'itemCount',
|
|
787
|
+
op: ic[1]!,
|
|
788
|
+
value: +ic[2]!,
|
|
789
|
+
ref: 'ITEM',
|
|
790
|
+
});
|
|
791
|
+
} else if (ic.length === 4 && isCondOp(ic[2]!)) {
|
|
792
|
+
conditions.push({
|
|
793
|
+
subject: 'self',
|
|
794
|
+
metric: 'itemCount',
|
|
795
|
+
op: ic[2]!,
|
|
796
|
+
value: +ic[3]!,
|
|
797
|
+
ref: 'ITEM',
|
|
798
|
+
});
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
const bareCount = when.match(/^itemcount\s*([<>]=?)\s*(\d+)$/);
|
|
802
|
+
if (bareCount && isCondOp(bareCount[1]!) && !conditions.some((c) => c.metric === 'itemCount')) {
|
|
803
|
+
conditions.push({
|
|
804
|
+
subject: 'self',
|
|
805
|
+
metric: 'itemCount',
|
|
806
|
+
op: bareCount[1]!,
|
|
807
|
+
value: +bareCount[2]!,
|
|
808
|
+
ref: 'ITEM',
|
|
809
|
+
});
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
// soul shard prose ("soul shards < 2") - match op/value next to the shard phrase only.
|
|
813
|
+
// Do not re-scan the whole when (would steal target healthPct's "< 25" from Drain Soul AND clauses).
|
|
814
|
+
if (/soul\s*shard/.test(when) && !conditions.some((c) => c.metric === 'itemCount' && c.ref === SOUL_SHARD_ITEM_REF)) {
|
|
815
|
+
const m =
|
|
816
|
+
when.match(/soul\s*shards?\s*([<>]=?)\s*(\d+)/) ||
|
|
817
|
+
when.match(/itemcount\s*\(\s*['"]?soul\s*shard['"]?\s*\)\s*([<>]=?)\s*(\d+)/i);
|
|
818
|
+
if (m && isCondOp(m[1]!)) {
|
|
819
|
+
conditions.push({
|
|
820
|
+
subject: 'self',
|
|
821
|
+
metric: 'itemCount',
|
|
822
|
+
op: m[1]!,
|
|
823
|
+
value: +m[2]!,
|
|
824
|
+
ref: SOUL_SHARD_ITEM_REF,
|
|
825
|
+
});
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
// off CD - session usability only (audit: after pattern scan; clears conditions)
|
|
830
|
+
if (/^off cd$|off cooldown|on cooldown/.test(when) || when === 'off cd') {
|
|
831
|
+
return alwaysOrPartial(
|
|
832
|
+
flags,
|
|
833
|
+
flags.length ? `spell needs engine: ${flags.join(', ')}` : 'cooldown fallthrough is free',
|
|
834
|
+
);
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
const hasGap = flags.some((f) => (ENGINE_GAP_FLAGS as readonly string[]).includes(f));
|
|
838
|
+
|
|
839
|
+
if (flags.includes('or-condition') || hasGap) {
|
|
840
|
+
// gap + no extractable conditions → unmapped (cannot implement yet) gap/OR + some conditions → partial
|
|
841
|
+
// (usable AND subset) OR only + no gap → partial
|
|
842
|
+
const status: WhenMapStatus =
|
|
843
|
+
conditions.length || !hasGap
|
|
844
|
+
? hasGap || flags.includes('or-condition')
|
|
845
|
+
? 'partial'
|
|
846
|
+
: 'mapped'
|
|
847
|
+
: 'unmapped';
|
|
848
|
+
return {
|
|
849
|
+
status,
|
|
850
|
+
conditions,
|
|
851
|
+
flags,
|
|
852
|
+
reason: gapReason(flags),
|
|
853
|
+
};
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
if (conditions.length) return { status: 'mapped', conditions, flags };
|
|
857
|
+
|
|
858
|
+
// Bare "usable", with only noise left after stripping, is the session gate. Leftover intent must
|
|
859
|
+
// NOT claim ALWAYS with empty conditions — that silently dropped authored gates.
|
|
860
|
+
if (/usable/.test(when) && conditions.length === 0) {
|
|
861
|
+
const leftover = when
|
|
862
|
+
.replace(/\busable\b/g, ' ')
|
|
863
|
+
.replace(/\b(always|opener|filler|fallback|off\s*cd|on\s*cooldown)\b/g, ' ')
|
|
864
|
+
.replace(/[().,;:/]/g, ' ')
|
|
865
|
+
.replace(/\s+/g, ' ')
|
|
866
|
+
.trim();
|
|
867
|
+
if (!leftover) {
|
|
868
|
+
// Still defense-react by label (safety if early branch missed).
|
|
869
|
+
if (isDefenseReactSpellLabel(spellLabel)) {
|
|
870
|
+
return {
|
|
871
|
+
status: 'mapped',
|
|
872
|
+
conditions: [{ ...DEFENSE_REACT_COND }],
|
|
873
|
+
flags,
|
|
874
|
+
reason: 'defense-react spell (Revenge) requires dodge/parry/block react',
|
|
875
|
+
};
|
|
876
|
+
}
|
|
877
|
+
return { status: 'always', conditions: [], flags, reason: 'usable = session gate only' };
|
|
878
|
+
}
|
|
879
|
+
return {
|
|
880
|
+
status: flags.includes('or-condition') || flags.includes('talent-gated') ? 'partial' : 'unmapped',
|
|
881
|
+
conditions: [],
|
|
882
|
+
flags,
|
|
883
|
+
reason: `usable phrase not fully mapped: "${whenRaw}"`,
|
|
884
|
+
};
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
return { status: 'unmapped', conditions: [], flags, reason: `no pattern for: "${whenRaw}"` };
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
// ---- Materialize for runtime Rotation -------------------------------------
|
|
891
|
+
|
|
892
|
+
export interface MaterializeRefs {
|
|
893
|
+
/** Spell id of the rule action (resolves ACTION_SPELL). */
|
|
894
|
+
actionSpellId?: number;
|
|
895
|
+
/** Item entry of the rule action (resolves ITEM). */
|
|
896
|
+
itemEntry?: number;
|
|
897
|
+
// Totem element slot for the action summon spell (resolves TOTEM_SLOT → index 0–3). Wave 1D - from
|
|
898
|
+
// spell's summon_totem effect.
|
|
899
|
+
totemSlot?: TotemSlot;
|
|
900
|
+
// Named debuff overrides (defaults from {@link NAMED_DEBUFF_SPELL_IDS}). Keys match WhenRefPlaceholder
|
|
901
|
+
// names used as debuff ids.
|
|
902
|
+
namedDebuffs?: Partial<Record<NamedDebuffKey, number>>;
|
|
903
|
+
// The action spell's SpellEntry.StackAmount - resolves {@link ACTION_STACK_CAP} sentinel values on stack
|
|
904
|
+
// conditions (Sunder Armor → 5).
|
|
905
|
+
actionStackAmount?: number;
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
// Convert WhenCondition rows to Conditions with numeric refs only, dropping any whose symbolic ref
|
|
909
|
+
// cannot be resolved. A condition needing an id that was not supplied is skipped.
|
|
910
|
+
export function materializeConditions(
|
|
911
|
+
conditions: readonly WhenCondition[],
|
|
912
|
+
refs: MaterializeRefs = {},
|
|
913
|
+
): Condition[] {
|
|
914
|
+
const out: Condition[] = [];
|
|
915
|
+
|
|
916
|
+
for (const c of conditions) {
|
|
917
|
+
let refNum: number | undefined;
|
|
918
|
+
if (c.ref == null) {
|
|
919
|
+
refNum = undefined;
|
|
920
|
+
} else if (typeof c.ref === 'number') {
|
|
921
|
+
refNum = c.ref;
|
|
922
|
+
} else if (c.ref === 'ACTION_SPELL') {
|
|
923
|
+
if (refs.actionSpellId == null) continue;
|
|
924
|
+
refNum = refs.actionSpellId;
|
|
925
|
+
} else if (c.ref === 'ITEM') {
|
|
926
|
+
if (refs.itemEntry == null) continue;
|
|
927
|
+
refNum = refs.itemEntry;
|
|
928
|
+
} else if (c.ref === 'TOTEM_SLOT') {
|
|
929
|
+
if (refs.totemSlot == null) continue;
|
|
930
|
+
refNum = totemSlotIndex(refs.totemSlot);
|
|
931
|
+
} else if (c.ref in NAMED_DEBUFF_SPELL_IDS) {
|
|
932
|
+
const key = c.ref as NamedDebuffKey;
|
|
933
|
+
refNum = refs.namedDebuffs?.[key] ?? NAMED_DEBUFF_SPELL_IDS[key];
|
|
934
|
+
} else {
|
|
935
|
+
continue;
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
// Stack-cap sentinel → the action spell's own StackAmount (or the classic default of 5).
|
|
939
|
+
let value = c.value;
|
|
940
|
+
if ((c.metric === 'debuffStacks' || c.metric === 'buffStacks') && value === ACTION_STACK_CAP) {
|
|
941
|
+
value = refs.actionStackAmount != null && refs.actionStackAmount > 1
|
|
942
|
+
? refs.actionStackAmount
|
|
943
|
+
: DEFAULT_STACK_CAP;
|
|
944
|
+
}
|
|
945
|
+
const cond: Condition = {
|
|
946
|
+
subject: c.subject,
|
|
947
|
+
metric: c.metric,
|
|
948
|
+
op: c.op,
|
|
949
|
+
value,
|
|
950
|
+
...(refNum != null ? { ref: refNum } : {}),
|
|
951
|
+
};
|
|
952
|
+
out.push(cond);
|
|
953
|
+
}
|
|
954
|
+
return out;
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
// True when the mapped when is safe to use as session-only (no conditions needed). Includes always, noop,
|
|
958
|
+
// and off-CD style empties.
|
|
959
|
+
export function isWhenAlways(result: WhenMapResult): boolean {
|
|
960
|
+
return result.status === 'always' || result.status === 'noop';
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
// Whether this when is multi-target gated (flag set; conditions include enemyCount when mapped). Wave 1B:
|
|
964
|
+
// multi rules ship with `enemyCount >= 2` and fire only in multi fights.
|
|
965
|
+
export function isMultiTargetWhen(result: WhenMapResult): boolean {
|
|
966
|
+
return result.flags.includes('multi-target');
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
// Map when + immediately materialize for a known spell/item action. Convenience for buildSuggestionRotation
|
|
970
|
+
// / tests.
|
|
971
|
+
export function mapWhenToConditions(
|
|
972
|
+
whenRaw: string | undefined | null,
|
|
973
|
+
opts: MaterializeRefs & { spellLabel?: string } = {},
|
|
974
|
+
): { result: WhenMapResult; conditions: Condition[] } {
|
|
975
|
+
const result = mapWhen(whenRaw, opts.spellLabel ?? '');
|
|
976
|
+
return { result, conditions: materializeConditions(result.conditions, opts) };
|
|
977
|
+
}
|