azeroth-shell 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +138 -2
- package/bin/azsh.mjs +19 -0
- package/docs/aifid/eventai-texts.json +4414 -0
- package/docs/dungeons/atlas/atlas-rows-dungeons.json +8989 -0
- package/docs/dungeons/survey/pack-id-migration.json +2418 -0
- package/package.json +26 -4
- package/src/autopilot/bossSkip.ts +26 -0
- package/src/autopilot/combatRotation.ts +824 -0
- package/src/autopilot/config.ts +533 -0
- package/src/autopilot/consumables.ts +58 -0
- package/src/autopilot/encounterStand.ts +121 -0
- package/src/autopilot/objectGatePlan.ts +53 -0
- package/src/autopilot/pathEngage.ts +229 -0
- package/src/autopilot/plan.ts +1643 -0
- package/src/autopilot/questPolicy.ts +274 -0
- package/src/autopilot/routeStep.ts +69 -0
- package/src/autopilot/sessionReport.ts +88 -0
- package/src/autopilot/topOffPower.ts +26 -0
- package/src/autopilot/view.ts +476 -0
- package/src/cli/bootCheck.mjs +34 -0
- package/src/cli/bootData.mjs +57 -0
- package/src/cli/combatLogFilter.ts +153 -0
- package/src/cli/combatLogFormat.ts +613 -0
- package/src/cli/fileRepository.mjs +105 -0
- package/src/cli/gzLoader.mjs +31 -0
- package/src/cli/liveGauntletEscort.ts +978 -0
- package/src/cli/liveStratUndead.ts +305 -0
- package/src/cli/macroHostCombat.ts +545 -0
- package/src/cli/macroHostWorld.ts +330 -0
- package/src/cli/prefs.mjs +31 -0
- package/src/cli/register.mjs +4 -0
- package/src/cli/repl.mjs +693 -0
- package/src/cli/rotationText.mjs +226 -0
- package/src/cli/squad.mjs +105 -0
- package/src/cli/term.mjs +126 -0
- package/src/cli/text.mjs +122 -0
- package/src/cli/tui.mjs +626 -0
- package/src/cli/tuiArena.mjs +109 -0
- package/src/cli/tuiAutopilotSettings.mjs +93 -0
- package/src/cli/tuiBags.mjs +180 -0
- package/src/cli/tuiBars.mjs +133 -0
- package/src/cli/tuiBg.mjs +243 -0
- package/src/cli/tuiBulk.mjs +162 -0
- package/src/cli/tuiCheck.mjs +1882 -0
- package/src/cli/tuiCity.mjs +396 -0
- package/src/cli/tuiCompanionKit.mjs +300 -0
- package/src/cli/tuiCompanions.mjs +471 -0
- package/src/cli/tuiDev.mjs +62 -0
- package/src/cli/tuiDungeon.mjs +606 -0
- package/src/cli/tuiEnchantTarget.mjs +120 -0
- package/src/cli/tuiFight.mjs +577 -0
- package/src/cli/tuiFightPanes.mjs +228 -0
- package/src/cli/tuiFloor.mjs +506 -0
- package/src/cli/tuiGear.mjs +158 -0
- package/src/cli/tuiHonor.mjs +74 -0
- package/src/cli/tuiLoot.mjs +97 -0
- package/src/cli/tuiMacros.mjs +144 -0
- package/src/cli/tuiOutfitter.mjs +115 -0
- package/src/cli/tuiPet.mjs +116 -0
- package/src/cli/tuiProfessions.mjs +800 -0
- package/src/cli/tuiRaid.mjs +127 -0
- package/src/cli/tuiRep.mjs +65 -0
- package/src/cli/tuiSaves.mjs +69 -0
- package/src/cli/tuiSearch.mjs +363 -0
- package/src/cli/tuiSettings.mjs +151 -0
- package/src/cli/tuiSimLab.mjs +80 -0
- package/src/cli/tuiTalents.mjs +60 -0
- package/src/cli/tuiViews.mjs +1178 -0
- package/src/cli/tuiWiki.mjs +181 -0
- package/src/cli/tuiWorld.mjs +361 -0
- package/src/cli/wikiIndex.ts +259 -0
- package/src/cli/wikiSources.ts +355 -0
- package/src/data/alteracValley.ts +176 -0
- package/src/data/appearanceOptions.ts +534 -0
- package/src/data/applyLootChanceSanity.ts +21 -0
- package/src/data/createFlavor.ts +96 -0
- package/src/data/customItems.ts +33 -0
- package/src/data/dataStore.ts +1904 -0
- package/src/data/dungeonGameObjects.ts +84 -0
- package/src/data/dungeonPlateCover.ts +66 -0
- package/src/data/dungeonSpawns.ts +294 -0
- package/src/data/dungeons/alterac-valley.ts +135 -0
- package/src/data/dungeons/apply-dungeon-rooms.ts +29 -0
- package/src/data/dungeons/apply-encounter-outdoors.ts +72 -0
- package/src/data/dungeons/apply-instance-geometry.ts +65 -0
- package/src/data/dungeons/apply-spawn-placement.ts +171 -0
- package/src/data/dungeons/blackfathom-deeps.ts +539 -0
- package/src/data/dungeons/blackrock-depths.ts +1410 -0
- package/src/data/dungeons/blackwing-lair.ts +129 -0
- package/src/data/dungeons/boss-eventai.ts +8 -0
- package/src/data/dungeons/deadmines.ts +410 -0
- package/src/data/dungeons/dire-maul-east.ts +980 -0
- package/src/data/dungeons/dire-maul-north.ts +661 -0
- package/src/data/dungeons/dire-maul-west.ts +785 -0
- package/src/data/dungeons/dungeon-rooms.json +5479 -0
- package/src/data/dungeons/encounter-outdoors.json +359 -0
- package/src/data/dungeons/eventai/blackfathom-deeps.ts +308 -0
- package/src/data/dungeons/eventai/blackrock-depths.ts +1257 -0
- package/src/data/dungeons/eventai/deadmines.ts +264 -0
- package/src/data/dungeons/eventai/dire-maul-east.ts +320 -0
- package/src/data/dungeons/eventai/gnomeregan.ts +213 -0
- package/src/data/dungeons/eventai/helpers.ts +79 -0
- package/src/data/dungeons/eventai/index.ts +133 -0
- package/src/data/dungeons/eventai/lbrs.ts +372 -0
- package/src/data/dungeons/eventai/maraudon.ts +323 -0
- package/src/data/dungeons/eventai/ragefire-chasm.ts +108 -0
- package/src/data/dungeons/eventai/razorfen-downs.ts +207 -0
- package/src/data/dungeons/eventai/razorfen-kraul.ts +326 -0
- package/src/data/dungeons/eventai/scholomance.ts +680 -0
- package/src/data/dungeons/eventai/shadowfang-keep.ts +230 -0
- package/src/data/dungeons/eventai/sm-cathedral.ts +75 -0
- package/src/data/dungeons/eventai/sm-graveyard.ts +150 -0
- package/src/data/dungeons/eventai/sm-library.ts +55 -0
- package/src/data/dungeons/eventai/stratholme-undead.ts +127 -0
- package/src/data/dungeons/eventai/sunken-temple.ts +582 -0
- package/src/data/dungeons/eventai/the-stockade.ts +228 -0
- package/src/data/dungeons/eventai/ubrs.ts +225 -0
- package/src/data/dungeons/eventai/uldaman.ts +355 -0
- package/src/data/dungeons/eventai/wailing-caverns.ts +396 -0
- package/src/data/dungeons/eventai/zul-farrak.ts +591 -0
- package/src/data/dungeons/gnomeregan.ts +909 -0
- package/src/data/dungeons/index.ts +126 -0
- package/src/data/dungeons/instance-geometry.json +5233 -0
- package/src/data/dungeons/key-sources.json +169 -0
- package/src/data/dungeons/lbrs.ts +996 -0
- package/src/data/dungeons/maraudon.ts +786 -0
- package/src/data/dungeons/molten-core.ts +194 -0
- package/src/data/dungeons/naxxramas.ts +173 -0
- package/src/data/dungeons/onyxias-lair.ts +71 -0
- package/src/data/dungeons/pack-from-clusters.ts +1256 -0
- package/src/data/dungeons/ragefire-chasm.ts +238 -0
- package/src/data/dungeons/razorfen-downs.ts +698 -0
- package/src/data/dungeons/razorfen-kraul.ts +766 -0
- package/src/data/dungeons/ruins-of-ahnqiraj.ts +121 -0
- package/src/data/dungeons/scholomance.ts +1076 -0
- package/src/data/dungeons/shadowfang-keep.ts +740 -0
- package/src/data/dungeons/sm-armory.ts +266 -0
- package/src/data/dungeons/sm-cathedral.ts +430 -0
- package/src/data/dungeons/sm-graveyard.ts +482 -0
- package/src/data/dungeons/sm-library.ts +337 -0
- package/src/data/dungeons/stratholme-live.ts +808 -0
- package/src/data/dungeons/stratholme-undead.ts +1164 -0
- package/src/data/dungeons/sunken-temple.ts +931 -0
- package/src/data/dungeons/temple-of-ahnqiraj.ts +119 -0
- package/src/data/dungeons/the-stockade.ts +282 -0
- package/src/data/dungeons/ubrs.ts +1286 -0
- package/src/data/dungeons/uldaman.ts +685 -0
- package/src/data/dungeons/wailing-caverns.ts +356 -0
- package/src/data/dungeons/zul-farrak.ts +686 -0
- package/src/data/dungeons/zul-gurub.ts +142 -0
- package/src/data/dungeons.ts +42 -0
- package/src/data/fixtures.ts +446 -0
- package/src/data/gameobject-data.json.gz +0 -0
- package/src/data/item-data.json.gz +0 -0
- package/src/data/loot-data.json.gz +0 -0
- package/src/data/maps/atlas-approach-maps.json +1425 -0
- package/src/data/maps/atlas-landmarks.json +1711 -0
- package/src/data/maps/dungeon-viewports.json +392 -0
- package/src/data/materializeModDamagePercentTaken.ts +70 -0
- package/src/data/materializeModHealthRegen.ts +89 -0
- package/src/data/materializeSpellReputation.ts +26 -0
- package/src/data/pageTexts.ts +19 -0
- package/src/data/profession-data.json.gz +0 -0
- package/src/data/raid-plans/blackfathom-deeps.json +86 -0
- package/src/data/raid-plans/blackrock-depths.json +419 -0
- package/src/data/raid-plans/blackwing-lair.json +328 -0
- package/src/data/raid-plans/deadmines.json +55 -0
- package/src/data/raid-plans/dire-maul-east.json +94 -0
- package/src/data/raid-plans/dire-maul-north.json +70 -0
- package/src/data/raid-plans/dire-maul-west.json +75 -0
- package/src/data/raid-plans/gnomeregan.json +131 -0
- package/src/data/raid-plans/lbrs.json +176 -0
- package/src/data/raid-plans/maraudon.json +102 -0
- package/src/data/raid-plans/molten-core.json +169 -0
- package/src/data/raid-plans/naxxramas.json +354 -0
- package/src/data/raid-plans/onyxias-lair.json +18 -0
- package/src/data/raid-plans/ragefire-chasm.json +30 -0
- package/src/data/raid-plans/razorfen-downs.json +75 -0
- package/src/data/raid-plans/razorfen-kraul.json +53 -0
- package/src/data/raid-plans/ruins-of-ahnqiraj.json +110 -0
- package/src/data/raid-plans/scholomance.json +170 -0
- package/src/data/raid-plans/shadowfang-keep.json +87 -0
- package/src/data/raid-plans/sm-armory.json +53 -0
- package/src/data/raid-plans/sm-cathedral.json +72 -0
- package/src/data/raid-plans/sm-graveyard.json +63 -0
- package/src/data/raid-plans/sm-library.json +23 -0
- package/src/data/raid-plans/stratholme-live.json +129 -0
- package/src/data/raid-plans/stratholme-undead.json +73 -0
- package/src/data/raid-plans/sunken-temple.json +159 -0
- package/src/data/raid-plans/temple-of-ahnqiraj.json +163 -0
- package/src/data/raid-plans/the-stockade.json +42 -0
- package/src/data/raid-plans/ubrs.json +53 -0
- package/src/data/raid-plans/uldaman.json +131 -0
- package/src/data/raid-plans/wailing-caverns.json +90 -0
- package/src/data/raid-plans/zul-farrak.json +156 -0
- package/src/data/raid-plans/zul-gurub.json +307 -0
- package/src/data/raidInstanceCreatures.mjs +473 -0
- package/src/data/rotations/index.ts +152 -0
- package/src/data/rotations/layout.mjs +72 -0
- package/src/data/rotations/pve/druid/balance.json +754 -0
- package/src/data/rotations/pve/druid/feral-tank.json +2448 -0
- package/src/data/rotations/pve/druid/feral.json +2660 -0
- package/src/data/rotations/pve/druid/restoration.json +424 -0
- package/src/data/rotations/pve/hunter/beast-mastery.json +1288 -0
- package/src/data/rotations/pve/hunter/marksmanship.json +1260 -0
- package/src/data/rotations/pve/hunter/survival.json +1373 -0
- package/src/data/rotations/pve/mage/arcane-leveling.json +1798 -0
- package/src/data/rotations/pve/mage/fire-leveling.json +2003 -0
- package/src/data/rotations/pve/mage/frost-leveling.json +1912 -0
- package/src/data/rotations/pve/paladin/holy.json +755 -0
- package/src/data/rotations/pve/paladin/protection.json +962 -0
- package/src/data/rotations/pve/paladin/retribution.json +924 -0
- package/src/data/rotations/pve/priest/discipline.json +772 -0
- package/src/data/rotations/pve/priest/holy.json +707 -0
- package/src/data/rotations/pve/priest/shadow.json +787 -0
- package/src/data/rotations/pve/rogue/assassination.json +2477 -0
- package/src/data/rotations/pve/rogue/combat.json +2483 -0
- package/src/data/rotations/pve/rogue/subtlety.json +2523 -0
- package/src/data/rotations/pve/shaman/elemental.json +1157 -0
- package/src/data/rotations/pve/shaman/enhancement.json +1085 -0
- package/src/data/rotations/pve/shaman/restoration.json +592 -0
- package/src/data/rotations/pve/warlock/affliction.json +1185 -0
- package/src/data/rotations/pve/warlock/demonology.json +1165 -0
- package/src/data/rotations/pve/warlock/destruction.json +1177 -0
- package/src/data/rotations/pve/warrior/arms.json +3020 -0
- package/src/data/rotations/pve/warrior/fury.json +2996 -0
- package/src/data/rotations/pve/warrior/protection.json +2509 -0
- package/src/data/rotations/pvp/druid/balance.json +593 -0
- package/src/data/rotations/pvp/druid/feral.json +3276 -0
- package/src/data/rotations/pvp/druid/restoration.json +662 -0
- package/src/data/rotations/pvp/hunter/beast-mastery.json +665 -0
- package/src/data/rotations/pvp/hunter/marksmanship.json +2406 -0
- package/src/data/rotations/pvp/hunter/survival.json +635 -0
- package/src/data/rotations/pvp/mage/arcane.json +574 -0
- package/src/data/rotations/pvp/mage/fire.json +570 -0
- package/src/data/rotations/pvp/mage/frost.json +4048 -0
- package/src/data/rotations/pvp/paladin/holy.json +1498 -0
- package/src/data/rotations/pvp/paladin/protection.json +567 -0
- package/src/data/rotations/pvp/paladin/retribution.json +1110 -0
- package/src/data/rotations/pvp/priest/discipline.json +1848 -0
- package/src/data/rotations/pvp/priest/holy.json +6340 -0
- package/src/data/rotations/pvp/priest/shadow.json +2329 -0
- package/src/data/rotations/pvp/rogue/assassination.json +1322 -0
- package/src/data/rotations/pvp/rogue/combat.json +5258 -0
- package/src/data/rotations/pvp/rogue/subtlety.json +586 -0
- package/src/data/rotations/pvp/shaman/elemental.json +1404 -0
- package/src/data/rotations/pvp/shaman/enhancement.json +1277 -0
- package/src/data/rotations/pvp/shaman/restoration.json +2490 -0
- package/src/data/rotations/pvp/warlock/affliction.json +1017 -0
- package/src/data/rotations/pvp/warlock/demonology.json +1503 -0
- package/src/data/rotations/pvp/warlock/destruction.json +638 -0
- package/src/data/rotations/pvp/warrior/arms.json +5665 -0
- package/src/data/rotations/pvp/warrior/fury.json +850 -0
- package/src/data/rotations/pvp/warrior/protection.json +777 -0
- package/src/data/schema/bundle.ts +511 -0
- package/src/data/schema/constants.ts +49 -0
- package/src/data/schema/creature.ts +454 -0
- package/src/data/schema/encounter.ts +155 -0
- package/src/data/schema/faction.ts +48 -0
- package/src/data/schema/item.ts +297 -0
- package/src/data/schema/itemEnchant.ts +105 -0
- package/src/data/schema/npc.ts +44 -0
- package/src/data/schema/primitives.ts +295 -0
- package/src/data/schema/profession.ts +226 -0
- package/src/data/schema/quest.ts +154 -0
- package/src/data/schema/spell.ts +1149 -0
- package/src/data/schema/talent.ts +74 -0
- package/src/data/schema/world.ts +124 -0
- package/src/data/schema.ts +19 -0
- package/src/data/skinNodeGapFill.ts +68 -0
- package/src/data/spell-data.json.gz +0 -0
- package/src/data/spell-script-targets.json +1 -0
- package/src/data/tables/ahItemValues.json.gz +0 -0
- package/src/data/tables/alteracValley.json.gz +0 -0
- package/src/data/tables/areatriggerTeleports.json.gz +0 -0
- package/src/data/tables/botNames.json.gz +0 -0
- package/src/data/tables/botPopulation.json.gz +0 -0
- package/src/data/tables/botSpecs.json.gz +0 -0
- package/src/data/tables/classLevelStats.json.gz +0 -0
- package/src/data/tables/combatConditions.json.gz +0 -0
- package/src/data/tables/combatSkillMeta.json.gz +0 -0
- package/src/data/tables/conditions.json.gz +0 -0
- package/src/data/tables/createInfo.json.gz +0 -0
- package/src/data/tables/creatureAggroGroups.json.gz +0 -0
- package/src/data/tables/creatureClassLevelStats.json.gz +0 -0
- package/src/data/tables/creaturePatrolPacks.json.gz +0 -0
- package/src/data/tables/creatureWeapons.json.gz +0 -0
- package/src/data/tables/creatures.json.gz +0 -0
- package/src/data/tables/dbScripts.json.gz +0 -0
- package/src/data/tables/dungeonAuthoredRoutes.json.gz +0 -0
- package/src/data/tables/dungeonCensus.json.gz +0 -0
- package/src/data/tables/dungeonGameObjects.json.gz +0 -0
- package/src/data/tables/dungeonPacks.json.gz +0 -0
- package/src/data/tables/dungeonPlateCover.json.gz +0 -0
- package/src/data/tables/dungeonSpawns.json.gz +0 -0
- package/src/data/tables/dungeonSurvey.json.gz +0 -0
- package/src/data/tables/durabilityCosts.json.gz +0 -0
- package/src/data/tables/durabilityQuality.json.gz +0 -0
- package/src/data/tables/enchantApplicators.json.gz +0 -0
- package/src/data/tables/entranceYards.json.gz +0 -0
- package/src/data/tables/explorationBasexp.json.gz +0 -0
- package/src/data/tables/factionTemplates.json.gz +0 -0
- package/src/data/tables/factions.json.gz +0 -0
- package/src/data/tables/gameEvents.json.gz +0 -0
- package/src/data/tables/gameObjects.json.gz +0 -0
- package/src/data/tables/gossipMenus.json.gz +0 -0
- package/src/data/tables/graveyards.json.gz +0 -0
- package/src/data/tables/instanceMaps.json.gz +0 -0
- package/src/data/tables/itemEnchantmentTemplates.json.gz +0 -0
- package/src/data/tables/itemEnchants.json.gz +0 -0
- package/src/data/tables/itemRandomProperties.json.gz +0 -0
- package/src/data/tables/itemSets.json.gz +0 -0
- package/src/data/tables/items.json.gz +0 -0
- package/src/data/tables/levelStats.json.gz +0 -0
- package/src/data/tables/locks.json.gz +0 -0
- package/src/data/tables/map-pin-overrides.json.gz +0 -0
- package/src/data/tables/nonCombatTrash.json.gz +0 -0
- package/src/data/tables/npcTexts.json.gz +0 -0
- package/src/data/tables/pageTexts.json.gz +0 -0
- package/src/data/tables/petAbilityTP.json.gz +0 -0
- package/src/data/tables/petGenericSpells.json.gz +0 -0
- package/src/data/tables/petLevelStats.json.gz +0 -0
- package/src/data/tables/playerbot-weightscales.json.gz +0 -0
- package/src/data/tables/pools.json.gz +0 -0
- package/src/data/tables/quests.json.gz +0 -0
- package/src/data/tables/races.json.gz +0 -0
- package/src/data/tables/reputationRanks.json.gz +0 -0
- package/src/data/tables/reputationRates.json.gz +0 -0
- package/src/data/tables/reputationSpillover.json.gz +0 -0
- package/src/data/tables/ridingSpells.json.gz +0 -0
- package/src/data/tables/scriptTexts.json.gz +0 -0
- package/src/data/tables/soundClipVolume.json.gz +0 -0
- package/src/data/tables/spellChain.json.gz +0 -0
- package/src/data/tables/spellTeleports.json.gz +0 -0
- package/src/data/tables/spells.json.gz +0 -0
- package/src/data/tables/talents.json.gz +0 -0
- package/src/data/tables/tavernTriggers.json.gz +0 -0
- package/src/data/tables/taxiNodes.json.gz +0 -0
- package/src/data/tables/taxiRoutes.json.gz +0 -0
- package/src/data/tables/trainers.json.gz +0 -0
- package/src/data/tables/transports.json.gz +0 -0
- package/src/data/tables/travelAnchors.json.gz +0 -0
- package/src/data/tables/travelEdges.json.gz +0 -0
- package/src/data/tables/unitConditions.json.gz +0 -0
- package/src/data/tables/vendors.json.gz +0 -0
- package/src/data/tables/weaponEnchantProcs.json.gz +0 -0
- package/src/data/tables/xp.json.gz +0 -0
- package/src/data/tables/zoneWeather.json.gz +0 -0
- package/src/data/tables/zones.json.gz +0 -0
- package/src/data/world-data.ts +56 -0
- package/src/data/zone-music-sets.json +2751 -0
- package/src/dev/etl/lib/loot-chance-sanity.mjs +180 -0
- package/src/domain/audioQuality.mjs +145 -0
- package/src/domain/bg/ab.ts +433 -0
- package/src/domain/bg/arenaComps.ts +644 -0
- package/src/domain/bg/arenaLab.ts +695 -0
- package/src/domain/bg/arenaPace.ts +31 -0
- package/src/domain/bg/arenaRating.ts +110 -0
- package/src/domain/bg/av.ts +758 -0
- package/src/domain/bg/avEnemyPush.ts +219 -0
- package/src/domain/bg/avField.ts +283 -0
- package/src/domain/bg/avInstanceNodes.ts +197 -0
- package/src/domain/bg/avInstanceScore.ts +123 -0
- package/src/domain/bg/avQuestItems.ts +55 -0
- package/src/domain/bg/avQuests.ts +210 -0
- package/src/domain/bg/avSession.ts +196 -0
- package/src/domain/bg/bgConsumes.ts +269 -0
- package/src/domain/bg/bgPrebuff.ts +153 -0
- package/src/domain/bg/bgRest.ts +91 -0
- package/src/domain/bg/bgRoster.ts +305 -0
- package/src/domain/bg/bgTier.ts +61 -0
- package/src/domain/bg/bgWorld.ts +862 -0
- package/src/domain/bg/match.ts +215 -0
- package/src/domain/bg/strategies.ts +552 -0
- package/src/domain/bg/types.ts +291 -0
- package/src/domain/bg/wsg.ts +264 -0
- package/src/domain/bots/actionProviderSpec.ts +38 -0
- package/src/domain/bots/autoConsumables.ts +285 -0
- package/src/domain/bots/betweenPullRest.ts +239 -0
- package/src/domain/bots/botGear.ts +248 -0
- package/src/domain/bots/botInventory.ts +486 -0
- package/src/domain/bots/botPet.ts +535 -0
- package/src/domain/bots/botPool.ts +291 -0
- package/src/domain/bots/botProfessions.ts +334 -0
- package/src/domain/bots/companionActionBar.ts +209 -0
- package/src/domain/bots/companionHireCost.ts +236 -0
- package/src/domain/bots/companionMissions.ts +582 -0
- package/src/domain/bots/companionPrep.ts +254 -0
- package/src/domain/bots/companionQuests.ts +270 -0
- package/src/domain/bots/companionRep.ts +75 -0
- package/src/domain/bots/companionRotation.ts +708 -0
- package/src/domain/bots/companionXp.ts +66 -0
- package/src/domain/bots/consumableShare.ts +811 -0
- package/src/domain/bots/dpsMate.ts +1072 -0
- package/src/domain/bots/groupCompReport.ts +132 -0
- package/src/domain/bots/healthstoneSupply.ts +198 -0
- package/src/domain/bots/outfitter.ts +1056 -0
- package/src/domain/bots/paladinPrePull.ts +231 -0
- package/src/domain/bots/partyRole.ts +40 -0
- package/src/domain/bots/playerbotEquipCache.ts +412 -0
- package/src/domain/bots/playerbotItemEligibility.ts +60 -0
- package/src/domain/bots/playerbotStatWeight.ts +853 -0
- package/src/domain/bots/playerbotUnavailableItems.ts +147 -0
- package/src/domain/bots/prePullBuffs.ts +219 -0
- package/src/domain/bots/prePullStealth.ts +82 -0
- package/src/domain/bots/runSupply.ts +251 -0
- package/src/domain/bots/runSupplyPrefs.ts +28 -0
- package/src/domain/bots/sendTradeGoods.ts +394 -0
- package/src/domain/bots/soulShardCap.ts +35 -0
- package/src/domain/bots/squad.ts +842 -0
- package/src/domain/bots/squadRun.ts +81 -0
- package/src/domain/character/actionbar.ts +346 -0
- package/src/domain/character/appearance.ts +165 -0
- package/src/domain/character/buildCombatant.ts +1726 -0
- package/src/domain/character/character.ts +356 -0
- package/src/domain/character/characterName.ts +43 -0
- package/src/domain/character/characterRatings.ts +424 -0
- package/src/domain/character/characterSpells.ts +282 -0
- package/src/domain/character/characterStats.ts +1559 -0
- package/src/domain/character/characterTalents.ts +398 -0
- package/src/domain/character/combatSkills.ts +994 -0
- package/src/domain/character/displayForm.ts +72 -0
- package/src/domain/character/formTalentAuras.ts +171 -0
- package/src/domain/character/forms.ts +499 -0
- package/src/domain/character/races.ts +40 -0
- package/src/domain/character/resurrectionSickness.ts +49 -0
- package/src/domain/character/spellbook.ts +169 -0
- package/src/domain/character/stanceBar.ts +354 -0
- package/src/domain/character/stancePrereq.ts +70 -0
- package/src/domain/character/talentBuilds.ts +63 -0
- package/src/domain/character/talentImport.ts +130 -0
- package/src/domain/character/talentLink.ts +123 -0
- package/src/domain/character/talents.ts +201 -0
- package/src/domain/core/conditionSnapshot.ts +92 -0
- package/src/domain/core/hover.ts +14 -0
- package/src/domain/core/ids.ts +58 -0
- package/src/domain/core/internalNameTags.ts +5 -0
- package/src/domain/core/runtimeDataPatches.ts +357 -0
- package/src/domain/creature/aiTargeting.ts +588 -0
- package/src/domain/creature/combatCondition.ts +157 -0
- package/src/domain/creature/creatureAggro.ts +804 -0
- package/src/domain/creature/creatureAi.ts +206 -0
- package/src/domain/creature/creatureAiConstants.ts +661 -0
- package/src/domain/creature/creatureCastList.ts +1007 -0
- package/src/domain/creature/creatureEventAi.ts +1409 -0
- package/src/domain/creature/creatureGroups.ts +144 -0
- package/src/domain/creature/creatureLinking.ts +333 -0
- package/src/domain/creature/creatureScaling.ts +320 -0
- package/src/domain/creature/creatureTrigger.ts +53 -0
- package/src/domain/creature/creatureWander.ts +74 -0
- package/src/domain/creature/eventAiTexts.ts +145 -0
- package/src/domain/creature/faction.ts +287 -0
- package/src/domain/creature/forcedReaction.ts +48 -0
- package/src/domain/creature/outdoorHuntable.ts +74 -0
- package/src/domain/creature/patrolPacks.ts +210 -0
- package/src/domain/creature/reputation.ts +967 -0
- package/src/domain/creature/unitFlags.ts +74 -0
- package/src/domain/creature/worldBosses.ts +393 -0
- package/src/domain/dungeonMusic.mjs +48 -0
- package/src/domain/economy/auction.ts +282 -0
- package/src/domain/economy/auctionBot.ts +1060 -0
- package/src/domain/economy/honorPrice.ts +100 -0
- package/src/domain/economy/mail.ts +958 -0
- package/src/domain/economy/money.ts +42 -0
- package/src/domain/economy/syntheticClassTrainers.ts +62 -0
- package/src/domain/economy/trading.ts +296 -0
- package/src/domain/economy/vendorSellAll.ts +252 -0
- package/src/domain/economy/vendorStock.ts +146 -0
- package/src/domain/items/ammo.ts +817 -0
- package/src/domain/items/bank.ts +162 -0
- package/src/domain/items/consumableFamily.ts +205 -0
- package/src/domain/items/craftUpgrades.ts +83 -0
- package/src/domain/items/createItem.ts +93 -0
- package/src/domain/items/durability.ts +581 -0
- package/src/domain/items/equipment.ts +441 -0
- package/src/domain/items/equipmentHelper.ts +767 -0
- package/src/domain/items/inventory.ts +561 -0
- package/src/domain/items/itemBonding.ts +93 -0
- package/src/domain/items/itemContainer.ts +245 -0
- package/src/domain/items/itemDisplayName.ts +33 -0
- package/src/domain/items/itemInstance.ts +181 -0
- package/src/domain/items/itemRandomEnchantOutcomes.ts +315 -0
- package/src/domain/items/itemRandomProps.ts +77 -0
- package/src/domain/items/itemRestrictions.ts +329 -0
- package/src/domain/items/itemTeaches.ts +82 -0
- package/src/domain/items/itemUseCooldown.ts +52 -0
- package/src/domain/items/itemUseTarget.ts +90 -0
- package/src/domain/items/junkCategories.ts +174 -0
- package/src/domain/items/junkFilter.ts +368 -0
- package/src/domain/items/keyring.ts +131 -0
- package/src/domain/items/loot.ts +221 -0
- package/src/domain/items/mounts.ts +190 -0
- package/src/domain/items/onUsePayload.ts +102 -0
- package/src/domain/items/pendingLoot.ts +107 -0
- package/src/domain/items/relic.ts +105 -0
- package/src/domain/items/rocketBoots.ts +36 -0
- package/src/domain/items/sortContainer.ts +139 -0
- package/src/domain/items/spareContainers.ts +71 -0
- package/src/domain/items/spellReagentIndex.ts +131 -0
- package/src/domain/items/staleConsumables.ts +66 -0
- package/src/domain/items/weaponSpender.ts +110 -0
- package/src/domain/listDungeonIds.mjs +28 -0
- package/src/domain/macro/compose.ts +239 -0
- package/src/domain/macro/conditions.ts +260 -0
- package/src/domain/macro/creatureTypes.ts +40 -0
- package/src/domain/macro/describe.ts +169 -0
- package/src/domain/macro/icon.ts +60 -0
- package/src/domain/macro/index.ts +20 -0
- package/src/domain/macro/normalize.ts +112 -0
- package/src/domain/macro/parse.ts +316 -0
- package/src/domain/macro/plan.ts +288 -0
- package/src/domain/macro/rotation.ts +590 -0
- package/src/domain/macro/rotationEnv.ts +173 -0
- package/src/domain/macro/slots.ts +101 -0
- package/src/domain/macro/snapshot.ts +114 -0
- package/src/domain/macro/templates.ts +446 -0
- package/src/domain/macro/types.ts +70 -0
- package/src/domain/macro/units.ts +93 -0
- package/src/domain/macro/weaponTypes.ts +83 -0
- package/src/domain/nav/cityTeleports.ts +10 -0
- package/src/domain/nav/mounting.ts +113 -0
- package/src/domain/nav/nav.ts +43 -0
- package/src/domain/nav/navCollision.ts +606 -0
- package/src/domain/nav/navOutdoors.ts +91 -0
- package/src/domain/nav/navRegistry.ts +179 -0
- package/src/domain/nav/navRoomGraph.ts +302 -0
- package/src/domain/nav/navTypes.ts +43 -0
- package/src/domain/nav/navmesh.ts +1715 -0
- package/src/domain/nav/speed.ts +200 -0
- package/src/domain/nav/storey.ts +10 -0
- package/src/domain/nav/travel.ts +725 -0
- package/src/domain/nav/travelTypes.ts +75 -0
- package/src/domain/pet/pet.ts +1150 -0
- package/src/domain/pet/petActionBar.ts +180 -0
- package/src/domain/pet/petSpellbook.ts +39 -0
- package/src/domain/pet/petStable.ts +81 -0
- package/src/domain/professions/autoDisenchant.ts +236 -0
- package/src/domain/professions/characterEnchants.ts +176 -0
- package/src/domain/professions/craftCooldown.ts +52 -0
- package/src/domain/professions/enchantApply.ts +62 -0
- package/src/domain/professions/enchantTargets.ts +114 -0
- package/src/domain/professions/enchanting.ts +236 -0
- package/src/domain/professions/gatherFilter.ts +149 -0
- package/src/domain/professions/gearEnchant.ts +137 -0
- package/src/domain/professions/heldTools.ts +29 -0
- package/src/domain/professions/learnAllRecipes.ts +146 -0
- package/src/domain/professions/miningHarvest.ts +69 -0
- package/src/domain/professions/partyDisenchant.ts +294 -0
- package/src/domain/professions/partyWork.ts +83 -0
- package/src/domain/professions/pickpocket.ts +172 -0
- package/src/domain/professions/poisons.ts +240 -0
- package/src/domain/professions/professions.ts +677 -0
- package/src/domain/professions/rareNodes.ts +45 -0
- package/src/domain/professions/skinLoot.ts +27 -0
- package/src/domain/professions/vendorReagents.ts +152 -0
- package/src/domain/professions/weaponImbueHand.ts +171 -0
- package/src/domain/questFarmFilter.mjs +42 -0
- package/src/domain/quests/doQuest.ts +1204 -0
- package/src/domain/quests/gossip.ts +308 -0
- package/src/domain/quests/gossipTalk.ts +298 -0
- package/src/domain/quests/interpreter/canComplete.ts +150 -0
- package/src/domain/quests/interpreter/claim.ts +137 -0
- package/src/domain/quests/interpreter/dbscript/handlers.ts +1371 -0
- package/src/domain/quests/interpreter/dbscript/handlersBatch.ts +1251 -0
- package/src/domain/quests/interpreter/dbscript/hooks.ts +331 -0
- package/src/domain/quests/interpreter/dbscript/index.ts +212 -0
- package/src/domain/quests/interpreter/dbscript/opcodes.ts +257 -0
- package/src/domain/quests/interpreter/dbscript/registry.ts +1194 -0
- package/src/domain/quests/interpreter/dbscript/registryAreatriggerScripts.ts +539 -0
- package/src/domain/quests/interpreter/dbscript/registryAshenvale.ts +553 -0
- package/src/domain/quests/interpreter/dbscript/registryAzshara.ts +272 -0
- package/src/domain/quests/interpreter/dbscript/registryDarkshore.ts +637 -0
- package/src/domain/quests/interpreter/dbscript/registryDesolace.ts +501 -0
- package/src/domain/quests/interpreter/dbscript/registryDustwallowMarsh.ts +735 -0
- package/src/domain/quests/interpreter/dbscript/registryFelwood.ts +493 -0
- package/src/domain/quests/interpreter/dbscript/registryFeralas.ts +485 -0
- package/src/domain/quests/interpreter/dbscript/registryGoScripts.ts +203 -0
- package/src/domain/quests/interpreter/dbscript/registryMoonglade.ts +288 -0
- package/src/domain/quests/interpreter/dbscript/registryNpcProfessions.ts +230 -0
- package/src/domain/quests/interpreter/dbscript/registryNpcsSpecial.ts +545 -0
- package/src/domain/quests/interpreter/dbscript/registryRazorfenDowns.ts +293 -0
- package/src/domain/quests/interpreter/dbscript/registryRazorfenKraul.ts +221 -0
- package/src/domain/quests/interpreter/dbscript/registryRedridge.ts +112 -0
- package/src/domain/quests/interpreter/dbscript/registrySearingGorge.ts +125 -0
- package/src/domain/quests/interpreter/dbscript/registrySiblings.ts +51 -0
- package/src/domain/quests/interpreter/dbscript/registrySilverpineForest.ts +172 -0
- package/src/domain/quests/interpreter/dbscript/registryStonetalonMountains.ts +180 -0
- package/src/domain/quests/interpreter/dbscript/registryStormwindCity.ts +369 -0
- package/src/domain/quests/interpreter/dbscript/registryStranglethornVale.ts +115 -0
- package/src/domain/quests/interpreter/dbscript/registryStratholme.ts +146 -0
- package/src/domain/quests/interpreter/dbscript/registrySunkenTemple.ts +149 -0
- package/src/domain/quests/interpreter/dbscript/registrySwampOfSorrows.ts +163 -0
- package/src/domain/quests/interpreter/dbscript/registryTanaris.ts +318 -0
- package/src/domain/quests/interpreter/dbscript/registryTeldrassil.ts +120 -0
- package/src/domain/quests/interpreter/dbscript/registryTheBarrens.ts +603 -0
- package/src/domain/quests/interpreter/dbscript/registryThousandNeedles.ts +499 -0
- package/src/domain/quests/interpreter/dbscript/registryTirisfalGlades.ts +222 -0
- package/src/domain/quests/interpreter/dbscript/registryUngoroCrater.ts +291 -0
- package/src/domain/quests/interpreter/dbscript/registryWarEffort.ts +773 -0
- package/src/domain/quests/interpreter/dbscript/registryWesternPlaguelands.ts +206 -0
- package/src/domain/quests/interpreter/dbscript/registryWestfall.ts +190 -0
- package/src/domain/quests/interpreter/dbscript/registryWetlands.ts +186 -0
- package/src/domain/quests/interpreter/dbscript/registryWinterspring.ts +235 -0
- package/src/domain/quests/interpreter/dbscript/types.ts +817 -0
- package/src/domain/quests/interpreter/dbscript/vm.ts +171 -0
- package/src/domain/quests/interpreter/diff.ts +349 -0
- package/src/domain/quests/interpreter/fixtures/oracle-questlog-qi2.json +2417 -0
- package/src/domain/quests/interpreter/flags.ts +101 -0
- package/src/domain/quests/interpreter/index.ts +113 -0
- package/src/domain/quests/interpreter/live.ts +178 -0
- package/src/domain/quests/interpreter/types.ts +81 -0
- package/src/domain/quests/interpreter/updaters.ts +412 -0
- package/src/domain/quests/questCorpseUse.ts +155 -0
- package/src/domain/quests/questDialog.ts +43 -0
- package/src/domain/quests/questFight.ts +34 -0
- package/src/domain/quests/questObjectiveLabel.ts +39 -0
- package/src/domain/quests/questRewardChoice.ts +85 -0
- package/src/domain/quests/questScriptCredit.ts +26 -0
- package/src/domain/quests/questScriptItemUse.ts +74 -0
- package/src/domain/quests/questTameRods.ts +79 -0
- package/src/domain/quests/questlog.ts +1545 -0
- package/src/domain/quests/talkDeliver.ts +170 -0
- package/src/domain/raid/globalActionBar.ts +195 -0
- package/src/domain/raid/instanceRoster.ts +194 -0
- package/src/domain/raid/partySummon.ts +198 -0
- package/src/domain/raid/partyVault.ts +320 -0
- package/src/domain/raid/raidBossAbilities.ts +268 -0
- package/src/domain/raid/raidComp.ts +335 -0
- package/src/domain/raid/raidCustomRows.ts +453 -0
- package/src/domain/raid/raidEncounterGear.ts +298 -0
- package/src/domain/raid/raidEncounterTactics.ts +412 -0
- package/src/domain/raid/raidPlan.ts +509 -0
- package/src/domain/raid/raidPlanEdits.ts +98 -0
- package/src/domain/raid/raidPlanPacks.ts +480 -0
- package/src/domain/raid/raidRecovery.ts +183 -0
- package/src/domain/raid/raidRosterTemplate.ts +138 -0
- package/src/domain/rotation/auraSide.ts +68 -0
- package/src/domain/rotation/build.ts +3031 -0
- package/src/domain/rotation/classes/druid.ts +58 -0
- package/src/domain/rotation/classes/hooks.ts +59 -0
- package/src/domain/rotation/classes/hunter.ts +156 -0
- package/src/domain/rotation/classes/index.ts +104 -0
- package/src/domain/rotation/classes/mage.ts +99 -0
- package/src/domain/rotation/classes/paladin.ts +296 -0
- package/src/domain/rotation/classes/priest.ts +94 -0
- package/src/domain/rotation/classes/pullOpener.ts +92 -0
- package/src/domain/rotation/classes/rogue.ts +69 -0
- package/src/domain/rotation/classes/shaman.ts +29 -0
- package/src/domain/rotation/classes/supportSpec.ts +94 -0
- package/src/domain/rotation/classes/warlock.ts +81 -0
- package/src/domain/rotation/classes/warrior.ts +402 -0
- package/src/domain/rotation/classify.ts +1381 -0
- package/src/domain/rotation/condMetricPicker.ts +379 -0
- package/src/domain/rotation/consumables.ts +242 -0
- package/src/domain/rotation/evaluate.ts +1115 -0
- package/src/domain/rotation/finisherLadder.ts +145 -0
- package/src/domain/rotation/invent.ts +938 -0
- package/src/domain/rotation/killOrder.ts +30 -0
- package/src/domain/rotation/openerForm.ts +22 -0
- package/src/domain/rotation/paladinBuffs.ts +568 -0
- package/src/domain/rotation/prebuff.ts +283 -0
- package/src/domain/rotation/raidRowTuning.ts +34 -0
- package/src/domain/rotation/rotation.ts +11 -0
- package/src/domain/rotation/rotationProfiles.ts +180 -0
- package/src/domain/rotation/rotationSuggestions.ts +851 -0
- package/src/domain/rotation/ruleAfterChain.ts +49 -0
- package/src/domain/rotation/spec.ts +70 -0
- package/src/domain/rotation/spellPicker.ts +140 -0
- package/src/domain/rotation/stand.ts +143 -0
- package/src/domain/rotation/types.ts +718 -0
- package/src/domain/run/battlegroundRun.ts +111 -0
- package/src/domain/run/canEnterContext.ts +32 -0
- package/src/domain/run/death.ts +561 -0
- package/src/domain/run/deathRecovery.ts +289 -0
- package/src/domain/run/duel.ts +141 -0
- package/src/domain/run/dungeonRun.ts +344 -0
- package/src/domain/run/floorRest.ts +159 -0
- package/src/domain/run/honor.ts +557 -0
- package/src/domain/run/honorWeek.ts +180 -0
- package/src/domain/run/whenMap.ts +977 -0
- package/src/domain/scriptdev/arathiHighlands.ts +445 -0
- package/src/domain/scriptdev/ashenvale.ts +635 -0
- package/src/domain/scriptdev/ashenvaleHelpers.ts +1215 -0
- package/src/domain/scriptdev/azshara.ts +892 -0
- package/src/domain/scriptdev/blackfathomDeeps.ts +212 -0
- package/src/domain/scriptdev/blackrockDepths.ts +1434 -0
- package/src/domain/scriptdev/blackrockSpire.ts +730 -0
- package/src/domain/scriptdev/blackwingLair.ts +521 -0
- package/src/domain/scriptdev/burningSteppes.ts +62 -0
- package/src/domain/scriptdev/classFilter.ts +43 -0
- package/src/domain/scriptdev/darkshore.ts +817 -0
- package/src/domain/scriptdev/darkshoreHelpers.ts +853 -0
- package/src/domain/scriptdev/deadmines.ts +331 -0
- package/src/domain/scriptdev/desolace.ts +1239 -0
- package/src/domain/scriptdev/direMaul.ts +859 -0
- package/src/domain/scriptdev/durotar.ts +532 -0
- package/src/domain/scriptdev/dustwallowMarsh.ts +758 -0
- package/src/domain/scriptdev/dustwallowMarshHelpers.ts +994 -0
- package/src/domain/scriptdev/easternPlaguelands.ts +21 -0
- package/src/domain/scriptdev/felwood.ts +1055 -0
- package/src/domain/scriptdev/feralas.ts +571 -0
- package/src/domain/scriptdev/feralasHelpers.ts +838 -0
- package/src/domain/scriptdev/gnomeregan.ts +466 -0
- package/src/domain/scriptdev/guards.ts +616 -0
- package/src/domain/scriptdev/hinterlands.ts +693 -0
- package/src/domain/scriptdev/host.ts +1134 -0
- package/src/domain/scriptdev/index.ts +123 -0
- package/src/domain/scriptdev/instanceRaids.ts +136 -0
- package/src/domain/scriptdev/itemScripts.ts +37 -0
- package/src/domain/scriptdev/lochModan.ts +283 -0
- package/src/domain/scriptdev/maraudon.ts +232 -0
- package/src/domain/scriptdev/moltenCore.ts +831 -0
- package/src/domain/scriptdev/moonglade.ts +659 -0
- package/src/domain/scriptdev/moongladeHelpers.ts +933 -0
- package/src/domain/scriptdev/naxxramas.ts +577 -0
- package/src/domain/scriptdev/naxxramasConstruct.ts +364 -0
- package/src/domain/scriptdev/naxxramasFrostwyrm.ts +378 -0
- package/src/domain/scriptdev/naxxramasMilitary.ts +276 -0
- package/src/domain/scriptdev/npcProfessions.ts +1025 -0
- package/src/domain/scriptdev/npcsSpecial.ts +1379 -0
- package/src/domain/scriptdev/onyxiasLair.ts +313 -0
- package/src/domain/scriptdev/orgrimmar.ts +147 -0
- package/src/domain/scriptdev/professionSpecConsumer.ts +481 -0
- package/src/domain/scriptdev/razorfenDowns.ts +468 -0
- package/src/domain/scriptdev/razorfenKraul.ts +410 -0
- package/src/domain/scriptdev/redridgeMountains.ts +163 -0
- package/src/domain/scriptdev/registry.ts +945 -0
- package/src/domain/scriptdev/ruinsOfAhnqiraj.ts +356 -0
- package/src/domain/scriptdev/scarletMonastery.ts +713 -0
- package/src/domain/scriptdev/scholomance.ts +682 -0
- package/src/domain/scriptdev/searingGorge.ts +295 -0
- package/src/domain/scriptdev/shadowfangKeep.ts +181 -0
- package/src/domain/scriptdev/silithus.ts +71 -0
- package/src/domain/scriptdev/silverpineForest.ts +662 -0
- package/src/domain/scriptdev/stonetalonMountains.ts +493 -0
- package/src/domain/scriptdev/stormwindCity.ts +1192 -0
- package/src/domain/scriptdev/stranglethornVale.ts +402 -0
- package/src/domain/scriptdev/stratholme.ts +650 -0
- package/src/domain/scriptdev/stratholmeScripts.ts +505 -0
- package/src/domain/scriptdev/sunkenTemple.ts +736 -0
- package/src/domain/scriptdev/swampOfSorrows.ts +22 -0
- package/src/domain/scriptdev/tanaris.ts +391 -0
- package/src/domain/scriptdev/tanarisHelpers.ts +661 -0
- package/src/domain/scriptdev/teldrassil.ts +143 -0
- package/src/domain/scriptdev/templeOfAhnqiraj.ts +1013 -0
- package/src/domain/scriptdev/theBarrens.ts +709 -0
- package/src/domain/scriptdev/theBarrensHelpers.ts +1026 -0
- package/src/domain/scriptdev/thousandNeedles.ts +426 -0
- package/src/domain/scriptdev/thousandNeedlesHelpers.ts +566 -0
- package/src/domain/scriptdev/tirisfalGlades.ts +533 -0
- package/src/domain/scriptdev/types.ts +1026 -0
- package/src/domain/scriptdev/uldaman.ts +437 -0
- package/src/domain/scriptdev/ungoroCrater.ts +549 -0
- package/src/domain/scriptdev/ungoroCraterHelpers.ts +1006 -0
- package/src/domain/scriptdev/wailingCaverns.ts +700 -0
- package/src/domain/scriptdev/warEffort.ts +371 -0
- package/src/domain/scriptdev/westernPlaguelands.ts +952 -0
- package/src/domain/scriptdev/westfall.ts +767 -0
- package/src/domain/scriptdev/wetlands.ts +660 -0
- package/src/domain/scriptdev/winterspring.ts +482 -0
- package/src/domain/scriptdev/winterspringHelpers.ts +801 -0
- package/src/domain/scriptdev/worldBosses.ts +605 -0
- package/src/domain/scriptdev/zulfarrak.ts +478 -0
- package/src/domain/scriptdev/zulgurub.ts +1152 -0
- package/src/domain/sim/dummySim.ts +408 -0
- package/src/domain/sim/targetDummy.ts +29 -0
- package/src/domain/social/guild.ts +148 -0
- package/src/domain/spells/areaAuraMembership.ts +93 -0
- package/src/domain/spells/breakableStunCc.ts +166 -0
- package/src/domain/spells/cancelAura.ts +80 -0
- package/src/domain/spells/diminishing.ts +167 -0
- package/src/domain/spells/dispel.ts +149 -0
- package/src/domain/spells/dispelMechanic.ts +105 -0
- package/src/domain/spells/equipSpells.ts +247 -0
- package/src/domain/spells/learnOnTargets.ts +260 -0
- package/src/domain/spells/mergeSchoolImmunityFromRaw.ts +66 -0
- package/src/domain/spells/resurrectSpell.ts +124 -0
- package/src/domain/spells/spellPushback.ts +39 -0
- package/src/domain/spells/spellReflect.ts +43 -0
- package/src/domain/spells/stealth.ts +183 -0
- package/src/domain/spells/totem.ts +394 -0
- package/src/domain/spells/worldCast.ts +187 -0
- package/src/domain/world/areaTriggerLocks.ts +177 -0
- package/src/domain/world/dungeonMusic.ts +108 -0
- package/src/domain/world/gameEvents.ts +119 -0
- package/src/domain/world/gameObjects.ts +1030 -0
- package/src/domain/world/goEventFire.ts +234 -0
- package/src/domain/world/goMoTransport.ts +74 -0
- package/src/domain/world/goTransport.ts +81 -0
- package/src/domain/world/hazards.ts +459 -0
- package/src/domain/world/openLock.ts +398 -0
- package/src/domain/world/pools.ts +470 -0
- package/src/domain/world/restArea.ts +37 -0
- package/src/domain/world/weather.ts +201 -0
- package/src/domain/zoneAmbience.mjs +87 -0
- package/src/domain/zoneMusic.mjs +62 -0
- package/src/domain/zoneMusicQueue.mjs +7 -0
- package/src/engine/combat/activeSeal.ts +39 -0
- package/src/engine/combat/aiTargetResolve.ts +64 -0
- package/src/engine/combat/aoeCast.ts +289 -0
- package/src/engine/combat/applyConsumeAura.ts +74 -0
- package/src/engine/combat/applyDemonicSacrifice.ts +70 -0
- package/src/engine/combat/applyDispelMechanic.ts +30 -0
- package/src/engine/combat/applyHealEffect.ts +301 -0
- package/src/engine/combat/applySchoolAbsorb.ts +114 -0
- package/src/engine/combat/applySpell.ts +3169 -0
- package/src/engine/combat/applySpellLate.ts +2026 -0
- package/src/engine/combat/applySpellLateBag.ts +144 -0
- package/src/engine/combat/areaAura.ts +283 -0
- package/src/engine/combat/attackTable.ts +508 -0
- package/src/engine/combat/battleRez.ts +87 -0
- package/src/engine/combat/castAction.ts +36 -0
- package/src/engine/combat/castTargetGates.ts +75 -0
- package/src/engine/combat/castableKit.ts +68 -0
- package/src/engine/combat/ccMirrorUpgrade.ts +39 -0
- package/src/engine/combat/chainFan.ts +210 -0
- package/src/engine/combat/channel.ts +423 -0
- package/src/engine/combat/chaseCloseness.ts +95 -0
- package/src/engine/combat/cmangosCastGates.ts +129 -0
- package/src/engine/combat/combatFlag.ts +77 -0
- package/src/engine/combat/combatGeometry.ts +1329 -0
- package/src/engine/combat/combustion.ts +68 -0
- package/src/engine/combat/context.ts +730 -0
- package/src/engine/combat/createSession.ts +1165 -0
- package/src/engine/combat/creatureLeash.ts +38 -0
- package/src/engine/combat/crowdControl.ts +1259 -0
- package/src/engine/combat/dispelDuty.ts +54 -0
- package/src/engine/combat/dispelReflect.ts +609 -0
- package/src/engine/combat/displaceFloor.ts +113 -0
- package/src/engine/combat/duelBounds.ts +47 -0
- package/src/engine/combat/equippedItemGate.ts +297 -0
- package/src/engine/combat/evadeLifecycle.ts +63 -0
- package/src/engine/combat/eventAi.ts +2220 -0
- package/src/engine/combat/facing.ts +74 -0
- package/src/engine/combat/fearFlee.ts +137 -0
- package/src/engine/combat/fighterFactory.ts +1144 -0
- package/src/engine/combat/forceDespawnAction.ts +51 -0
- package/src/engine/combat/formulas.ts +807 -0
- package/src/engine/combat/friendlyFan.ts +55 -0
- package/src/engine/combat/groundPoolTick.ts +210 -0
- package/src/engine/combat/hazards.ts +114 -0
- package/src/engine/combat/healTargets.ts +226 -0
- package/src/engine/combat/heartbeatResist.ts +49 -0
- package/src/engine/combat/hostileItemUse.ts +75 -0
- package/src/engine/combat/interruptAuras.ts +66 -0
- package/src/engine/combat/itemRescue.ts +49 -0
- package/src/engine/combat/itemUse.ts +260 -0
- package/src/engine/combat/kitById.ts +23 -0
- package/src/engine/combat/knockBack.ts +201 -0
- package/src/engine/combat/leap.ts +89 -0
- package/src/engine/combat/mitigation.ts +587 -0
- package/src/engine/combat/modTaunt.ts +43 -0
- package/src/engine/combat/motionClaim.ts +268 -0
- package/src/engine/combat/motionGate.ts +150 -0
- package/src/engine/combat/motionGenerator.ts +27 -0
- package/src/engine/combat/navSight.ts +138 -0
- package/src/engine/combat/perfSink.ts +28 -0
- package/src/engine/combat/periodicDue.ts +55 -0
- package/src/engine/combat/petAuras.ts +86 -0
- package/src/engine/combat/pickAction.ts +3449 -0
- package/src/engine/combat/powerForm.ts +735 -0
- package/src/engine/combat/powerPools.ts +49 -0
- package/src/engine/combat/predicates.ts +538 -0
- package/src/engine/combat/procsDamage.ts +1823 -0
- package/src/engine/combat/reactiveGates.ts +135 -0
- package/src/engine/combat/roles.ts +389 -0
- package/src/engine/combat/rotationSubject.ts +78 -0
- package/src/engine/combat/ruleAfter.ts +106 -0
- package/src/engine/combat/seedDisplayAuras.ts +203 -0
- package/src/engine/combat/seedOocEffects.ts +317 -0
- package/src/engine/combat/seedSchoolImmunities.ts +45 -0
- package/src/engine/combat/session-types.ts +458 -0
- package/src/engine/combat/sessionApi.ts +1785 -0
- package/src/engine/combat/sessionCharge.ts +124 -0
- package/src/engine/combat/sessionChase.ts +869 -0
- package/src/engine/combat/sessionDeaths.ts +469 -0
- package/src/engine/combat/sessionFocus.ts +506 -0
- package/src/engine/combat/sessionFollow.ts +167 -0
- package/src/engine/combat/sessionGeometry.ts +188 -0
- package/src/engine/combat/sessionHome.ts +75 -0
- package/src/engine/combat/sessionInject.ts +719 -0
- package/src/engine/combat/sessionMechanicMove.ts +555 -0
- package/src/engine/combat/sessionMotion.ts +1553 -0
- package/src/engine/combat/sessionMotionKit.ts +247 -0
- package/src/engine/combat/sessionMoveIntent.ts +49 -0
- package/src/engine/combat/sessionMoveOrder.ts +200 -0
- package/src/engine/combat/sessionPathTo.ts +657 -0
- package/src/engine/combat/sessionPools.ts +688 -0
- package/src/engine/combat/sessionSteer.ts +144 -0
- package/src/engine/combat/sessionStepBack.ts +151 -0
- package/src/engine/combat/sessionStepWrap.ts +116 -0
- package/src/engine/combat/sessionView.ts +442 -0
- package/src/engine/combat/simEffects.ts +32 -0
- package/src/engine/combat/simFacade.ts +620 -0
- package/src/engine/combat/simPump.ts +264 -0
- package/src/engine/combat/simSnapshot.ts +165 -0
- package/src/engine/combat/simThreadPool.ts +35 -0
- package/src/engine/combat/skeramImages.ts +57 -0
- package/src/engine/combat/slowUpdate.ts +178 -0
- package/src/engine/combat/snapToFloor.ts +42 -0
- package/src/engine/combat/speedAura.ts +29 -0
- package/src/engine/combat/spellReagents.ts +71 -0
- package/src/engine/combat/stealthDetect.ts +93 -0
- package/src/engine/combat/stepBackMotion.ts +171 -0
- package/src/engine/combat/stepSession.ts +3102 -0
- package/src/engine/combat/summonCast.ts +243 -0
- package/src/engine/combat/thaddiusPolarity.ts +97 -0
- package/src/engine/combat/threat.ts +388 -0
- package/src/engine/combat/threatOps.ts +272 -0
- package/src/engine/combat/tickWorkerBody.ts +211 -0
- package/src/engine/combat/totemAuras.ts +122 -0
- package/src/engine/combat/triggerPayload.ts +42 -0
- package/src/engine/combat/triggeredCompanion.ts +63 -0
- package/src/engine/combat/types.ts +1897 -0
- package/src/engine/combat/useObjectTrap.ts +140 -0
- package/src/engine/combat/walkSurface.ts +54 -0
- package/src/engine/combat/weapon.ts +1248 -0
- package/src/engine/combat/worldFrame.ts +43 -0
- package/src/engine/combat.solo-golden.json +2242 -0
- package/src/engine/combat.ts +84 -0
- package/src/engine/core/detMath.ts +289 -0
- package/src/engine/core/events.ts +357 -0
- package/src/engine/core/rng.ts +36 -0
- package/src/engine/game/actionBars.ts +124 -0
- package/src/engine/game/activateObjectFromSpell.ts +320 -0
- package/src/engine/game/applyActiveObjectFromDbScript.ts +98 -0
- package/src/engine/game/applyDeathAndSpellScripts.ts +268 -0
- package/src/engine/game/applyDoorFromDbScript.ts +388 -0
- package/src/engine/game/applyEscortFromDbScript.ts +290 -0
- package/src/engine/game/applyGoSpellcasterCast.ts +40 -0
- package/src/engine/game/applyHoverFromDbScript.ts +110 -0
- package/src/engine/game/applyOocResurrect.ts +71 -0
- package/src/engine/game/applySpellDurability.ts +115 -0
- package/src/engine/game/applyTailFromDbScript.ts +478 -0
- package/src/engine/game/applyTerminateFromDbScript.ts +95 -0
- package/src/engine/game/auctionMail.ts +269 -0
- package/src/engine/game/bagOverflow.ts +130 -0
- package/src/engine/game/bank.ts +110 -0
- package/src/engine/game/barAutofill.ts +26 -0
- package/src/engine/game/battleground.ts +369 -0
- package/src/engine/game/combatEnemySpec.ts +216 -0
- package/src/engine/game/combatObjectTraps.ts +167 -0
- package/src/engine/game/combatSeed.ts +320 -0
- package/src/engine/game/combatSession.ts +3241 -0
- package/src/engine/game/combatSessionClock.ts +62 -0
- package/src/engine/game/companionQuestActions.ts +242 -0
- package/src/engine/game/companionTraining.ts +40 -0
- package/src/engine/game/consumables.ts +624 -0
- package/src/engine/game/context.ts +53 -0
- package/src/engine/game/createHealthstone.ts +45 -0
- package/src/engine/game/deathFlow.ts +127 -0
- package/src/engine/game/devGrant.ts +117 -0
- package/src/engine/game/dynamicObject.ts +365 -0
- package/src/engine/game/enchantItem.ts +177 -0
- package/src/engine/game/equipmentHelper.ts +806 -0
- package/src/engine/game/factionState.ts +108 -0
- package/src/engine/game/garmentsOoc.ts +69 -0
- package/src/engine/game/globalActionBar.ts +179 -0
- package/src/engine/game/goInteractQuestCredit.ts +51 -0
- package/src/engine/game/goMoTransportUse.ts +61 -0
- package/src/engine/game/goTransportUse.ts +60 -0
- package/src/engine/game/healthstoneUpkeep.ts +59 -0
- package/src/engine/game/killSkin.ts +124 -0
- package/src/engine/game/learnFromItem.ts +118 -0
- package/src/engine/game/loadReconcile.ts +551 -0
- package/src/engine/game/loot.ts +294 -0
- package/src/engine/game/macros.ts +125 -0
- package/src/engine/game/mail.ts +293 -0
- package/src/engine/game/meetingStoneQueue.ts +75 -0
- package/src/engine/game/meetingStoneUse.ts +54 -0
- package/src/engine/game/newGameState.ts +363 -0
- package/src/engine/game/oocAuraInterrupt.ts +92 -0
- package/src/engine/game/oocCast.ts +241 -0
- package/src/engine/game/oocCastEffects.ts +803 -0
- package/src/engine/game/oocCastMethods.ts +1077 -0
- package/src/engine/game/openLockFromSpell.ts +174 -0
- package/src/engine/game/outdoorPvp.ts +187 -0
- package/src/engine/game/outfitter.ts +644 -0
- package/src/engine/game/paladinBoard.ts +393 -0
- package/src/engine/game/partyAuras.ts +121 -0
- package/src/engine/game/persistCombatAuras.ts +91 -0
- package/src/engine/game/pets.ts +459 -0
- package/src/engine/game/prePullHealthstones.ts +154 -0
- package/src/engine/game/professions.ts +2227 -0
- package/src/engine/game/pruneStaleRuntime.ts +39 -0
- package/src/engine/game/questFightCredit.ts +36 -0
- package/src/engine/game/questItemOnCorpse.ts +166 -0
- package/src/engine/game/questItemOnCreature.ts +103 -0
- package/src/engine/game/questLog.ts +879 -0
- package/src/engine/game/questSpellComplete.ts +21 -0
- package/src/engine/game/questTurnIn.ts +598 -0
- package/src/engine/game/raidParty.ts +32 -0
- package/src/engine/game/reagentBuyIn.ts +39 -0
- package/src/engine/game/regenRest.ts +186 -0
- package/src/engine/game/rotation.ts +425 -0
- package/src/engine/game/runFullDungeon.ts +611 -0
- package/src/engine/game/runSupply.ts +80 -0
- package/src/engine/game/sanitizeDriftedItems.ts +135 -0
- package/src/engine/game/scriptDevGoUse.ts +397 -0
- package/src/engine/game/scriptDevInnkeeper.ts +150 -0
- package/src/engine/game/scriptDevProfessionSpec.ts +99 -0
- package/src/engine/game/sendEventFromSpell.ts +87 -0
- package/src/engine/game/sortContainers.ts +85 -0
- package/src/engine/game/spellReputation.ts +69 -0
- package/src/engine/game/squad/squadDungeonSeating.ts +197 -0
- package/src/engine/game/squadDungeon.ts +4222 -0
- package/src/engine/game/squadQuestShare.ts +260 -0
- package/src/engine/game/summonObjectSlot.ts +69 -0
- package/src/engine/game/summonObjectWild.ts +73 -0
- package/src/engine/game/summoningRitualUse.ts +141 -0
- package/src/engine/game/talents.ts +356 -0
- package/src/engine/game/tamingRodUse.ts +66 -0
- package/src/engine/game/tempSpawnCreature.ts +136 -0
- package/src/engine/game/tickDungeonPatrolScripts.ts +205 -0
- package/src/engine/game/tickTimedQuests.ts +28 -0
- package/src/engine/game/trade.ts +586 -0
- package/src/engine/game/travel.ts +1155 -0
- package/src/engine/game/types.ts +1855 -0
- package/src/engine/game/vendorOffers.ts +244 -0
- package/src/engine/game/weaponImbueItem.ts +281 -0
- package/src/engine/game/worldSession.ts +183 -0
- package/src/engine/game/worldState.ts +166 -0
- package/src/engine/game.ts +968 -0
- package/src/engine/spells/GAP.md +67 -0
- package/src/engine/spells/absorbs.ts +376 -0
- package/src/engine/spells/addTargetTrigger.ts +53 -0
- package/src/engine/spells/auraPerSecondCost.ts +50 -0
- package/src/engine/spells/auraStacking.ts +497 -0
- package/src/engine/spells/cmangos-special-cases-combustion.ts +13 -0
- package/src/engine/spells/cmangos-special-cases-s18.ts +445 -0
- package/src/engine/spells/cmangos-special-cases-s19.ts +324 -0
- package/src/engine/spells/cmangos-special-cases-s20.ts +385 -0
- package/src/engine/spells/cmangos-special-cases-s21.ts +116 -0
- package/src/engine/spells/cmangos-special-cases-s22.ts +24 -0
- package/src/engine/spells/cmangos-special-cases-s23.ts +52 -0
- package/src/engine/spells/cmangos-special-cases.ts +1570 -0
- package/src/engine/spells/conditions.ts +718 -0
- package/src/engine/spells/effects.ts +203 -0
- package/src/engine/spells/fixtures/oracle-effects-lock9a.json +1 -0
- package/src/engine/spells/immunity.ts +942 -0
- package/src/engine/spells/intentEffects.ts +351 -0
- package/src/engine/spells/interpreter/GAPS.md +21 -0
- package/src/engine/spells/interpreter/amount.ts +109 -0
- package/src/engine/spells/interpreter/class-scripts-kit.ts +478 -0
- package/src/engine/spells/interpreter/diff.ts +246 -0
- package/src/engine/spells/interpreter/duration.ts +90 -0
- package/src/engine/spells/interpreter/form-attrs.json +1 -0
- package/src/engine/spells/interpreter/form-attrs.ts +95 -0
- package/src/engine/spells/interpreter/handlers/aura-remove.ts +113 -0
- package/src/engine/spells/interpreter/handlers/auras-control.ts +1547 -0
- package/src/engine/spells/interpreter/handlers/auras-core.ts +1583 -0
- package/src/engine/spells/interpreter/handlers/auras-misc.ts +1774 -0
- package/src/engine/spells/interpreter/handlers/effect-disenchant.ts +17 -0
- package/src/engine/spells/interpreter/handlers/effect-skinning.ts +20 -0
- package/src/engine/spells/interpreter/handlers/effects-action-utility.ts +1455 -0
- package/src/engine/spells/interpreter/handlers/effects-core.ts +432 -0
- package/src/engine/spells/interpreter/handlers/effects-remainder.ts +105 -0
- package/src/engine/spells/interpreter/handlers/effects-summon-item.ts +687 -0
- package/src/engine/spells/interpreter/handlers/mod-increase-energy-percent.ts +36 -0
- package/src/engine/spells/interpreter/handlers/mod-increase-energy.ts +36 -0
- package/src/engine/spells/interpreter/handlers/periodic-trigger-zero.ts +327 -0
- package/src/engine/spells/interpreter/handlers/procs.ts +131 -0
- package/src/engine/spells/interpreter/handlers/registry.ts +975 -0
- package/src/engine/spells/interpreter/handlers/shared.ts +667 -0
- package/src/engine/spells/interpreter/handlers.ts +9 -0
- package/src/engine/spells/interpreter/hunter-kit.ts +202 -0
- package/src/engine/spells/interpreter/index.ts +525 -0
- package/src/engine/spells/interpreter/item-triggers.ts +1121 -0
- package/src/engine/spells/interpreter/lift-consume-energy.ts +37 -0
- package/src/engine/spells/interpreter/mage-portals.ts +37 -0
- package/src/engine/spells/interpreter/materialize-charm.ts +88 -0
- package/src/engine/spells/interpreter/materialize-dispel-mechanic.ts +25 -0
- package/src/engine/spells/interpreter/materialize-rating-buffs.ts +81 -0
- package/src/engine/spells/interpreter/materialize-speed.ts +109 -0
- package/src/engine/spells/interpreter/materialize-spell-magnet.ts +22 -0
- package/src/engine/spells/interpreter/opcodes.ts +789 -0
- package/src/engine/spells/interpreter/paladin-kit.ts +95 -0
- package/src/engine/spells/interpreter/paladin-seals.ts +499 -0
- package/src/engine/spells/interpreter/priest-warlock-kit.ts +135 -0
- package/src/engine/spells/interpreter/proc.ts +443 -0
- package/src/engine/spells/interpreter/registry/helpers.ts +16 -0
- package/src/engine/spells/interpreter/registry/index.ts +216 -0
- package/src/engine/spells/interpreter/registry/packs/class-abilities.ts +304 -0
- package/src/engine/spells/interpreter/registry/packs/dire-maul.ts +44 -0
- package/src/engine/spells/interpreter/registry/packs/dummy-script-tail.ts +1065 -0
- package/src/engine/spells/interpreter/registry/packs/ex-wave-m.ts +70 -0
- package/src/engine/spells/interpreter/registry/packs/life-tap.ts +107 -0
- package/src/engine/spells/interpreter/registry/packs/paladin.ts +246 -0
- package/src/engine/spells/interpreter/registry/packs/raid-script-summons.ts +26 -0
- package/src/engine/spells/interpreter/registry/packs/raid-threat-wipe.ts +22 -0
- package/src/engine/spells/interpreter/registry/packs/shaman.ts +214 -0
- package/src/engine/spells/interpreter/registry/packs/si4-dummy-generic-a.ts +269 -0
- package/src/engine/spells/interpreter/registry/packs/si4-dummy-generic-b.ts +370 -0
- package/src/engine/spells/interpreter/registry/packs/si4-dummy-generic-c.ts +172 -0
- package/src/engine/spells/interpreter/registry/packs/si4-dummy-hunter.ts +60 -0
- package/src/engine/spells/interpreter/registry/packs/si4-dummy-warrior.ts +31 -0
- package/src/engine/spells/interpreter/registry/packs/si4-script-generic-a.ts +114 -0
- package/src/engine/spells/interpreter/registry/packs/si4-script-generic-b.ts +249 -0
- package/src/engine/spells/interpreter/registry/packs/si4-script-generic-c.ts +233 -0
- package/src/engine/spells/interpreter/registry/types.ts +48 -0
- package/src/engine/spells/interpreter/talent-scripted.ts +329 -0
- package/src/engine/spells/interpreter/targeting.ts +90 -0
- package/src/engine/spells/interpreter/types-intent.ts +1501 -0
- package/src/engine/spells/interpreter/types.ts +419 -0
- package/src/engine/spells/interpreter/warrior-druid-kit.ts +314 -0
- package/src/engine/spells/interpreter/weapon-imbue-kit.ts +384 -0
- package/src/engine/spells/interrupt.ts +217 -0
- package/src/engine/spells/meleeAttackReset.ts +60 -0
- package/src/engine/spells/oocTriggerSpell.ts +49 -0
- package/src/engine/spells/overrideClassScripts.ts +319 -0
- package/src/engine/spells/parryHaste.ts +20 -0
- package/src/engine/spells/procs.ts +300 -0
- package/src/engine/spells/recovery.ts +203 -0
- package/src/engine/spells/scriptTargetDest.ts +76 -0
- package/src/engine/spells/scriptTargets.ts +85 -0
- package/src/engine/spells/singleTargetAura.ts +82 -0
- package/src/engine/spells/specialCasePayloads.ts +57 -0
- package/src/engine/spells/spellAttributes.ts +249 -0
- package/src/engine/spells/spellBonus.ts +143 -0
- package/src/engine/spells/spellModIntents.ts +419 -0
- package/src/engine/spells/spellMods.ts +283 -0
- package/src/engine/spells/spellRadius.ts +15 -0
- package/src/engine/spells/trapObjects.ts +26 -0
- package/src/json.d.ts +7 -0
- package/src/persistence/memoryRepository.ts +23 -0
- package/src/persistence/saveBackups.ts +162 -0
- package/src/persistence/saveFile.ts +68 -0
- package/src/persistence/saveRepository.ts +11 -0
- package/src/persistence/saveShape.ts +668 -0
- package/src/progression/leveling.ts +89 -0
- package/src/progression/rest.ts +1434 -0
- package/src/progression/training.ts +226 -0
- package/src/progression/xpGain.ts +369 -0
- package/src/quests/quests.ts +1580 -0
- package/src/world/aoePull.ts +198 -0
- package/src/world/areaTableDbc.ts +39 -0
- package/src/world/areaTableMapIdPairs.ts +141 -0
- package/src/world/bakeSlug.ts +43 -0
- package/src/world/continuousDungeon.ts +1250 -0
- package/src/world/dungeonBakeProjection.ts +190 -0
- package/src/world/dungeonMapDensity.ts +342 -0
- package/src/world/dungeonMapProjection.ts +135 -0
- package/src/world/dungeonNav.ts +904 -0
- package/src/world/dungeonNpcSim.ts +147 -0
- package/src/world/dungeonObjectives.ts +234 -0
- package/src/world/dungeonPreset.ts +35 -0
- package/src/world/dungeonRoute.ts +311 -0
- package/src/world/dungeonRouteGeometry.ts +732 -0
- package/src/world/dungeonRouteOrder.ts +1037 -0
- package/src/world/dungeonWingRooms.ts +426 -0
- package/src/world/escort.ts +296 -0
- package/src/world/goPoolRoll.ts +75 -0
- package/src/world/instanceObjects.ts +785 -0
- package/src/world/instances.ts +1572 -0
- package/src/world/meetingStones.ts +56 -0
- package/src/world/navmeshFloors.ts +145 -0
- package/src/world/nearGrid.ts +167 -0
- package/src/world/packBudget.ts +613 -0
- package/src/world/rareRoll.ts +335 -0
- package/src/world/routeAuthoring.ts +132 -0
- package/src/world/routeEdit.ts +209 -0
- package/src/world/world.ts +812 -0
- package/src/world/zoneHazards.ts +47 -0
|
@@ -0,0 +1,862 @@
|
|
|
1
|
+
// The BG world layer — map, positions, orders, objectives and the engagement shards combat runs
|
|
2
|
+
// inside. Strategy ~1 Hz, order 2–5 Hz, rotation 10 Hz. Deterministic: no Date, no Math.random.
|
|
3
|
+
|
|
4
|
+
import { detHypot } from '../../engine/core/detMath.ts';
|
|
5
|
+
import { HONORLESS_TARGET_DURATION_MS, victimGrantsPvpCredit } from '../run/honor.ts';
|
|
6
|
+
import {
|
|
7
|
+
findPathForMap, floorZForMap, isWalkablePointForMap, nearestWalkablePointForMap,
|
|
8
|
+
} from '../nav/navRegistry.ts';
|
|
9
|
+
import {
|
|
10
|
+
type BgObjective,
|
|
11
|
+
type BgOrder,
|
|
12
|
+
type BgPos,
|
|
13
|
+
type BgTeam,
|
|
14
|
+
type BgUnit,
|
|
15
|
+
type BgUnitId,
|
|
16
|
+
type BgUnitView,
|
|
17
|
+
type BgView,
|
|
18
|
+
type ScoreType,
|
|
19
|
+
type BgScoreboardEntry,
|
|
20
|
+
type BgVisionConfig,
|
|
21
|
+
emptyBgScore,
|
|
22
|
+
FAIR_VISION,
|
|
23
|
+
OTHER_TEAM,
|
|
24
|
+
} from './types.ts';
|
|
25
|
+
|
|
26
|
+
/** Cite: BattleGround.h:90 CHECK_PLAYER_POSITION_INVERVAL. */
|
|
27
|
+
const START_POS_CHECK_MS = 1000;
|
|
28
|
+
|
|
29
|
+
/** Repath floor. Cite: TargetedMovementGenerator.cpp:242 i_recheckDistance.Reset(250). */
|
|
30
|
+
const ROUTE_RECHECK_MS = 250;
|
|
31
|
+
/** Backoff after a refused step or a failed search. Cite: TargetedMovementGenerator.cpp:202 AddDelay. */
|
|
32
|
+
const ROUTE_BLOCKED_MS = 1000;
|
|
33
|
+
/** A route is stale once its destination strayed this far — a chase target inside it keeps the corridor. */
|
|
34
|
+
const ROUTE_STALE_YD = 8;
|
|
35
|
+
/** Shared-solve cells. At 16/8 yd a 40-body march bought one 142k-poly A* per body — 47% of all
|
|
36
|
+
* CPU (profile 2026-08-30); coarse cells make it ONE corridor, joined via nearestLegIndex. */
|
|
37
|
+
const SOLVE_FROM_CELL_YD = 64;
|
|
38
|
+
const SOLVE_TO_CELL_YD = 48;
|
|
39
|
+
const SOLVE_TTL_MS = 20_000;
|
|
40
|
+
const SOLVE_CAP = 512;
|
|
41
|
+
/**
|
|
42
|
+
* findPath calls ONE tick may spend. Over budget a unit keeps its straight aim and searches on a
|
|
43
|
+
* later tick — the degradation a failed search already had.
|
|
44
|
+
*
|
|
45
|
+
* 2 starved the field without ever saving a search. The asks arrive in BURSTS, so a cap of 2 spent
|
|
46
|
+
* 12% of what it allows over 600 ticks and still turned two thirds of the asks away, and each
|
|
47
|
+
* refusal put a body on a straight line into rock. Swept on src/dev/capabilities/bgMarch.mjs, same
|
|
48
|
+
* tree, only this constant moving:
|
|
49
|
+
*
|
|
50
|
+
* budget 2 -> 149 searches, 315 refused, 40/80 advanced
|
|
51
|
+
* budget 4 -> 138 searches, 126 refused, 48/80
|
|
52
|
+
* budget 8 -> 145 searches, 40 refused, 43/80
|
|
53
|
+
* budget 16 -> 139 searches, 0 refused, 44/80
|
|
54
|
+
* budget 32 -> 139 searches, 0 refused, 44/80 (saturated at 16)
|
|
55
|
+
*
|
|
56
|
+
* The search COUNT is flat, so this buys the corridors back for free: 1317 ms median at 2 against
|
|
57
|
+
* 1335 ms at 16 over 5 runs each, inside the run-to-run spread. It removes a starvation, it does
|
|
58
|
+
* not add work — a body that gets its corridor first ask stops re-asking.
|
|
59
|
+
*/
|
|
60
|
+
const SEARCH_BUDGET_PER_TICK = 16;
|
|
61
|
+
/** Polygons ONE search may visit. Dun Baldar -> Frostwolf needs 22,657; a shallower cap failed the
|
|
62
|
+
* cross-valley march and read as units clipping through rock. Sharing pays it down, not depth. */
|
|
63
|
+
const SEARCH_MAX_VISITED = 40_000;
|
|
64
|
+
|
|
65
|
+
/** Deterministic per-unit stagger, so a crowd's backoffs do not all expire on one tick. */
|
|
66
|
+
function unitJitterMs(id: string): number {
|
|
67
|
+
let h = 0;
|
|
68
|
+
for (let i = 0; i < id.length; i++) h = (h * 31 + id.charCodeAt(i)) | 0;
|
|
69
|
+
return (h >>> 0) % ROUTE_BLOCKED_MS;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** Entry leg for a corridor adopted mid-path — the leg nearest the unit, so a shared solve whose
|
|
73
|
+
* start cell sits behind it costs at most one cell of backtrack. */
|
|
74
|
+
function nearestLegIndex(legs: readonly BgPos[], pos: BgPos): number {
|
|
75
|
+
let best = 0;
|
|
76
|
+
let bestD = Infinity;
|
|
77
|
+
for (let i = 0; i < legs.length; i++) {
|
|
78
|
+
const d = detHypot(legs[i]!.x - pos.x, legs[i]!.y - pos.y);
|
|
79
|
+
if (d < bestD) { bestD = d; best = i; }
|
|
80
|
+
}
|
|
81
|
+
return best;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export interface BgWorldOpts {
|
|
85
|
+
mapId: number;
|
|
86
|
+
teamSize: number;
|
|
87
|
+
/** Order-layer tick, ms. §6a says 2-5 Hz; 200 ms is the default. */
|
|
88
|
+
tickMs?: number;
|
|
89
|
+
/** Gate countdown before the match starts, ms. Cite: BattleGroundStartTimeIntervals 2m. */
|
|
90
|
+
countdownMs?: number;
|
|
91
|
+
/** StartMaxDist — the starting-gate leash, yards (§6g). WSG/AB 75, AV 100. */
|
|
92
|
+
startMaxDist?: number;
|
|
93
|
+
/** Two units within this distance are in contact and share an engagement shard. */
|
|
94
|
+
engageYd?: number;
|
|
95
|
+
// Match clock cap in ms on the same scale as `t`; 0 or absent means no limit. A PRODUCT RULE,
|
|
96
|
+
// because the combat session under this world caps itself and nothing closed the world loop.
|
|
97
|
+
timeLimitMs?: number;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** Units whose position ANOTHER system writes. The world stops advancing their orders: two
|
|
101
|
+
* owners on one `pos` draw the body at both, which reads as a chip jiggling in place. */
|
|
102
|
+
export type BgPosOwnedElsewhere = (u: BgUnit) => boolean;
|
|
103
|
+
|
|
104
|
+
/** A cluster of units in contact — what becomes one combat session. */
|
|
105
|
+
export interface BgShard {
|
|
106
|
+
id: number;
|
|
107
|
+
units: BgUnitId[];
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export interface BgTickStats {
|
|
111
|
+
t: number;
|
|
112
|
+
shards: number;
|
|
113
|
+
/** Units inside some shard this tick. */
|
|
114
|
+
engaged: number;
|
|
115
|
+
/** Largest shard, in units — this is what has to stay under the W1 ceiling. */
|
|
116
|
+
largestShard: number;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export class BgWorld {
|
|
120
|
+
readonly mapId: number;
|
|
121
|
+
readonly teamSize: number;
|
|
122
|
+
readonly tickMs: number;
|
|
123
|
+
readonly countdownMs: number;
|
|
124
|
+
readonly startMaxDist: number;
|
|
125
|
+
readonly engageYd: number;
|
|
126
|
+
readonly timeLimitMs: number;
|
|
127
|
+
|
|
128
|
+
/** Match clock, ms. Negative during the gate countdown; 0 when gates open. */
|
|
129
|
+
t: number;
|
|
130
|
+
readonly units = new Map<BgUnitId, BgUnit>();
|
|
131
|
+
readonly objectives = new Map<string, BgObjective>();
|
|
132
|
+
score: Record<BgTeam, number> = { alliance: 0, horde: 0 };
|
|
133
|
+
readonly scoreboard = new Map<BgUnitId, BgScoreboardEntry>();
|
|
134
|
+
/** Team start points — also the leash anchors before gates open. */
|
|
135
|
+
readonly startPos: Record<BgTeam, BgPos> = { alliance: { x: 0, y: 0 }, horde: { x: 0, y: 0 } };
|
|
136
|
+
ended = false;
|
|
137
|
+
winner: BgTeam | null = null;
|
|
138
|
+
|
|
139
|
+
/** Kills credited since the last `takeKillCredit()`. Drained by the honor bookkeeper. */
|
|
140
|
+
private killCredit: Array<{ killer: BgUnitId; victim: BgUnitId; victimLevel: number }> = [];
|
|
141
|
+
|
|
142
|
+
private shards: BgShard[] = [];
|
|
143
|
+
/** Uniform bucket grid over the live roster, rebuilt once per tick. See `regrid`. */
|
|
144
|
+
private grid = new Map<number, BgUnitId[]>();
|
|
145
|
+
private gridCell = 30;
|
|
146
|
+
// One routed path per unit; `blockedUntil` is the repath throttle
|
|
147
|
+
// (TargetedMovementGenerator.cpp:242 Reset(250), :202 AddDelay 1000 ms).
|
|
148
|
+
private routes = new Map<BgUnitId, {
|
|
149
|
+
to: BgPos; legs: readonly BgPos[]; leg: number; blockedUntil: number;
|
|
150
|
+
}>();
|
|
151
|
+
// Solves shared by quantized (start cell → dest cell): a marching crowd walks one corridor,
|
|
152
|
+
// and `legs: null` caches "no path" so an unreachable order is one search per cell per TTL.
|
|
153
|
+
private solves = new Map<string, { legs: readonly BgPos[] | null; at: number }>();
|
|
154
|
+
// A wall-refused unit holds its aim until this clock, then re-searches — it outlives the
|
|
155
|
+
// route deletion that armed it, or the very next tick re-ran the full A*.
|
|
156
|
+
private repathHoldUntil = new Map<BgUnitId, number>();
|
|
157
|
+
private visionByTeam: Record<BgTeam, BgVisionConfig> = {
|
|
158
|
+
alliance: FAIR_VISION,
|
|
159
|
+
horde: FAIR_VISION,
|
|
160
|
+
};
|
|
161
|
+
/** Cite: BattleGround.cpp:197 m_validStartPositionTimer = 0. */
|
|
162
|
+
private startPosCheckRemainMs = 0;
|
|
163
|
+
|
|
164
|
+
constructor(opts: BgWorldOpts) {
|
|
165
|
+
this.mapId = opts.mapId;
|
|
166
|
+
this.teamSize = opts.teamSize;
|
|
167
|
+
this.tickMs = opts.tickMs ?? 200;
|
|
168
|
+
this.countdownMs = opts.countdownMs ?? 120_000;
|
|
169
|
+
this.startMaxDist = opts.startMaxDist ?? 75;
|
|
170
|
+
this.engageYd = opts.engageYd ?? 30;
|
|
171
|
+
this.timeLimitMs = Math.max(0, opts.timeLimitMs ?? 0);
|
|
172
|
+
this.t = -this.countdownMs;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/** True once the gates are open and units may leave the tunnel. */
|
|
176
|
+
get gatesOpen(): boolean {
|
|
177
|
+
return this.t >= 0;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/** Outside StartMaxDist of the team start loc while gates are shut. Cite: BattleGround.cpp:365. */
|
|
181
|
+
beyondStartMax(u: BgUnit, pos: BgPos = u.pos): boolean {
|
|
182
|
+
if (this.gatesOpen || !(this.startMaxDist > 0)) return false;
|
|
183
|
+
// A creature is not in m_Players, so the gate leash never sees it. Cite: BattleGround.cpp:359
|
|
184
|
+
// `for (const auto& itr : GetPlayers())`. Without this every AV body outside StartMaxDist was
|
|
185
|
+
// teleported INTO the keep of the team neutralSideFor handed it, mine troggs included.
|
|
186
|
+
if (u.npc) return false;
|
|
187
|
+
const a = this.startPos[u.team];
|
|
188
|
+
return detHypot(pos.x - a.x, pos.y - a.y) > this.startMaxDist;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/** Snap back to the team start loc. Cite: BattleGround.cpp:367 TeleportTo. */
|
|
192
|
+
snapToStart(u: BgUnit): void {
|
|
193
|
+
const a = this.startPos[u.team];
|
|
194
|
+
u.pos = { x: a.x, y: a.y };
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/** Cast Honorless Target 2479 on this unit. Cite: MovementHandler.cpp:241–242. */
|
|
198
|
+
applyHonorlessTarget(u: BgUnit): void {
|
|
199
|
+
u.honorlessUntilMs = this.t + HONORLESS_TARGET_DURATION_MS;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/** Victim still holds aura 2479. Cite: Player.cpp:6626–6627 RewardHonor. */
|
|
203
|
+
isHonorless(u: BgUnit): boolean {
|
|
204
|
+
return !victimGrantsPvpCredit(u.honorlessUntilMs, this.t);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Periodic start-gate leash. C++ checks every 1000 ms and teleports anyone outside. Cite:
|
|
208
|
+
// BattleGround.cpp:352–375; BattleGround.h:90.
|
|
209
|
+
private enforceStartMaxDist(dtMs: number): void {
|
|
210
|
+
if (this.gatesOpen || !(this.startMaxDist > 0)) return;
|
|
211
|
+
if (this.startPosCheckRemainMs >= dtMs) {
|
|
212
|
+
this.startPosCheckRemainMs -= dtMs;
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
this.startPosCheckRemainMs = START_POS_CHECK_MS;
|
|
216
|
+
for (const u of this.units.values()) {
|
|
217
|
+
if (!this.alive(u)) continue;
|
|
218
|
+
if (this.beyondStartMax(u)) this.snapToStart(u);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
setVision(team: BgTeam, cfg: BgVisionConfig): void {
|
|
223
|
+
this.visionByTeam[team] = cfg;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
visionOf(team: BgTeam): BgVisionConfig {
|
|
227
|
+
return this.visionByTeam[team];
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
addUnit(u: BgUnit): void {
|
|
231
|
+
this.units.set(u.id, u);
|
|
232
|
+
// Seat the body ON the mesh. A seat spread across the tunnel keeps the START row's z, and
|
|
233
|
+
// `isWalkablePointForMap` is z-sensitive: at the bake z, 20 of Alterac's 40 Alliance seats and
|
|
234
|
+
// 10 of its 40 Horde seats read off-mesh, so `stepToward` refused every step out of the keep
|
|
235
|
+
// and armed a repath hold instead. That is 30 bodies of 80 standing in their own base for the
|
|
236
|
+
// whole match — src/dev/capabilities/bgMarch.mjs. Cite: Map.cpp GetHeight on spawn.
|
|
237
|
+
this.settleZ(u);
|
|
238
|
+
this.seatOnFloor(u);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/** Put one body on the mesh. No mesh registered yet leaves it where it is. */
|
|
242
|
+
private seatOnFloor(u: BgUnit): void {
|
|
243
|
+
const snap = nearestWalkablePointForMap(this.mapId, u.pos.x, u.pos.y, u.z);
|
|
244
|
+
if (!snap) return;
|
|
245
|
+
u.pos = snap;
|
|
246
|
+
this.settleZ(u);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Re-seat every living body on the floor, for a mesh that arrived AFTER the units did.
|
|
251
|
+
*
|
|
252
|
+
* `addUnit` runs at construction and Alterac's mesh is an 11.87 MB fetch, so every one of its
|
|
253
|
+
* bodies was added while `nearestWalkablePointForMap` still answered null — the snap above
|
|
254
|
+
* no-oped for all of them, and an off-mesh body has `stepToward` refuse every step and re-arm the
|
|
255
|
+
* repath hold forever. That is the same "standing in their own base for the whole match" the
|
|
256
|
+
* comment in `addUnit` records, arriving through the load clock instead of through the bake z.
|
|
257
|
+
*/
|
|
258
|
+
resettleOnFloor(): number {
|
|
259
|
+
let moved = 0;
|
|
260
|
+
for (const u of this.units.values()) {
|
|
261
|
+
if (!this.alive(u)) continue;
|
|
262
|
+
const before = u.pos;
|
|
263
|
+
this.settleZ(u);
|
|
264
|
+
this.seatOnFloor(u);
|
|
265
|
+
if (u.pos !== before) moved++;
|
|
266
|
+
}
|
|
267
|
+
this.routes.clear();
|
|
268
|
+
this.repathHoldUntil.clear();
|
|
269
|
+
return moved;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
addObjective(o: BgObjective): void {
|
|
273
|
+
this.objectives.set(o.id, o);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
/** Cite: BattleGround.cpp:1383 UpdatePlayerScore. */
|
|
279
|
+
updatePlayerScore(unitId: BgUnitId, type: ScoreType, value: number): void {
|
|
280
|
+
let entry = this.scoreboard.get(unitId);
|
|
281
|
+
if (!entry) {
|
|
282
|
+
entry = emptyBgScore();
|
|
283
|
+
this.scoreboard.set(unitId, entry);
|
|
284
|
+
}
|
|
285
|
+
entry[type] += value;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
unitsOf(team: BgTeam): BgUnit[] {
|
|
289
|
+
const out: BgUnit[] = [];
|
|
290
|
+
for (const u of this.units.values()) if (u.team === team) out.push(u);
|
|
291
|
+
return out;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
livingOf(team: BgTeam): BgUnit[] {
|
|
295
|
+
return this.unitsOf(team).filter((u) => this.alive(u));
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
alive(u: BgUnit): boolean {
|
|
299
|
+
return u.hp > 0 && u.deadUntilMs == null;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// Issue an order — the ONLY way a unit's intent changes, which is what makes it the lockstep wire
|
|
303
|
+
// format. Validity is checked here so a local bug and a hostile peer are rejected the same way.
|
|
304
|
+
issue(unitId: BgUnitId, order: BgOrder, byTeam?: BgTeam): boolean {
|
|
305
|
+
const u = this.units.get(unitId);
|
|
306
|
+
if (!u) return false;
|
|
307
|
+
if (byTeam && u.team !== byTeam) return false;
|
|
308
|
+
if (!this.alive(u)) return false;
|
|
309
|
+
// A raycast hop reads no corridor, so a route left from an earlier order would only rot.
|
|
310
|
+
if (order.kind === 'move' && order.straight) this.routes.delete(unitId);
|
|
311
|
+
|
|
312
|
+
// Same-destination re-issues (1 Hz per unit) and `to`-less orders (follow/assist) keep the
|
|
313
|
+
// route: waypointToward's own staleness check tracks a moving target.
|
|
314
|
+
const prev = this.routes.get(unitId);
|
|
315
|
+
const to = 'to' in order ? order.to : null;
|
|
316
|
+
if (prev && to && detHypot(prev.to.x - to.x, prev.to.y - to.y) >= 3) {
|
|
317
|
+
this.routes.delete(unitId);
|
|
318
|
+
}
|
|
319
|
+
u.order = order;
|
|
320
|
+
return true;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// ---- movement -----------------------------------------------------------
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* The next waypoint on the routed path to `to`, or `to` itself when this map has no navmesh.
|
|
327
|
+
*
|
|
328
|
+
* A battleground used to walk in a straight line because maps 30/489/529 had vmaps and no
|
|
329
|
+
* mmtiles. All three have both now (bake-navmesh.mjs NAVMESH_SLUG_BY_MAP_ID; 489/529 since 2026-09-02), and a
|
|
330
|
+
* 2,800 yd valley with a mountain down the middle is the one BG where that mattered: a straight
|
|
331
|
+
* line from Dun Baldar to Frostwolf Keep runs through the ridge.
|
|
332
|
+
*/
|
|
333
|
+
private waypointToward(u: BgUnit, to: BgPos): BgPos {
|
|
334
|
+
if (isWalkablePointForMap(this.mapId, u.pos.x, u.pos.y, u.z) == null) return to;
|
|
335
|
+
const cached = this.routes.get(u.id);
|
|
336
|
+
if (!cached) {
|
|
337
|
+
const hold = this.repathHoldUntil.get(u.id);
|
|
338
|
+
if (hold != null && this.t < hold) {
|
|
339
|
+
// AddDelay holds the re-SEARCH, never the use of a corridor another body already paid for.
|
|
340
|
+
// Holding both is what pinned 28 of 30 stuck bodies to their keep: the hold handed back the
|
|
341
|
+
// same straight aim that the floor clamp had just refused, the refusal re-armed the hold,
|
|
342
|
+
// and the body could not reach the pathfinder again. Cite:
|
|
343
|
+
// TargetedMovementGenerator.cpp:202 AddDelay.
|
|
344
|
+
const shared = this.peekSolve(u, to);
|
|
345
|
+
if (!shared) return to;
|
|
346
|
+
const sleg = nearestLegIndex(shared, u.pos);
|
|
347
|
+
this.routes.set(u.id, {
|
|
348
|
+
to: { x: to.x, y: to.y }, legs: shared, leg: sleg, blockedUntil: this.t + ROUTE_RECHECK_MS,
|
|
349
|
+
});
|
|
350
|
+
return shared[sleg] ?? to;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
if (cached) {
|
|
354
|
+
// A route within ROUTE_STALE_YD of the asked destination keeps walking; exhausted legs
|
|
355
|
+
// fall through to `to` itself, so a chase still homes on the live target.
|
|
356
|
+
const fresh = detHypot(cached.to.x - to.x, cached.to.y - to.y) < ROUTE_STALE_YD;
|
|
357
|
+
if (fresh || this.t < cached.blockedUntil) {
|
|
358
|
+
// Advance past legs already reached, then aim at the next one.
|
|
359
|
+
while (cached.leg < cached.legs.length
|
|
360
|
+
&& detHypot(cached.legs[cached.leg]!.x - u.pos.x, cached.legs[cached.leg]!.y - u.pos.y) < 3) {
|
|
361
|
+
cached.leg++;
|
|
362
|
+
}
|
|
363
|
+
return cached.legs[cached.leg] ?? to;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
const solved = this.solveRoute(u, to);
|
|
367
|
+
// Budget, not geometry: this body has no answer YET. Aim straight for this one tick and ask
|
|
368
|
+
// again on the next, when the per-tick budget is fresh. Caching the straight line here is what
|
|
369
|
+
// stranded a 40v40 in its keeps — the fallback route read `fresh` for ROUTE_BLOCKED_MS, so the
|
|
370
|
+
// body walked at the ridge, was refused by the floor clamp, dropped the route and armed a hold,
|
|
371
|
+
// and the hold sent it back to the same straight aim without ever re-searching. Measured on the
|
|
372
|
+
// shipped code (src/dev/capabilities/bgMarch.mjs): 30 of 80 bots inside 20 yd of spawn after
|
|
373
|
+
// 60 s, with 91 solves refused against only 107 run — the budget was bursty, never exhausted.
|
|
374
|
+
if (solved.deferred) { this.aimWasDeferred.add(u.id); return to; }
|
|
375
|
+
this.aimWasDeferred.delete(u.id);
|
|
376
|
+
// No route is not a licence to walk through the mountain: aim at the destination, let the
|
|
377
|
+
// floor clamp refuse the steps that leave the mesh, and back a miss off with jitter.
|
|
378
|
+
const legs = solved.legs ?? [{ x: to.x, y: to.y }];
|
|
379
|
+
const leg = nearestLegIndex(legs, u.pos);
|
|
380
|
+
this.routes.set(u.id, {
|
|
381
|
+
to: { x: to.x, y: to.y },
|
|
382
|
+
legs,
|
|
383
|
+
leg,
|
|
384
|
+
blockedUntil: this.t + (solved.legs
|
|
385
|
+
? ROUTE_RECHECK_MS
|
|
386
|
+
: ROUTE_BLOCKED_MS + unitJitterMs(u.id)),
|
|
387
|
+
});
|
|
388
|
+
return legs[leg] ?? to;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/** Live findPath calls this world has made — the number the bgRoutes capability row bounds.
|
|
392
|
+
* 581 creatures re-searching a 142k-poly mesh at 10 Hz was the 2 fps AV floor (2026-08-30). */
|
|
393
|
+
pathSearches = 0;
|
|
394
|
+
/** Spent against SEARCH_BUDGET_PER_TICK, cleared at the top of every tick. */
|
|
395
|
+
private searchesThisTick = 0;
|
|
396
|
+
/** Searches refused for budget this match — the number that says the budget is too tight. */
|
|
397
|
+
searchesDeferred = 0;
|
|
398
|
+
/**
|
|
399
|
+
* Units whose current aim is the straight line a BUDGET refusal handed back, not a corridor.
|
|
400
|
+
*
|
|
401
|
+
* `stepToward` must not read a wall under that aim as "geometry refused me" — arming the repath
|
|
402
|
+
* hold there costs the body a full second of grinding the wall for a failure that was the
|
|
403
|
+
* budget's, and the hold then hands back the same straight aim. Cite:
|
|
404
|
+
* TargetedMovementGenerator.cpp:202 AddDelay, which delays a re-search after a real failure.
|
|
405
|
+
*/
|
|
406
|
+
private aimWasDeferred = new Set<BgUnitId>();
|
|
407
|
+
|
|
408
|
+
/** The shared solve key: one findPath per (start cell → dest cell) per TTL. */
|
|
409
|
+
private solveKey(u: BgUnit, to: BgPos): string {
|
|
410
|
+
const q = (v: number, cell: number): number => Math.floor(v / cell);
|
|
411
|
+
return `${q(u.pos.x, SOLVE_FROM_CELL_YD)},${q(u.pos.y, SOLVE_FROM_CELL_YD)},${q(u.z, 20)}`
|
|
412
|
+
+ `|${q(to.x, SOLVE_TO_CELL_YD)},${q(to.y, SOLVE_TO_CELL_YD)}`;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/** A corridor another body already paid for, or null. Spends no budget and runs no search. */
|
|
416
|
+
private peekSolve(u: BgUnit, to: BgPos): readonly BgPos[] | null {
|
|
417
|
+
const hit = this.solves.get(this.solveKey(u, to));
|
|
418
|
+
return hit && this.t - hit.at < SOLVE_TTL_MS ? hit.legs : null;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
/** One findPath per (start cell → dest cell) per TTL — a marching crowd shares its corridor.
|
|
422
|
+
* `deferred` is "the budget said not this tick", which is NOT the same answer as "no route". */
|
|
423
|
+
private solveRoute(u: BgUnit, to: BgPos): { legs: readonly BgPos[] | null; deferred?: boolean } {
|
|
424
|
+
const key = this.solveKey(u, to);
|
|
425
|
+
const hit = this.solves.get(key);
|
|
426
|
+
if (hit && this.t - hit.at < SOLVE_TTL_MS) return hit;
|
|
427
|
+
// Out of budget: answer "no route" WITHOUT caching it. Caching would poison the shared corridor
|
|
428
|
+
// with a false no-path for the whole TTL; the caller aims straight and re-asks after its backoff.
|
|
429
|
+
if (this.searchesThisTick >= SEARCH_BUDGET_PER_TICK) {
|
|
430
|
+
this.searchesDeferred++;
|
|
431
|
+
return { legs: null, deferred: true };
|
|
432
|
+
}
|
|
433
|
+
this.searchesThisTick++;
|
|
434
|
+
this.pathSearches++;
|
|
435
|
+
// A deep search stays legal; what was not affordable is doing one PER BODY. The solve cells
|
|
436
|
+
// above are what makes a marching crowd share a single corridor.
|
|
437
|
+
const path = findPathForMap(
|
|
438
|
+
this.mapId,
|
|
439
|
+
{ x: u.pos.x, y: u.pos.y, z: u.z },
|
|
440
|
+
{ x: to.x, y: to.y },
|
|
441
|
+
undefined,
|
|
442
|
+
{ maxVisited: SEARCH_MAX_VISITED },
|
|
443
|
+
);
|
|
444
|
+
const entry = { legs: path ? path.map((p) => ({ x: p.x, y: p.y })) : null, at: this.t };
|
|
445
|
+
if (this.solves.size >= SOLVE_CAP) {
|
|
446
|
+
const oldest = this.solves.keys().next().value;
|
|
447
|
+
if (oldest !== undefined) this.solves.delete(oldest);
|
|
448
|
+
}
|
|
449
|
+
this.solves.set(key, entry);
|
|
450
|
+
return entry;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
/** `straight` is ComputePathToRandomPoint's raycast: aim at the point, let the floor clamp cut
|
|
454
|
+
* the walk short at the first wall. Cite: PathFinder.cpp:1357 + :692 raycast, not findPath. */
|
|
455
|
+
private stepToward(u: BgUnit, to: BgPos, dtMs: number, straight = false): void {
|
|
456
|
+
const stepYd = u.speedYd * (dtMs / 1000);
|
|
457
|
+
if (!(stepYd > 0)) return;
|
|
458
|
+
const aim = straight ? to : this.waypointToward(u, to);
|
|
459
|
+
const dx = aim.x - u.pos.x;
|
|
460
|
+
const dy = aim.y - u.pos.y;
|
|
461
|
+
const dist = detHypot(dx, dy);
|
|
462
|
+
if (dist <= 0.01) return;
|
|
463
|
+
// Before gates open, StartMaxDist leashes you to the tunnel.
|
|
464
|
+
// Cite: BattleGround.cpp:352–368 STATUS_WAIT_JOIN + GetStartMaxDist + TeleportTo.
|
|
465
|
+
const travel = Math.min(stepYd, dist);
|
|
466
|
+
const next: BgPos = { x: u.pos.x + (dx / dist) * travel, y: u.pos.y + (dy / dist) * travel };
|
|
467
|
+
if (this.beyondStartMax(u, next)) return;
|
|
468
|
+
// A loaded mesh that refuses the step wins — CLAUDE.md §5, the same rule displacement follows.
|
|
469
|
+
// `null` is "no geometry registered", which is every BG but Alterac and is a fail-open.
|
|
470
|
+
const z = floorZForMap(this.mapId, next.x, next.y, u.z);
|
|
471
|
+
if (z == null) { u.pos = next; return; }
|
|
472
|
+
if (isWalkablePointForMap(this.mapId, next.x, next.y, u.z) === false) {
|
|
473
|
+
// Wall: drop the route and hold the re-search (TargetedMovementGenerator.cpp:202 AddDelay).
|
|
474
|
+
// Arm only when no hold is live — re-arming per refused tick slides the expiry forever.
|
|
475
|
+
this.routes.delete(u.id);
|
|
476
|
+
// ...but NOT when this aim is the straight line a budget refusal handed back. That wall says
|
|
477
|
+
// nothing about geometry, and the hold then feeds the body the SAME straight aim for a second
|
|
478
|
+
// without ever re-searching. It stays queued instead and asks again next tick.
|
|
479
|
+
if (this.aimWasDeferred.has(u.id)) return;
|
|
480
|
+
const hold = this.repathHoldUntil.get(u.id);
|
|
481
|
+
if (hold == null || hold <= this.t) {
|
|
482
|
+
this.repathHoldUntil.set(u.id, this.t + ROUTE_BLOCKED_MS + unitJitterMs(u.id));
|
|
483
|
+
}
|
|
484
|
+
return;
|
|
485
|
+
}
|
|
486
|
+
u.pos = next;
|
|
487
|
+
u.z = z;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
/** Re-seat floor height after something OTHER than stepUnit moved the body — the session owns
|
|
491
|
+
* friendly seats, so their `z` was never re-derived and stayed the height they spawned at. */
|
|
492
|
+
settleZ(u: BgUnit): void {
|
|
493
|
+
const z = floorZForMap(this.mapId, u.pos.x, u.pos.y, u.z);
|
|
494
|
+
if (z != null) u.z = z;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
/** Distance between two units, yards. */
|
|
498
|
+
distance(a: BgUnit, b: BgUnit): number {
|
|
499
|
+
return detHypot(a.pos.x - b.pos.x, a.pos.y - b.pos.y);
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
private advanceOrder(u: BgUnit, dtMs: number): void {
|
|
503
|
+
const o = u.order;
|
|
504
|
+
switch (o.kind) {
|
|
505
|
+
case 'move':
|
|
506
|
+
this.stepToward(u, o.to, dtMs, o.straight === true);
|
|
507
|
+
break;
|
|
508
|
+
case 'attack-move':
|
|
509
|
+
case 'retreat':
|
|
510
|
+
this.stepToward(u, o.to, dtMs);
|
|
511
|
+
break;
|
|
512
|
+
case 'patrol': {
|
|
513
|
+
const wp = o.waypoints[o.index % Math.max(1, o.waypoints.length)];
|
|
514
|
+
if (!wp) break;
|
|
515
|
+
this.stepToward(u, wp, dtMs);
|
|
516
|
+
if (detHypot(u.pos.x - wp.x, u.pos.y - wp.y) < 2) {
|
|
517
|
+
u.order = { ...o, index: (o.index + 1) % o.waypoints.length };
|
|
518
|
+
}
|
|
519
|
+
break;
|
|
520
|
+
}
|
|
521
|
+
case 'follow':
|
|
522
|
+
case 'assist': {
|
|
523
|
+
const tgt = this.units.get(o.target);
|
|
524
|
+
if (!tgt) break;
|
|
525
|
+
// Tracking an ENEMY only works while your team can still see them, or the order is a fog
|
|
526
|
+
// leak with extra steps. Losing sight stops the unit and the strategy layer re-decides.
|
|
527
|
+
if (tgt.team !== u.team && !tgt.carryingFlag && !this.canSee(u.team, tgt)) {
|
|
528
|
+
break;
|
|
529
|
+
}
|
|
530
|
+
// Stop a body-length short so a follower does not stand inside its leader.
|
|
531
|
+
const d = detHypot(tgt.pos.x - u.pos.x, tgt.pos.y - u.pos.y);
|
|
532
|
+
if (d > 4) this.stepToward(u, tgt.pos, dtMs);
|
|
533
|
+
break;
|
|
534
|
+
}
|
|
535
|
+
case 'use-object': {
|
|
536
|
+
const obj = this.objectives.get(o.objectId);
|
|
537
|
+
if (obj) this.stepToward(u, obj.pos, dtMs);
|
|
538
|
+
break;
|
|
539
|
+
}
|
|
540
|
+
case 'cast-on':
|
|
541
|
+
case 'hold':
|
|
542
|
+
break;
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
// ---- spatial index ------------------------------------------------------
|
|
547
|
+
|
|
548
|
+
// One bucket grid over every living unit, rebuilt at the top of each tick. Alterac Valley is why:
|
|
549
|
+
// its field is ~760 creature bodies on top of 80 seats, and both the sight test and the shard
|
|
550
|
+
// walk were pairwise over the whole roster — rebuildShards' same-team merge scanned `live` INSIDE
|
|
551
|
+
// its own double loop, so it was O(n^3) and 836 units is 5.8e8 checks per tick.
|
|
552
|
+
private regrid(): void {
|
|
553
|
+
this.grid.clear();
|
|
554
|
+
this.gridCell = Math.max(1, this.engageYd);
|
|
555
|
+
for (const u of this.units.values()) {
|
|
556
|
+
if (!this.alive(u)) continue;
|
|
557
|
+
const key = this.cellKey(u.pos.x, u.pos.y);
|
|
558
|
+
const bucket = this.grid.get(key);
|
|
559
|
+
if (bucket) bucket.push(u.id);
|
|
560
|
+
else this.grid.set(key, [u.id]);
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
private cellKey(x: number, y: number): number {
|
|
565
|
+
// 16 bits of cell index per axis: the widest BG (AV, ~3400 yd) is 114 cells at 30 yd.
|
|
566
|
+
const cx = Math.floor(x / this.gridCell) & 0xffff;
|
|
567
|
+
const cy = Math.floor(y / this.gridCell) & 0xffff;
|
|
568
|
+
return (cx << 16) | cy;
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
// Public read of the same index the tick uses. A rules module scanning every unit per objective
|
|
572
|
+
// per tick is 15 x 1,280 x 10 Hz on Alterac Valley; this is the same answer for the cells that
|
|
573
|
+
// can hold it. Exact range is still the caller's to check.
|
|
574
|
+
unitsNear(x: number, y: number, radiusYd: number): BgUnit[] {
|
|
575
|
+
return this.nearby(x, y, radiusYd, []);
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
/** Live units within `radiusYd` of a point, from the grid. Never exact — callers re-check range. */
|
|
579
|
+
private nearby(x: number, y: number, radiusYd: number, out: BgUnit[]): BgUnit[] {
|
|
580
|
+
out.length = 0;
|
|
581
|
+
const span = Math.ceil(radiusYd / this.gridCell);
|
|
582
|
+
const cx = Math.floor(x / this.gridCell);
|
|
583
|
+
const cy = Math.floor(y / this.gridCell);
|
|
584
|
+
for (let i = -span; i <= span; i++) {
|
|
585
|
+
for (let j = -span; j <= span; j++) {
|
|
586
|
+
const bucket = this.grid.get((((cx + i) & 0xffff) << 16) | ((cy + j) & 0xffff));
|
|
587
|
+
if (!bucket) continue;
|
|
588
|
+
for (const id of bucket) {
|
|
589
|
+
const u = this.units.get(id);
|
|
590
|
+
if (u) out.push(u);
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
return out;
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
// ---- visibility (§6g) ---------------------------------------------------
|
|
598
|
+
|
|
599
|
+
// Is `target` perceptible to `team` right now, under that team's vision config? Radius only: no BG ships
|
|
600
|
+
// a collision asset, so `cfg.seeThroughWalls` has no reader here.
|
|
601
|
+
canSee(team: BgTeam, target: BgUnit): boolean {
|
|
602
|
+
if (target.team === team) return true;
|
|
603
|
+
const cfg = this.visionByTeam[team];
|
|
604
|
+
const scratch: BgUnit[] = [];
|
|
605
|
+
for (const w of this.nearby(target.pos.x, target.pos.y, cfg.sightYd, scratch)) {
|
|
606
|
+
if (w.team !== team || !this.alive(w)) continue;
|
|
607
|
+
if (detHypot(w.pos.x - target.pos.x, w.pos.y - target.pos.y) > cfg.sightYd) continue;
|
|
608
|
+
return true;
|
|
609
|
+
}
|
|
610
|
+
return false;
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
private toUnitView(u: BgUnit, own: boolean): BgUnitView {
|
|
614
|
+
return {
|
|
615
|
+
id: u.id,
|
|
616
|
+
team: u.team,
|
|
617
|
+
name: u.name,
|
|
618
|
+
cls: u.cls,
|
|
619
|
+
level: u.level,
|
|
620
|
+
pos: { x: u.pos.x, y: u.pos.y },
|
|
621
|
+
hpPct: u.maxHp > 0 ? (u.hp / u.maxHp) * 100 : 0,
|
|
622
|
+
alive: this.alive(u),
|
|
623
|
+
role: u.role,
|
|
624
|
+
...(u.carryingFlag ? { carryingFlag: u.carryingFlag } : {}),
|
|
625
|
+
...(u.npc ? { post: { x: u.npc.post.x, y: u.npc.post.y }, wanderYd: u.npc.wanderYd ?? 0 } : {}),
|
|
626
|
+
// An enemy's assignment is not visible; own orders are.
|
|
627
|
+
...(own ? { order: u.order } : {}),
|
|
628
|
+
};
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
// Build the per-team view — the ONLY thing a strategy may read. A carried flag is always visible,
|
|
632
|
+
// because the real client shows the carrier on both HUDs.
|
|
633
|
+
viewFor(team: BgTeam): BgView {
|
|
634
|
+
const own: BgUnitView[] = [];
|
|
635
|
+
const mine: BgUnit[] = [];
|
|
636
|
+
for (const u of this.units.values()) if (u.team === team) mine.push(u);
|
|
637
|
+
for (const u of mine) own.push(this.toUnitView(u, true));
|
|
638
|
+
|
|
639
|
+
const enemies: BgUnitView[] = [];
|
|
640
|
+
for (const u of this.units.values()) {
|
|
641
|
+
if (u.team === team) continue;
|
|
642
|
+
if (!this.alive(u)) continue;
|
|
643
|
+
if (u.carryingFlag || this.canSee(team, u)) enemies.push(this.toUnitView(u, false));
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
return {
|
|
647
|
+
team,
|
|
648
|
+
t: this.t,
|
|
649
|
+
own,
|
|
650
|
+
enemies,
|
|
651
|
+
objectives: [...this.objectives.values()].map((o) => ({ ...o })),
|
|
652
|
+
score: { ...this.score },
|
|
653
|
+
scoreboard: this.scoreboard,
|
|
654
|
+
vision: this.visionByTeam[team],
|
|
655
|
+
};
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
// ---- engagement sharding (§6c) ------------------------------------------
|
|
659
|
+
|
|
660
|
+
// Cluster units in contact into shards by single-link over `engageYd`, so a chain of fighters is
|
|
661
|
+
// one fight. Only clusters holding BOTH teams count. Neighbours come off the tick's grid, so this
|
|
662
|
+
// is O(n·k) rather than the pairwise walk it replaced.
|
|
663
|
+
rebuildShards(): BgShard[] {
|
|
664
|
+
const live: BgUnit[] = [];
|
|
665
|
+
for (const u of this.units.values()) if (this.alive(u)) live.push(u);
|
|
666
|
+
const parent = new Map<BgUnitId, BgUnitId>();
|
|
667
|
+
const find = (a: BgUnitId): BgUnitId => {
|
|
668
|
+
let r = a;
|
|
669
|
+
while (parent.get(r) !== r) r = parent.get(r)!;
|
|
670
|
+
while (parent.get(a) !== r) {
|
|
671
|
+
const nxt = parent.get(a)!;
|
|
672
|
+
parent.set(a, r);
|
|
673
|
+
a = nxt;
|
|
674
|
+
}
|
|
675
|
+
return r;
|
|
676
|
+
};
|
|
677
|
+
for (const u of live) parent.set(u.id, u.id);
|
|
678
|
+
|
|
679
|
+
const scratch: BgUnit[] = [];
|
|
680
|
+
// Pass 1: contact means an ENEMY within reach.
|
|
681
|
+
for (const a of live) {
|
|
682
|
+
for (const b of this.nearby(a.pos.x, a.pos.y, this.engageYd, scratch)) {
|
|
683
|
+
if (b.team === a.team || b.id === a.id) continue;
|
|
684
|
+
if (this.distance(a, b) > this.engageYd) continue;
|
|
685
|
+
const ra = find(a.id);
|
|
686
|
+
const rb = find(b.id);
|
|
687
|
+
if (ra !== rb) parent.set(ra, rb);
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
// A component is "engaged" once it holds both teams — the flag the same-team merge below reads.
|
|
692
|
+
// Computing it once beats the `live.some(...)` this loop used to run per pair, which made the
|
|
693
|
+
// whole walk cubic.
|
|
694
|
+
const teamsOf = new Map<BgUnitId, number>();
|
|
695
|
+
const bit = (t: BgTeam): number => (t === 'alliance' ? 1 : 2);
|
|
696
|
+
for (const u of live) {
|
|
697
|
+
const r = find(u.id);
|
|
698
|
+
teamsOf.set(r, (teamsOf.get(r) ?? 0) | bit(u.team));
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
// Pass 2: a same-team unit joins the shard of any engaged ally it is standing with.
|
|
702
|
+
for (const a of live) {
|
|
703
|
+
for (const b of this.nearby(a.pos.x, a.pos.y, this.engageYd, scratch)) {
|
|
704
|
+
if (b.team !== a.team || b.id === a.id) continue;
|
|
705
|
+
if (this.distance(a, b) > this.engageYd) continue;
|
|
706
|
+
const ra = find(a.id);
|
|
707
|
+
const rb = find(b.id);
|
|
708
|
+
if (ra === rb) continue;
|
|
709
|
+
const ta = teamsOf.get(ra) ?? 0;
|
|
710
|
+
const tb = teamsOf.get(rb) ?? 0;
|
|
711
|
+
if (ta !== 3 && tb !== 3) continue;
|
|
712
|
+
parent.set(ra, rb);
|
|
713
|
+
teamsOf.set(find(ra), ta | tb);
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
const groups = new Map<BgUnitId, BgUnitId[]>();
|
|
718
|
+
for (const u of live) {
|
|
719
|
+
const r = find(u.id);
|
|
720
|
+
const g = groups.get(r);
|
|
721
|
+
if (g) g.push(u.id);
|
|
722
|
+
else groups.set(r, [u.id]);
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
const out: BgShard[] = [];
|
|
726
|
+
for (const ids of groups.values()) {
|
|
727
|
+
if (ids.length < 2) continue;
|
|
728
|
+
const teams = new Set(ids.map((id) => this.units.get(id)!.team));
|
|
729
|
+
if (teams.size < 2) continue; // allies standing together are not a fight
|
|
730
|
+
out.push({ id: out.length, units: ids });
|
|
731
|
+
}
|
|
732
|
+
for (const u of this.units.values()) u.shard = undefined;
|
|
733
|
+
for (const s of out) for (const id of s.units) this.units.get(id)!.shard = s.id;
|
|
734
|
+
this.shards = out;
|
|
735
|
+
return out;
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
currentShards(): readonly BgShard[] {
|
|
739
|
+
return this.shards;
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
// ---- tick ---------------------------------------------------------------
|
|
743
|
+
|
|
744
|
+
/** Rebuild engagement shards each tick. Off with no ShardResolver: the union-find over every body
|
|
745
|
+
* was 12.5% of AV's CPU feeding a resolver that returns nothing (profile 2026-08-30). */
|
|
746
|
+
trackShards = true;
|
|
747
|
+
|
|
748
|
+
/** Set by the surface that also mirrors positions, from its OWN owner test, so the two are
|
|
749
|
+
* one fact. Null means the world owns every body, which is what a headless match wants. */
|
|
750
|
+
posOwnedElsewhere: ((u: BgUnit) => boolean) | null = null;
|
|
751
|
+
|
|
752
|
+
/** Hook the rules module installs: called once per tick after movement. */
|
|
753
|
+
onTick: ((world: BgWorld, dtMs: number) => void) | null = null;
|
|
754
|
+
// Where a revived unit of `team` comes back, set by the rules module. It lives at the one place a
|
|
755
|
+
// revive happens, because inferring it from full-hp guessed wrong and teleported the roster.
|
|
756
|
+
// `unit` is the corpse: AB picks the owned node's yard nearest to where you fell, which is what
|
|
757
|
+
// GraveyardManager::GetClosestGraveYard does. WSG ignores it — one yard per team.
|
|
758
|
+
graveyardOf: ((team: BgTeam, unit?: BgUnit) => BgPos) | null = null;
|
|
759
|
+
|
|
760
|
+
// Does the graveyard cycle run at all? WSG and AB leave it on; arena turns it off, because
|
|
761
|
+
// last-team-standing is not a mode you can respawn into.
|
|
762
|
+
respawns = true;
|
|
763
|
+
|
|
764
|
+
// Advance the world one order-layer tick. Pure in (state, dt): the same sequence of ticks and orders
|
|
765
|
+
// always gives the same world, which is what the lockstep barrier needs.
|
|
766
|
+
tick(dtMs = this.tickMs): BgTickStats {
|
|
767
|
+
this.t += dtMs;
|
|
768
|
+
this.searchesThisTick = 0;
|
|
769
|
+
this.regrid();
|
|
770
|
+
this.enforceStartMaxDist(dtMs);
|
|
771
|
+
|
|
772
|
+
for (const u of this.units.values()) {
|
|
773
|
+
// A finished match resurrects nobody, and a mode with no graveyard cycle never does. Without
|
|
774
|
+
// the first guard the loser stood up on the end card; without the second a partial wipe bought 30 s.
|
|
775
|
+
if (this.respawns && !this.ended && u.deadUntilMs != null && this.t >= u.deadUntilMs) {
|
|
776
|
+
// The graveyard cycle revives at the graveyard the team owns (§13b).
|
|
777
|
+
u.deadUntilMs = undefined;
|
|
778
|
+
u.hp = u.maxHp;
|
|
779
|
+
const gy = this.graveyardOf?.(u.team, u);
|
|
780
|
+
if (gy) u.pos = { x: gy.x, y: gy.y };
|
|
781
|
+
// GY rez teleports into a PvP-enforced map → CastSpell(2479).
|
|
782
|
+
// Cite: MovementHandler.cpp:241–242; Player.cpp:6861 InBattleGround.
|
|
783
|
+
this.applyHonorlessTarget(u);
|
|
784
|
+
}
|
|
785
|
+
if (!this.alive(u)) continue;
|
|
786
|
+
// Another owner writes this body's pos; stepping it here only makes a position that is
|
|
787
|
+
// discarded, after regrid and the shard walk have already read it.
|
|
788
|
+
if (this.posOwnedElsewhere?.(u)) continue;
|
|
789
|
+
this.advanceOrder(u, dtMs);
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
this.regrid(); // movement moved everyone — the rules hook and the shard walk want the new cells
|
|
793
|
+
this.onTick?.(this, dtMs);
|
|
794
|
+
this.checkTimeLimit();
|
|
795
|
+
if (!this.trackShards) {
|
|
796
|
+
this.shards = [];
|
|
797
|
+
return { t: this.t, shards: 0, engaged: 0, largestShard: 0 };
|
|
798
|
+
}
|
|
799
|
+
const shards = this.rebuildShards();
|
|
800
|
+
let engaged = 0;
|
|
801
|
+
let largest = 0;
|
|
802
|
+
for (const s of shards) {
|
|
803
|
+
engaged += s.units.length;
|
|
804
|
+
if (s.units.length > largest) largest = s.units.length;
|
|
805
|
+
}
|
|
806
|
+
return { t: this.t, shards: shards.length, engaged, largestShard: largest };
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
// End the match on the clock cap, after the rules module had its tick to win it outright. Higher
|
|
810
|
+
// score takes it; equal ends with no winner, the shape GetPrematureWinner uses.
|
|
811
|
+
private checkTimeLimit(): void {
|
|
812
|
+
if (this.ended || this.timeLimitMs <= 0 || this.t < this.timeLimitMs) return;
|
|
813
|
+
this.ended = true;
|
|
814
|
+
const a = this.score.alliance;
|
|
815
|
+
const h = this.score.horde;
|
|
816
|
+
this.winner = a === h ? null : a > h ? 'alliance' : 'horde';
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
/** Kill a unit and start its graveyard timer. Cite: 30 s resurrection cycle (§13b). */
|
|
820
|
+
kill(u: BgUnit, respawnMs = 30_000): void {
|
|
821
|
+
u.hp = 0;
|
|
822
|
+
u.deadUntilMs = this.t + respawnMs;
|
|
823
|
+
u.order = { kind: 'hold' };
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
// Honorable-kill credit: `killerId` landed the blow on `victimId`. The resolver is the only place
|
|
827
|
+
// that knows, and until it said so nobody but the player banked contribution.
|
|
828
|
+
creditKill(killerId: BgUnitId, victimId: BgUnitId): void {
|
|
829
|
+
const killer = this.units.get(killerId);
|
|
830
|
+
const victim = this.units.get(victimId);
|
|
831
|
+
if (!killer || !victim || killer.team === victim.team) return;
|
|
832
|
+
// RewardHonor pays nothing while the victim holds Honorless Target 2479.
|
|
833
|
+
if (this.isHonorless(victim)) return;
|
|
834
|
+
this.killCredit.push({ killer: killerId, victim: victimId, victimLevel: victim.level });
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
/** Drain the credited kills since the last call. */
|
|
838
|
+
takeKillCredit(): Array<{ killer: BgUnitId; victim: BgUnitId; victimLevel: number }> {
|
|
839
|
+
const out = this.killCredit;
|
|
840
|
+
this.killCredit = [];
|
|
841
|
+
return out;
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
/** Nearest living enemy to `u` that `u`'s team can actually see. */
|
|
845
|
+
nearestVisibleEnemy(u: BgUnit): BgUnit | null {
|
|
846
|
+
let best: BgUnit | null = null;
|
|
847
|
+
let bestD = Infinity;
|
|
848
|
+
const scratch: BgUnit[] = [];
|
|
849
|
+
for (const o of this.nearby(u.pos.x, u.pos.y, this.visionByTeam[u.team].sightYd, scratch)) {
|
|
850
|
+
if (o.team === u.team || !this.alive(o)) continue;
|
|
851
|
+
if (!o.carryingFlag && !this.canSee(u.team, o)) continue;
|
|
852
|
+
const d = this.distance(u, o);
|
|
853
|
+
if (d < bestD) {
|
|
854
|
+
bestD = d;
|
|
855
|
+
best = o;
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
return best;
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
export { OTHER_TEAM };
|