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,851 @@
|
|
|
1
|
+
// Authored rotation SUGGESTION schema plus pure parse and normalize. Content lives in
|
|
2
|
+
// docs/rotation_sugguestions and compiles to src/data/rotations — the browser never parses markdown.
|
|
3
|
+
|
|
4
|
+
import { CLASS } from '../../data/schema.ts';
|
|
5
|
+
import { sanitizeStepBackYd } from './stand.ts';
|
|
6
|
+
import type { RuleMove } from './types.ts';
|
|
7
|
+
|
|
8
|
+
// ---- Class keys -----------------------------------------------------------
|
|
9
|
+
|
|
10
|
+
export const SUGGESTION_CLASS_KEYS = [
|
|
11
|
+
'warrior',
|
|
12
|
+
'paladin',
|
|
13
|
+
'hunter',
|
|
14
|
+
'rogue',
|
|
15
|
+
'priest',
|
|
16
|
+
'shaman',
|
|
17
|
+
'mage',
|
|
18
|
+
'warlock',
|
|
19
|
+
'druid',
|
|
20
|
+
] as const;
|
|
21
|
+
|
|
22
|
+
export type SuggestionClassKey = (typeof SUGGESTION_CLASS_KEYS)[number];
|
|
23
|
+
|
|
24
|
+
export const SUGGESTION_CLASS_IDS: Record<SuggestionClassKey, number> = {
|
|
25
|
+
warrior: CLASS.WARRIOR,
|
|
26
|
+
paladin: CLASS.PALADIN,
|
|
27
|
+
hunter: CLASS.HUNTER,
|
|
28
|
+
rogue: CLASS.ROGUE,
|
|
29
|
+
priest: CLASS.PRIEST,
|
|
30
|
+
shaman: CLASS.SHAMAN,
|
|
31
|
+
mage: CLASS.MAGE,
|
|
32
|
+
warlock: CLASS.WARLOCK,
|
|
33
|
+
druid: CLASS.DRUID,
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/** Reverse map: CLASS id → suggestion slug (or null for unsupported classes). */
|
|
37
|
+
const CLASS_ID_TO_KEY = new Map<number, SuggestionClassKey>(
|
|
38
|
+
SUGGESTION_CLASS_KEYS.map((k) => [SUGGESTION_CLASS_IDS[k], k]),
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
/** Map a character `cls` id to a suggestion pack key, or null if none. */
|
|
42
|
+
export function suggestionClassKeyFromClassId(classId: number): SuggestionClassKey | null {
|
|
43
|
+
return CLASS_ID_TO_KEY.get(classId) ?? null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// G16: the variant name for "my list against THIS class". Nothing authors one yet, and that is
|
|
47
|
+
// fine - `selectBand` falls a named variant it cannot find back to the variant-less pvp pool.
|
|
48
|
+
export function vsClassVariant(enemyClassId: number | null | undefined): string | undefined {
|
|
49
|
+
const key = enemyClassId != null ? suggestionClassKeyFromClassId(enemyClassId) : null;
|
|
50
|
+
return key ? `vs-${key}` : undefined;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Primary tree when the character has 0 talent points (plan § Spec defaults). */
|
|
54
|
+
export const CLASS_DEFAULT_SPEC: Record<SuggestionClassKey, string> = {
|
|
55
|
+
warrior: 'Arms',
|
|
56
|
+
paladin: 'Retribution',
|
|
57
|
+
hunter: 'Beast Mastery',
|
|
58
|
+
rogue: 'Combat',
|
|
59
|
+
priest: 'Shadow',
|
|
60
|
+
shaman: 'Enhancement',
|
|
61
|
+
mage: 'Frost',
|
|
62
|
+
warlock: 'Affliction',
|
|
63
|
+
// L1–9 has no Bear/Cat yet; Balance matches the real starter kit (Moonfire/Wrath). Feral from L10+.
|
|
64
|
+
druid: 'Balance',
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export const SUGGESTION_PHASES = ['buffs', 'pull', 'recovery', 'combat'] as const;
|
|
68
|
+
export type SuggestionPhase = (typeof SUGGESTION_PHASES)[number];
|
|
69
|
+
|
|
70
|
+
// ---- Raw MD / committed JSON shape ----------------------------------------
|
|
71
|
+
|
|
72
|
+
// A baked condition row. When a pack rule carries these the builder uses them verbatim and invents
|
|
73
|
+
// no gates of its own — everything editable lives here.
|
|
74
|
+
export interface RawSuggestionCondition {
|
|
75
|
+
subject?: 'self' | 'target' | 'pet';
|
|
76
|
+
metric: string;
|
|
77
|
+
op: string;
|
|
78
|
+
value: number;
|
|
79
|
+
/** Spell/item id, or `"ACTION_SPELL"` for the rule's own resolved spell. */
|
|
80
|
+
ref?: number | 'ACTION_SPELL' | 'ITEM' | 'TOTEM_SLOT';
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** One priority row as authored in the MD JSON. */
|
|
84
|
+
export interface RawSuggestionRule {
|
|
85
|
+
spell?: string;
|
|
86
|
+
item?: string;
|
|
87
|
+
when?: string;
|
|
88
|
+
/** Pre-baked conditions — wins over free-text `when` when non-empty. */
|
|
89
|
+
conditions?: RawSuggestionCondition[];
|
|
90
|
+
/** `'other'` = cast at a non-focus, not-already-controlled hostile (crowd control). */
|
|
91
|
+
target?: 'focus' | 'other';
|
|
92
|
+
/** G15: after-cast retreat, yards from the focus. Sanitized by `sanitizeStepBackYd`. */
|
|
93
|
+
after?: { stepBackYd?: number };
|
|
94
|
+
// A walk instead of a cast — the RuleMove the builder hands to `advanceGapClose`. A row carrying
|
|
95
|
+
// one names no spell, so `move` and `spell`/`item` are exclusive.
|
|
96
|
+
move?: RuleMove;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** One level×spec band as authored (may be stub-only with a note). */
|
|
100
|
+
export type BandMode = 'pvp';
|
|
101
|
+
|
|
102
|
+
export interface RawSuggestionBand {
|
|
103
|
+
levels?: string;
|
|
104
|
+
spec?: string;
|
|
105
|
+
/** Some files also carry a talent-tree label (e.g. paladin.md). */
|
|
106
|
+
tree?: string;
|
|
107
|
+
/** `"pvp"` = duel / battleground / arena only. Absent = PvE, and PvE never sees a pvp band. */
|
|
108
|
+
mode?: string;
|
|
109
|
+
/** Names a SECOND pvp list for the same tree+levels. Only a request naming it selects it. */
|
|
110
|
+
variant?: string;
|
|
111
|
+
note?: string;
|
|
112
|
+
buffs?: RawSuggestionRule[];
|
|
113
|
+
pull?: RawSuggestionRule[];
|
|
114
|
+
recovery?: RawSuggestionRule[];
|
|
115
|
+
combat?: RawSuggestionRule[];
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// ---- Normalized model -----------------------------------------------------
|
|
119
|
+
|
|
120
|
+
export type SuggestionRuleKind = 'spell' | 'item' | 'noop' | 'move';
|
|
121
|
+
|
|
122
|
+
/** One actionable (or intentional no-op) priority entry after normalize. */
|
|
123
|
+
export interface SuggestionRule {
|
|
124
|
+
/** Original spell/item label from the MD. */
|
|
125
|
+
label: string;
|
|
126
|
+
// Ordered alternative labels after alias expand / slash-or split. Each entry is `normalizeSpellName`'d.
|
|
127
|
+
// Empty when kind === 'noop'.
|
|
128
|
+
labels: string[];
|
|
129
|
+
/** Raw "when" string — mapped to Condition[] in Wave 0B when `conditions` is empty. */
|
|
130
|
+
when: string;
|
|
131
|
+
kind: SuggestionRuleKind;
|
|
132
|
+
// Pre-baked conditions from materialized packs. When set, the builder skips inventing gates (role-bucket
|
|
133
|
+
// / semantic inject) for this row — the pack IS the rotation.
|
|
134
|
+
conditions?: RawSuggestionCondition[];
|
|
135
|
+
// `other` aims the rule at a living hostile that is NOT the focus and is not already controlled —
|
|
136
|
+
// the crowd-control selector. Omitted means the current target.
|
|
137
|
+
target?: 'focus' | 'other';
|
|
138
|
+
/** G15: authored after-cast retreat, yards. Reaches `RotationRule.after` in the builder. */
|
|
139
|
+
after?: { stepBackYd?: number };
|
|
140
|
+
/** Set only when `kind === 'move'`; becomes `RotationRule.action` verbatim. */
|
|
141
|
+
move?: RuleMove;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export interface SuggestionBand {
|
|
145
|
+
/** Original levels string (`"1-3"`, `"60"`, …). */
|
|
146
|
+
levels: string;
|
|
147
|
+
levelLo: number;
|
|
148
|
+
levelHi: number;
|
|
149
|
+
/** Raw MD `spec` field. */
|
|
150
|
+
specRaw: string;
|
|
151
|
+
/** Normalized primary tree name (e.g. Frost, Arms, Combat). */
|
|
152
|
+
spec: string;
|
|
153
|
+
// All trees this band applies to. Dual-authored labels like `Assassination/Subtlety` expand to both trees
|
|
154
|
+
// so `selectBand` matches either request (not just the primary).
|
|
155
|
+
specs: string[];
|
|
156
|
+
/** Raw MD `tree` if present. */
|
|
157
|
+
treeRaw?: string;
|
|
158
|
+
/** Set only when the band is authored for PvP; PvE selection filters these out entirely. */
|
|
159
|
+
mode?: BandMode;
|
|
160
|
+
/** Set only on a pvp band, so a variant can never reach PvE selection at all. */
|
|
161
|
+
variant?: string;
|
|
162
|
+
note?: string;
|
|
163
|
+
/** True when the band is only a note (no phase lists). */
|
|
164
|
+
stub: boolean;
|
|
165
|
+
phases: Record<SuggestionPhase, SuggestionRule[]>;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export interface ClassSuggestions {
|
|
169
|
+
classKey: SuggestionClassKey;
|
|
170
|
+
classId: number;
|
|
171
|
+
bands: SuggestionBand[];
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// ---- Name / alias helpers (mirrors audit-rotation-suggestions.mjs) --------
|
|
175
|
+
|
|
176
|
+
// Common free-text aliases from the suggestion MD / audit script. Values are already suitable for further
|
|
177
|
+
// name lookup (not re-normalized here).
|
|
178
|
+
export const SPELL_ALIASES: Readonly<Record<string, readonly string[]>> = {
|
|
179
|
+
'arcane intellect / arcane brilliance': ['arcane intellect', 'arcane brilliance'],
|
|
180
|
+
'conjure food / conjure water': ['conjure food', 'conjure water'],
|
|
181
|
+
'conjure mana agate / citrine': ['conjure mana agate', 'conjure mana citrine'],
|
|
182
|
+
'conjure mana ruby / citrine': ['conjure mana ruby', 'conjure mana citrine'],
|
|
183
|
+
'demon skin/armor': ['demon skin', 'demon armor'],
|
|
184
|
+
'demon skin / armor': ['demon skin', 'demon armor'],
|
|
185
|
+
// After normalizeSpellName strips `/` → spaces
|
|
186
|
+
'demon skin armor': ['demon skin', 'demon armor'],
|
|
187
|
+
'healing potion / healthstone': ['healing potion', 'major healing potion', 'healthstone'],
|
|
188
|
+
'use healthstone': [
|
|
189
|
+
'healthstone',
|
|
190
|
+
'minor healthstone',
|
|
191
|
+
'lesser healthstone',
|
|
192
|
+
'greater healthstone',
|
|
193
|
+
'major healthstone',
|
|
194
|
+
],
|
|
195
|
+
'health potion': [
|
|
196
|
+
'healing potion',
|
|
197
|
+
'minor healing potion',
|
|
198
|
+
'lesser healing potion',
|
|
199
|
+
'greater healing potion',
|
|
200
|
+
'major healing potion',
|
|
201
|
+
'superior healing potion',
|
|
202
|
+
],
|
|
203
|
+
'healing potion': [
|
|
204
|
+
'healing potion',
|
|
205
|
+
'minor healing potion',
|
|
206
|
+
'lesser healing potion',
|
|
207
|
+
'greater healing potion',
|
|
208
|
+
'major healing potion',
|
|
209
|
+
'superior healing potion',
|
|
210
|
+
],
|
|
211
|
+
// Priest (and others) recovery row often says just "potion"
|
|
212
|
+
potion: [
|
|
213
|
+
'healing potion',
|
|
214
|
+
'minor healing potion',
|
|
215
|
+
'lesser healing potion',
|
|
216
|
+
'greater healing potion',
|
|
217
|
+
'major healing potion',
|
|
218
|
+
'superior healing potion',
|
|
219
|
+
],
|
|
220
|
+
'auto-attack': [],
|
|
221
|
+
none: [],
|
|
222
|
+
'n/a': [],
|
|
223
|
+
autoattack: [],
|
|
224
|
+
'auto attack': [],
|
|
225
|
+
// Hunter Feed Pet (spell 6991) is not in the bake; happiness is raised via game.feedPet(food item),
|
|
226
|
+
// not a castable rotation spell. Intentional noop so builder/audit do not thrash unresolved.
|
|
227
|
+
'feed pet': [],
|
|
228
|
+
'instant vi / deadly v': ['instant poison vi', 'deadly poison v', 'instant poison', 'deadly poison'],
|
|
229
|
+
'instant / deadly poison': ['instant poison', 'deadly poison'],
|
|
230
|
+
'instant poison': ['instant poison'],
|
|
231
|
+
// Warrior Prot hybrid filler (40+ bands) — prefer WW → BT → MS when known
|
|
232
|
+
'whirlwind/bloodthirst/mortal strike (hybrid)': ['whirlwind', 'bloodthirst', 'mortal strike'],
|
|
233
|
+
'whirlwind bloodthirst mortal strike': ['whirlwind', 'bloodthirst', 'mortal strike'],
|
|
234
|
+
// Wave 2-SHA: slash earth totems keep full Classic names (bare "stoneskin" is the aura, not the summon)
|
|
235
|
+
'stoneskin/strength of earth totem': ['stoneskin totem', 'strength of earth totem'],
|
|
236
|
+
'stoneskin strength of earth totem': ['stoneskin totem', 'strength of earth totem'],
|
|
237
|
+
'strength of earth/stoneskin totem': ['strength of earth totem', 'stoneskin totem'],
|
|
238
|
+
'strength of earth stoneskin totem': ['strength of earth totem', 'stoneskin totem'],
|
|
239
|
+
// Resto solo filler row — "shocks" is not a spell name
|
|
240
|
+
'shocks/flame shock': ['flame shock', 'earth shock', 'frost shock'],
|
|
241
|
+
'shocks flame shock': ['flame shock', 'earth shock', 'frost shock'],
|
|
242
|
+
// Resto fallback "auto-attack or LB" → Lightning Bolt only (auto-attack is engine melee, not a rule)
|
|
243
|
+
'auto-attack or lb': ['lightning bolt'],
|
|
244
|
+
'auto attack or lb': ['lightning bolt'],
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
// Fold free-text spell and item labels for alias lookup and bake resolve. Non-rank parentheticals
|
|
248
|
+
// stay as tokens, so "Faerie Fire (Feral)" is not "Faerie Fire". Memoized: 2.6% of a tick profile.
|
|
249
|
+
const normalizedNames = new Map<string, string>();
|
|
250
|
+
|
|
251
|
+
export function normalizeSpellName(s: string): string {
|
|
252
|
+
const key = String(s);
|
|
253
|
+
const hit = normalizedNames.get(key);
|
|
254
|
+
if (hit !== undefined) return hit;
|
|
255
|
+
const out = normalizeSpellNameUncached(key);
|
|
256
|
+
if (normalizedNames.size < 50_000) normalizedNames.set(key, out);
|
|
257
|
+
return out;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function normalizeSpellNameUncached(s: string): string {
|
|
261
|
+
return String(s)
|
|
262
|
+
.toLowerCase()
|
|
263
|
+
.replace(/\(rank\s*\d+\)/gi, '')
|
|
264
|
+
.replace(/\(if[^)]*\)/gi, '')
|
|
265
|
+
.replace(/\(([^)]*)\)/g, ' $1 ')
|
|
266
|
+
.replace(/['']/g, "'")
|
|
267
|
+
.replace(/[^a-z0-9'+\-\s]/g, ' ')
|
|
268
|
+
.replace(/\s+/g, ' ')
|
|
269
|
+
.trim();
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// Parenthetical rank adjectives (Create Healthstone (Major), (Rank N)). Not (Feral) / (Bear).
|
|
273
|
+
const RANK_PAREN_RE = /\((rank\s*\d+|minor|lesser|greater|major|superior)\)/gi;
|
|
274
|
+
|
|
275
|
+
/** Name with rank parentheses stripped, so every Create Healthstone rank shares one key. */
|
|
276
|
+
export function rankBaseSpellName(s: string): string {
|
|
277
|
+
return normalizeSpellName(String(s).replace(RANK_PAREN_RE, ''));
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// Parse a level band string into inclusive lo/hi. Accepts `"1-3"`, en-dash `"1–3"`, or a single level
|
|
281
|
+
// `"60"`. Unparseable → full classic range 1–60.
|
|
282
|
+
export function parseLevelBand(levels: string | number | undefined | null): { lo: number; hi: number } {
|
|
283
|
+
const m = String(levels ?? '').match(/(\d+)\s*[-–]\s*(\d+)/);
|
|
284
|
+
if (m) return { lo: +m[1], hi: +m[2] };
|
|
285
|
+
const n = parseInt(String(levels ?? ''), 10);
|
|
286
|
+
if (Number.isFinite(n)) return { lo: n, hi: n };
|
|
287
|
+
return { lo: 1, hi: 60 };
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// Split "A / B / C" or "A or B" alternatives; expand known combined aliases. Empty / none / n/a /
|
|
291
|
+
// auto-attack → []. Lowercase + collapse whitespace, keep `/` so alias keys like `demon skin/armor` match.
|
|
292
|
+
function aliasLookupKey(s: string): string {
|
|
293
|
+
return String(s).toLowerCase().replace(/\s+/g, ' ').trim();
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
export function splitAlternatives(raw: string): string[] {
|
|
297
|
+
const s = String(raw).trim();
|
|
298
|
+
if (!s || /^none$/i.test(s) || /^n\/a$/i.test(s)) return [];
|
|
299
|
+
// Prefer keys that still contain `/` (authoring form), then fully folded names.
|
|
300
|
+
const candidates = [aliasLookupKey(s), normalizeSpellName(s)];
|
|
301
|
+
for (const key of candidates) {
|
|
302
|
+
if (Object.prototype.hasOwnProperty.call(SPELL_ALIASES, key)) {
|
|
303
|
+
return [...SPELL_ALIASES[key]!];
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// "X or Y" openers (skip Demon Skin/Armor style — handled by alias; also skip "or" inside armor phrases)
|
|
308
|
+
if (/\bor\b/i.test(s) && !/armor/i.test(s)) {
|
|
309
|
+
return s
|
|
310
|
+
.split(/\bor\b/i)
|
|
311
|
+
.map((x) => normalizeSpellName(x))
|
|
312
|
+
.filter(Boolean);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// Slash alternatives: "Sinister Strike / Backstab"
|
|
316
|
+
if (s.includes('/')) {
|
|
317
|
+
const parts = s
|
|
318
|
+
.split('/')
|
|
319
|
+
.map((x) =>
|
|
320
|
+
normalizeSpellName(
|
|
321
|
+
x
|
|
322
|
+
.replace(/\(if.*?\)/gi, '')
|
|
323
|
+
.replace(/if talented/gi, '')
|
|
324
|
+
.replace(/if dipped/gi, ''),
|
|
325
|
+
),
|
|
326
|
+
)
|
|
327
|
+
.filter(Boolean)
|
|
328
|
+
.filter((x) => x !== 'if talented' && x !== 'if available' && x !== 'if dipped');
|
|
329
|
+
// Wave 2-SHA: "Stoneskin/Strength of Earth Totem" → both * Totem (not the passive aura name)
|
|
330
|
+
if (parts.length > 1 && parts.some((p) => /\btotem\b/.test(p))) {
|
|
331
|
+
return parts.map((p) => (/\btotem\b/.test(p) ? p : `${p} totem`));
|
|
332
|
+
}
|
|
333
|
+
return parts;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
return [
|
|
337
|
+
normalizeSpellName(s.replace(/\(if.*?\)/gi, '').replace(/,?\s*if talented.*/i, '')),
|
|
338
|
+
].filter(Boolean);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// ---- Spec normalize -------------------------------------------------------
|
|
342
|
+
|
|
343
|
+
// Map free-text MD spec labels → canonical talent tree names used for band pick. Keys are lowercased labels
|
|
344
|
+
// as they appear (or after light fold).
|
|
345
|
+
const SPEC_CANONICAL: Readonly<Record<string, string>> = {
|
|
346
|
+
// Mage
|
|
347
|
+
frost: 'Frost',
|
|
348
|
+
'frost leveling': 'Frost',
|
|
349
|
+
fire: 'Fire',
|
|
350
|
+
'fire leveling': 'Fire',
|
|
351
|
+
arcane: 'Arcane',
|
|
352
|
+
'arcane leveling': 'Arcane',
|
|
353
|
+
// Warrior
|
|
354
|
+
arms: 'Arms',
|
|
355
|
+
fury: 'Fury',
|
|
356
|
+
protection: 'Protection',
|
|
357
|
+
prot: 'Protection',
|
|
358
|
+
// Warlock
|
|
359
|
+
affliction: 'Affliction',
|
|
360
|
+
demonology: 'Demonology',
|
|
361
|
+
destruction: 'Destruction',
|
|
362
|
+
demo: 'Demonology',
|
|
363
|
+
destro: 'Destruction',
|
|
364
|
+
// Priest
|
|
365
|
+
discipline: 'Discipline',
|
|
366
|
+
disc: 'Discipline',
|
|
367
|
+
holy: 'Holy',
|
|
368
|
+
shadow: 'Shadow',
|
|
369
|
+
// Paladin
|
|
370
|
+
retribution: 'Retribution',
|
|
371
|
+
ret: 'Retribution',
|
|
372
|
+
// Hunter
|
|
373
|
+
'beast mastery': 'Beast Mastery',
|
|
374
|
+
bm: 'Beast Mastery',
|
|
375
|
+
marksmanship: 'Marksmanship',
|
|
376
|
+
mm: 'Marksmanship',
|
|
377
|
+
survival: 'Survival',
|
|
378
|
+
// Rogue
|
|
379
|
+
combat: 'Combat',
|
|
380
|
+
'combat (optimal solo)': 'Combat',
|
|
381
|
+
'combat optimal solo': 'Combat',
|
|
382
|
+
assassination: 'Assassination',
|
|
383
|
+
subtlety: 'Subtlety',
|
|
384
|
+
'assassination/subtlety': 'Assassination',
|
|
385
|
+
'assassination subtlety': 'Assassination',
|
|
386
|
+
// Druid — canonical spec is "Feral" (matches data packs); talent tab "Feral Combat" aliases here.
|
|
387
|
+
// "Feral tank" is the role-facing bear-tank band (Classic name; same Feral Combat talents).
|
|
388
|
+
feral: 'Feral',
|
|
389
|
+
'feral combat': 'Feral',
|
|
390
|
+
'feral tank': 'Feral tank',
|
|
391
|
+
feraltank: 'Feral tank',
|
|
392
|
+
// Retail-era synonym kept as alias only.
|
|
393
|
+
guardian: 'Feral tank',
|
|
394
|
+
bear: 'Feral tank',
|
|
395
|
+
balance: 'Balance',
|
|
396
|
+
restoration: 'Restoration',
|
|
397
|
+
resto: 'Restoration',
|
|
398
|
+
// Shaman
|
|
399
|
+
enhancement: 'Enhancement',
|
|
400
|
+
enhance: 'Enhancement',
|
|
401
|
+
elemental: 'Elemental',
|
|
402
|
+
ele: 'Elemental',
|
|
403
|
+
// Product / leveling labels (some MD rows)
|
|
404
|
+
baseline: 'baseline',
|
|
405
|
+
'wand spec leveling': 'Shadow',
|
|
406
|
+
'wand spec': 'Shadow',
|
|
407
|
+
'pre-shadowform leveling': 'Shadow',
|
|
408
|
+
'pre-shadowform': 'Shadow',
|
|
409
|
+
'shadow leveling': 'Shadow',
|
|
410
|
+
};
|
|
411
|
+
|
|
412
|
+
function foldSpecKey(raw: string): string {
|
|
413
|
+
return String(raw)
|
|
414
|
+
.toLowerCase()
|
|
415
|
+
.replace(/\(.*?\)/g, ' ')
|
|
416
|
+
.replace(/leveling/g, ' ')
|
|
417
|
+
.replace(/optimal\s+solo/g, ' ')
|
|
418
|
+
.replace(/['']/g, "'")
|
|
419
|
+
.replace(/[^a-z0-9'+\-\/\s]/g, ' ')
|
|
420
|
+
.replace(/\s+/g, ' ')
|
|
421
|
+
.trim();
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// Normalize an authored spec to a canonical tree name for band matching, falling back to the class
|
|
425
|
+
// default. A dual label keeps the FIRST tree as primary; use band.specs for full membership.
|
|
426
|
+
export function normalizeSpecKey(
|
|
427
|
+
classKey: SuggestionClassKey,
|
|
428
|
+
specRaw: string | undefined | null,
|
|
429
|
+
treeRaw?: string | undefined | null,
|
|
430
|
+
): string {
|
|
431
|
+
return normalizeSpecKeys(classKey, specRaw, treeRaw)[0]!;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
// All canonical trees implied by an MD `spec` label. Splits dual-tree authorship (`Assassination/Subtlety`)
|
|
435
|
+
// so both trees match the band.
|
|
436
|
+
export function normalizeSpecKeys(
|
|
437
|
+
classKey: SuggestionClassKey,
|
|
438
|
+
specRaw: string | undefined | null,
|
|
439
|
+
treeRaw?: string | undefined | null,
|
|
440
|
+
): string[] {
|
|
441
|
+
const tryMap = (raw: string | undefined | null): string | null => {
|
|
442
|
+
if (raw == null || String(raw).trim() === '') return null;
|
|
443
|
+
const exact = String(raw).toLowerCase().trim();
|
|
444
|
+
if (SPEC_CANONICAL[exact]) return SPEC_CANONICAL[exact]!;
|
|
445
|
+
const folded = foldSpecKey(raw);
|
|
446
|
+
if (SPEC_CANONICAL[folded]) return SPEC_CANONICAL[folded]!;
|
|
447
|
+
// Title-case fallback when it already looks like a simple tree name
|
|
448
|
+
if (/^[a-z]+(?:\s+[a-z]+)?$/i.test(String(raw).trim()) && !/^baseline$/i.test(String(raw))) {
|
|
449
|
+
return String(raw)
|
|
450
|
+
.trim()
|
|
451
|
+
.split(/\s+/)
|
|
452
|
+
.map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())
|
|
453
|
+
.join(' ');
|
|
454
|
+
}
|
|
455
|
+
return null;
|
|
456
|
+
};
|
|
457
|
+
|
|
458
|
+
const mapOne = (raw: string | undefined | null): string | null => {
|
|
459
|
+
const fromTree = tryMap(treeRaw);
|
|
460
|
+
const fromSpec = tryMap(raw);
|
|
461
|
+
if (fromSpec === 'baseline') {
|
|
462
|
+
return fromTree && fromTree !== 'baseline' ? fromTree : CLASS_DEFAULT_SPEC[classKey];
|
|
463
|
+
}
|
|
464
|
+
if (fromSpec && fromSpec !== 'baseline') return fromSpec;
|
|
465
|
+
if (fromTree && fromTree !== 'baseline') return fromTree;
|
|
466
|
+
return null;
|
|
467
|
+
};
|
|
468
|
+
|
|
469
|
+
// Dual-tree labels: split on `/` before whole-string canonical lookup so "Assassination/Subtlety" applies
|
|
470
|
+
// to both trees (SPEC_CANONICAL maps the mash solely to Assassination for legacy primary-key callers).
|
|
471
|
+
const raw = specRaw != null ? String(specRaw).trim() : '';
|
|
472
|
+
if (raw.includes('/')) {
|
|
473
|
+
const parts = raw
|
|
474
|
+
.split('/')
|
|
475
|
+
.map((p) => p.trim())
|
|
476
|
+
.filter(Boolean);
|
|
477
|
+
if (parts.length > 1) {
|
|
478
|
+
const keys: string[] = [];
|
|
479
|
+
const seen = new Set<string>();
|
|
480
|
+
for (const part of parts) {
|
|
481
|
+
// Map each side alone (no treeRaw — tree applies to whole row, not each half).
|
|
482
|
+
const k = mapOne(part) ?? tryMap(part);
|
|
483
|
+
if (k && k !== 'baseline' && !seen.has(k)) {
|
|
484
|
+
seen.add(k);
|
|
485
|
+
keys.push(k);
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
if (keys.length > 1) return keys;
|
|
489
|
+
if (keys.length === 1) return keys;
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
const single = mapOne(specRaw);
|
|
494
|
+
if (single && single !== 'baseline') return [single];
|
|
495
|
+
return [CLASS_DEFAULT_SPEC[classKey]];
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
/** True when band membership includes `want` (primary or dual-spec). */
|
|
499
|
+
export function bandMatchesSpec(band: SuggestionBand, want: string): boolean {
|
|
500
|
+
if (band.spec === want) return true;
|
|
501
|
+
return band.specs.includes(want);
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
// Parse stub notes like `identical to Affliction` / `identical to Affliction (pet…)`. Returns the
|
|
505
|
+
// referenced tree label or null.
|
|
506
|
+
export function parseIdenticalToNote(note: string | undefined | null): string | null {
|
|
507
|
+
if (note == null || String(note).trim() === '') return null;
|
|
508
|
+
const m = String(note).match(/identical\s+to\s+([A-Za-z]+(?:\s+[A-Za-z]+)?)/i);
|
|
509
|
+
return m ? m[1]!.trim() : null;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
/** Distance from `level` to a band's inclusive range (0 if inside). */
|
|
513
|
+
function levelBandDistance(level: number, band: SuggestionBand): number {
|
|
514
|
+
if (level < band.levelLo) return band.levelLo - level;
|
|
515
|
+
if (level > band.levelHi) return level - band.levelHi;
|
|
516
|
+
return 0;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
/** Clone a donor band under a requested tree identity (stub resolve / rebrand). */
|
|
520
|
+
function rebrandBand(donor: SuggestionBand, want: string, stub?: SuggestionBand): SuggestionBand {
|
|
521
|
+
return {
|
|
522
|
+
...donor,
|
|
523
|
+
spec: want,
|
|
524
|
+
specs: [want],
|
|
525
|
+
stub: false,
|
|
526
|
+
note: stub?.note ?? donor.note,
|
|
527
|
+
specRaw: stub?.specRaw ?? want,
|
|
528
|
+
};
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
// ---- Rule / band normalize ------------------------------------------------
|
|
532
|
+
|
|
533
|
+
function isNoopLabel(label: string): boolean {
|
|
534
|
+
const key = normalizeSpellName(label);
|
|
535
|
+
if (!key || key === 'none' || key === 'n/a' || key === 'autoattack' || /^auto[- ]?attack$/.test(key)) {
|
|
536
|
+
return true;
|
|
537
|
+
}
|
|
538
|
+
if (Object.prototype.hasOwnProperty.call(SPELL_ALIASES, key) && SPELL_ALIASES[key]!.length === 0) {
|
|
539
|
+
return true;
|
|
540
|
+
}
|
|
541
|
+
return false;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
/** Reader label for a move row — what the editor and the audit print instead of a spell name. */
|
|
545
|
+
function moveLabel(move: RuleMove): string {
|
|
546
|
+
switch (move.kind) {
|
|
547
|
+
case 'keep_range': return `keep ${move.minYd} yd`;
|
|
548
|
+
case 'spread': return `spread ${move.minYd} yd`;
|
|
549
|
+
case 'flee_raid': return `run out ${move.yd} yd`;
|
|
550
|
+
case 'stack_on': return `stack on ${'unit' in move ? move.unit : move.role}`;
|
|
551
|
+
case 'behind_target': return 'get behind';
|
|
552
|
+
case 'flank_target': return 'flank';
|
|
553
|
+
case 'move_to': return `move to ${move.x},${move.y}`;
|
|
554
|
+
case 'avoid_zone': return `avoid ${move.id}`;
|
|
555
|
+
case 'split_by_aura': return `split ${move.awayYd} yd`;
|
|
556
|
+
default: return 'move';
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
export function normalizeSuggestionRule(raw: RawSuggestionRule): SuggestionRule {
|
|
561
|
+
const hasItem = raw.item != null && String(raw.item).trim() !== '';
|
|
562
|
+
const hasSpell = raw.spell != null && String(raw.spell).trim() !== '';
|
|
563
|
+
const label = String(hasSpell ? raw.spell : hasItem ? raw.item : '').trim();
|
|
564
|
+
const when = String(raw.when ?? '').trim();
|
|
565
|
+
const baked = Array.isArray(raw.conditions) && raw.conditions.length > 0
|
|
566
|
+
? raw.conditions.map((c) => ({
|
|
567
|
+
subject: c.subject,
|
|
568
|
+
metric: String(c.metric ?? ''),
|
|
569
|
+
op: String(c.op ?? '=='),
|
|
570
|
+
value: Number(c.value) || 0,
|
|
571
|
+
...(c.ref != null ? { ref: c.ref } : {}),
|
|
572
|
+
}))
|
|
573
|
+
: undefined;
|
|
574
|
+
|
|
575
|
+
// A move row is decided before the spell path: it carries no label to resolve, so the noop and
|
|
576
|
+
// empty-labels guards below would drop it.
|
|
577
|
+
if (raw.move) {
|
|
578
|
+
return {
|
|
579
|
+
label: moveLabel(raw.move), labels: [], when, kind: 'move', move: raw.move,
|
|
580
|
+
...(baked ? { conditions: baked } : {}),
|
|
581
|
+
};
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
if (isNoopLabel(label)) {
|
|
585
|
+
return { label: label || 'none', labels: [], when, kind: 'noop', ...(baked ? { conditions: baked } : {}) };
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
const kind: SuggestionRuleKind = hasItem && !hasSpell ? 'item' : 'spell';
|
|
589
|
+
const labels = splitAlternatives(label);
|
|
590
|
+
const target = raw.target === 'other' ? 'other' as const : undefined;
|
|
591
|
+
const stepBackYd = sanitizeStepBackYd(raw.after?.stepBackYd);
|
|
592
|
+
return {
|
|
593
|
+
label, labels, when, kind,
|
|
594
|
+
...(baked ? { conditions: baked } : {}),
|
|
595
|
+
...(target ? { target } : {}),
|
|
596
|
+
...(stepBackYd ? { after: { stepBackYd } } : {}),
|
|
597
|
+
};
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
export function normalizeSuggestionBand(
|
|
601
|
+
classKey: SuggestionClassKey,
|
|
602
|
+
raw: RawSuggestionBand,
|
|
603
|
+
): SuggestionBand {
|
|
604
|
+
const levels = String(raw.levels ?? '1-60');
|
|
605
|
+
const { lo, hi } = parseLevelBand(levels);
|
|
606
|
+
const specRaw = String(raw.spec ?? '');
|
|
607
|
+
const treeRaw = raw.tree != null ? String(raw.tree) : undefined;
|
|
608
|
+
// Strict: only the one known mode normalizes, so a typo reads as PvE rather than as a band
|
|
609
|
+
// nothing can ever select.
|
|
610
|
+
const mode: BandMode | undefined =
|
|
611
|
+
String(raw.mode ?? '').trim().toLowerCase() === 'pvp' ? 'pvp' : undefined;
|
|
612
|
+
// Variant discriminates the pvp pool only: dropping it off a PvE band is what makes
|
|
613
|
+
// "a variant never leaks into levelling" structural rather than a selector rule.
|
|
614
|
+
const variantRaw = String(raw.variant ?? '').trim();
|
|
615
|
+
const variant = mode === 'pvp' && variantRaw ? variantRaw : undefined;
|
|
616
|
+
const note = raw.note != null ? String(raw.note) : undefined;
|
|
617
|
+
|
|
618
|
+
const phases: Record<SuggestionPhase, SuggestionRule[]> = {
|
|
619
|
+
buffs: [],
|
|
620
|
+
pull: [],
|
|
621
|
+
recovery: [],
|
|
622
|
+
combat: [],
|
|
623
|
+
};
|
|
624
|
+
|
|
625
|
+
let anyPhase = false;
|
|
626
|
+
for (const phase of SUGGESTION_PHASES) {
|
|
627
|
+
const list = raw[phase];
|
|
628
|
+
if (!Array.isArray(list)) continue;
|
|
629
|
+
anyPhase = true;
|
|
630
|
+
phases[phase] = list.map((r) => normalizeSuggestionRule(r ?? {}));
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
// Stub: note-only rows (no phase lists) — warlock "identical to Affliction" style
|
|
634
|
+
const stub = !anyPhase;
|
|
635
|
+
const specs = normalizeSpecKeys(classKey, specRaw, treeRaw);
|
|
636
|
+
|
|
637
|
+
return {
|
|
638
|
+
levels,
|
|
639
|
+
levelLo: lo,
|
|
640
|
+
levelHi: hi,
|
|
641
|
+
specRaw,
|
|
642
|
+
spec: specs[0]!,
|
|
643
|
+
specs,
|
|
644
|
+
treeRaw,
|
|
645
|
+
...(mode ? { mode } : {}),
|
|
646
|
+
...(variant ? { variant } : {}),
|
|
647
|
+
note,
|
|
648
|
+
stub,
|
|
649
|
+
phases,
|
|
650
|
+
};
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
export function normalizeClassSuggestions(
|
|
654
|
+
classKey: SuggestionClassKey,
|
|
655
|
+
rawBands: readonly RawSuggestionBand[],
|
|
656
|
+
): ClassSuggestions {
|
|
657
|
+
if (!Array.isArray(rawBands)) {
|
|
658
|
+
throw new Error(`rotationSuggestions: ${classKey} expected array of bands`);
|
|
659
|
+
}
|
|
660
|
+
return {
|
|
661
|
+
classKey,
|
|
662
|
+
classId: SUGGESTION_CLASS_IDS[classKey],
|
|
663
|
+
bands: rawBands.map((b) => normalizeSuggestionBand(classKey, b)),
|
|
664
|
+
};
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
// ---- Source parse (MD / JSON text → raw array) ----------------------------
|
|
668
|
+
|
|
669
|
+
// Parse suggestion source text (raw JSON array, or MD with a leading/trailing prose wrapping a `[...]` JSON
|
|
670
|
+
// array). Throws if no array can be extracted.
|
|
671
|
+
export function parseSuggestionDocument(text: string): RawSuggestionBand[] {
|
|
672
|
+
const trimmed = String(text).trim();
|
|
673
|
+
if (!trimmed) throw new Error('rotationSuggestions: empty source');
|
|
674
|
+
|
|
675
|
+
const tryParse = (s: string): RawSuggestionBand[] => {
|
|
676
|
+
const v = JSON.parse(s) as unknown;
|
|
677
|
+
if (!Array.isArray(v)) throw new Error('rotationSuggestions: expected JSON array');
|
|
678
|
+
return v as RawSuggestionBand[];
|
|
679
|
+
};
|
|
680
|
+
|
|
681
|
+
try {
|
|
682
|
+
return tryParse(trimmed);
|
|
683
|
+
} catch {
|
|
684
|
+
const start = trimmed.indexOf('[');
|
|
685
|
+
const end = trimmed.lastIndexOf(']');
|
|
686
|
+
if (start >= 0 && end > start) {
|
|
687
|
+
return tryParse(trimmed.slice(start, end + 1));
|
|
688
|
+
}
|
|
689
|
+
throw new Error('rotationSuggestions: cannot parse suggestion source');
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
/** True if `key` is a known suggestion class slug. */
|
|
694
|
+
export function isSuggestionClassKey(key: string): key is SuggestionClassKey {
|
|
695
|
+
return (SUGGESTION_CLASS_KEYS as readonly string[]).includes(key);
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
// ---- Load committed JSON ---------------------------------------------------
|
|
699
|
+
// One file per class per spec per mode, merged by src/data/rotations/index.ts.
|
|
700
|
+
|
|
701
|
+
import { ROTATION_PACKS } from '../../data/rotations/index.ts';
|
|
702
|
+
|
|
703
|
+
/** Load and normalize one class from its committed `src/data/rotations/<mode>/<class>/*.json`. */
|
|
704
|
+
export function getClassSuggestions(classKey: SuggestionClassKey): ClassSuggestions {
|
|
705
|
+
const raw = ROTATION_PACKS[classKey];
|
|
706
|
+
if (!raw) throw new Error(`rotationSuggestions: unknown class key "${classKey}"`);
|
|
707
|
+
return normalizeClassSuggestions(classKey, raw);
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
/** Load all nine class suggestion packs (throws if any fail). */
|
|
711
|
+
export function loadAllSuggestionClasses(): Record<SuggestionClassKey, ClassSuggestions> {
|
|
712
|
+
const out = {} as Record<SuggestionClassKey, ClassSuggestions>;
|
|
713
|
+
for (const key of SUGGESTION_CLASS_KEYS) {
|
|
714
|
+
out[key] = getClassSuggestions(key);
|
|
715
|
+
}
|
|
716
|
+
return out;
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
// ---- Band pick (Wave 0C) --------------------------------------------------
|
|
720
|
+
|
|
721
|
+
// Pick the best non-stub band for this level and primary spec: a covering band for the tree, then a
|
|
722
|
+
// rebranded stub donor, then the nearest same-tree band, then the class default, then any.
|
|
723
|
+
export function selectBand(
|
|
724
|
+
pack: ClassSuggestions,
|
|
725
|
+
level: number,
|
|
726
|
+
spec: string,
|
|
727
|
+
opts?: { mode?: BandMode; variant?: string },
|
|
728
|
+
): SuggestionBand | null {
|
|
729
|
+
const pve = pack.bands.filter((b) => b.mode === undefined);
|
|
730
|
+
if (opts?.mode !== 'pvp') return pickBand(pack.classKey, pve, level, spec);
|
|
731
|
+
// A pvp band applies only to the tree AND the levels it was authored for: the PvE tail would hand
|
|
732
|
+
// a level-19 mage a level-60 list. Variant is an EQUALITY filter, never a preference — but a
|
|
733
|
+
// variant the asker names is a choice of LIST, not a choice of fight, so a level no variant band
|
|
734
|
+
// covers falls to the variant-less pvp pool before the PvE ladder. A promoted duelist names its
|
|
735
|
+
// variant on the seat (`ArenaCompSeat.rotation`, arenaComps.ts) and its variant is authored at 60,
|
|
736
|
+
// so without this the top three rungs of every tier fought a levelling list below 60 while the
|
|
737
|
+
// build they beat fought the pvp one. The reverse never happens: an asker naming no variant sees
|
|
738
|
+
// only the variant-less pool, which is G1's no-leak rule.
|
|
739
|
+
const want = String(opts.variant ?? '').trim() || undefined;
|
|
740
|
+
for (const v of want ? [want, undefined] : [undefined]) {
|
|
741
|
+
const pvp = pack.bands.filter((b) => b.mode === 'pvp' && (b.variant ?? undefined) === v);
|
|
742
|
+
const hit = pvp.length ? pickBand(pack.classKey, pvp, level, spec) : null;
|
|
743
|
+
if (hit && bandMatchesSpec(hit, spec) && level >= hit.levelLo && level <= hit.levelHi) return hit;
|
|
744
|
+
}
|
|
745
|
+
return pickBand(pack.classKey, pve, level, spec);
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
/** The band ladder, over one already-mode-filtered pool. */
|
|
749
|
+
function pickBand(
|
|
750
|
+
classKey: SuggestionClassKey,
|
|
751
|
+
bands: readonly SuggestionBand[],
|
|
752
|
+
level: number,
|
|
753
|
+
spec: string,
|
|
754
|
+
): SuggestionBand | null {
|
|
755
|
+
const covering = bands.filter((b) => level >= b.levelLo && level <= b.levelHi);
|
|
756
|
+
const nonStubCovering = covering.filter((b) => !b.stub);
|
|
757
|
+
|
|
758
|
+
const bySpecIn = (want: string, pool: readonly SuggestionBand[]): SuggestionBand | undefined =>
|
|
759
|
+
pool.find((b) => bandMatchesSpec(b, want));
|
|
760
|
+
|
|
761
|
+
// 1. Exact tree at this level (incl. dual-spec membership).
|
|
762
|
+
const exact = bySpecIn(spec, nonStubCovering);
|
|
763
|
+
if (exact) return exact;
|
|
764
|
+
|
|
765
|
+
// 2. Stub "identical to X" at this level → donor content, requested identity.
|
|
766
|
+
const stub = covering.find((b) => b.stub && bandMatchesSpec(b, spec));
|
|
767
|
+
if (stub) {
|
|
768
|
+
const targetRaw = parseIdenticalToNote(stub.note);
|
|
769
|
+
if (targetRaw) {
|
|
770
|
+
const target = normalizeSpecKey(classKey, targetRaw);
|
|
771
|
+
// Prefer covering donor; else nearest same-tree (not recursive rebrand of another stub).
|
|
772
|
+
let donor = bySpecIn(target, nonStubCovering);
|
|
773
|
+
if (!donor) {
|
|
774
|
+
const sameTree = bands.filter((b) => !b.stub && bandMatchesSpec(b, target));
|
|
775
|
+
if (sameTree.length) {
|
|
776
|
+
donor = sameTree.reduce((best, b) =>
|
|
777
|
+
levelBandDistance(level, b) < levelBandDistance(level, best) ? b : best,
|
|
778
|
+
);
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
if (donor) return rebrandBand(donor, spec, stub);
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
// 3. Nearest non-stub of the **requested** tree (any level) before wrong-tree default.
|
|
786
|
+
const sameSpecAll = bands.filter((b) => !b.stub && bandMatchesSpec(b, spec));
|
|
787
|
+
if (sameSpecAll.length) {
|
|
788
|
+
return sameSpecAll.reduce((best, b) =>
|
|
789
|
+
levelBandDistance(level, b) < levelBandDistance(level, best) ? b : best,
|
|
790
|
+
);
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
// 3b. Only stubs exist for this tree (e.g. Demonology everywhere) but no covering
|
|
794
|
+
// row at this exact level — still try any stub + identical-to resolve.
|
|
795
|
+
const anyStub = bands.find((b) => b.stub && bandMatchesSpec(b, spec));
|
|
796
|
+
if (anyStub) {
|
|
797
|
+
const targetRaw = parseIdenticalToNote(anyStub.note);
|
|
798
|
+
if (targetRaw) {
|
|
799
|
+
const target = normalizeSpecKey(classKey, targetRaw);
|
|
800
|
+
const donor =
|
|
801
|
+
bySpecIn(target, nonStubCovering) ??
|
|
802
|
+
(() => {
|
|
803
|
+
const sameTree = bands.filter((b) => !b.stub && bandMatchesSpec(b, target));
|
|
804
|
+
if (!sameTree.length) return undefined;
|
|
805
|
+
return sameTree.reduce((best, b) =>
|
|
806
|
+
levelBandDistance(level, b) < levelBandDistance(level, best) ? b : best,
|
|
807
|
+
);
|
|
808
|
+
})();
|
|
809
|
+
if (donor) return rebrandBand(donor, spec, anyStub);
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
if (!nonStubCovering.length) return null;
|
|
814
|
+
|
|
815
|
+
// 4–5. Class default, then any covering non-stub.
|
|
816
|
+
return (
|
|
817
|
+
bySpecIn(CLASS_DEFAULT_SPEC[classKey], nonStubCovering) ??
|
|
818
|
+
nonStubCovering[0] ??
|
|
819
|
+
null
|
|
820
|
+
);
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
// Resolve a free-text, case-variant or authored spec label to a real talent tree name for this
|
|
824
|
+
// class, or null when none match. Accepts exact names, any case, and the pack aliases.
|
|
825
|
+
export function resolveTalentTreeName(
|
|
826
|
+
classId: number,
|
|
827
|
+
trees: readonly { name: string }[],
|
|
828
|
+
raw: string | null | undefined,
|
|
829
|
+
): string | null {
|
|
830
|
+
if (raw == null) return null;
|
|
831
|
+
const s = String(raw).trim();
|
|
832
|
+
if (!s) return null;
|
|
833
|
+
|
|
834
|
+
const exact = trees.find((t) => t.name === s);
|
|
835
|
+
if (exact) return exact.name;
|
|
836
|
+
|
|
837
|
+
const lower = s.toLowerCase();
|
|
838
|
+
const ci = trees.find((t) => t.name.toLowerCase() === lower);
|
|
839
|
+
if (ci) return ci.name;
|
|
840
|
+
|
|
841
|
+
const classKey = suggestionClassKeyFromClassId(classId);
|
|
842
|
+
if (!classKey) return null;
|
|
843
|
+
|
|
844
|
+
const canon = normalizeSpecKey(classKey, s);
|
|
845
|
+
const byCanon = trees.find((t) => {
|
|
846
|
+
if (t.name === canon) return true;
|
|
847
|
+
if (t.name.toLowerCase() === canon.toLowerCase()) return true;
|
|
848
|
+
return normalizeSpecKey(classKey, t.name) === canon;
|
|
849
|
+
});
|
|
850
|
+
return byCanon?.name ?? null;
|
|
851
|
+
}
|