@v12-engine/engine 0.1.0 → 0.4.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/dist/abilities/amounts.d.ts +28 -0
- package/dist/abilities/amounts.js +74 -0
- package/dist/abilities/amounts.js.map +1 -0
- package/dist/abilities/buffs.d.ts +106 -6
- package/dist/abilities/buffs.js +443 -0
- package/dist/abilities/buffs.js.map +1 -0
- package/dist/abilities/castTold.d.ts +2 -0
- package/dist/abilities/castTold.js +66 -0
- package/dist/abilities/castTold.js.map +1 -0
- package/dist/abilities/chance.d.ts +38 -0
- package/dist/abilities/chance.js +77 -0
- package/dist/abilities/chance.js.map +1 -0
- package/dist/abilities/charges.d.ts +18 -0
- package/dist/abilities/charges.js +101 -0
- package/dist/abilities/charges.js.map +1 -0
- package/dist/abilities/control.d.ts +28 -0
- package/dist/abilities/control.js +113 -0
- package/dist/abilities/control.js.map +1 -0
- package/dist/abilities/dispel.js +51 -0
- package/dist/abilities/dispel.js.map +1 -0
- package/dist/abilities/effectFields.d.ts +1 -1
- package/dist/abilities/effectFields.js +676 -0
- package/dist/abilities/effectFields.js.map +1 -0
- package/dist/abilities/effectIndex.d.ts +27 -0
- package/dist/abilities/effectIndex.js +64 -0
- package/dist/abilities/effectIndex.js.map +1 -0
- package/dist/abilities/effects/buff.d.ts +9 -3
- package/dist/abilities/effects/buff.js +84 -0
- package/dist/abilities/effects/buff.js.map +1 -0
- package/dist/abilities/effects/conditions.d.ts +2 -0
- package/dist/abilities/effects/conditions.js +41 -0
- package/dist/abilities/effects/conditions.js.map +1 -0
- package/dist/abilities/effects/core.js +54 -0
- package/dist/abilities/effects/core.js.map +1 -0
- package/dist/abilities/effects/damage.d.ts +1 -1
- package/dist/abilities/effects/damage.js +43 -0
- package/dist/abilities/effects/damage.js.map +1 -0
- package/dist/abilities/effects/heal.d.ts +2 -2
- package/dist/abilities/effects/heal.js +51 -0
- package/dist/abilities/effects/heal.js.map +1 -0
- package/dist/abilities/effects/missile.d.ts +13 -1
- package/dist/abilities/effects/missile.js +104 -0
- package/dist/abilities/effects/missile.js.map +1 -0
- package/dist/abilities/effects/morph.d.ts +5 -0
- package/dist/abilities/effects/morph.js +43 -0
- package/dist/abilities/effects/morph.js.map +1 -0
- package/dist/abilities/effects/moves.d.ts +16 -4
- package/dist/abilities/effects/moves.js +212 -0
- package/dist/abilities/effects/moves.js.map +1 -0
- package/dist/abilities/effects/passives.d.ts +19 -9
- package/dist/abilities/effects/passives.js +131 -0
- package/dist/abilities/effects/passives.js.map +1 -0
- package/dist/abilities/effects/proxy.d.ts +5 -0
- package/dist/abilities/effects/proxy.js +60 -0
- package/dist/abilities/effects/proxy.js.map +1 -0
- package/dist/abilities/effects/sight.d.ts +2 -2
- package/dist/abilities/effects/sight.js +39 -0
- package/dist/abilities/effects/sight.js.map +1 -0
- package/dist/abilities/effects/spawn.d.ts +5 -2
- package/dist/abilities/effects/spawn.js +40 -0
- package/dist/abilities/effects/spawn.js.map +1 -0
- package/dist/abilities/effects/timed.d.ts +2 -2
- package/dist/abilities/effects/timed.js +96 -0
- package/dist/abilities/effects/timed.js.map +1 -0
- package/dist/abilities/effects/trade.d.ts +1 -1
- package/dist/abilities/effects/trade.js +25 -0
- package/dist/abilities/effects/trade.js.map +1 -0
- package/dist/abilities/effects.d.ts +97 -23
- package/dist/abilities/effects.js +860 -0
- package/dist/abilities/effects.js.map +1 -0
- package/dist/abilities/land.d.ts +38 -4
- package/dist/abilities/land.js +189 -0
- package/dist/abilities/land.js.map +1 -0
- package/dist/abilities/recast.d.ts +45 -0
- package/dist/abilities/recast.js +118 -0
- package/dist/abilities/recast.js.map +1 -0
- package/dist/abilities/scaled.js +40 -0
- package/dist/abilities/scaled.js.map +1 -0
- package/dist/abilities/screen.d.ts +6 -0
- package/dist/abilities/screen.js +83 -0
- package/dist/abilities/screen.js.map +1 -0
- package/dist/abilities/shapes.d.ts +66 -0
- package/dist/abilities/shapes.js +122 -0
- package/dist/abilities/shapes.js.map +1 -0
- package/dist/abilities/text.d.ts +14 -2
- package/dist/abilities/text.js +204 -0
- package/dist/abilities/text.js.map +1 -0
- package/dist/abilities/triggers.d.ts +98 -0
- package/dist/abilities/triggers.js +351 -0
- package/dist/abilities/triggers.js.map +1 -0
- package/dist/abilityChanges.d.ts +131 -0
- package/dist/abilityChanges.js +345 -0
- package/dist/abilityChanges.js.map +1 -0
- package/dist/ai/area.d.ts +4 -1
- package/dist/ai/brain.d.ts +4 -1
- package/dist/ai/brain.js +844 -0
- package/dist/ai/brain.js.map +1 -0
- package/dist/ai/budget.js +74 -0
- package/dist/ai/budget.js.map +1 -0
- package/dist/ai/checks.d.ts +9 -1
- package/dist/ai/checks.js +242 -0
- package/dist/ai/checks.js.map +1 -0
- package/dist/ai/computer.d.ts +11 -4
- package/dist/ai/computer.js +251 -0
- package/dist/ai/computer.js.map +1 -0
- package/dist/ai/defence.d.ts +4 -0
- package/dist/ai/defence.js +430 -0
- package/dist/ai/defence.js.map +1 -0
- package/dist/ai/define.d.ts +3 -2
- package/dist/ai/define.js +31 -0
- package/dist/ai/define.js.map +1 -0
- package/dist/ai/economy.d.ts +10 -7
- package/dist/ai/economy.js +780 -0
- package/dist/ai/economy.js.map +1 -0
- package/dist/ai/geometry.js +38 -0
- package/dist/ai/geometry.js.map +1 -0
- package/dist/ai/goals.d.ts +1 -0
- package/dist/ai/goals.js +560 -0
- package/dist/ai/goals.js.map +1 -0
- package/dist/ai/knowledge.d.ts +72 -7
- package/dist/ai/knowledge.js +804 -0
- package/dist/ai/knowledge.js.map +1 -0
- package/dist/ai/lanes.d.ts +10 -2
- package/dist/ai/lanes.js +715 -0
- package/dist/ai/lanes.js.map +1 -0
- package/dist/ai/melee/build.js +264 -0
- package/dist/ai/melee/build.js.map +1 -0
- package/dist/ai/melee/goals.d.ts +7 -0
- package/dist/ai/melee/goals.js +720 -0
- package/dist/ai/melee/goals.js.map +1 -0
- package/dist/ai/melee/heroes.js +68 -0
- package/dist/ai/melee/heroes.js.map +1 -0
- package/dist/ai/melee/index.d.ts +1 -1
- package/dist/ai/melee/index.js +51 -0
- package/dist/ai/melee/index.js.map +1 -0
- package/dist/ai/melee/production.js +29 -0
- package/dist/ai/melee/production.js.map +1 -0
- package/dist/ai/melee/surrender.js +64 -0
- package/dist/ai/melee/surrender.js.map +1 -0
- package/dist/ai/micro.d.ts +9 -0
- package/dist/ai/micro.js +1316 -0
- package/dist/ai/micro.js.map +1 -0
- package/dist/ai/mission.d.ts +9 -2
- package/dist/ai/mission.js +538 -0
- package/dist/ai/mission.js.map +1 -0
- package/dist/ai/missionRules.d.ts +1 -1
- package/dist/ai/missionRules.js +26 -0
- package/dist/ai/missionRules.js.map +1 -0
- package/dist/ai/module.d.ts +6 -2
- package/dist/ai/module.js +37 -0
- package/dist/ai/module.js.map +1 -0
- package/dist/ai/options.d.ts +3 -3
- package/dist/ai/plans/build.d.ts +20 -1
- package/dist/ai/plans/build.js +608 -0
- package/dist/ai/plans/build.js.map +1 -0
- package/dist/ai/plans/placement.d.ts +4 -1
- package/dist/ai/plans/placement.js +295 -0
- package/dist/ai/plans/placement.js.map +1 -0
- package/dist/ai/plans/plans.d.ts +9 -0
- package/dist/ai/plans/plans.js +110 -0
- package/dist/ai/plans/plans.js.map +1 -0
- package/dist/ai/plans/production.d.ts +14 -2
- package/dist/ai/plans/production.js +434 -0
- package/dist/ai/plans/production.js.map +1 -0
- package/dist/ai/plans/purse.d.ts +6 -3
- package/dist/ai/plans/purse.js +139 -0
- package/dist/ai/plans/purse.js.map +1 -0
- package/dist/ai/plans/tech.d.ts +6 -0
- package/dist/ai/plans/tech.js +122 -0
- package/dist/ai/plans/tech.js.map +1 -0
- package/dist/ai/profiles.d.ts +4 -4
- package/dist/{profiles-B3NS9jwk.js → ai/profiles.js} +3 -98
- package/dist/ai/profiles.js.map +1 -0
- package/dist/ai/reach.js +54 -0
- package/dist/ai/reach.js.map +1 -0
- package/dist/ai/report.d.ts +8 -0
- package/dist/ai/report.js +87 -0
- package/dist/ai/report.js.map +1 -0
- package/dist/ai/roles.d.ts +4 -0
- package/dist/ai/roles.js +207 -0
- package/dist/ai/roles.js.map +1 -0
- package/dist/ai/rules.d.ts +8 -2
- package/dist/ai/rules.js +416 -0
- package/dist/ai/rules.js.map +1 -0
- package/dist/ai/scouting.d.ts +6 -0
- package/dist/ai/scouting.js +324 -0
- package/dist/ai/scouting.js.map +1 -0
- package/dist/ai/settings.js +99 -0
- package/dist/ai/settings.js.map +1 -0
- package/dist/ai/squads.d.ts +21 -2
- package/dist/ai/squads.js +916 -0
- package/dist/ai/squads.js.map +1 -0
- package/dist/ai/strength.js +320 -0
- package/dist/ai/strength.js.map +1 -0
- package/dist/ai/task.d.ts +3 -1
- package/dist/ai/task.js +17 -0
- package/dist/ai/task.js.map +1 -0
- package/dist/ai/tasks/attack.js +24 -0
- package/dist/ai/tasks/attack.js.map +1 -0
- package/dist/ai/tasks/capture.d.ts +3 -3
- package/dist/ai/tasks/capture.js +37 -0
- package/dist/ai/tasks/capture.js.map +1 -0
- package/dist/ai/tasks/creep.js +29 -0
- package/dist/ai/tasks/creep.js.map +1 -0
- package/dist/ai/tasks/defend.js +61 -0
- package/dist/ai/tasks/defend.js.map +1 -0
- package/dist/ai/tasks/drop.js +81 -0
- package/dist/ai/tasks/drop.js.map +1 -0
- package/dist/ai/tasks/escort.js +59 -0
- package/dist/ai/tasks/escort.js.map +1 -0
- package/dist/ai/tasks/gather.js +48 -0
- package/dist/ai/tasks/gather.js.map +1 -0
- package/dist/ai/tasks/harass.js +39 -0
- package/dist/ai/tasks/harass.js.map +1 -0
- package/dist/ai/tasks/hold.js +32 -0
- package/dist/ai/tasks/hold.js.map +1 -0
- package/dist/ai/tasks/index.js +34 -0
- package/dist/ai/tasks/index.js.map +1 -0
- package/dist/ai/tasks/move.js +26 -0
- package/dist/ai/tasks/move.js.map +1 -0
- package/dist/ai/tasks/patrol.js +59 -0
- package/dist/ai/tasks/patrol.js.map +1 -0
- package/dist/ai/tasks/retreat.js +28 -0
- package/dist/ai/tasks/retreat.js.map +1 -0
- package/dist/ai/tasks/scout.js +73 -0
- package/dist/ai/tasks/scout.js.map +1 -0
- package/dist/ai/tasks/shared.d.ts +1 -1
- package/dist/ai/tasks/shared.js +137 -0
- package/dist/ai/tasks/shared.js.map +1 -0
- package/dist/ai/team.d.ts +18 -1
- package/dist/ai/team.js +492 -0
- package/dist/ai/team.js.map +1 -0
- package/dist/ai/threat.d.ts +6 -0
- package/dist/ai/threat.js +206 -0
- package/dist/ai/threat.js.map +1 -0
- package/dist/ai/view.d.ts +21 -7
- package/dist/ai/view.js +677 -0
- package/dist/ai/view.js.map +1 -0
- package/dist/ai/waves.d.ts +6 -0
- package/dist/ai/waves.js +410 -0
- package/dist/ai/waves.js.map +1 -0
- package/dist/ai.js +54 -6239
- package/dist/aiTesting.d.ts +6 -3
- package/dist/aiTesting.js +229 -0
- package/dist/aiTesting.js.map +1 -0
- package/dist/areas.d.ts +4 -1
- package/dist/areas.js +295 -0
- package/dist/areas.js.map +1 -0
- package/dist/attacks.d.ts +3 -3
- package/dist/attacks.js +127 -0
- package/dist/attacks.js.map +1 -0
- package/dist/burning.d.ts +267 -0
- package/dist/burning.js +795 -0
- package/dist/burning.js.map +1 -0
- package/dist/bytes.js +21 -0
- package/dist/bytes.js.map +1 -0
- package/dist/callings.d.ts +71 -0
- package/dist/callings.js +157 -0
- package/dist/callings.js.map +1 -0
- package/dist/cameraOrders.d.ts +78 -0
- package/dist/cameraOrders.js +114 -0
- package/dist/cameraOrders.js.map +1 -0
- package/dist/camps.d.ts +70 -4
- package/dist/camps.js +501 -0
- package/dist/camps.js.map +1 -0
- package/dist/capture.d.ts +15 -3
- package/dist/capture.js +304 -0
- package/dist/capture.js.map +1 -0
- package/dist/cellLayers.d.ts +78 -13
- package/dist/cellLayers.js +275 -0
- package/dist/cellLayers.js.map +1 -0
- package/dist/cellPatches.d.ts +24 -0
- package/dist/cellPatches.js +73 -0
- package/dist/cellPatches.js.map +1 -0
- package/dist/cinematics.d.ts +10 -5
- package/dist/cinematics.js +161 -0
- package/dist/cinematics.js.map +1 -0
- package/dist/clock.d.ts +2 -2
- package/dist/clock.js +78 -0
- package/dist/clock.js.map +1 -0
- package/dist/commands.d.ts +36 -4
- package/dist/commands.js +636 -0
- package/dist/commands.js.map +1 -0
- package/dist/components.d.ts +31 -10
- package/dist/components.js +74 -0
- package/dist/components.js.map +1 -0
- package/dist/computers.d.ts +4 -4
- package/dist/computers.js +194 -0
- package/dist/computers.js.map +1 -0
- package/dist/concealment.d.ts +25 -2
- package/dist/concealment.js +409 -0
- package/dist/concealment.js.map +1 -0
- package/dist/coreComponents.js +130 -0
- package/dist/coreComponents.js.map +1 -0
- package/dist/createGame.d.ts +306 -0
- package/dist/createGame.js +405 -0
- package/dist/createGame.js.map +1 -0
- package/dist/dashing.d.ts +18 -2
- package/dist/dashing.js +41 -0
- package/dist/dashing.js.map +1 -0
- package/dist/debug.d.ts +8 -0
- package/dist/debug.js +5 -3
- package/dist/debug2.js +76 -0
- package/dist/debug2.js.map +1 -0
- package/dist/debugCommands.d.ts +6 -6
- package/dist/debugCommands.js +537 -0
- package/dist/debugCommands.js.map +1 -0
- package/dist/debugging.d.ts +1 -0
- package/dist/defaultSets.d.ts +183 -0
- package/dist/defaultSets.js +216 -0
- package/dist/defaultSets.js.map +1 -0
- package/dist/definitions.d.ts +6 -0
- package/dist/definitions.js +78 -0
- package/dist/definitions.js.map +1 -0
- package/dist/defs.d.ts +1895 -165
- package/dist/defs.js +380 -0
- package/dist/defs.js.map +1 -0
- package/dist/denying.d.ts +4 -4
- package/dist/denying.js +106 -0
- package/dist/denying.js.map +1 -0
- package/dist/destructibles.d.ts +2 -2
- package/dist/destructibles.js +36 -0
- package/dist/destructibles.js.map +1 -0
- package/dist/determinism.d.ts +4 -4
- package/dist/determinism.js +247 -0
- package/dist/determinism.js.map +1 -0
- package/dist/dialog.d.ts +17 -2
- package/dist/dialog.js +108 -0
- package/dist/dialog.js.map +1 -0
- package/dist/effectRefs.js +28 -0
- package/dist/effectRefs.js.map +1 -0
- package/dist/effects.d.ts +27 -11
- package/dist/effects.js +110 -0
- package/dist/effects.js.map +1 -0
- package/dist/endings.d.ts +1 -1
- package/dist/endings.js +78 -0
- package/dist/endings.js.map +1 -0
- package/dist/engagement.d.ts +40 -6
- package/dist/engagement.js +530 -0
- package/dist/engagement.js.map +1 -0
- package/dist/engineEvents.d.ts +72 -9
- package/dist/engineEvents.js +520 -0
- package/dist/engineEvents.js.map +1 -0
- package/dist/entity.d.ts +275 -26
- package/dist/entity.js +441 -0
- package/dist/entity.js.map +1 -0
- package/dist/entityIndex.d.ts +10 -3
- package/dist/entityIndex.js +149 -0
- package/dist/entityIndex.js.map +1 -0
- package/dist/errors.d.ts +6 -2
- package/dist/errors.js +59 -0
- package/dist/errors.js.map +1 -0
- package/dist/events.d.ts +11 -5
- package/dist/events.js +158 -0
- package/dist/events.js.map +1 -0
- package/dist/exactMath.js +273 -0
- package/dist/exactMath.js.map +1 -0
- package/dist/features.d.ts +1 -1
- package/dist/features.js +127 -0
- package/dist/features.js.map +1 -0
- package/dist/fields.d.ts +25 -5
- package/dist/fields.js +140 -0
- package/dist/fields.js.map +1 -0
- package/dist/fixture.d.ts +3 -3
- package/dist/fixture.js +512 -0
- package/dist/fixture.js.map +1 -0
- package/dist/fog.d.ts +26 -3
- package/dist/fog.js +333 -0
- package/dist/fog.js.map +1 -0
- package/dist/foliage.d.ts +476 -0
- package/dist/foliage.js +1478 -0
- package/dist/foliage.js.map +1 -0
- package/dist/foliageDebug.d.ts +57 -0
- package/dist/foliageDebug.js +172 -0
- package/dist/foliageDebug.js.map +1 -0
- package/dist/foliageRegrowth.d.ts +20 -0
- package/dist/foliageRegrowth.js +332 -0
- package/dist/foliageRegrowth.js.map +1 -0
- package/dist/formState.d.ts +67 -0
- package/dist/formState.js +65 -0
- package/dist/formState.js.map +1 -0
- package/dist/formation.d.ts +46 -8
- package/dist/formation.js +297 -0
- package/dist/formation.js.map +1 -0
- package/dist/forms.d.ts +58 -0
- package/dist/forms.js +146 -0
- package/dist/forms.js.map +1 -0
- package/dist/friendlyFire.d.ts +2 -2
- package/dist/friendlyFire.js +37 -0
- package/dist/friendlyFire.js.map +1 -0
- package/dist/game.d.ts +141 -48
- package/dist/game.js +834 -0
- package/dist/game.js.map +1 -0
- package/dist/gameData.d.ts +96 -22
- package/dist/gameData.js +1690 -0
- package/dist/gameData.js.map +1 -0
- package/dist/gameFiles.d.ts +3 -3
- package/dist/gameFiles.js +14 -0
- package/dist/gameFiles.js.map +1 -0
- package/dist/gates.js +92 -0
- package/dist/gates.js.map +1 -0
- package/dist/generate.d.ts +28 -1
- package/dist/generate.js +1062 -0
- package/dist/generate.js.map +1 -0
- package/dist/generateWorker.d.ts +7 -3
- package/dist/generateWorker.js +86 -0
- package/dist/generateWorker.js.map +1 -0
- package/dist/grid.d.ts +9 -0
- package/dist/grid.js +102 -0
- package/dist/grid.js.map +1 -0
- package/dist/ground.d.ts +17 -1
- package/dist/ground.js +375 -0
- package/dist/ground.js.map +1 -0
- package/dist/groundObjects.d.ts +70 -0
- package/dist/groundObjects.js +371 -0
- package/dist/groundObjects.js.map +1 -0
- package/dist/groundSpeed.d.ts +20 -3
- package/dist/groundSpeed.js +117 -0
- package/dist/groundSpeed.js.map +1 -0
- package/dist/hero.d.ts +126 -10
- package/dist/hero.js +432 -0
- package/dist/hero.js.map +1 -0
- package/dist/holds.d.ts +94 -0
- package/dist/holds.js +305 -0
- package/dist/holds.js.map +1 -0
- package/dist/home.d.ts +1 -1
- package/dist/home.js +30 -0
- package/dist/home.js.map +1 -0
- package/dist/hooks.d.ts +339 -57
- package/dist/hooks.js +105 -0
- package/dist/hooks.js.map +1 -0
- package/dist/hotReload.d.ts +6 -5
- package/dist/hotReload.js +145 -0
- package/dist/hotReload.js.map +1 -0
- package/dist/ids.d.ts +3 -3
- package/dist/ids.js +30 -0
- package/dist/ids.js.map +1 -0
- package/dist/idsFile.d.ts +36 -0
- package/dist/idsFile.js +134 -0
- package/dist/idsFile.js.map +1 -0
- package/dist/index.d.ts +105 -68
- package/dist/index.js +194 -4701
- package/dist/inspect.d.ts +29 -2
- package/dist/{inspect-D9dWHmZ0.js → inspect.js} +21 -12
- package/dist/inspect.js.map +1 -0
- package/dist/inventory.d.ts +14 -1
- package/dist/inventory.js +84 -0
- package/dist/inventory.js.map +1 -0
- package/dist/items.d.ts +136 -8
- package/dist/items.js +585 -0
- package/dist/items.js.map +1 -0
- package/dist/lanes.d.ts +12 -3
- package/dist/lanes.js +496 -0
- package/dist/lanes.js.map +1 -0
- package/dist/life.d.ts +6 -2
- package/dist/life.js +287 -0
- package/dist/life.js.map +1 -0
- package/dist/log.d.ts +26 -3
- package/dist/log.js +192 -0
- package/dist/log.js.map +1 -0
- package/dist/manaBurn.d.ts +2 -2
- package/dist/manaBurn.js +75 -0
- package/dist/manaBurn.js.map +1 -0
- package/dist/map/file.d.ts +56 -3
- package/dist/map/file.js +264 -0
- package/dist/map/file.js.map +1 -0
- package/dist/map/images.js +61 -0
- package/dist/map/images.js.map +1 -0
- package/dist/map/look.d.ts +1 -1
- package/dist/map/look.js +30 -0
- package/dist/map/look.js.map +1 -0
- package/dist/map/pathProfile.js +183 -0
- package/dist/map/pathProfile.js.map +1 -0
- package/dist/map/resize.d.ts +4 -0
- package/dist/map/resize.js +136 -0
- package/dist/map/resize.js.map +1 -0
- package/dist/map/schema.js +257 -0
- package/dist/map/schema.js.map +1 -0
- package/dist/map/terrain.js +214 -0
- package/dist/map/terrain.js.map +1 -0
- package/dist/map/types.d.ts +92 -13
- package/dist/map/types.js +251 -0
- package/dist/map/types.js.map +1 -0
- package/dist/mapCheck/cells.js +94 -0
- package/dist/mapCheck/cells.js.map +1 -0
- package/dist/mapCheck/rules/foliage.d.ts +9 -0
- package/dist/mapCheck/rules/foliage.js +83 -0
- package/dist/mapCheck/rules/foliage.js.map +1 -0
- package/dist/mapCheck/rules/names.js +39 -0
- package/dist/mapCheck/rules/names.js.map +1 -0
- package/dist/mapCheck/rules/objects.d.ts +1 -1
- package/dist/mapCheck/rules/objects.js +56 -0
- package/dist/mapCheck/rules/objects.js.map +1 -0
- package/dist/mapCheck/rules/paths.js +32 -0
- package/dist/mapCheck/rules/paths.js.map +1 -0
- package/dist/mapCheck/rules/players.js +20 -0
- package/dist/mapCheck/rules/players.js.map +1 -0
- package/dist/mapCheck/rules/races.js +56 -0
- package/dist/mapCheck/rules/races.js.map +1 -0
- package/dist/mapCheck/rules/random.js +47 -0
- package/dist/mapCheck/rules/random.js.map +1 -0
- package/dist/mapCheck/rules/regions.js +30 -0
- package/dist/mapCheck/rules/regions.js.map +1 -0
- package/dist/mapCheck/rules/targets.js +31 -0
- package/dist/mapCheck/rules/targets.js.map +1 -0
- package/dist/mapCheck/rules/walking.js +45 -0
- package/dist/mapCheck/rules/walking.js.map +1 -0
- package/dist/mapCheck.d.ts +2 -2
- package/dist/mapCheck.js +63 -0
- package/dist/mapCheck.js.map +1 -0
- package/dist/mapFields.d.ts +25 -2
- package/dist/mapFields.js +134 -0
- package/dist/mapFields.js.map +1 -0
- package/dist/mapFile.js +176 -0
- package/dist/mapFile.js.map +1 -0
- package/dist/mapMeasure.d.ts +8 -0
- package/dist/mapMeasure.js +283 -0
- package/dist/mapMeasure.js.map +1 -0
- package/dist/mapMerge.d.ts +1 -0
- package/dist/mapMerge.js +172 -0
- package/dist/mapMerge.js.map +1 -0
- package/dist/mapObjectives.js +138 -0
- package/dist/mapObjectives.js.map +1 -0
- package/dist/mapObjects.js +80 -0
- package/dist/mapObjects.js.map +1 -0
- package/dist/math.d.ts +37 -7
- package/dist/math.js +155 -0
- package/dist/math.js.map +1 -0
- package/dist/messages.d.ts +71 -4
- package/dist/messages.js +29 -0
- package/dist/messages.js.map +1 -0
- package/dist/missionRules.d.ts +10 -2
- package/dist/{missionRules-C-bGxm0Q.js → missionRules.js} +30 -150
- package/dist/missionRules.js.map +1 -0
- package/dist/mods.d.ts +39 -20
- package/dist/mods.js +271 -0
- package/dist/mods.js.map +1 -0
- package/dist/moves.d.ts +87 -0
- package/dist/moves.js +539 -0
- package/dist/moves.js.map +1 -0
- package/dist/names.d.ts +7 -0
- package/dist/names.js +122 -0
- package/dist/names.js.map +1 -0
- package/dist/navigation/agentParams.js +14 -0
- package/dist/navigation/agentParams.js.map +1 -0
- package/dist/navigation/air.d.ts +7 -3
- package/dist/navigation/air.js +401 -0
- package/dist/navigation/air.js.map +1 -0
- package/dist/navigation/builds.d.ts +34 -2
- package/dist/navigation/builds.js +287 -0
- package/dist/navigation/builds.js.map +1 -0
- package/dist/navigation/groundAreas.d.ts +59 -1
- package/dist/navigation/groundAreas.js +407 -0
- package/dist/navigation/groundAreas.js.map +1 -0
- package/dist/navigation/navigation.d.ts +98 -9
- package/dist/navigation/recast.d.ts +194 -18
- package/dist/navigation/recast.js +1379 -0
- package/dist/navigation/recast.js.map +1 -0
- package/dist/navigation/sidePaths.d.ts +8 -3
- package/dist/navigation/sidePaths.js +241 -0
- package/dist/navigation/sidePaths.js.map +1 -0
- package/dist/navigation/sized.js +243 -0
- package/dist/navigation/sized.js.map +1 -0
- package/dist/nearest.js +32 -0
- package/dist/nearest.js.map +1 -0
- package/dist/noise.js +59 -0
- package/dist/noise.js.map +1 -0
- package/dist/objectives.d.ts +12 -3
- package/dist/objectives.js +144 -0
- package/dist/objectives.js.map +1 -0
- package/dist/orders/basic.d.ts +5 -5
- package/dist/orders/basic.js +417 -0
- package/dist/orders/basic.js.map +1 -0
- package/dist/orders/build.js +278 -0
- package/dist/orders/build.js.map +1 -0
- package/dist/orders/cast.d.ts +13 -3
- package/dist/orders/cast.js +558 -0
- package/dist/orders/cast.js.map +1 -0
- package/dist/orders/facts.js +16 -0
- package/dist/orders/facts.js.map +1 -0
- package/dist/orders/harvest.d.ts +21 -5
- package/dist/orders/harvest.js +540 -0
- package/dist/orders/harvest.js.map +1 -0
- package/dist/orders/idle.d.ts +3 -1
- package/dist/orders/idle.js +234 -0
- package/dist/orders/idle.js.map +1 -0
- package/dist/orders/items.js +92 -0
- package/dist/orders/items.js.map +1 -0
- package/dist/orders/queue.js +108 -0
- package/dist/orders/queue.js.map +1 -0
- package/dist/orders/waiting.d.ts +39 -0
- package/dist/orders/waiting.js +149 -0
- package/dist/orders/waiting.js.map +1 -0
- package/dist/pack.schema.js +13 -0
- package/dist/pack.schema.js.map +1 -0
- package/dist/pack.schema.json +7622 -841
- package/dist/packs/director/index.d.ts +13 -5
- package/dist/packs/director/index.js +204 -0
- package/dist/packs/director/index.js.map +1 -0
- package/dist/packs/heroes/campaign.d.ts +3 -2
- package/dist/packs/heroes/campaign.js +241 -0
- package/dist/packs/heroes/campaign.js.map +1 -0
- package/dist/packs/heroes/carry.d.ts +6 -0
- package/dist/packs/heroes/carry.js +112 -0
- package/dist/packs/heroes/carry.js.map +1 -0
- package/dist/packs/heroes/commands.js +115 -0
- package/dist/packs/heroes/commands.js.map +1 -0
- package/dist/packs/heroes/fallen.d.ts +43 -0
- package/dist/packs/heroes/fallen.js +61 -0
- package/dist/packs/heroes/fallen.js.map +1 -0
- package/dist/packs/heroes/hire.js +60 -0
- package/dist/packs/heroes/hire.js.map +1 -0
- package/dist/packs/heroes/index.d.ts +7 -6
- package/dist/packs/heroes/index.js +130 -0
- package/dist/packs/heroes/index.js.map +1 -0
- package/dist/packs/heroes/loop.d.ts +95 -0
- package/dist/packs/heroes/loop.js +250 -0
- package/dist/packs/heroes/loop.js.map +1 -0
- package/dist/packs/heroes/making.d.ts +6 -3
- package/dist/packs/heroes/making.js +55 -0
- package/dist/packs/heroes/making.js.map +1 -0
- package/dist/packs/heroes/respawn.d.ts +3 -3
- package/dist/packs/heroes/respawn.js +87 -0
- package/dist/packs/heroes/respawn.js.map +1 -0
- package/dist/packs/heroes/sets.d.ts +32 -0
- package/dist/packs/heroes/sets.js +51 -0
- package/dist/packs/heroes/sets.js.map +1 -0
- package/dist/packs/heroes/spells.d.ts +16 -0
- package/dist/packs/heroes/spells.js +269 -0
- package/dist/packs/heroes/spells.js.map +1 -0
- package/dist/packs/items/defaults.d.ts +43 -0
- package/dist/packs/items/defaults.js +1504 -0
- package/dist/packs/items/defaults.js.map +1 -0
- package/dist/packs/items/index.d.ts +27 -0
- package/dist/packs/items/index.js +214 -0
- package/dist/packs/items/index.js.map +1 -0
- package/dist/packs/moba/index.d.ts +3 -3
- package/dist/packs/moba/index.js +174 -0
- package/dist/packs/moba/index.js.map +1 -0
- package/dist/packs/pack.d.ts +15 -15
- package/dist/packs/pack.js +14 -0
- package/dist/packs/pack.js.map +1 -0
- package/dist/packs.d.ts +15 -7
- package/dist/packs.js +222 -0
- package/dist/packs.js.map +1 -0
- package/dist/paths.d.ts +2 -0
- package/dist/paths.js +109 -0
- package/dist/paths.js.map +1 -0
- package/dist/plain.js +57 -0
- package/dist/plain.js.map +1 -0
- package/dist/player.d.ts +33 -10
- package/dist/player.js +159 -0
- package/dist/player.js.map +1 -0
- package/dist/portals.d.ts +1 -1
- package/dist/portals.js +194 -0
- package/dist/portals.js.map +1 -0
- package/dist/prefabs.d.ts +25 -2
- package/dist/prefabs.js +239 -0
- package/dist/prefabs.js.map +1 -0
- package/dist/presetBuildings.js +58 -0
- package/dist/presetBuildings.js.map +1 -0
- package/dist/presetFoliage.d.ts +27 -0
- package/dist/presetFoliage.js +98 -0
- package/dist/presetFoliage.js.map +1 -0
- package/dist/presetGround.js +65 -0
- package/dist/presetGround.js.map +1 -0
- package/dist/proxies.d.ts +12 -0
- package/dist/proxies.js +79 -0
- package/dist/proxies.js.map +1 -0
- package/dist/query.d.ts +56 -0
- package/dist/query.js +88 -0
- package/dist/query.js.map +1 -0
- package/dist/races.d.ts +15 -14
- package/dist/races.js +172 -0
- package/dist/races.js.map +1 -0
- package/dist/randomGroups.js +91 -0
- package/dist/randomGroups.js.map +1 -0
- package/dist/registry.d.ts +117 -53
- package/dist/registry.js +323 -0
- package/dist/registry.js.map +1 -0
- package/dist/remains.d.ts +11 -9
- package/dist/remains.js +188 -0
- package/dist/remains.js.map +1 -0
- package/dist/replication.d.ts +12 -7
- package/dist/replication.js +100 -0
- package/dist/replication.js.map +1 -0
- package/dist/rng.d.ts +2 -0
- package/dist/rng.js +40 -0
- package/dist/rng.js.map +1 -0
- package/dist/rules.d.ts +186 -99
- package/dist/rules.js +179 -0
- package/dist/rules.js.map +1 -0
- package/dist/rulesCheck.d.ts +5 -4
- package/dist/rulesCheck.js +693 -0
- package/dist/rulesCheck.js.map +1 -0
- package/dist/runes.d.ts +2 -2
- package/dist/runes.js +80 -0
- package/dist/runes.js.map +1 -0
- package/dist/save.d.ts +37 -12
- package/dist/save.js +532 -0
- package/dist/save.js.map +1 -0
- package/dist/scenario.d.ts +2 -2
- package/dist/scenario.js +99 -0
- package/dist/scenario.js.map +1 -0
- package/dist/scheduler.d.ts +3 -0
- package/dist/scheduler.js +156 -0
- package/dist/scheduler.js.map +1 -0
- package/dist/score.d.ts +19 -19
- package/dist/score.js +709 -0
- package/dist/score.js.map +1 -0
- package/dist/sequences.d.ts +10 -6
- package/dist/sequences.js +206 -0
- package/dist/sequences.js.map +1 -0
- package/dist/server/doorman.js +154 -0
- package/dist/server/doorman.js.map +1 -0
- package/dist/server/gameServer.d.ts +16 -1
- package/dist/server/gameServer.js +643 -0
- package/dist/server/gameServer.js.map +1 -0
- package/dist/server/index.d.ts +1 -1
- package/dist/server/lobby.js +199 -0
- package/dist/server/lobby.js.map +1 -0
- package/dist/server/log.js +18 -0
- package/dist/server/log.js.map +1 -0
- package/dist/server/match.js +267 -0
- package/dist/server/match.js.map +1 -0
- package/dist/server/mode.d.ts +18 -9
- package/dist/server/mode.js +220 -0
- package/dist/server/mode.js.map +1 -0
- package/dist/{navigation-worker.js → server/navigation-worker.js} +1 -1
- package/dist/server/navigation-worker.js.map +1 -0
- package/dist/server/navigation.js +39 -0
- package/dist/server/navigation.js.map +1 -0
- package/dist/server/ops.d.ts +4 -0
- package/dist/server/ops.js +137 -0
- package/dist/server/ops.js.map +1 -0
- package/dist/server/packs.d.ts +3 -3
- package/dist/server/packs.js +32 -0
- package/dist/server/packs.js.map +1 -0
- package/dist/server/ratings.d.ts +5 -0
- package/dist/server/ratings.js +104 -0
- package/dist/server/ratings.js.map +1 -0
- package/dist/server/relay.d.ts +12 -2
- package/dist/server/relay.js +144 -0
- package/dist/server/relay.js.map +1 -0
- package/dist/server/rooms.d.ts +9 -2
- package/dist/server/rooms.js +442 -0
- package/dist/server/rooms.js.map +1 -0
- package/dist/server/seat.js +116 -0
- package/dist/server/seat.js.map +1 -0
- package/dist/server/seatSettings.d.ts +3 -3
- package/dist/server/seatSettings.js +63 -0
- package/dist/server/seatSettings.js.map +1 -0
- package/dist/server/secret.js +13 -0
- package/dist/server/secret.js.map +1 -0
- package/dist/server/start.d.ts +13 -6
- package/dist/server/start.js +76 -0
- package/dist/server/start.js.map +1 -0
- package/dist/server/websocket.d.ts +9 -1
- package/dist/server/websocket.js +306 -0
- package/dist/server/websocket.js.map +1 -0
- package/dist/server.js +15 -2861
- package/dist/session/can.js +26 -0
- package/dist/session/can.js.map +1 -0
- package/dist/session/commandReplay.d.ts +8 -2
- package/dist/session/commandReplay.js +293 -0
- package/dist/session/commandReplay.js.map +1 -0
- package/dist/session/debug.js +151 -0
- package/dist/session/debug.js.map +1 -0
- package/dist/session/delay.js +62 -0
- package/dist/session/delay.js.map +1 -0
- package/dist/session/delta.d.ts +14 -1
- package/dist/session/delta.js +407 -0
- package/dist/session/delta.js.map +1 -0
- package/dist/session/entityState.js +415 -0
- package/dist/session/entityState.js.map +1 -0
- package/dist/session/local.d.ts +47 -5
- package/dist/session/local.js +670 -0
- package/dist/session/local.js.map +1 -0
- package/dist/session/memory.d.ts +20 -2
- package/dist/session/memory.js +131 -0
- package/dist/session/memory.js.map +1 -0
- package/dist/session/protocol.d.ts +325 -31
- package/dist/session/protocol.js +55 -0
- package/dist/session/protocol.js.map +1 -0
- package/dist/session/remote.d.ts +74 -12
- package/dist/session/remote.js +1394 -0
- package/dist/session/remote.js.map +1 -0
- package/dist/session/replay.d.ts +11 -2
- package/dist/session/replay.js +160 -0
- package/dist/session/replay.js.map +1 -0
- package/dist/session/seed.js +12 -0
- package/dist/session/seed.js.map +1 -0
- package/dist/session/share.d.ts +5 -1
- package/dist/session/share.js +94 -0
- package/dist/session/share.js.map +1 -0
- package/dist/session/socket.d.ts +1 -1
- package/dist/session/socket.js +29 -0
- package/dist/session/socket.js.map +1 -0
- package/dist/session/wire.d.ts +5 -0
- package/dist/session/wire.js +84 -0
- package/dist/session/wire.js.map +1 -0
- package/dist/session/worker.d.ts +77 -12
- package/dist/session/worker.js +499 -0
- package/dist/session/worker.js.map +1 -0
- package/dist/shared.d.ts +31 -5
- package/dist/shared.js +166 -0
- package/dist/shared.js.map +1 -0
- package/dist/sides.d.ts +9 -3
- package/dist/sides.js +149 -0
- package/dist/sides.js.map +1 -0
- package/dist/sight.js +85 -0
- package/dist/sight.js.map +1 -0
- package/dist/simulate-worker.js +1 -1
- package/dist/simulate.d.ts +12 -8
- package/dist/{simulate-oXBiw1Ff.js → simulate.js} +10 -11
- package/dist/simulate.js.map +1 -0
- package/dist/smart.js +77 -0
- package/dist/smart.js.map +1 -0
- package/dist/spatial.d.ts +32 -16
- package/dist/spatial.js +234 -0
- package/dist/spatial.js.map +1 -0
- package/dist/spawning.d.ts +1 -0
- package/dist/spawning.js +224 -0
- package/dist/spawning.js.map +1 -0
- package/dist/stances.d.ts +6 -3
- package/dist/stances.js +169 -0
- package/dist/stances.js.map +1 -0
- package/dist/start.d.ts +10 -10
- package/dist/start.js +75 -0
- package/dist/start.js.map +1 -0
- package/dist/stats.d.ts +42 -16
- package/dist/stats.js +290 -0
- package/dist/stats.js.map +1 -0
- package/dist/summoned.d.ts +52 -0
- package/dist/summoned.js +38 -0
- package/dist/summoned.js.map +1 -0
- package/dist/summons.d.ts +10 -13
- package/dist/summons.js +271 -0
- package/dist/summons.js.map +1 -0
- package/dist/systems/abilities.js +224 -0
- package/dist/systems/abilities.js.map +1 -0
- package/dist/systems/combat.d.ts +35 -1
- package/dist/systems/combat.js +677 -0
- package/dist/systems/combat.js.map +1 -0
- package/dist/systems/combatTold.d.ts +3 -1
- package/dist/systems/combatTold.js +85 -0
- package/dist/systems/combatTold.js.map +1 -0
- package/dist/systems/construction.js +80 -0
- package/dist/systems/construction.js.map +1 -0
- package/dist/systems/economy.d.ts +0 -6
- package/dist/systems/economy.js +128 -0
- package/dist/systems/economy.js.map +1 -0
- package/dist/systems/fog.d.ts +1 -1
- package/dist/systems/fog.js +120 -0
- package/dist/systems/fog.js.map +1 -0
- package/dist/systems/life.js +32 -0
- package/dist/systems/life.js.map +1 -0
- package/dist/systems/movement.d.ts +24 -12
- package/dist/systems/movement.js +1247 -0
- package/dist/systems/movement.js.map +1 -0
- package/dist/systems/orders.js +64 -0
- package/dist/systems/orders.js.map +1 -0
- package/dist/systems/production.js +322 -0
- package/dist/systems/production.js.map +1 -0
- package/dist/systems/productionQueue.js +120 -0
- package/dist/systems/productionQueue.js.map +1 -0
- package/dist/systems/victory.d.ts +1 -1
- package/dist/systems/victory.js +56 -0
- package/dist/systems/victory.js.map +1 -0
- package/dist/talk.d.ts +6 -6
- package/dist/talk.js +153 -0
- package/dist/talk.js.map +1 -0
- package/dist/targeting.d.ts +142 -0
- package/dist/targeting.js +49 -0
- package/dist/targeting.js.map +1 -0
- package/dist/tech.d.ts +20 -3
- package/dist/tech.js +239 -0
- package/dist/tech.js.map +1 -0
- package/dist/techTree.d.ts +7 -0
- package/dist/techTree.js +90 -0
- package/dist/techTree.js.map +1 -0
- package/dist/terrain.d.ts +59 -7
- package/dist/terrain.js +389 -0
- package/dist/terrain.js.map +1 -0
- package/dist/terrainSave.d.ts +6 -0
- package/dist/terrainSave.js +74 -0
- package/dist/terrainSave.js.map +1 -0
- package/dist/testing.d.ts +8 -7
- package/dist/testing.js +13 -739
- package/dist/testing.js.map +1 -1
- package/dist/tiles.d.ts +1 -1
- package/dist/tiles.js +43 -0
- package/dist/tiles.js.map +1 -0
- package/dist/timers.d.ts +29 -4
- package/dist/timers.js +242 -0
- package/dist/timers.js.map +1 -0
- package/dist/tomes.d.ts +4 -4
- package/dist/tomes.js +94 -0
- package/dist/tomes.js.map +1 -0
- package/dist/trade.js +103 -0
- package/dist/trade.js.map +1 -0
- package/dist/transport.d.ts +6 -1
- package/dist/transport.js +281 -0
- package/dist/transport.js.map +1 -0
- package/dist/tunables.d.ts +10 -3
- package/dist/tunables.js +56 -0
- package/dist/tunables.js.map +1 -0
- package/dist/unitResources.d.ts +67 -0
- package/dist/unitResources.js +266 -0
- package/dist/unitResources.js.map +1 -0
- package/dist/upkeep.d.ts +6 -1
- package/dist/upkeep.js +26 -0
- package/dist/upkeep.js.map +1 -0
- package/dist/veterancy.d.ts +8 -3
- package/dist/veterancy.js +131 -0
- package/dist/veterancy.js.map +1 -0
- package/dist/vision.d.ts +36 -0
- package/dist/vision.js +133 -0
- package/dist/vision.js.map +1 -0
- package/dist/walls.d.ts +1 -1
- package/dist/walls.js +278 -0
- package/dist/walls.js.map +1 -0
- package/dist/world.d.ts +606 -88
- package/dist/world.js +1263 -0
- package/dist/world.js.map +1 -0
- package/package.json +2 -2
- package/dist/ai.js.map +0 -1
- package/dist/attributes.d.ts +0 -66
- package/dist/brain-BvVdUhX8.js +0 -7659
- package/dist/brain-BvVdUhX8.js.map +0 -1
- package/dist/builds-C6LfgvEU.js +0 -460
- package/dist/builds-C6LfgvEU.js.map +0 -1
- package/dist/coreComponents-syuh2fPG.js +0 -5149
- package/dist/coreComponents-syuh2fPG.js.map +0 -1
- package/dist/debugCommands-CzjrSm66.js +0 -14739
- package/dist/debugCommands-CzjrSm66.js.map +0 -1
- package/dist/determinism-BCymQwiE.js +0 -518
- package/dist/determinism-BCymQwiE.js.map +0 -1
- package/dist/game-DiJEN-Ks.js +0 -5800
- package/dist/game-DiJEN-Ks.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/inspect-D9dWHmZ0.js.map +0 -1
- package/dist/local-Dkovq42k.js +0 -1379
- package/dist/local-Dkovq42k.js.map +0 -1
- package/dist/missionRules-C-bGxm0Q.js.map +0 -1
- package/dist/navigation-worker.js.map +0 -1
- package/dist/packs-g5thvmGn.js +0 -3199
- package/dist/packs-g5thvmGn.js.map +0 -1
- package/dist/profiles-B3NS9jwk.js.map +0 -1
- package/dist/server.js.map +0 -1
- package/dist/simulate-oXBiw1Ff.js.map +0 -1
|
@@ -0,0 +1,530 @@
|
|
|
1
|
+
import { atan2, cos, hypot, sin } from "./exactMath.js";
|
|
2
|
+
import { closestPointOnRect } from "./math.js";
|
|
3
|
+
import { statsOf } from "./stats.js";
|
|
4
|
+
import { distanceToEdge, fighting, moving } from "./entity.js";
|
|
5
|
+
import { rangeAgainst } from "./attacks.js";
|
|
6
|
+
//#region src/engagement.ts
|
|
7
|
+
/** How wide one ring of reach is: attackers whose ranges are this close fight from the same ring */
|
|
8
|
+
var BAND = 1.5;
|
|
9
|
+
/**
|
|
10
|
+
* How much farther an attack reaches a structure, whose edge is its footprint's: the navmesh keeps units a little away
|
|
11
|
+
* from walls (`engage`, the stances pack, and where an attacker stands by a building)
|
|
12
|
+
*
|
|
13
|
+
* @beta
|
|
14
|
+
*/
|
|
15
|
+
var STRUCTURE_REACH = .4;
|
|
16
|
+
/** Spots on a ring at most: past that, room is there for everyone */
|
|
17
|
+
var MOST_SLOTS = 48;
|
|
18
|
+
/**
|
|
19
|
+
* Seconds a target that could not be got at is left alone (see `shun`)
|
|
20
|
+
*
|
|
21
|
+
* @beta
|
|
22
|
+
*/
|
|
23
|
+
var SHUN_TIME = 4;
|
|
24
|
+
/**
|
|
25
|
+
* The ring an attacker fights from, by its reach: 0 for the melee
|
|
26
|
+
*
|
|
27
|
+
* @beta
|
|
28
|
+
*/
|
|
29
|
+
function bandOf(world, attacker) {
|
|
30
|
+
return Math.floor(statsOf(world, attacker).attackRange / BAND);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* The layer an attacker fights from, as the game's rules say (`RuleSettings.combat.engageLayer`)
|
|
34
|
+
*
|
|
35
|
+
* @beta
|
|
36
|
+
*/
|
|
37
|
+
function engageLayer(world, attacker) {
|
|
38
|
+
return world.settings.combat.engageLayer(world, attacker);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* The engine's: from the air for what flies, from the water for boats, from the ground for the rest
|
|
42
|
+
*
|
|
43
|
+
* @beta
|
|
44
|
+
*/
|
|
45
|
+
function defaultEngageLayer(_world, attacker) {
|
|
46
|
+
return attacker.flying ? "air" : attacker.def.naval ? "water" : "ground";
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* The engine's room around a target for attackers like this one: as many as stand side by side around it, on the ring
|
|
50
|
+
* they fight from. Few for the melee around a footman, many around a town hall, all of them for long guns
|
|
51
|
+
*
|
|
52
|
+
* @beta
|
|
53
|
+
*/
|
|
54
|
+
function defaultEngageRoom(world, target, attacker) {
|
|
55
|
+
const reach = rangeAgainst(world, attacker, target);
|
|
56
|
+
const width = attacker.def.radius * 2 + .15;
|
|
57
|
+
const footprint = target.def.footprint;
|
|
58
|
+
const edge = footprint ? 2 * (footprint.w + footprint.d) : 2 * Math.PI * target.def.radius;
|
|
59
|
+
return Math.max(1, Math.floor((edge + 2 * Math.PI * (attacker.def.radius + reach)) / width));
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* How many attackers like this one may fight the target at once, as the game's rules say (`RuleSettings.combat.engageRoom`)
|
|
63
|
+
*
|
|
64
|
+
* @beta
|
|
65
|
+
*/
|
|
66
|
+
function roomFor(world, target, attacker) {
|
|
67
|
+
return world.settings.combat.engageRoom(world, target, attacker);
|
|
68
|
+
}
|
|
69
|
+
/** Who is engaged with whom, worked out again once a tick, when first asked */
|
|
70
|
+
var index = /* @__PURE__ */ new WeakMap();
|
|
71
|
+
function engagements(world) {
|
|
72
|
+
let cached = index.get(world);
|
|
73
|
+
if (cached?.tick === world.tick) return cached.by;
|
|
74
|
+
if (!cached) index.set(world, cached = {
|
|
75
|
+
tick: world.tick,
|
|
76
|
+
by: /* @__PURE__ */ new Map()
|
|
77
|
+
});
|
|
78
|
+
cached.tick = world.tick;
|
|
79
|
+
cached.by.clear();
|
|
80
|
+
for (const entity of world.units.values()) {
|
|
81
|
+
const target = entity.get(fighting)?.engaged;
|
|
82
|
+
if (!target || !entity.alive) continue;
|
|
83
|
+
const engaged = cached.by.get(target);
|
|
84
|
+
if (engaged) engaged.all.push(entity);
|
|
85
|
+
else cached.by.set(target, {
|
|
86
|
+
all: [entity],
|
|
87
|
+
rings: void 0
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
return cached.by;
|
|
91
|
+
}
|
|
92
|
+
/** Puts the attacker on the list of what it is engaged with now, in this tick's index: others picking in the same tick see it at once */
|
|
93
|
+
function enlist(world, attacker, target) {
|
|
94
|
+
const by = engagements(world);
|
|
95
|
+
const engaged = by.get(target.id);
|
|
96
|
+
if (!engaged) by.set(target.id, {
|
|
97
|
+
all: [attacker],
|
|
98
|
+
rings: void 0
|
|
99
|
+
});
|
|
100
|
+
else {
|
|
101
|
+
engaged.all.push(attacker);
|
|
102
|
+
if (engaged.rings) join(engaged.rings, attacker, engageLayer(world, attacker), bandOf(world, attacker));
|
|
103
|
+
moved(world, target.id);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/** Takes the attacker off the list of what it was engaged with, in this tick's index */
|
|
107
|
+
function unlist(world, attacker) {
|
|
108
|
+
const id = attacker.get(fighting)?.engaged;
|
|
109
|
+
const cached = index.get(world);
|
|
110
|
+
if (!id || cached?.tick !== world.tick) return;
|
|
111
|
+
const engaged = cached.by.get(id);
|
|
112
|
+
if (!engaged || !drop(engaged.all, attacker) || !engaged.rings) return;
|
|
113
|
+
for (const ring of engaged.rings) if (drop(ring.members, attacker)) break;
|
|
114
|
+
moved(world, id);
|
|
115
|
+
}
|
|
116
|
+
/** Takes the first of the attacker off the list: whether it was on it */
|
|
117
|
+
function drop(list, attacker) {
|
|
118
|
+
const at = list.indexOf(attacker);
|
|
119
|
+
if (at >= 0) list.splice(at, 1);
|
|
120
|
+
return at >= 0;
|
|
121
|
+
}
|
|
122
|
+
/** Adds the attacker to its ring of those round a target, making the ring when it is the first of it */
|
|
123
|
+
function join(rings, attacker, layer, band) {
|
|
124
|
+
for (const ring of rings) {
|
|
125
|
+
if (ring.layer !== layer || ring.band !== band) continue;
|
|
126
|
+
ring.members.push(attacker);
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
rings.push({
|
|
130
|
+
layer,
|
|
131
|
+
band,
|
|
132
|
+
members: [attacker],
|
|
133
|
+
held: /* @__PURE__ */ new Map()
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
/** Forgets the spots held round a target as this tick's index has them: one engaged with it took or let go of one */
|
|
137
|
+
function moved(world, target) {
|
|
138
|
+
const cached = index.get(world);
|
|
139
|
+
if (cached?.tick !== world.tick) return;
|
|
140
|
+
for (const ring of cached.by.get(target)?.rings ?? []) ring.held.clear();
|
|
141
|
+
}
|
|
142
|
+
/** The ring of those engaged with the target of an attacker of that layer and band, the attacker in it if it is one */
|
|
143
|
+
function ringOf(world, target, layer, band) {
|
|
144
|
+
const engaged = engagements(world).get(target.id);
|
|
145
|
+
if (!engaged) return void 0;
|
|
146
|
+
if (!engaged.rings) {
|
|
147
|
+
engaged.rings = [];
|
|
148
|
+
for (const other of engaged.all) join(engaged.rings, other, engageLayer(world, other), bandOf(world, other));
|
|
149
|
+
}
|
|
150
|
+
for (const ring of engaged.rings) if (ring.layer === layer && ring.band === band) return ring;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Everyone fighting the target or closing in on it: of one layer only, when one is named
|
|
154
|
+
*
|
|
155
|
+
* @beta
|
|
156
|
+
*/
|
|
157
|
+
function attackersOf(world, target, layer) {
|
|
158
|
+
const all = engagements(world).get(target.id)?.all ?? [];
|
|
159
|
+
return layer === void 0 ? [...all] : all.filter((attacker) => engageLayer(world, attacker) === layer);
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* How many attackers like this one (the same layer, the same ring) the target has already, the attacker left out
|
|
163
|
+
*
|
|
164
|
+
* @beta
|
|
165
|
+
*/
|
|
166
|
+
function engagedLike(world, target, attacker) {
|
|
167
|
+
const ring = ringOf(world, target, engageLayer(world, attacker), bandOf(world, attacker));
|
|
168
|
+
let count = 0;
|
|
169
|
+
if (ring) {
|
|
170
|
+
for (const other of ring.members) if (other !== attacker) count++;
|
|
171
|
+
}
|
|
172
|
+
return count;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Whether the target has no room left for another attacker like this one
|
|
176
|
+
*
|
|
177
|
+
* @beta
|
|
178
|
+
*/
|
|
179
|
+
function isCrowded(world, target, attacker) {
|
|
180
|
+
return engagedLike(world, target, attacker) >= roomFor(world, target, attacker);
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* What the attacker is fighting or closing in on, if anything
|
|
184
|
+
*
|
|
185
|
+
* @beta
|
|
186
|
+
*/
|
|
187
|
+
function engagedWith(world, attacker) {
|
|
188
|
+
const id = attacker.get(fighting)?.engaged;
|
|
189
|
+
return id ? world.get(id) : void 0;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Marks the attacker engaged with the target, giving it a spot around it when it fights from close by (and has none
|
|
193
|
+
* there yet). The engine does this as a unit fights or closes in; a game's own fighting can too
|
|
194
|
+
*
|
|
195
|
+
* @beta
|
|
196
|
+
*/
|
|
197
|
+
function engageWith(world, attacker, target) {
|
|
198
|
+
const combat = attacker.get(fighting);
|
|
199
|
+
if (!combat) return;
|
|
200
|
+
if (combat.engaged === target.id && combat.slot !== null) return;
|
|
201
|
+
if (combat.engaged !== target.id) {
|
|
202
|
+
unlist(world, attacker);
|
|
203
|
+
enlist(world, attacker, target);
|
|
204
|
+
}
|
|
205
|
+
const had = combat.slot;
|
|
206
|
+
combat.engaged = target.id;
|
|
207
|
+
combat.slot = null;
|
|
208
|
+
if (!attacker.flying && !target.def.footprint) combat.slot = chooseSlot(world, attacker, target);
|
|
209
|
+
if (combat.slot !== had) moved(world, target.id);
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Gives the attacker engaged with the target the spot round it at that angle, seen from it: where one that waited for
|
|
213
|
+
* room goes in to (`holdOff`)
|
|
214
|
+
*
|
|
215
|
+
* @internal
|
|
216
|
+
*/
|
|
217
|
+
function takeSpot(world, attacker, target, angle) {
|
|
218
|
+
const combat = attacker.get(fighting);
|
|
219
|
+
if (!combat) return;
|
|
220
|
+
combat.slot = angle;
|
|
221
|
+
moved(world, target.id);
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Lets go of whatever the attacker was engaged with, and of its spot there. Without the world, the rest of the tick
|
|
225
|
+
* still counts it there, with its spot
|
|
226
|
+
*
|
|
227
|
+
* @beta
|
|
228
|
+
*/
|
|
229
|
+
function release(attacker, world) {
|
|
230
|
+
const combat = attacker.get(fighting);
|
|
231
|
+
if (!combat) return;
|
|
232
|
+
if (world && combat.engaged) unlist(world, attacker);
|
|
233
|
+
combat.engaged = 0;
|
|
234
|
+
combat.slot = null;
|
|
235
|
+
}
|
|
236
|
+
/** The spots others hold on the ring of an attacker that holds one there too: filled again for each such ask */
|
|
237
|
+
var others = /* @__PURE__ */ new Set();
|
|
238
|
+
var nowhere = /* @__PURE__ */ new Set();
|
|
239
|
+
/**
|
|
240
|
+
* The spots of the attacker's ring around the target that others like it hold, by number: `count` of them round it, the
|
|
241
|
+
* first straight down the z axis from the target
|
|
242
|
+
*
|
|
243
|
+
* @internal
|
|
244
|
+
*/
|
|
245
|
+
function heldSlots(world, attacker, target, count) {
|
|
246
|
+
const ring = ringOf(world, target, engageLayer(world, attacker), bandOf(world, attacker));
|
|
247
|
+
if (!ring) return nowhere;
|
|
248
|
+
const own = attacker.get(fighting)?.slot;
|
|
249
|
+
if (own !== null && own !== void 0) return spotsHeld(ring.members, attacker, count, others);
|
|
250
|
+
let held = ring.held.get(count);
|
|
251
|
+
if (!held) ring.held.set(count, held = spotsHeld(ring.members, attacker, count, /* @__PURE__ */ new Set()));
|
|
252
|
+
return held;
|
|
253
|
+
}
|
|
254
|
+
/** The spots, of `count` round a target, that those on a ring hold, the attacker left out: into `into`, emptied first */
|
|
255
|
+
function spotsHeld(members, attacker, count, into) {
|
|
256
|
+
const step = Math.PI * 2 / count;
|
|
257
|
+
into.clear();
|
|
258
|
+
for (const other of members) {
|
|
259
|
+
const slot = other.get(fighting)?.slot;
|
|
260
|
+
if (other === attacker || slot === null || slot === void 0) continue;
|
|
261
|
+
into.add((Math.round(slot / step) % count + count) % count);
|
|
262
|
+
}
|
|
263
|
+
return into;
|
|
264
|
+
}
|
|
265
|
+
/** The direction the attacker is in, seen from the target: an angle about the up axis */
|
|
266
|
+
function angleFrom(attacker, target) {
|
|
267
|
+
return atan2(attacker.pos.x - target.pos.x, attacker.pos.z - target.pos.z) + 0;
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* The k-th spot by number out from the nearest, one side and then the other: the nearest, the one past it, the one
|
|
271
|
+
* before it, two past it, and so on (the nearest as it is: a -0 stays one, as an angle of it did)
|
|
272
|
+
*/
|
|
273
|
+
var outFrom = (nearest, k) => k % 2 ? nearest + (k + 1) / 2 : nearest - k / 2;
|
|
274
|
+
/**
|
|
275
|
+
* A free spot around the target for the attacker, as an angle seen from the target: the one nearest the side it comes
|
|
276
|
+
* from, of those on its ring that no one like it holds. None when every one is held: never one held already
|
|
277
|
+
*/
|
|
278
|
+
function chooseSlot(world, attacker, target) {
|
|
279
|
+
const from = angleFrom(attacker, target);
|
|
280
|
+
const count = Math.min(roomFor(world, target, attacker), MOST_SLOTS);
|
|
281
|
+
const held = heldSlots(world, attacker, target, Math.max(count, 1));
|
|
282
|
+
if (count <= 1) return held.size ? null : from;
|
|
283
|
+
const step = Math.PI * 2 / count;
|
|
284
|
+
const nearest = Math.round(from / step);
|
|
285
|
+
for (let k = 0; k <= 2 * Math.floor(count / 2); k++) {
|
|
286
|
+
const at = outFrom(nearest, k);
|
|
287
|
+
if (!held.has((at % count + count) % count)) return at * step + 0;
|
|
288
|
+
}
|
|
289
|
+
return null;
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Where the attacker goes to fight the target from: its spot around it, out where its weapon reaches, or the target
|
|
293
|
+
* itself without one. The game's `approach` hook has the last word
|
|
294
|
+
*
|
|
295
|
+
* @beta
|
|
296
|
+
*/
|
|
297
|
+
function spotFor(world, attacker, target) {
|
|
298
|
+
const slot = attacker.get(fighting)?.engaged === target.id ? attacker.get(fighting).slot : null;
|
|
299
|
+
let point = target.pos;
|
|
300
|
+
if (slot !== null && slot !== void 0) {
|
|
301
|
+
const reach = rangeAgainst(world, attacker, target);
|
|
302
|
+
const out = Math.max(target.def.radius + attacker.def.radius + reach * .5 - .5, target.def.radius * .5);
|
|
303
|
+
point = {
|
|
304
|
+
x: target.pos.x + sin(slot) * out,
|
|
305
|
+
z: target.pos.z + cos(slot) * out
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
if (!world.hooks.has("approach")) return point;
|
|
309
|
+
return world.hooks.run("approach", {
|
|
310
|
+
attacker,
|
|
311
|
+
target,
|
|
312
|
+
point
|
|
313
|
+
}).point;
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Whether the attacker has been closing in on the target for longer than the game lets it (`RuleSettings.combat.giveUpChase`) without getting closer
|
|
317
|
+
*
|
|
318
|
+
* @beta
|
|
319
|
+
*/
|
|
320
|
+
function isBlocked(world, attacker, target) {
|
|
321
|
+
const m = attacker.get(moving);
|
|
322
|
+
if (!m || m.goalEntity !== target.id) return false;
|
|
323
|
+
return (m.status === "failed" ? Infinity : m.status === "moving" ? m.stalledTime : 0) > world.settings.combat.giveUpChase(world, attacker, target);
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Has the attacker leave the target alone for a while: not picked by itself again until then
|
|
327
|
+
*
|
|
328
|
+
* @beta
|
|
329
|
+
*/
|
|
330
|
+
function shun(world, attacker, target, seconds = 4) {
|
|
331
|
+
const combat = attacker.get(fighting);
|
|
332
|
+
if (!combat) return;
|
|
333
|
+
const until = world.time + seconds;
|
|
334
|
+
combat.shunned = (combat.shunned ?? []).filter(([id, end]) => id !== target.id && end > world.time);
|
|
335
|
+
combat.shunned.push([target.id, until]);
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Whether the attacker leaves the target alone for now (see `shun`)
|
|
339
|
+
*
|
|
340
|
+
* @beta
|
|
341
|
+
*/
|
|
342
|
+
function isShunned(world, attacker, target) {
|
|
343
|
+
const shunned = attacker.get(fighting)?.shunned;
|
|
344
|
+
if (!shunned?.length) return false;
|
|
345
|
+
for (let i = 0; i < shunned.length; i++) if (shunned[i][0] === target.id && shunned[i][1] > world.time) return true;
|
|
346
|
+
return false;
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* The engine's distance from the middle of a target at which an attacker waits for room there
|
|
350
|
+
* (`RuleSettings.combat.queueDistance`): just behind those fighting it, the target's size, two of the attacker, its reach
|
|
351
|
+
* and half a cell out
|
|
352
|
+
*
|
|
353
|
+
* @beta
|
|
354
|
+
*/
|
|
355
|
+
function defaultQueueDistance(world, attacker, target) {
|
|
356
|
+
const footprint = target.def.footprint;
|
|
357
|
+
return (footprint ? hypot(footprint.w, footprint.d) / 2 : target.def.radius) + 2 * attacker.def.radius + rangeAgainst(world, attacker, target) + .5;
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Where an attacker waits for room at a target (`holdOff`): out at the game's queue distance
|
|
361
|
+
* (`RuleSettings.combat.queueDistance`) on its own side of it, or at `angle` (seen from the target, about the up axis), on
|
|
362
|
+
* ground it can stand on
|
|
363
|
+
*
|
|
364
|
+
* @beta
|
|
365
|
+
*/
|
|
366
|
+
function queuePoint(world, attacker, target, angle = angleFrom(attacker, target)) {
|
|
367
|
+
const out = world.settings.combat.queueDistance(world, attacker, target);
|
|
368
|
+
const point = {
|
|
369
|
+
x: target.pos.x + sin(angle) * out,
|
|
370
|
+
z: target.pos.z + cos(angle) * out
|
|
371
|
+
};
|
|
372
|
+
return world.navFor(attacker).closestPoint(point, 2) ?? point;
|
|
373
|
+
}
|
|
374
|
+
/** What stands around a spot, asked of the grid again and again */
|
|
375
|
+
var around = [];
|
|
376
|
+
/**
|
|
377
|
+
* Whether no one stands on the point for the attacker to stand there: no one but itself and its target, nor an ally that
|
|
378
|
+
* would step aside for it (`RuleSettings.movement.makesWay`: standing about, or waiting as it does)
|
|
379
|
+
*/
|
|
380
|
+
function standsFree(world, attacker, target, point) {
|
|
381
|
+
const radius = attacker.def.radius;
|
|
382
|
+
for (const other of world.spatial.query(point.x, point.z, radius, around)) {
|
|
383
|
+
if (other === attacker || other === target || !other.alive || other.hidden || other.flying) continue;
|
|
384
|
+
if ((other.def.footprint ? distanceToEdge(point, other) : hypot(other.pos.x - point.x, other.pos.z - point.z) - other.def.radius) >= radius * .85) continue;
|
|
385
|
+
if (!world.areAllies(attacker.owner, other.owner) || !world.settings.movement.makesWay(world, attacker, other)) return false;
|
|
386
|
+
}
|
|
387
|
+
return true;
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Whether the attacker can walk straight to a point by a unit it fights: not through it, nor through anyone who would not
|
|
391
|
+
* step aside for it on the way. (Round a building, the way round is the navigation's, and a walk held up is given up)
|
|
392
|
+
*/
|
|
393
|
+
function clearWay(world, attacker, target, point, origin = attacker.pos) {
|
|
394
|
+
if (target.def.footprint) return true;
|
|
395
|
+
const radius = attacker.def.radius;
|
|
396
|
+
const dx = point.x - origin.x;
|
|
397
|
+
const dz = point.z - origin.z;
|
|
398
|
+
const length = hypot(dx, dz);
|
|
399
|
+
const steps = Math.ceil(length / .5);
|
|
400
|
+
for (let i = 1; i <= steps; i++) {
|
|
401
|
+
const x = origin.x + dx * i / steps;
|
|
402
|
+
const z = origin.z + dz * i / steps;
|
|
403
|
+
if (hypot(target.pos.x - x, target.pos.z - z) < target.def.radius + radius - .1) return false;
|
|
404
|
+
for (const other of world.spatial.query(x, z, radius, around)) {
|
|
405
|
+
if (other === attacker || other === target || !other.alive || other.hidden || other.flying || other.def.footprint) continue;
|
|
406
|
+
if (hypot(other.pos.x - x, other.pos.z - z) >= other.def.radius + radius - .1) continue;
|
|
407
|
+
if (!world.areAllies(attacker.owner, other.owner) || !world.settings.movement.makesWay(world, attacker, other)) return false;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
return true;
|
|
411
|
+
}
|
|
412
|
+
/** The queue point in the direction (x, z), of unit length, from the target */
|
|
413
|
+
function queueAt(world, attacker, target, x, z) {
|
|
414
|
+
const out = world.settings.combat.queueDistance(world, attacker, target);
|
|
415
|
+
return {
|
|
416
|
+
x: target.pos.x + x * out,
|
|
417
|
+
z: target.pos.z + z * out
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
/**
|
|
421
|
+
* Which way from the target the spots are that others like the attacker are on their way to (`spotFor`'s), as x, z
|
|
422
|
+
* pairs of unit length: filled again by every `findSpot`
|
|
423
|
+
*/
|
|
424
|
+
var heading = [];
|
|
425
|
+
/** Whether a place out at `out` in the direction (x, z) from the target is less than `width` from a spot in `heading` */
|
|
426
|
+
function headedFor(x, z, out, width) {
|
|
427
|
+
for (let i = 0; i < heading.length; i += 2) if (hypot(heading[i] - x, heading[i + 1] - z) * out < width) return true;
|
|
428
|
+
return false;
|
|
429
|
+
}
|
|
430
|
+
/** The place `findSpot` tries, made again for each: copied when it is the one */
|
|
431
|
+
var trying = {
|
|
432
|
+
x: 0,
|
|
433
|
+
z: 0
|
|
434
|
+
};
|
|
435
|
+
/**
|
|
436
|
+
* Where the attacker could fight the target from now: a place with room for it (`isCrowded`) where no one stands, nor
|
|
437
|
+
* is on the way to: round a unit on its ring, round a building by its sides, the nearest its own side first. `straight`
|
|
438
|
+
* (the default): only one it can walk straight to without pushing through those fighting a unit (round a building, the
|
|
439
|
+
* way round is the navigation's); false: any, however far round. None when there is no room for it or every place is
|
|
440
|
+
* taken; the target's own place for what flies. What an attacker waiting for room (`holdOff`) asks before it goes in
|
|
441
|
+
*
|
|
442
|
+
* @beta
|
|
443
|
+
*/
|
|
444
|
+
function freeSpot(world, attacker, target, straight = true) {
|
|
445
|
+
return findSpot(world, attacker, target, straight ? "straight" : "any");
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* The nearest place by angle from the attacker's side, of those with room for it, that it can go in to from outside
|
|
449
|
+
* those fighting the target (from the queue point at its angle): where an attacker whose own side is held goes round the
|
|
450
|
+
* ring to (`holdOff`). Whether it can walk straight there from where it stands is not asked
|
|
451
|
+
*
|
|
452
|
+
* @internal
|
|
453
|
+
*/
|
|
454
|
+
function ringSpot(world, attacker, target) {
|
|
455
|
+
return findSpot(world, attacker, target, "ring");
|
|
456
|
+
}
|
|
457
|
+
/**
|
|
458
|
+
* Whether an ally anchored in a fight stands on the straight way from the attacker to the place it would fight its unit
|
|
459
|
+
* target from (`spotFor`, the `approach` hook's point): what an attacker coming in on a held side finds out before it
|
|
460
|
+
* walks into their backs
|
|
461
|
+
*
|
|
462
|
+
* @internal
|
|
463
|
+
*/
|
|
464
|
+
function anchoredInWay(world, attacker, target) {
|
|
465
|
+
const slot = attacker.get(fighting)?.slot;
|
|
466
|
+
if (slot === null || slot === void 0 || target.def.footprint || attacker.flying) return false;
|
|
467
|
+
const spot = spotFor(world, attacker, target);
|
|
468
|
+
const dx = spot.x - attacker.pos.x;
|
|
469
|
+
const dz = spot.z - attacker.pos.z;
|
|
470
|
+
const length = hypot(dx, dz);
|
|
471
|
+
if (length > 12) return false;
|
|
472
|
+
const radius = attacker.def.radius;
|
|
473
|
+
const steps = Math.ceil(length / .5);
|
|
474
|
+
for (let i = 1; i <= steps; i++) {
|
|
475
|
+
const x = attacker.pos.x + dx * i / steps;
|
|
476
|
+
const z = attacker.pos.z + dz * i / steps;
|
|
477
|
+
for (const other of world.spatial.query(x, z, radius, around)) {
|
|
478
|
+
if (other === attacker || other === target || !other.alive || other.hidden || other.flying || other.def.footprint) continue;
|
|
479
|
+
if (!other.get(moving)?.anchored || !world.areAllies(attacker.owner, other.owner)) continue;
|
|
480
|
+
if (hypot(other.pos.x - x, other.pos.z - z) < other.def.radius + radius - .1) return true;
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
return false;
|
|
484
|
+
}
|
|
485
|
+
function findSpot(world, attacker, target, way) {
|
|
486
|
+
if (isCrowded(world, target, attacker)) return void 0;
|
|
487
|
+
if (attacker.flying) return target.pos;
|
|
488
|
+
const reach = rangeAgainst(world, attacker, target);
|
|
489
|
+
const footprint = target.def.footprint;
|
|
490
|
+
const margin = attacker.def.radius + Math.max(reach + (footprint ? STRUCTURE_REACH : 0) - .15, .05);
|
|
491
|
+
const out = target.def.radius + margin;
|
|
492
|
+
const width = attacker.def.radius * 2 + .15;
|
|
493
|
+
const count = Math.max(8, Math.floor((footprint ? 2 * (footprint.w + footprint.d) + 2 * Math.PI * margin : 2 * Math.PI * out) / (width / 4)));
|
|
494
|
+
const step = Math.PI * 2 / count;
|
|
495
|
+
heading.length = 0;
|
|
496
|
+
if (!footprint) for (const other of ringOf(world, target, engageLayer(world, attacker), bandOf(world, attacker))?.members ?? []) {
|
|
497
|
+
const slot = other.get(fighting)?.slot;
|
|
498
|
+
if (other === attacker || slot === null || slot === void 0 || other.get(moving)?.status !== "moving") continue;
|
|
499
|
+
heading.push(sin(slot), cos(slot));
|
|
500
|
+
}
|
|
501
|
+
const hooked = world.hooks.has("approach");
|
|
502
|
+
const nearest = Math.round(angleFrom(attacker, target) / step);
|
|
503
|
+
for (let k = 0; k <= 2 * Math.floor(count / 2); k++) {
|
|
504
|
+
const angle = outFrom(nearest, k) * step;
|
|
505
|
+
const x = sin(angle);
|
|
506
|
+
const z = cos(angle);
|
|
507
|
+
if (headedFor(x, z, out, width)) continue;
|
|
508
|
+
trying.x = target.pos.x + x * out;
|
|
509
|
+
trying.z = target.pos.z + z * out;
|
|
510
|
+
let point = footprint ? closestPointOnRect(trying, target.rect, margin) : trying;
|
|
511
|
+
if (!footprint && hooked) point = world.hooks.run("approach", {
|
|
512
|
+
attacker,
|
|
513
|
+
target,
|
|
514
|
+
point: {
|
|
515
|
+
x: trying.x,
|
|
516
|
+
z: trying.z
|
|
517
|
+
}
|
|
518
|
+
}).point;
|
|
519
|
+
if (!standsFree(world, attacker, target, point)) continue;
|
|
520
|
+
if (way !== "any" && !clearWay(world, attacker, target, point, way === "straight" ? attacker.pos : queueAt(world, attacker, target, x, z))) continue;
|
|
521
|
+
return point === trying ? {
|
|
522
|
+
x: trying.x,
|
|
523
|
+
z: trying.z
|
|
524
|
+
} : point;
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
//#endregion
|
|
528
|
+
export { SHUN_TIME, STRUCTURE_REACH, anchoredInWay, attackersOf, bandOf, defaultEngageLayer, defaultEngageRoom, defaultQueueDistance, engageLayer, engageWith, engagedLike, engagedWith, freeSpot, heldSlots, isBlocked, isCrowded, isShunned, queuePoint, release, ringSpot, roomFor, shun, spotFor, takeSpot };
|
|
529
|
+
|
|
530
|
+
//# sourceMappingURL=engagement.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engagement.js","names":[],"sources":["../src/engagement.ts"],"sourcesContent":["import { distanceToEdge, type Entity, type EntityId } from './entity'\nimport { closestPointOnRect, type Vec2 } from './math'\nimport { statsOf } from './stats'\nimport { rangeAgainst } from './attacks'\nimport type { World } from './world'\nimport { atan2, cos, hypot, sin } from './exactMath'\nimport { moving, fighting } from './entity'\n\n/*\n * Who fights whom, and where around them: so that a crowd spreads around what it fights instead of queueing behind\n * the first to get there, picks another enemy when one is full, and does not stand still behind its own.\n *\n * An attacker fighting or closing in on a target is engaged with it (`CombatState.engaged`). Around every target there\n * is room for so many attackers at once (`RuleSettings.combat.engageRoom`), counted apart for each layer they fight from\n * (`RuleSettings.combat.engageLayer`: the ground, the air, the water, or a game's own) and for how far they reach: the melee in\n * one ring, short bows in a wider one, long guns in one wider still. Melee and the like take a spot of their own on\n * their ring (`CombatState.slot`), and walk there, which is what makes them surround it. A unit that picked a target\n * itself and cannot get at it for a while (`RuleSettings.combat.giveUpChase`) lets it go, and leaves it alone for a few seconds.\n *\n * All of it is the engine's way until a game says otherwise: the rules, the `targetScore` hook (which is told how full\n * a target is) and the `approach` hook (where an attacker goes to fight). And all of it can be asked about, from here.\n */\n\n/**\n * Where an attacker fights from: `ground`, `air` and `water` for the engine, any other name for a game's own\n *\n * @beta\n */\nexport type EngageLayer = 'ground' | 'air' | 'water' | (string & {})\n\n/** How wide one ring of reach is: attackers whose ranges are this close fight from the same ring */\nconst BAND = 1.5\n/**\n * How much farther an attack reaches a structure, whose edge is its footprint's: the navmesh keeps units a little away\n * from walls (`engage`, the stances pack, and where an attacker stands by a building)\n *\n * @beta\n */\nexport const STRUCTURE_REACH = 0.4\n/** Spots on a ring at most: past that, room is there for everyone */\nconst MOST_SLOTS = 48\n/**\n * Seconds a target that could not be got at is left alone (see `shun`)\n *\n * @beta\n */\nexport const SHUN_TIME = 4\n\n/**\n * The ring an attacker fights from, by its reach: 0 for the melee\n *\n * @beta\n */\nexport function bandOf(world: World, attacker: Entity): number {\n\treturn Math.floor(statsOf(world, attacker).attackRange / BAND)\n}\n\n/**\n * The layer an attacker fights from, as the game's rules say (`RuleSettings.combat.engageLayer`)\n *\n * @beta\n */\nexport function engageLayer(world: World, attacker: Entity): EngageLayer {\n\treturn world.settings.combat.engageLayer(world, attacker)\n}\n\n/**\n * The engine's: from the air for what flies, from the water for boats, from the ground for the rest\n *\n * @beta\n */\nexport function defaultEngageLayer(_world: World, attacker: Entity): EngageLayer {\n\treturn attacker.flying ? 'air' : attacker.def.naval ? 'water' : 'ground'\n}\n\n/**\n * The engine's room around a target for attackers like this one: as many as stand side by side around it, on the ring\n * they fight from. Few for the melee around a footman, many around a town hall, all of them for long guns\n *\n * @beta\n */\nexport function defaultEngageRoom(world: World, target: Entity, attacker: Entity): number {\n\tconst reach = rangeAgainst(world, attacker, target)\n\tconst width = attacker.def.radius * 2 + 0.15\n\tconst footprint = target.def.footprint\n\tconst edge = footprint ? 2 * (footprint.w + footprint.d) : 2 * Math.PI * target.def.radius\n\treturn Math.max(1, Math.floor((edge + 2 * Math.PI * (attacker.def.radius + reach)) / width))\n}\n\n/**\n * How many attackers like this one may fight the target at once, as the game's rules say (`RuleSettings.combat.engageRoom`)\n *\n * @beta\n */\nexport function roomFor(world: World, target: Entity, attacker: Entity): number {\n\treturn world.settings.combat.engageRoom(world, target, attacker)\n}\n\n/**\n * Those engaged with one target: all of them, in the order they came, and by ring (`Ring`) once the target is asked\n * who holds what around it\n */\ninterface Engaged {\n\tall: Entity[]\n\trings: Ring[] | undefined\n}\n\n/**\n * Those of one layer and one band engaged with a target, worked out once a tick per target when first asked: an\n * attacker's band is its stats', and a crowd round one target asked that of every other, each of them, every tick.\n * And the spots they hold, by how many there are round it (`heldSlots`), worked out again once one of those engaged\n * with the target takes or lets go of one: the crowd that waits for room asks every tick, and the spots seldom change\n */\ninterface Ring {\n\tlayer: EngageLayer\n\tband: number\n\tmembers: Entity[]\n\theld: Map<number, Set<number>>\n}\n\n/** Who is engaged with whom, worked out again once a tick, when first asked */\nconst index = new WeakMap<World, { tick: number; by: Map<EntityId, Engaged> }>()\n\nfunction engagements(world: World): Map<EntityId, Engaged> {\n\tlet cached = index.get(world)\n\tif (cached?.tick === world.tick) return cached.by\n\tif (!cached) index.set(world, (cached = { tick: world.tick, by: new Map() }))\n\tcached.tick = world.tick\n\tcached.by.clear()\n\tfor (const entity of world.units.values()) {\n\t\tconst target = entity.get(fighting)?.engaged\n\t\tif (!target || !entity.alive) continue\n\t\tconst engaged = cached.by.get(target)\n\t\tif (engaged) engaged.all.push(entity)\n\t\telse cached.by.set(target, { all: [entity], rings: undefined })\n\t}\n\treturn cached.by\n}\n\n/** Puts the attacker on the list of what it is engaged with now, in this tick's index: others picking in the same tick see it at once */\nfunction enlist(world: World, attacker: Entity, target: Entity): void {\n\tconst by = engagements(world)\n\tconst engaged = by.get(target.id)\n\tif (!engaged) by.set(target.id, { all: [attacker], rings: undefined })\n\telse {\n\t\tengaged.all.push(attacker)\n\t\tif (engaged.rings) join(engaged.rings, attacker, engageLayer(world, attacker), bandOf(world, attacker))\n\t\tmoved(world, target.id)\n\t}\n}\n\n/** Takes the attacker off the list of what it was engaged with, in this tick's index */\nfunction unlist(world: World, attacker: Entity): void {\n\tconst id = attacker.get(fighting)?.engaged\n\tconst cached = index.get(world)\n\tif (!id || cached?.tick !== world.tick) return\n\tconst engaged = cached.by.get(id)\n\tif (!engaged || !drop(engaged.all, attacker) || !engaged.rings) return\n\tfor (const ring of engaged.rings) if (drop(ring.members, attacker)) break\n\tmoved(world, id)\n}\n\n/** Takes the first of the attacker off the list: whether it was on it */\nfunction drop(list: Entity[], attacker: Entity): boolean {\n\tconst at = list.indexOf(attacker)\n\tif (at >= 0) list.splice(at, 1)\n\treturn at >= 0\n}\n\n/** Adds the attacker to its ring of those round a target, making the ring when it is the first of it */\nfunction join(rings: Ring[], attacker: Entity, layer: EngageLayer, band: number): void {\n\tfor (const ring of rings) {\n\t\tif (ring.layer !== layer || ring.band !== band) continue\n\t\tring.members.push(attacker)\n\t\treturn\n\t}\n\trings.push({ layer, band, members: [attacker], held: new Map() })\n}\n\n/** Forgets the spots held round a target as this tick's index has them: one engaged with it took or let go of one */\nfunction moved(world: World, target: EntityId): void {\n\tconst cached = index.get(world)\n\tif (cached?.tick !== world.tick) return\n\tfor (const ring of cached.by.get(target)?.rings ?? []) ring.held.clear()\n}\n\n/** The ring of those engaged with the target of an attacker of that layer and band, the attacker in it if it is one */\nfunction ringOf(world: World, target: Entity, layer: EngageLayer, band: number): Ring | undefined {\n\tconst engaged = engagements(world).get(target.id)\n\tif (!engaged) return undefined\n\tif (!engaged.rings) {\n\t\tengaged.rings = []\n\t\tfor (const other of engaged.all) join(engaged.rings, other, engageLayer(world, other), bandOf(world, other))\n\t}\n\tfor (const ring of engaged.rings) if (ring.layer === layer && ring.band === band) return ring\n\treturn undefined\n}\n\n/**\n * Everyone fighting the target or closing in on it: of one layer only, when one is named\n *\n * @beta\n */\nexport function attackersOf(world: World, target: Entity, layer?: EngageLayer): Entity[] {\n\tconst all = engagements(world).get(target.id)?.all ?? []\n\treturn layer === undefined ? [...all] : all.filter((attacker) => engageLayer(world, attacker) === layer)\n}\n\n/**\n * How many attackers like this one (the same layer, the same ring) the target has already, the attacker left out\n *\n * @beta\n */\nexport function engagedLike(world: World, target: Entity, attacker: Entity): number {\n\tconst ring = ringOf(world, target, engageLayer(world, attacker), bandOf(world, attacker))\n\tlet count = 0\n\tif (ring) for (const other of ring.members) if (other !== attacker) count++\n\treturn count\n}\n\n/**\n * Whether the target has no room left for another attacker like this one\n *\n * @beta\n */\nexport function isCrowded(world: World, target: Entity, attacker: Entity): boolean {\n\treturn engagedLike(world, target, attacker) >= roomFor(world, target, attacker)\n}\n\n/**\n * What the attacker is fighting or closing in on, if anything\n *\n * @beta\n */\nexport function engagedWith(world: World, attacker: Entity): Entity | undefined {\n\tconst id = attacker.get(fighting)?.engaged\n\treturn id ? world.get(id) : undefined\n}\n\n/**\n * Marks the attacker engaged with the target, giving it a spot around it when it fights from close by (and has none\n * there yet). The engine does this as a unit fights or closes in; a game's own fighting can too\n *\n * @beta\n */\nexport function engageWith(world: World, attacker: Entity, target: Entity): void {\n\tconst combat = attacker.get(fighting)\n\tif (!combat) return\n\tif (combat.engaged === target.id && combat.slot !== null) return\n\tif (combat.engaged !== target.id) {\n\t\tunlist(world, attacker)\n\t\tenlist(world, attacker, target)\n\t}\n\tconst had = combat.slot\n\tcombat.engaged = target.id\n\tcombat.slot = null\n\t// what flies goes over, what hits a building goes to its nearest side: no spot to keep. None either when the ring is\n\t// full: it waits (`holdOff`) rather than take a place that is held\n\tif (!attacker.flying && !target.def.footprint) combat.slot = chooseSlot(world, attacker, target)\n\tif (combat.slot !== had) moved(world, target.id)\n}\n\n/**\n * Gives the attacker engaged with the target the spot round it at that angle, seen from it: where one that waited for\n * room goes in to (`holdOff`)\n *\n * @internal\n */\nexport function takeSpot(world: World, attacker: Entity, target: Entity, angle: number): void {\n\tconst combat = attacker.get(fighting)\n\tif (!combat) return\n\tcombat.slot = angle\n\tmoved(world, target.id)\n}\n\n/**\n * Lets go of whatever the attacker was engaged with, and of its spot there. Without the world, the rest of the tick\n * still counts it there, with its spot\n *\n * @beta\n */\nexport function release(attacker: Entity, world?: World): void {\n\tconst combat = attacker.get(fighting)\n\tif (!combat) return\n\tif (world && combat.engaged) unlist(world, attacker)\n\tcombat.engaged = 0\n\tcombat.slot = null\n}\n\n/** The spots others hold on the ring of an attacker that holds one there too: filled again for each such ask */\nconst others = new Set<number>()\nconst nowhere: ReadonlySet<number> = new Set()\n\n/**\n * The spots of the attacker's ring around the target that others like it hold, by number: `count` of them round it, the\n * first straight down the z axis from the target\n *\n * @internal\n */\nexport function heldSlots(world: World, attacker: Entity, target: Entity, count: number): ReadonlySet<number> {\n\tconst ring = ringOf(world, target, engageLayer(world, attacker), bandOf(world, attacker))\n\tif (!ring) return nowhere\n\t// one with no spot of its own (one asking for one, `engageWith`) has nothing of its own to leave out: what the ring\n\t// holds, as worked out already\n\tconst own = attacker.get(fighting)?.slot\n\tif (own !== null && own !== undefined) return spotsHeld(ring.members, attacker, count, others)\n\tlet held = ring.held.get(count)\n\tif (!held) ring.held.set(count, (held = spotsHeld(ring.members, attacker, count, new Set())))\n\treturn held\n}\n\n/** The spots, of `count` round a target, that those on a ring hold, the attacker left out: into `into`, emptied first */\nfunction spotsHeld(members: readonly Entity[], attacker: Entity, count: number, into: Set<number>): Set<number> {\n\tconst step = (Math.PI * 2) / count\n\tinto.clear()\n\tfor (const other of members) {\n\t\tconst slot = other.get(fighting)?.slot\n\t\tif (other === attacker || slot === null || slot === undefined) continue\n\t\tinto.add(((Math.round(slot / step) % count) + count) % count)\n\t}\n\treturn into\n}\n\n/** The direction the attacker is in, seen from the target: an angle about the up axis */\nfunction angleFrom(attacker: Entity, target: Entity): number {\n\t// `+ 0` makes a -0 (the round of a small negative, an angle of nothing below the axis) 0: a save writes -0 as 0, and a\n\t// loaded game must hold what the game it was saved from holds\n\treturn atan2(attacker.pos.x - target.pos.x, attacker.pos.z - target.pos.z) + 0\n}\n\n/**\n * The k-th spot by number out from the nearest, one side and then the other: the nearest, the one past it, the one\n * before it, two past it, and so on (the nearest as it is: a -0 stays one, as an angle of it did)\n */\nconst outFrom = (nearest: number, k: number): number => (k % 2 ? nearest + (k + 1) / 2 : nearest - k / 2)\n\n/**\n * A free spot around the target for the attacker, as an angle seen from the target: the one nearest the side it comes\n * from, of those on its ring that no one like it holds. None when every one is held: never one held already\n */\nfunction chooseSlot(world: World, attacker: Entity, target: Entity): number | null {\n\tconst from = angleFrom(attacker, target)\n\tconst count = Math.min(roomFor(world, target, attacker), MOST_SLOTS)\n\tconst held = heldSlots(world, attacker, target, Math.max(count, 1))\n\tif (count <= 1) return held.size ? null : from\n\tconst step = (Math.PI * 2) / count\n\tconst nearest = Math.round(from / step)\n\tfor (let k = 0; k <= 2 * Math.floor(count / 2); k++) {\n\t\tconst at = outFrom(nearest, k)\n\t\tif (!held.has(((at % count) + count) % count)) return at * step + 0\n\t}\n\treturn null\n}\n\n/**\n * Where the attacker goes to fight the target from: its spot around it, out where its weapon reaches, or the target\n * itself without one. The game's `approach` hook has the last word\n *\n * @beta\n */\nexport function spotFor(world: World, attacker: Entity, target: Entity): Vec2 {\n\tconst slot = attacker.get(fighting)?.engaged === target.id ? attacker.get(fighting)!.slot : null\n\tlet point: Vec2 = target.pos\n\tif (slot !== null && slot !== undefined) {\n\t\t// on its side of the target and well inside its reach, so that it walks on until it is in reach: units keep a\n\t\t// little more apart than they are wide, and a spot right at the edge of its reach is one it may never get to\n\t\tconst reach = rangeAgainst(world, attacker, target)\n\t\tconst out = Math.max(target.def.radius + attacker.def.radius + reach * 0.5 - 0.5, target.def.radius * 0.5)\n\t\tpoint = { x: target.pos.x + sin(slot) * out, z: target.pos.z + cos(slot) * out }\n\t}\n\tif (!world.hooks.has('approach')) return point\n\treturn world.hooks.run('approach', { attacker, target, point }).point\n}\n\n/**\n * Whether the attacker has been closing in on the target for longer than the game lets it (`RuleSettings.combat.giveUpChase`) without getting closer\n *\n * @beta\n */\nexport function isBlocked(world: World, attacker: Entity, target: Entity): boolean {\n\tconst m = attacker.get(moving)\n\tif (!m || m.goalEntity !== target.id) return false\n\tconst stalled = m.status === 'failed' ? Infinity : m.status === 'moving' ? m.stalledTime : 0\n\treturn stalled > world.settings.combat.giveUpChase(world, attacker, target)\n}\n\n/**\n * Has the attacker leave the target alone for a while: not picked by itself again until then\n *\n * @beta\n */\nexport function shun(world: World, attacker: Entity, target: Entity, seconds = SHUN_TIME): void {\n\tconst combat = attacker.get(fighting)\n\tif (!combat) return\n\tconst until = world.time + seconds\n\tcombat.shunned = (combat.shunned ?? []).filter(([id, end]) => id !== target.id && end > world.time)\n\tcombat.shunned.push([target.id, until])\n}\n\n/**\n * Whether the attacker leaves the target alone for now (see `shun`)\n *\n * @beta\n */\nexport function isShunned(world: World, attacker: Entity, target: Entity): boolean {\n\tconst shunned = attacker.get(fighting)?.shunned\n\tif (!shunned?.length) return false\n\tfor (let i = 0; i < shunned.length; i++) if (shunned[i][0] === target.id && shunned[i][1] > world.time) return true\n\treturn false\n}\n\n/**\n * The engine's distance from the middle of a target at which an attacker waits for room there\n * (`RuleSettings.combat.queueDistance`): just behind those fighting it, the target's size, two of the attacker, its reach\n * and half a cell out\n *\n * @beta\n */\nexport function defaultQueueDistance(world: World, attacker: Entity, target: Entity): number {\n\tconst footprint = target.def.footprint\n\tconst size = footprint ? hypot(footprint.w, footprint.d) / 2 : target.def.radius\n\treturn size + 2 * attacker.def.radius + rangeAgainst(world, attacker, target) + 0.5\n}\n\n/**\n * Where an attacker waits for room at a target (`holdOff`): out at the game's queue distance\n * (`RuleSettings.combat.queueDistance`) on its own side of it, or at `angle` (seen from the target, about the up axis), on\n * ground it can stand on\n *\n * @beta\n */\nexport function queuePoint(world: World, attacker: Entity, target: Entity, angle = angleFrom(attacker, target)): Vec2 {\n\tconst out = world.settings.combat.queueDistance(world, attacker, target)\n\tconst point = { x: target.pos.x + sin(angle) * out, z: target.pos.z + cos(angle) * out }\n\treturn world.navFor(attacker).closestPoint(point, 2) ?? point\n}\n\n/** What stands around a spot, asked of the grid again and again */\nconst around: Entity[] = []\n\n/**\n * Whether no one stands on the point for the attacker to stand there: no one but itself and its target, nor an ally that\n * would step aside for it (`RuleSettings.movement.makesWay`: standing about, or waiting as it does)\n */\nfunction standsFree(world: World, attacker: Entity, target: Entity, point: Vec2): boolean {\n\tconst radius = attacker.def.radius\n\tfor (const other of world.spatial.query(point.x, point.z, radius, around)) {\n\t\tif (other === attacker || other === target || !other.alive || other.hidden || other.flying) continue\n\t\tconst apart = other.def.footprint ? distanceToEdge(point, other) : hypot(other.pos.x - point.x, other.pos.z - point.z) - other.def.radius\n\t\t// anyone it would more than touch there stands in its place: a crowd's agents give a little\n\t\tif (apart >= radius * 0.85) continue\n\t\tif (!world.areAllies(attacker.owner, other.owner) || !world.settings.movement.makesWay(world, attacker, other)) return false\n\t}\n\treturn true\n}\n\n/**\n * Whether the attacker can walk straight to a point by a unit it fights: not through it, nor through anyone who would not\n * step aside for it on the way. (Round a building, the way round is the navigation's, and a walk held up is given up)\n */\nfunction clearWay(world: World, attacker: Entity, target: Entity, point: Vec2, origin: Vec2 = attacker.pos): boolean {\n\tif (target.def.footprint) return true\n\tconst radius = attacker.def.radius\n\tconst dx = point.x - origin.x\n\tconst dz = point.z - origin.z\n\tconst length = hypot(dx, dz)\n\tconst steps = Math.ceil(length / 0.5)\n\t// from a step off where it stands (what it stands among is no matter: it walks off) to the place itself\n\tfor (let i = 1; i <= steps; i++) {\n\t\tconst x = origin.x + (dx * i) / steps\n\t\tconst z = origin.z + (dz * i) / steps\n\t\tif (hypot(target.pos.x - x, target.pos.z - z) < target.def.radius + radius - 0.1) return false\n\t\tfor (const other of world.spatial.query(x, z, radius, around)) {\n\t\t\tif (other === attacker || other === target || !other.alive || other.hidden || other.flying || other.def.footprint) continue\n\t\t\tif (hypot(other.pos.x - x, other.pos.z - z) >= other.def.radius + radius - 0.1) continue\n\t\t\tif (!world.areAllies(attacker.owner, other.owner) || !world.settings.movement.makesWay(world, attacker, other)) return false\n\t\t}\n\t}\n\treturn true\n}\n\n/** The queue point in the direction (x, z), of unit length, from the target */\nfunction queueAt(world: World, attacker: Entity, target: Entity, x: number, z: number): Vec2 {\n\tconst out = world.settings.combat.queueDistance(world, attacker, target)\n\treturn { x: target.pos.x + x * out, z: target.pos.z + z * out }\n}\n\n/**\n * Which way from the target the spots are that others like the attacker are on their way to (`spotFor`'s), as x, z\n * pairs of unit length: filled again by every `findSpot`\n */\nconst heading: number[] = []\n\n/** Whether a place out at `out` in the direction (x, z) from the target is less than `width` from a spot in `heading` */\nfunction headedFor(x: number, z: number, out: number, width: number): boolean {\n\tfor (let i = 0; i < heading.length; i += 2) if (hypot(heading[i] - x, heading[i + 1] - z) * out < width) return true\n\treturn false\n}\n\n/** The place `findSpot` tries, made again for each: copied when it is the one */\nconst trying: Vec2 = { x: 0, z: 0 }\n\n/**\n * Where the attacker could fight the target from now: a place with room for it (`isCrowded`) where no one stands, nor\n * is on the way to: round a unit on its ring, round a building by its sides, the nearest its own side first. `straight`\n * (the default): only one it can walk straight to without pushing through those fighting a unit (round a building, the\n * way round is the navigation's); false: any, however far round. None when there is no room for it or every place is\n * taken; the target's own place for what flies. What an attacker waiting for room (`holdOff`) asks before it goes in\n *\n * @beta\n */\nexport function freeSpot(world: World, attacker: Entity, target: Entity, straight = true): Vec2 | undefined {\n\treturn findSpot(world, attacker, target, straight ? 'straight' : 'any')\n}\n\n/**\n * The nearest place by angle from the attacker's side, of those with room for it, that it can go in to from outside\n * those fighting the target (from the queue point at its angle): where an attacker whose own side is held goes round the\n * ring to (`holdOff`). Whether it can walk straight there from where it stands is not asked\n *\n * @internal\n */\nexport function ringSpot(world: World, attacker: Entity, target: Entity): Vec2 | undefined {\n\treturn findSpot(world, attacker, target, 'ring')\n}\n\n/**\n * Whether an ally anchored in a fight stands on the straight way from the attacker to the place it would fight its unit\n * target from (`spotFor`, the `approach` hook's point): what an attacker coming in on a held side finds out before it\n * walks into their backs\n *\n * @internal\n */\nexport function anchoredInWay(world: World, attacker: Entity, target: Entity): boolean {\n\tconst slot = attacker.get(fighting)?.slot\n\tif (slot === null || slot === undefined || target.def.footprint || attacker.flying) return false\n\tconst spot = spotFor(world, attacker, target)\n\tconst dx = spot.x - attacker.pos.x\n\tconst dz = spot.z - attacker.pos.z\n\tconst length = hypot(dx, dz)\n\t// far off, the way is for the navigation to find\n\tif (length > 12) return false\n\tconst radius = attacker.def.radius\n\tconst steps = Math.ceil(length / 0.5)\n\tfor (let i = 1; i <= steps; i++) {\n\t\tconst x = attacker.pos.x + (dx * i) / steps\n\t\tconst z = attacker.pos.z + (dz * i) / steps\n\t\tfor (const other of world.spatial.query(x, z, radius, around)) {\n\t\t\tif (other === attacker || other === target || !other.alive || other.hidden || other.flying || other.def.footprint) continue\n\t\t\tif (!other.get(moving)?.anchored || !world.areAllies(attacker.owner, other.owner)) continue\n\t\t\tif (hypot(other.pos.x - x, other.pos.z - z) < other.def.radius + radius - 0.1) return true\n\t\t}\n\t}\n\treturn false\n}\n\nfunction findSpot(world: World, attacker: Entity, target: Entity, way: 'any' | 'straight' | 'ring'): Vec2 | undefined {\n\tif (isCrowded(world, target, attacker)) return undefined\n\tif (attacker.flying) return target.pos\n\tconst reach = rangeAgainst(world, attacker, target)\n\tconst footprint = target.def.footprint\n\t// where it stands to hit it: out from a building's sides, or from a unit's edge, by its size and most of the way it\n\t// stops at (`engage`: a little inside its reach, the more for a building's edge)\n\tconst margin = attacker.def.radius + Math.max(reach + (footprint ? STRUCTURE_REACH : 0) - 0.15, 0.05)\n\tconst out = target.def.radius + margin\n\tconst width = attacker.def.radius * 2 + 0.15\n\t// places a quarter of a unit's width apart all the way round: those fighting stand where they got in reach, not on a grid\n\tconst count = Math.max(8, Math.floor((footprint ? 2 * (footprint.w + footprint.d) + 2 * Math.PI * margin : 2 * Math.PI * out) / (width / 4)))\n\tconst step = (Math.PI * 2) / count\n\t// those like it on their way to their spots round a unit: their places are taken\n\theading.length = 0\n\tif (!footprint) {\n\t\tfor (const other of ringOf(world, target, engageLayer(world, attacker), bandOf(world, attacker))?.members ?? []) {\n\t\t\tconst slot = other.get(fighting)?.slot\n\t\t\tif (other === attacker || slot === null || slot === undefined || other.get(moving)?.status !== 'moving') continue\n\t\t\theading.push(sin(slot), cos(slot))\n\t\t}\n\t}\n\tconst hooked = world.hooks.has('approach')\n\tconst nearest = Math.round(angleFrom(attacker, target) / step)\n\tfor (let k = 0; k <= 2 * Math.floor(count / 2); k++) {\n\t\tconst angle = outFrom(nearest, k) * step\n\t\tconst x = sin(angle)\n\t\tconst z = cos(angle)\n\t\tif (headedFor(x, z, out, width)) continue\n\t\ttrying.x = target.pos.x + x * out\n\t\ttrying.z = target.pos.z + z * out\n\t\tlet point = footprint ? closestPointOnRect(trying, target.rect, margin) : trying\n\t\t// the game's `approach` hook sees the place as it would take it, so that a flank it asks for is the one tried\n\t\tif (!footprint && hooked) point = world.hooks.run('approach', { attacker, target, point: { x: trying.x, z: trying.z } }).point\n\t\tif (!standsFree(world, attacker, target, point)) continue\n\t\tif (way !== 'any' && !clearWay(world, attacker, target, point, way === 'straight' ? attacker.pos : queueAt(world, attacker, target, x, z)))\n\t\t\tcontinue\n\t\treturn point === trying ? { x: trying.x, z: trying.z } : point\n\t}\n\treturn undefined\n}\n"],"mappings":";;;;;;;AA+BA,IAAM,OAAO;;;;;;;AAOb,IAAa,kBAAkB;;AAE/B,IAAM,aAAa;;;;;;AAMnB,IAAa,YAAY;;;;;;AAOzB,SAAgB,OAAO,OAAc,UAA0B;CAC9D,OAAO,KAAK,MAAM,QAAQ,OAAO,QAAQ,CAAC,CAAC,cAAc,IAAI;AAC9D;;;;;;AAOA,SAAgB,YAAY,OAAc,UAA+B;CACxE,OAAO,MAAM,SAAS,OAAO,YAAY,OAAO,QAAQ;AACzD;;;;;;AAOA,SAAgB,mBAAmB,QAAe,UAA+B;CAChF,OAAO,SAAS,SAAS,QAAQ,SAAS,IAAI,QAAQ,UAAU;AACjE;;;;;;;AAQA,SAAgB,kBAAkB,OAAc,QAAgB,UAA0B;CACzF,MAAM,QAAQ,aAAa,OAAO,UAAU,MAAM;CAClD,MAAM,QAAQ,SAAS,IAAI,SAAS,IAAI;CACxC,MAAM,YAAY,OAAO,IAAI;CAC7B,MAAM,OAAO,YAAY,KAAK,UAAU,IAAI,UAAU,KAAK,IAAI,KAAK,KAAK,OAAO,IAAI;CACpF,OAAO,KAAK,IAAI,GAAG,KAAK,OAAO,OAAO,IAAI,KAAK,MAAM,SAAS,IAAI,SAAS,UAAU,KAAK,CAAC;AAC5F;;;;;;AAOA,SAAgB,QAAQ,OAAc,QAAgB,UAA0B;CAC/E,OAAO,MAAM,SAAS,OAAO,WAAW,OAAO,QAAQ,QAAQ;AAChE;;AAyBA,IAAM,wBAAQ,IAAI,QAA6D;AAE/E,SAAS,YAAY,OAAsC;CAC1D,IAAI,SAAS,MAAM,IAAI,KAAK;CAC5B,IAAI,QAAQ,SAAS,MAAM,MAAM,OAAO,OAAO;CAC/C,IAAI,CAAC,QAAQ,MAAM,IAAI,OAAQ,SAAS;EAAE,MAAM,MAAM;EAAM,oBAAI,IAAI,IAAI;CAAE,CAAE;CAC5E,OAAO,OAAO,MAAM;CACpB,OAAO,GAAG,MAAM;CAChB,KAAK,MAAM,UAAU,MAAM,MAAM,OAAO,GAAG;EAC1C,MAAM,SAAS,OAAO,IAAI,QAAQ,CAAC,EAAE;EACrC,IAAI,CAAC,UAAU,CAAC,OAAO,OAAO;EAC9B,MAAM,UAAU,OAAO,GAAG,IAAI,MAAM;EACpC,IAAI,SAAS,QAAQ,IAAI,KAAK,MAAM;OAC/B,OAAO,GAAG,IAAI,QAAQ;GAAE,KAAK,CAAC,MAAM;GAAG,OAAO,KAAA;EAAU,CAAC;CAC/D;CACA,OAAO,OAAO;AACf;;AAGA,SAAS,OAAO,OAAc,UAAkB,QAAsB;CACrE,MAAM,KAAK,YAAY,KAAK;CAC5B,MAAM,UAAU,GAAG,IAAI,OAAO,EAAE;CAChC,IAAI,CAAC,SAAS,GAAG,IAAI,OAAO,IAAI;EAAE,KAAK,CAAC,QAAQ;EAAG,OAAO,KAAA;CAAU,CAAC;MAChE;EACJ,QAAQ,IAAI,KAAK,QAAQ;EACzB,IAAI,QAAQ,OAAO,KAAK,QAAQ,OAAO,UAAU,YAAY,OAAO,QAAQ,GAAG,OAAO,OAAO,QAAQ,CAAC;EACtG,MAAM,OAAO,OAAO,EAAE;CACvB;AACD;;AAGA,SAAS,OAAO,OAAc,UAAwB;CACrD,MAAM,KAAK,SAAS,IAAI,QAAQ,CAAC,EAAE;CACnC,MAAM,SAAS,MAAM,IAAI,KAAK;CAC9B,IAAI,CAAC,MAAM,QAAQ,SAAS,MAAM,MAAM;CACxC,MAAM,UAAU,OAAO,GAAG,IAAI,EAAE;CAChC,IAAI,CAAC,WAAW,CAAC,KAAK,QAAQ,KAAK,QAAQ,KAAK,CAAC,QAAQ,OAAO;CAChE,KAAK,MAAM,QAAQ,QAAQ,OAAO,IAAI,KAAK,KAAK,SAAS,QAAQ,GAAG;CACpE,MAAM,OAAO,EAAE;AAChB;;AAGA,SAAS,KAAK,MAAgB,UAA2B;CACxD,MAAM,KAAK,KAAK,QAAQ,QAAQ;CAChC,IAAI,MAAM,GAAG,KAAK,OAAO,IAAI,CAAC;CAC9B,OAAO,MAAM;AACd;;AAGA,SAAS,KAAK,OAAe,UAAkB,OAAoB,MAAoB;CACtF,KAAK,MAAM,QAAQ,OAAO;EACzB,IAAI,KAAK,UAAU,SAAS,KAAK,SAAS,MAAM;EAChD,KAAK,QAAQ,KAAK,QAAQ;EAC1B;CACD;CACA,MAAM,KAAK;EAAE;EAAO;EAAM,SAAS,CAAC,QAAQ;EAAG,sBAAM,IAAI,IAAI;CAAE,CAAC;AACjE;;AAGA,SAAS,MAAM,OAAc,QAAwB;CACpD,MAAM,SAAS,MAAM,IAAI,KAAK;CAC9B,IAAI,QAAQ,SAAS,MAAM,MAAM;CACjC,KAAK,MAAM,QAAQ,OAAO,GAAG,IAAI,MAAM,CAAC,EAAE,SAAS,CAAC,GAAG,KAAK,KAAK,MAAM;AACxE;;AAGA,SAAS,OAAO,OAAc,QAAgB,OAAoB,MAAgC;CACjG,MAAM,UAAU,YAAY,KAAK,CAAC,CAAC,IAAI,OAAO,EAAE;CAChD,IAAI,CAAC,SAAS,OAAO,KAAA;CACrB,IAAI,CAAC,QAAQ,OAAO;EACnB,QAAQ,QAAQ,CAAC;EACjB,KAAK,MAAM,SAAS,QAAQ,KAAK,KAAK,QAAQ,OAAO,OAAO,YAAY,OAAO,KAAK,GAAG,OAAO,OAAO,KAAK,CAAC;CAC5G;CACA,KAAK,MAAM,QAAQ,QAAQ,OAAO,IAAI,KAAK,UAAU,SAAS,KAAK,SAAS,MAAM,OAAO;AAE1F;;;;;;AAOA,SAAgB,YAAY,OAAc,QAAgB,OAA+B;CACxF,MAAM,MAAM,YAAY,KAAK,CAAC,CAAC,IAAI,OAAO,EAAE,CAAC,EAAE,OAAO,CAAC;CACvD,OAAO,UAAU,KAAA,IAAY,CAAC,GAAG,GAAG,IAAI,IAAI,QAAQ,aAAa,YAAY,OAAO,QAAQ,MAAM,KAAK;AACxG;;;;;;AAOA,SAAgB,YAAY,OAAc,QAAgB,UAA0B;CACnF,MAAM,OAAO,OAAO,OAAO,QAAQ,YAAY,OAAO,QAAQ,GAAG,OAAO,OAAO,QAAQ,CAAC;CACxF,IAAI,QAAQ;CACZ,IAAI,MAAW;OAAA,MAAM,SAAS,KAAK,SAAS,IAAI,UAAU,UAAU;CAAA;CACpE,OAAO;AACR;;;;;;AAOA,SAAgB,UAAU,OAAc,QAAgB,UAA2B;CAClF,OAAO,YAAY,OAAO,QAAQ,QAAQ,KAAK,QAAQ,OAAO,QAAQ,QAAQ;AAC/E;;;;;;AAOA,SAAgB,YAAY,OAAc,UAAsC;CAC/E,MAAM,KAAK,SAAS,IAAI,QAAQ,CAAC,EAAE;CACnC,OAAO,KAAK,MAAM,IAAI,EAAE,IAAI,KAAA;AAC7B;;;;;;;AAQA,SAAgB,WAAW,OAAc,UAAkB,QAAsB;CAChF,MAAM,SAAS,SAAS,IAAI,QAAQ;CACpC,IAAI,CAAC,QAAQ;CACb,IAAI,OAAO,YAAY,OAAO,MAAM,OAAO,SAAS,MAAM;CAC1D,IAAI,OAAO,YAAY,OAAO,IAAI;EACjC,OAAO,OAAO,QAAQ;EACtB,OAAO,OAAO,UAAU,MAAM;CAC/B;CACA,MAAM,MAAM,OAAO;CACnB,OAAO,UAAU,OAAO;CACxB,OAAO,OAAO;CAGd,IAAI,CAAC,SAAS,UAAU,CAAC,OAAO,IAAI,WAAW,OAAO,OAAO,WAAW,OAAO,UAAU,MAAM;CAC/F,IAAI,OAAO,SAAS,KAAK,MAAM,OAAO,OAAO,EAAE;AAChD;;;;;;;AAQA,SAAgB,SAAS,OAAc,UAAkB,QAAgB,OAAqB;CAC7F,MAAM,SAAS,SAAS,IAAI,QAAQ;CACpC,IAAI,CAAC,QAAQ;CACb,OAAO,OAAO;CACd,MAAM,OAAO,OAAO,EAAE;AACvB;;;;;;;AAQA,SAAgB,QAAQ,UAAkB,OAAqB;CAC9D,MAAM,SAAS,SAAS,IAAI,QAAQ;CACpC,IAAI,CAAC,QAAQ;CACb,IAAI,SAAS,OAAO,SAAS,OAAO,OAAO,QAAQ;CACnD,OAAO,UAAU;CACjB,OAAO,OAAO;AACf;;AAGA,IAAM,yBAAS,IAAI,IAAY;AAC/B,IAAM,0BAA+B,IAAI,IAAI;;;;;;;AAQ7C,SAAgB,UAAU,OAAc,UAAkB,QAAgB,OAAoC;CAC7G,MAAM,OAAO,OAAO,OAAO,QAAQ,YAAY,OAAO,QAAQ,GAAG,OAAO,OAAO,QAAQ,CAAC;CACxF,IAAI,CAAC,MAAM,OAAO;CAGlB,MAAM,MAAM,SAAS,IAAI,QAAQ,CAAC,EAAE;CACpC,IAAI,QAAQ,QAAQ,QAAQ,KAAA,GAAW,OAAO,UAAU,KAAK,SAAS,UAAU,OAAO,MAAM;CAC7F,IAAI,OAAO,KAAK,KAAK,IAAI,KAAK;CAC9B,IAAI,CAAC,MAAM,KAAK,KAAK,IAAI,OAAQ,OAAO,UAAU,KAAK,SAAS,UAAU,uBAAO,IAAI,IAAI,CAAC,CAAE;CAC5F,OAAO;AACR;;AAGA,SAAS,UAAU,SAA4B,UAAkB,OAAe,MAAgC;CAC/G,MAAM,OAAQ,KAAK,KAAK,IAAK;CAC7B,KAAK,MAAM;CACX,KAAK,MAAM,SAAS,SAAS;EAC5B,MAAM,OAAO,MAAM,IAAI,QAAQ,CAAC,EAAE;EAClC,IAAI,UAAU,YAAY,SAAS,QAAQ,SAAS,KAAA,GAAW;EAC/D,KAAK,KAAM,KAAK,MAAM,OAAO,IAAI,IAAI,QAAS,SAAS,KAAK;CAC7D;CACA,OAAO;AACR;;AAGA,SAAS,UAAU,UAAkB,QAAwB;CAG5D,OAAO,MAAM,SAAS,IAAI,IAAI,OAAO,IAAI,GAAG,SAAS,IAAI,IAAI,OAAO,IAAI,CAAC,IAAI;AAC9E;;;;;AAMA,IAAM,WAAW,SAAiB,MAAuB,IAAI,IAAI,WAAW,IAAI,KAAK,IAAI,UAAU,IAAI;;;;;AAMvG,SAAS,WAAW,OAAc,UAAkB,QAA+B;CAClF,MAAM,OAAO,UAAU,UAAU,MAAM;CACvC,MAAM,QAAQ,KAAK,IAAI,QAAQ,OAAO,QAAQ,QAAQ,GAAG,UAAU;CACnE,MAAM,OAAO,UAAU,OAAO,UAAU,QAAQ,KAAK,IAAI,OAAO,CAAC,CAAC;CAClE,IAAI,SAAS,GAAG,OAAO,KAAK,OAAO,OAAO;CAC1C,MAAM,OAAQ,KAAK,KAAK,IAAK;CAC7B,MAAM,UAAU,KAAK,MAAM,OAAO,IAAI;CACtC,KAAK,IAAI,IAAI,GAAG,KAAK,IAAI,KAAK,MAAM,QAAQ,CAAC,GAAG,KAAK;EACpD,MAAM,KAAK,QAAQ,SAAS,CAAC;EAC7B,IAAI,CAAC,KAAK,KAAM,KAAK,QAAS,SAAS,KAAK,GAAG,OAAO,KAAK,OAAO;CACnE;CACA,OAAO;AACR;;;;;;;AAQA,SAAgB,QAAQ,OAAc,UAAkB,QAAsB;CAC7E,MAAM,OAAO,SAAS,IAAI,QAAQ,CAAC,EAAE,YAAY,OAAO,KAAK,SAAS,IAAI,QAAQ,CAAC,CAAE,OAAO;CAC5F,IAAI,QAAc,OAAO;CACzB,IAAI,SAAS,QAAQ,SAAS,KAAA,GAAW;EAGxC,MAAM,QAAQ,aAAa,OAAO,UAAU,MAAM;EAClD,MAAM,MAAM,KAAK,IAAI,OAAO,IAAI,SAAS,SAAS,IAAI,SAAS,QAAQ,KAAM,IAAK,OAAO,IAAI,SAAS,EAAG;EACzG,QAAQ;GAAE,GAAG,OAAO,IAAI,IAAI,IAAI,IAAI,IAAI;GAAK,GAAG,OAAO,IAAI,IAAI,IAAI,IAAI,IAAI;EAAI;CAChF;CACA,IAAI,CAAC,MAAM,MAAM,IAAI,UAAU,GAAG,OAAO;CACzC,OAAO,MAAM,MAAM,IAAI,YAAY;EAAE;EAAU;EAAQ;CAAM,CAAC,CAAC,CAAC;AACjE;;;;;;AAOA,SAAgB,UAAU,OAAc,UAAkB,QAAyB;CAClF,MAAM,IAAI,SAAS,IAAI,MAAM;CAC7B,IAAI,CAAC,KAAK,EAAE,eAAe,OAAO,IAAI,OAAO;CAE7C,QADgB,EAAE,WAAW,WAAW,WAAW,EAAE,WAAW,WAAW,EAAE,cAAc,KAC1E,MAAM,SAAS,OAAO,YAAY,OAAO,UAAU,MAAM;AAC3E;;;;;;AAOA,SAAgB,KAAK,OAAc,UAAkB,QAAgB,UAAA,GAA2B;CAC/F,MAAM,SAAS,SAAS,IAAI,QAAQ;CACpC,IAAI,CAAC,QAAQ;CACb,MAAM,QAAQ,MAAM,OAAO;CAC3B,OAAO,WAAW,OAAO,WAAW,CAAC,EAAA,CAAG,QAAQ,CAAC,IAAI,SAAS,OAAO,OAAO,MAAM,MAAM,MAAM,IAAI;CAClG,OAAO,QAAQ,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC;AACvC;;;;;;AAOA,SAAgB,UAAU,OAAc,UAAkB,QAAyB;CAClF,MAAM,UAAU,SAAS,IAAI,QAAQ,CAAC,EAAE;CACxC,IAAI,CAAC,SAAS,QAAQ,OAAO;CAC7B,KAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK,IAAI,QAAQ,EAAE,CAAC,OAAO,OAAO,MAAM,QAAQ,EAAE,CAAC,KAAK,MAAM,MAAM,OAAO;CAC/G,OAAO;AACR;;;;;;;;AASA,SAAgB,qBAAqB,OAAc,UAAkB,QAAwB;CAC5F,MAAM,YAAY,OAAO,IAAI;CAE7B,QADa,YAAY,MAAM,UAAU,GAAG,UAAU,CAAC,IAAI,IAAI,OAAO,IAAI,UAC5D,IAAI,SAAS,IAAI,SAAS,aAAa,OAAO,UAAU,MAAM,IAAI;AACjF;;;;;;;;AASA,SAAgB,WAAW,OAAc,UAAkB,QAAgB,QAAQ,UAAU,UAAU,MAAM,GAAS;CACrH,MAAM,MAAM,MAAM,SAAS,OAAO,cAAc,OAAO,UAAU,MAAM;CACvE,MAAM,QAAQ;EAAE,GAAG,OAAO,IAAI,IAAI,IAAI,KAAK,IAAI;EAAK,GAAG,OAAO,IAAI,IAAI,IAAI,KAAK,IAAI;CAAI;CACvF,OAAO,MAAM,OAAO,QAAQ,CAAC,CAAC,aAAa,OAAO,CAAC,KAAK;AACzD;;AAGA,IAAM,SAAmB,CAAC;;;;;AAM1B,SAAS,WAAW,OAAc,UAAkB,QAAgB,OAAsB;CACzF,MAAM,SAAS,SAAS,IAAI;CAC5B,KAAK,MAAM,SAAS,MAAM,QAAQ,MAAM,MAAM,GAAG,MAAM,GAAG,QAAQ,MAAM,GAAG;EAC1E,IAAI,UAAU,YAAY,UAAU,UAAU,CAAC,MAAM,SAAS,MAAM,UAAU,MAAM,QAAQ;EAG5F,KAFc,MAAM,IAAI,YAAY,eAAe,OAAO,KAAK,IAAI,MAAM,MAAM,IAAI,IAAI,MAAM,GAAG,MAAM,IAAI,IAAI,MAAM,CAAC,IAAI,MAAM,IAAI,WAEtH,SAAS,KAAM;EAC5B,IAAI,CAAC,MAAM,UAAU,SAAS,OAAO,MAAM,KAAK,KAAK,CAAC,MAAM,SAAS,SAAS,SAAS,OAAO,UAAU,KAAK,GAAG,OAAO;CACxH;CACA,OAAO;AACR;;;;;AAMA,SAAS,SAAS,OAAc,UAAkB,QAAgB,OAAa,SAAe,SAAS,KAAc;CACpH,IAAI,OAAO,IAAI,WAAW,OAAO;CACjC,MAAM,SAAS,SAAS,IAAI;CAC5B,MAAM,KAAK,MAAM,IAAI,OAAO;CAC5B,MAAM,KAAK,MAAM,IAAI,OAAO;CAC5B,MAAM,SAAS,MAAM,IAAI,EAAE;CAC3B,MAAM,QAAQ,KAAK,KAAK,SAAS,EAAG;CAEpC,KAAK,IAAI,IAAI,GAAG,KAAK,OAAO,KAAK;EAChC,MAAM,IAAI,OAAO,IAAK,KAAK,IAAK;EAChC,MAAM,IAAI,OAAO,IAAK,KAAK,IAAK;EAChC,IAAI,MAAM,OAAO,IAAI,IAAI,GAAG,OAAO,IAAI,IAAI,CAAC,IAAI,OAAO,IAAI,SAAS,SAAS,IAAK,OAAO;EACzF,KAAK,MAAM,SAAS,MAAM,QAAQ,MAAM,GAAG,GAAG,QAAQ,MAAM,GAAG;GAC9D,IAAI,UAAU,YAAY,UAAU,UAAU,CAAC,MAAM,SAAS,MAAM,UAAU,MAAM,UAAU,MAAM,IAAI,WAAW;GACnH,IAAI,MAAM,MAAM,IAAI,IAAI,GAAG,MAAM,IAAI,IAAI,CAAC,KAAK,MAAM,IAAI,SAAS,SAAS,IAAK;GAChF,IAAI,CAAC,MAAM,UAAU,SAAS,OAAO,MAAM,KAAK,KAAK,CAAC,MAAM,SAAS,SAAS,SAAS,OAAO,UAAU,KAAK,GAAG,OAAO;EACxH;CACD;CACA,OAAO;AACR;;AAGA,SAAS,QAAQ,OAAc,UAAkB,QAAgB,GAAW,GAAiB;CAC5F,MAAM,MAAM,MAAM,SAAS,OAAO,cAAc,OAAO,UAAU,MAAM;CACvE,OAAO;EAAE,GAAG,OAAO,IAAI,IAAI,IAAI;EAAK,GAAG,OAAO,IAAI,IAAI,IAAI;CAAI;AAC/D;;;;;AAMA,IAAM,UAAoB,CAAC;;AAG3B,SAAS,UAAU,GAAW,GAAW,KAAa,OAAwB;CAC7E,KAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK,GAAG,IAAI,MAAM,QAAQ,KAAK,GAAG,QAAQ,IAAI,KAAK,CAAC,IAAI,MAAM,OAAO,OAAO;CAChH,OAAO;AACR;;AAGA,IAAM,SAAe;CAAE,GAAG;CAAG,GAAG;AAAE;;;;;;;;;;AAWlC,SAAgB,SAAS,OAAc,UAAkB,QAAgB,WAAW,MAAwB;CAC3G,OAAO,SAAS,OAAO,UAAU,QAAQ,WAAW,aAAa,KAAK;AACvE;;;;;;;;AASA,SAAgB,SAAS,OAAc,UAAkB,QAAkC;CAC1F,OAAO,SAAS,OAAO,UAAU,QAAQ,MAAM;AAChD;;;;;;;;AASA,SAAgB,cAAc,OAAc,UAAkB,QAAyB;CACtF,MAAM,OAAO,SAAS,IAAI,QAAQ,CAAC,EAAE;CACrC,IAAI,SAAS,QAAQ,SAAS,KAAA,KAAa,OAAO,IAAI,aAAa,SAAS,QAAQ,OAAO;CAC3F,MAAM,OAAO,QAAQ,OAAO,UAAU,MAAM;CAC5C,MAAM,KAAK,KAAK,IAAI,SAAS,IAAI;CACjC,MAAM,KAAK,KAAK,IAAI,SAAS,IAAI;CACjC,MAAM,SAAS,MAAM,IAAI,EAAE;CAE3B,IAAI,SAAS,IAAI,OAAO;CACxB,MAAM,SAAS,SAAS,IAAI;CAC5B,MAAM,QAAQ,KAAK,KAAK,SAAS,EAAG;CACpC,KAAK,IAAI,IAAI,GAAG,KAAK,OAAO,KAAK;EAChC,MAAM,IAAI,SAAS,IAAI,IAAK,KAAK,IAAK;EACtC,MAAM,IAAI,SAAS,IAAI,IAAK,KAAK,IAAK;EACtC,KAAK,MAAM,SAAS,MAAM,QAAQ,MAAM,GAAG,GAAG,QAAQ,MAAM,GAAG;GAC9D,IAAI,UAAU,YAAY,UAAU,UAAU,CAAC,MAAM,SAAS,MAAM,UAAU,MAAM,UAAU,MAAM,IAAI,WAAW;GACnH,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,EAAE,YAAY,CAAC,MAAM,UAAU,SAAS,OAAO,MAAM,KAAK,GAAG;GACnF,IAAI,MAAM,MAAM,IAAI,IAAI,GAAG,MAAM,IAAI,IAAI,CAAC,IAAI,MAAM,IAAI,SAAS,SAAS,IAAK,OAAO;EACvF;CACD;CACA,OAAO;AACR;AAEA,SAAS,SAAS,OAAc,UAAkB,QAAgB,KAAoD;CACrH,IAAI,UAAU,OAAO,QAAQ,QAAQ,GAAG,OAAO,KAAA;CAC/C,IAAI,SAAS,QAAQ,OAAO,OAAO;CACnC,MAAM,QAAQ,aAAa,OAAO,UAAU,MAAM;CAClD,MAAM,YAAY,OAAO,IAAI;CAG7B,MAAM,SAAS,SAAS,IAAI,SAAS,KAAK,IAAI,SAAS,YAAY,kBAAkB,KAAK,KAAM,GAAI;CACpG,MAAM,MAAM,OAAO,IAAI,SAAS;CAChC,MAAM,QAAQ,SAAS,IAAI,SAAS,IAAI;CAExC,MAAM,QAAQ,KAAK,IAAI,GAAG,KAAK,OAAO,YAAY,KAAK,UAAU,IAAI,UAAU,KAAK,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,QAAQ,QAAQ,EAAE,CAAC;CAC5I,MAAM,OAAQ,KAAK,KAAK,IAAK;CAE7B,QAAQ,SAAS;CACjB,IAAI,CAAC,WACJ,KAAK,MAAM,SAAS,OAAO,OAAO,QAAQ,YAAY,OAAO,QAAQ,GAAG,OAAO,OAAO,QAAQ,CAAC,CAAC,EAAE,WAAW,CAAC,GAAG;EAChH,MAAM,OAAO,MAAM,IAAI,QAAQ,CAAC,EAAE;EAClC,IAAI,UAAU,YAAY,SAAS,QAAQ,SAAS,KAAA,KAAa,MAAM,IAAI,MAAM,CAAC,EAAE,WAAW,UAAU;EACzG,QAAQ,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,CAAC;CAClC;CAED,MAAM,SAAS,MAAM,MAAM,IAAI,UAAU;CACzC,MAAM,UAAU,KAAK,MAAM,UAAU,UAAU,MAAM,IAAI,IAAI;CAC7D,KAAK,IAAI,IAAI,GAAG,KAAK,IAAI,KAAK,MAAM,QAAQ,CAAC,GAAG,KAAK;EACpD,MAAM,QAAQ,QAAQ,SAAS,CAAC,IAAI;EACpC,MAAM,IAAI,IAAI,KAAK;EACnB,MAAM,IAAI,IAAI,KAAK;EACnB,IAAI,UAAU,GAAG,GAAG,KAAK,KAAK,GAAG;EACjC,OAAO,IAAI,OAAO,IAAI,IAAI,IAAI;EAC9B,OAAO,IAAI,OAAO,IAAI,IAAI,IAAI;EAC9B,IAAI,QAAQ,YAAY,mBAAmB,QAAQ,OAAO,MAAM,MAAM,IAAI;EAE1E,IAAI,CAAC,aAAa,QAAQ,QAAQ,MAAM,MAAM,IAAI,YAAY;GAAE;GAAU;GAAQ,OAAO;IAAE,GAAG,OAAO;IAAG,GAAG,OAAO;GAAE;EAAE,CAAC,CAAC,CAAC;EACzH,IAAI,CAAC,WAAW,OAAO,UAAU,QAAQ,KAAK,GAAG;EACjD,IAAI,QAAQ,SAAS,CAAC,SAAS,OAAO,UAAU,QAAQ,OAAO,QAAQ,aAAa,SAAS,MAAM,QAAQ,OAAO,UAAU,QAAQ,GAAG,CAAC,CAAC,GACxI;EACD,OAAO,UAAU,SAAS;GAAE,GAAG,OAAO;GAAG,GAAG,OAAO;EAAE,IAAI;CAC1D;AAED"}
|