@v12-engine/engine 0.1.1 → 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,1247 @@
|
|
|
1
|
+
import { atan2, hypot } from "../exactMath.js";
|
|
2
|
+
import { closestPointOnRect, dist, rotateTowards } from "../math.js";
|
|
3
|
+
import { distanceToEdge, edgeDistance, fighting, moving } from "../entity.js";
|
|
4
|
+
import { isPhasing } from "../abilities/buffs.js";
|
|
5
|
+
import { spotFor } from "../engagement.js";
|
|
6
|
+
//#region src/systems/movement.ts
|
|
7
|
+
/**
|
|
8
|
+
* How close to a point counts as having reached it
|
|
9
|
+
*
|
|
10
|
+
* @internal
|
|
11
|
+
*/
|
|
12
|
+
var ARRIVE_RANGE = .2;
|
|
13
|
+
/** How fast a unit turns, in radians a second: its type's `turnRate`, else the game's (`RuleSettings.movement.turnRate`) */
|
|
14
|
+
var turnRateOf = (world, entity) => entity.def.turnRate ?? world.settings.movement.turnRate;
|
|
15
|
+
/**
|
|
16
|
+
* Point a unit should walk to in order to reach the target: next to its edge for structures, its spot around it for
|
|
17
|
+
* one fighting it (see `engagement.ts`)
|
|
18
|
+
*/
|
|
19
|
+
function approachPoint(world, entity, target) {
|
|
20
|
+
if (entity.flying) return target.pos;
|
|
21
|
+
if (target.def.footprint) return closestPointOnRect(entity.pos, target.rect, entity.def.radius + .15);
|
|
22
|
+
return entity.get(fighting)?.engaged === target.id ? spotFor(world, entity, target) : target.pos;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* How far along its route a unit is sent at a time (`Rules.paths: 'seen'`): as far as it sees, between 4 and 12.
|
|
26
|
+
* The navigation finds its way over that stretch with every building in it; one that changes the way is in sight, so
|
|
27
|
+
* its side sees it, and the route is planned again with it
|
|
28
|
+
*/
|
|
29
|
+
var stretchOf = (entity) => Math.min(Math.max(entity.def.sight ?? 8, 4), 12);
|
|
30
|
+
/** The team whose knowledge a ground unit's route is planned with, or none where routes know everything */
|
|
31
|
+
/** The movement of a unit this system runs for: it picks those that have one, so a unit without is a fault, said as such */
|
|
32
|
+
function movementOf(entity) {
|
|
33
|
+
const m = entity.get(moving);
|
|
34
|
+
if (!m) throw new Error(`${entity.def.id} ${entity.id} is moved but has no movement`);
|
|
35
|
+
return m;
|
|
36
|
+
}
|
|
37
|
+
function sideOf(world, entity) {
|
|
38
|
+
const paths = world.sidePaths;
|
|
39
|
+
if (!paths || entity.flying || entity.def.naval) return void 0;
|
|
40
|
+
const team = world.player(entity.owner).team;
|
|
41
|
+
return paths.has(team) ? team : void 0;
|
|
42
|
+
}
|
|
43
|
+
/** Plans a unit's route to its goal with what its side knows: none where its side knows no way, or the goal is in sight */
|
|
44
|
+
function planRoute(world, entity, team) {
|
|
45
|
+
const m = movementOf(entity);
|
|
46
|
+
const paths = world.sidePaths;
|
|
47
|
+
if (!paths) return;
|
|
48
|
+
m.routeVersion = paths.version(team);
|
|
49
|
+
m.routeAt = 1;
|
|
50
|
+
if (dist(entity.pos, m.navGoal) <= stretchOf(entity)) {
|
|
51
|
+
m.route = void 0;
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const route = paths.route(team, entity.pos, m.navGoal);
|
|
55
|
+
m.route = route && route.length > 1 ? route.map(({ x, z }) => ({
|
|
56
|
+
x,
|
|
57
|
+
z
|
|
58
|
+
})) : void 0;
|
|
59
|
+
}
|
|
60
|
+
/** How far a point is from a segment */
|
|
61
|
+
function distToSegment(p, a, b) {
|
|
62
|
+
const dx = b.x - a.x;
|
|
63
|
+
const dz = b.z - a.z;
|
|
64
|
+
const length = dx * dx + dz * dz;
|
|
65
|
+
const t = length > 0 ? Math.min(Math.max(((p.x - a.x) * dx + (p.z - a.z) * dz) / length, 0), 1) : 0;
|
|
66
|
+
return hypot(p.x - (a.x + dx * t), p.z - (a.z + dz * t));
|
|
67
|
+
}
|
|
68
|
+
/** The point a stretch ahead of a unit along its route; its goal itself once that is within the stretch */
|
|
69
|
+
function stretchPoint(entity) {
|
|
70
|
+
const m = movementOf(entity);
|
|
71
|
+
const route = m.route;
|
|
72
|
+
if (!route) return m.navGoal;
|
|
73
|
+
let leg = Math.max((m.routeAt ?? 1) - 1, 0);
|
|
74
|
+
let nearest = Infinity;
|
|
75
|
+
for (let i = leg; i < route.length - 1; i++) {
|
|
76
|
+
const d = distToSegment(entity.pos, route[i], route[i + 1]);
|
|
77
|
+
if (d < nearest - 1e-9) {
|
|
78
|
+
nearest = d;
|
|
79
|
+
leg = i;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
const at = Math.min(leg + 1, route.length - 1);
|
|
83
|
+
m.routeAt = at;
|
|
84
|
+
let left = stretchOf(entity);
|
|
85
|
+
let from = entity.pos;
|
|
86
|
+
for (let i = at; i < route.length; i++) {
|
|
87
|
+
const length = dist(from, route[i]);
|
|
88
|
+
if (length >= left) {
|
|
89
|
+
const t = left / length;
|
|
90
|
+
return {
|
|
91
|
+
x: from.x + (route[i].x - from.x) * t,
|
|
92
|
+
z: from.z + (route[i].z - from.z) * t
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
left -= length;
|
|
96
|
+
from = route[i];
|
|
97
|
+
}
|
|
98
|
+
return m.navGoal;
|
|
99
|
+
}
|
|
100
|
+
/** Sends the navigation where the unit is to walk now: its goal, or a stretch along its route */
|
|
101
|
+
function walk(world, entity) {
|
|
102
|
+
const m = movementOf(entity);
|
|
103
|
+
const to = m.route ? stretchPoint(entity) : m.navGoal;
|
|
104
|
+
m.stretch = m.route ? {
|
|
105
|
+
x: to.x,
|
|
106
|
+
z: to.z
|
|
107
|
+
} : void 0;
|
|
108
|
+
return world.nav.setDestination(entity.id, to);
|
|
109
|
+
}
|
|
110
|
+
/** Sends a walking unit on as it was, after something held it (a builder waiting for room): its stretch, or its goal */
|
|
111
|
+
function walkOn(world, entity) {
|
|
112
|
+
if (entity.get(moving)?.status === "moving") walk(world, entity);
|
|
113
|
+
}
|
|
114
|
+
function beginMove(world, entity, navGoal) {
|
|
115
|
+
const m = movementOf(entity);
|
|
116
|
+
m.bestDistance = Infinity;
|
|
117
|
+
m.finalFacing = null;
|
|
118
|
+
m.stalledTime = 0;
|
|
119
|
+
m.slowTime = 0;
|
|
120
|
+
m.detour = void 0;
|
|
121
|
+
delete m.tries;
|
|
122
|
+
delete m.triedAt;
|
|
123
|
+
m.navGoal.x = navGoal.x;
|
|
124
|
+
m.navGoal.z = navGoal.z;
|
|
125
|
+
m.navVersion = world.nav.version;
|
|
126
|
+
m.stuck = false;
|
|
127
|
+
if (m.anchored) {
|
|
128
|
+
m.anchored = false;
|
|
129
|
+
world.nav.setAnchored(entity.id, false);
|
|
130
|
+
}
|
|
131
|
+
const team = sideOf(world, entity);
|
|
132
|
+
if (team === void 0) m.route = void 0;
|
|
133
|
+
else planRoute(world, entity, team);
|
|
134
|
+
m.status = walk(world, entity) ? "moving" : "failed";
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Sends a unit walking to a point, the way around what is in the way. How it goes is in `entity.movement.status`:
|
|
138
|
+
* `moving` on the way, `arrived` once there, `failed` when there is no way there or it got stuck. Held up by others
|
|
139
|
+
* it tries again a few times before it gives up (`MovementState.tries`). An order calls this once and then watches the
|
|
140
|
+
* status; calling it again with the same goal starts the walk over
|
|
141
|
+
*
|
|
142
|
+
* @beta
|
|
143
|
+
*/
|
|
144
|
+
function moveTo(world, entity, goal, options = {}) {
|
|
145
|
+
const m = entity.get(moving);
|
|
146
|
+
if (!m || entity.hidden) return;
|
|
147
|
+
m.goal.x = goal.x;
|
|
148
|
+
m.goal.z = goal.z;
|
|
149
|
+
m.goalEntity = 0;
|
|
150
|
+
m.range = options.range ?? .2;
|
|
151
|
+
m.groupId = options.groupId ?? 0;
|
|
152
|
+
m.aside = options.aside || void 0;
|
|
153
|
+
delete m.asideDepth;
|
|
154
|
+
if (!options.aside) leavePlace(m);
|
|
155
|
+
beginMove(world, entity, goal);
|
|
156
|
+
m.finalFacing = options.facing ?? null;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Walks towards an entity until within `range` of its edge. Safe to call every tick.
|
|
160
|
+
*
|
|
161
|
+
* @beta
|
|
162
|
+
*/
|
|
163
|
+
function moveToEntity(world, entity, target, range) {
|
|
164
|
+
const m = entity.get(moving);
|
|
165
|
+
if (!m || entity.hidden) return;
|
|
166
|
+
if (m.status === "moving" && m.goalEntity === target.id && m.range === range) return;
|
|
167
|
+
m.goalEntity = target.id;
|
|
168
|
+
m.range = range;
|
|
169
|
+
m.groupId = 0;
|
|
170
|
+
m.aside = void 0;
|
|
171
|
+
leavePlace(m);
|
|
172
|
+
beginMove(world, entity, approachPoint(world, entity, target));
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Whether the unit is on its way to this very point
|
|
176
|
+
*
|
|
177
|
+
* @internal
|
|
178
|
+
*/
|
|
179
|
+
function isMovingTo(entity, goal) {
|
|
180
|
+
const m = entity.get(moving);
|
|
181
|
+
return !!m && m.status === "moving" && m.goalEntity === 0 && m.goal.x === goal.x && m.goal.z === goal.z;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Stops a unit where it is. Its status is `idle` after
|
|
185
|
+
*
|
|
186
|
+
* @beta
|
|
187
|
+
*/
|
|
188
|
+
function halt(world, entity) {
|
|
189
|
+
const m = entity.get(moving);
|
|
190
|
+
if (!m) return;
|
|
191
|
+
if (m.status === "moving") world.nav.clearDestination(entity.id);
|
|
192
|
+
m.status = "idle";
|
|
193
|
+
m.goalEntity = 0;
|
|
194
|
+
m.groupId = 0;
|
|
195
|
+
m.detour = void 0;
|
|
196
|
+
}
|
|
197
|
+
/** A unit that walks off on a move of its own: it has no place to go back to (`MovementState.place`) */
|
|
198
|
+
function leavePlace(m) {
|
|
199
|
+
delete m.place;
|
|
200
|
+
delete m.backTries;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Marks a unit as one of a formation sent to its places (`orderCommand`, with the order's group): it keeps the place it
|
|
204
|
+
* gets to (`MovementState.place`). Without a group, it is of none: given another order, it keeps no place
|
|
205
|
+
*
|
|
206
|
+
* @internal
|
|
207
|
+
*/
|
|
208
|
+
function joinFormation(entity, groupId = 0) {
|
|
209
|
+
const m = entity.get(moving);
|
|
210
|
+
if (!m) return;
|
|
211
|
+
leavePlace(m);
|
|
212
|
+
if (groupId) m.formation = groupId;
|
|
213
|
+
else delete m.formation;
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Anchored units stand their ground instead of being pushed around by units walking past.
|
|
217
|
+
*
|
|
218
|
+
* @beta
|
|
219
|
+
*/
|
|
220
|
+
function setAnchored(world, entity, anchored) {
|
|
221
|
+
const m = entity.get(moving);
|
|
222
|
+
if (!m || m.anchored === anchored) return;
|
|
223
|
+
if (anchored && m.status === "moving") halt(world, entity);
|
|
224
|
+
m.anchored = anchored;
|
|
225
|
+
world.nav.setAnchored(entity.id, anchored);
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Ghosts walk through other units. Classic RTS games do this for workers hauling resources so mining never jams.
|
|
229
|
+
*
|
|
230
|
+
* @beta
|
|
231
|
+
*/
|
|
232
|
+
function setGhost(world, entity, ghost) {
|
|
233
|
+
const m = entity.get(moving);
|
|
234
|
+
if (!m || m.ghost === ghost) return;
|
|
235
|
+
m.ghost = ghost;
|
|
236
|
+
world.nav.setGhost(entity.id, ghost || !world.nav.setPhasing && !!m.phased);
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Units that carry a buff that has them walk through others (`BuffDef.phasing`) phase on the navigation while they do
|
|
240
|
+
* (`Navigation.setPhasing`: on a crowd of their own, nobody's neighbour), and are not gone round nor asked aside.
|
|
241
|
+
* Walls, cliffs, buildings and trees are the navigation's ground, and stop them all the same
|
|
242
|
+
*/
|
|
243
|
+
function seeToPhasing(world) {
|
|
244
|
+
for (const entity of world.index.with(moving)) {
|
|
245
|
+
const m = entity.get(moving);
|
|
246
|
+
if (!m) continue;
|
|
247
|
+
const phasing = entity.buffs.length > 0 && entity.alive && !entity.hidden && isPhasing(world, entity);
|
|
248
|
+
if (phasing === !!m.phased) continue;
|
|
249
|
+
if (phasing) m.phased = true;
|
|
250
|
+
else delete m.phased;
|
|
251
|
+
if (world.nav.setPhasing) world.nav.setPhasing(entity.id, phasing);
|
|
252
|
+
else world.nav.setGhost(entity.id, phasing || m.ghost);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Turns a unit a little towards a point, as far as it turns in `dt` seconds (its type's `turnRate`, else the game's:
|
|
257
|
+
* `RuleSettings.movement.turnRate`). For orders that aim at something
|
|
258
|
+
*
|
|
259
|
+
* @beta
|
|
260
|
+
*/
|
|
261
|
+
function faceTowards(world, entity, point, dt) {
|
|
262
|
+
const m = entity.get(moving);
|
|
263
|
+
if (m) m.finalFacing = null;
|
|
264
|
+
const desired = atan2(point.x - entity.pos.x, point.z - entity.pos.z);
|
|
265
|
+
entity.facing = rotateTowards(entity.facing, desired, turnRateOf(world, entity) * dt);
|
|
266
|
+
}
|
|
267
|
+
function arrive(world, entity) {
|
|
268
|
+
world.nav.clearDestination(entity.id);
|
|
269
|
+
const m = movementOf(entity);
|
|
270
|
+
m.status = "arrived";
|
|
271
|
+
m.stalledTime = 0;
|
|
272
|
+
if (m.groupId && m.formation === m.groupId && !m.aside && !m.goalEntity) {
|
|
273
|
+
m.place = {
|
|
274
|
+
x: m.goal.x,
|
|
275
|
+
z: m.goal.z
|
|
276
|
+
};
|
|
277
|
+
if (dist(entity.pos, m.place) <= PLACE_OFF) delete m.backTries;
|
|
278
|
+
} else if (m.place && dist(entity.pos, m.place) <= PLACE_OFF) delete m.backTries;
|
|
279
|
+
}
|
|
280
|
+
/** True when the unit is bumping into a member of its own group that already reached its spot. */
|
|
281
|
+
function blockedByArrivedGroupMate(world, entity) {
|
|
282
|
+
const m = movementOf(entity);
|
|
283
|
+
if (!m.groupId) return false;
|
|
284
|
+
world.spatial.query(entity.pos.x, entity.pos.z, entity.def.radius + 1, neighbours);
|
|
285
|
+
for (const other of neighbours) {
|
|
286
|
+
const om = other.get(moving);
|
|
287
|
+
if (other === entity || !om || other.flying !== entity.flying) continue;
|
|
288
|
+
if (om.groupId !== m.groupId || om.status !== "arrived") continue;
|
|
289
|
+
if (distanceToEdge(entity.pos, other) - entity.def.radius < .25) return true;
|
|
290
|
+
}
|
|
291
|
+
return false;
|
|
292
|
+
}
|
|
293
|
+
/** Seconds a unit has to be held up before the ones in its way are asked to move */
|
|
294
|
+
var MAKE_WAY_AFTER = .2;
|
|
295
|
+
/** How many asked aside in turn, each by the one before held up on its step: the first by the mover, the next by it */
|
|
296
|
+
var ASIDE_DEPTH = 3;
|
|
297
|
+
/** Ticks between two requests by the same unit */
|
|
298
|
+
var MAKE_WAY_INTERVAL = 8;
|
|
299
|
+
/** Ticks between two looks ahead by the same unit, for units standing in its way */
|
|
300
|
+
var LOOK_AHEAD_INTERVAL = 4;
|
|
301
|
+
/** Room a unit keeps between itself and the units it goes round, past touching them */
|
|
302
|
+
var DETOUR_CLEARANCE = .3;
|
|
303
|
+
/**
|
|
304
|
+
* How far past the point beside a knot a unit going round it is sent on, towards its corner, once it is nearly there
|
|
305
|
+
* (`DETOUR_PAST_AT`): an agent slows down as it comes to where it was sent, and this way it is on its way again, at
|
|
306
|
+
* speed, before that
|
|
307
|
+
*/
|
|
308
|
+
var DETOUR_PAST = 1.5;
|
|
309
|
+
var DETOUR_PAST_AT = 1.2;
|
|
310
|
+
/** Under this part of its speed, a unit on its way counts as held up */
|
|
311
|
+
var SLOW_PART = .6;
|
|
312
|
+
/** How far round the point ahead a unit held up a while looks for those standing together in its way */
|
|
313
|
+
var HELD_REACH = 10;
|
|
314
|
+
/** Units standing in a knot past this many are not gone round: the way round them is for the path to find */
|
|
315
|
+
var KNOT_MOST = 24;
|
|
316
|
+
/**
|
|
317
|
+
* As many as a unit held up a while takes in, as it looks again (`tryAgain`): then it goes round however many
|
|
318
|
+
* stand together, however long the way round, where there is one
|
|
319
|
+
*/
|
|
320
|
+
var KNOT_HELD = 160;
|
|
321
|
+
/** The most a knot is grown to on this look: `KNOT_MOST`, or `KNOT_HELD` for a unit held up a while */
|
|
322
|
+
var knotMost = KNOT_MOST;
|
|
323
|
+
/**
|
|
324
|
+
* Whether another unit stands in a mover's way: there, standing still, and on the same crowd, where each steers
|
|
325
|
+
* round the other and neither walks through. What moves is steered round by the navigation; what is a ghost is walked
|
|
326
|
+
* through; what flies or sails goes its own way. What the mover walks to, or stands where it is
|
|
327
|
+
* going, is not in its way either: it stops by it, close enough (a follower by the one it follows, a unit sent where
|
|
328
|
+
* another stands), rather than send it off
|
|
329
|
+
*
|
|
330
|
+
* @beta
|
|
331
|
+
*/
|
|
332
|
+
function standsInWay(world, mover, other) {
|
|
333
|
+
const om = other.get(moving);
|
|
334
|
+
if (other === mover || !om || other.hidden || !other.alive) return false;
|
|
335
|
+
if (om.status === "moving" || om.ghost || om.phased) return false;
|
|
336
|
+
const m = mover.get(moving);
|
|
337
|
+
if (m?.phased) return false;
|
|
338
|
+
if (m && (other.id === m.goalEntity || hypot(other.pos.x - m.navGoal.x, other.pos.z - m.navGoal.z) < m.range + mover.def.radius + other.def.radius)) return false;
|
|
339
|
+
return world.nav.sameCrowd?.(mover.id, other.id) ?? true;
|
|
340
|
+
}
|
|
341
|
+
/** How far a point is from a segment */
|
|
342
|
+
function segmentDistance(px, pz, ax, az, bx, bz) {
|
|
343
|
+
const dx = bx - ax;
|
|
344
|
+
const dz = bz - az;
|
|
345
|
+
const length = dx * dx + dz * dz;
|
|
346
|
+
const t = length > 0 ? Math.min(Math.max(((px - ax) * dx + (pz - az) * dz) / length, 0), 1) : 0;
|
|
347
|
+
return hypot(px - (ax + dx * t), pz - (az + dz * t));
|
|
348
|
+
}
|
|
349
|
+
var probe = {
|
|
350
|
+
x: 0,
|
|
351
|
+
z: 0
|
|
352
|
+
};
|
|
353
|
+
/** Whether the navigation has walkable ground at a point: its nearest such point is no further than a hair */
|
|
354
|
+
function walkableAt(nav, x, z) {
|
|
355
|
+
probe.x = x;
|
|
356
|
+
probe.z = z;
|
|
357
|
+
const snapped = nav.closestPoint(probe, 1);
|
|
358
|
+
return !!snapped && hypot(snapped.x - x, snapped.z - z) <= .3;
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Where an ally in a mover's way steps to: aside, off the mover's way, the shorter way out of it first. The way is the
|
|
362
|
+
* leg the mover is on, to its corner, and the leg after (`agent.nx`): a step off the first onto the second, round a
|
|
363
|
+
* building's corner, would be no step at all. Where a side is not to be stood on (a wall), the other; where neither,
|
|
364
|
+
* nowhere
|
|
365
|
+
*/
|
|
366
|
+
function asidePoint(world, mover, other, dx, dz, agent) {
|
|
367
|
+
const rx = other.pos.x - mover.pos.x;
|
|
368
|
+
const rz = other.pos.z - mover.pos.z;
|
|
369
|
+
const clear = mover.def.radius + other.def.radius + .5;
|
|
370
|
+
const offset = rx * dz - rz * dx;
|
|
371
|
+
const first = Math.abs(offset) > .05 ? Math.sign(offset) : other.id % 2 ? 1 : -1;
|
|
372
|
+
const nav = world.navFor(other);
|
|
373
|
+
const { pos } = mover;
|
|
374
|
+
let taken = null;
|
|
375
|
+
const free = other.orders.length === 0;
|
|
376
|
+
for (let pass = 0; pass < 2; pass++) {
|
|
377
|
+
const side = pass === 0 ? first : -first;
|
|
378
|
+
for (let step = clear - Math.abs(offset); step <= clear * 3; step += .5) {
|
|
379
|
+
const x = other.pos.x + dz * side * step;
|
|
380
|
+
const z = other.pos.z - dx * side * step;
|
|
381
|
+
if (segmentDistance(x, z, pos.x, pos.z, agent.cx, agent.cz) < clear - .05) continue;
|
|
382
|
+
if (segmentDistance(x, z, agent.cx, agent.cz, agent.nx, agent.nz) < clear - .05) continue;
|
|
383
|
+
if (!walkableAt(nav, x, z)) break;
|
|
384
|
+
if (free && !roomFor(world, other, mover, x, z)) {
|
|
385
|
+
taken ??= {
|
|
386
|
+
x,
|
|
387
|
+
z
|
|
388
|
+
};
|
|
389
|
+
continue;
|
|
390
|
+
}
|
|
391
|
+
return {
|
|
392
|
+
x,
|
|
393
|
+
z
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
return taken;
|
|
398
|
+
}
|
|
399
|
+
var roomNear = [];
|
|
400
|
+
/** Whether a unit stepping aside has room at a point: nobody else stands there, nor steps aside onto it */
|
|
401
|
+
function roomFor(world, entity, mover, x, z) {
|
|
402
|
+
world.spatial.query(x, z, entity.def.radius + 1, roomNear);
|
|
403
|
+
for (const other of roomNear) {
|
|
404
|
+
if (other === entity || other === mover || other.hidden || other.flying !== entity.flying) continue;
|
|
405
|
+
const om = other.get(moving);
|
|
406
|
+
if (!om || om.ghost || om.phased) continue;
|
|
407
|
+
const room = entity.def.radius + other.def.radius - .05;
|
|
408
|
+
if (om.status !== "moving" && hypot(other.pos.x - x, other.pos.z - z) < room) return false;
|
|
409
|
+
if (om.aside && om.status === "moving" && hypot(om.goal.x - x, om.goal.z - z) < room) return false;
|
|
410
|
+
}
|
|
411
|
+
return true;
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* Asks an ally standing in a unit's way to step aside, as the rules allow (`RuleSettings.movement.makesWay`, the `makeWay` hook).
|
|
415
|
+
* `direction` is the way the unit is heading, a unit long; `agent` where its path goes, for the step to be off it.
|
|
416
|
+
* True when it goes
|
|
417
|
+
*
|
|
418
|
+
* @beta
|
|
419
|
+
*/
|
|
420
|
+
function stepAside(world, mover, other, direction, agent) {
|
|
421
|
+
const om = other.get(moving);
|
|
422
|
+
if (!om || !world.areAllies(mover.owner, other.owner) || !world.settings.movement.makesWay(world, mover, other)) return false;
|
|
423
|
+
const m = mover.get(moving);
|
|
424
|
+
if (m?.groupId && (om.groupId === m.groupId || om.formation === m.groupId)) return false;
|
|
425
|
+
let point = asidePoint(world, mover, other, direction.x, direction.z, agent);
|
|
426
|
+
if (world.hooks.has("makeWay")) point = world.hooks.run("makeWay", {
|
|
427
|
+
mover,
|
|
428
|
+
other,
|
|
429
|
+
direction,
|
|
430
|
+
point
|
|
431
|
+
}).point;
|
|
432
|
+
if (!point) return false;
|
|
433
|
+
moveTo(world, other, point, {
|
|
434
|
+
facing: om.finalFacing ?? other.facing,
|
|
435
|
+
aside: true
|
|
436
|
+
});
|
|
437
|
+
if (m?.aside) om.asideDepth = (m.asideDepth ?? 1) + 1;
|
|
438
|
+
return true;
|
|
439
|
+
}
|
|
440
|
+
var neighbours = [];
|
|
441
|
+
var inWay = [];
|
|
442
|
+
var knot = [];
|
|
443
|
+
/**
|
|
444
|
+
* What each of `neighbours` is to the unit looking ahead, by its index: not asked yet, clear, standing in its way, or in
|
|
445
|
+
* the knot. In a blob every member of the knot looks over every neighbour: `standsInWay` asked once each, and a mark
|
|
446
|
+
* rather than `knot.includes`, keep that from being a good part of the tick
|
|
447
|
+
*/
|
|
448
|
+
var standing = /* @__PURE__ */ new Uint8Array(256);
|
|
449
|
+
/**
|
|
450
|
+
* Where each of `neighbours` stands and how wide it is, by its index, read off it once as a knot is grown: the knot
|
|
451
|
+
* goes over the neighbours again for each of its members, and numbers side by side are read faster than each unit's
|
|
452
|
+
* place and type are got at again (nobody moves while the knot is grown)
|
|
453
|
+
*/
|
|
454
|
+
var nearX = /* @__PURE__ */ new Float64Array(256);
|
|
455
|
+
var nearZ = /* @__PURE__ */ new Float64Array(256);
|
|
456
|
+
var nearRadius = /* @__PURE__ */ new Float64Array(256);
|
|
457
|
+
/** The index in `neighbours` of each member of the knot, as it is grown from them */
|
|
458
|
+
var knotAt = /* @__PURE__ */ new Int32Array(256);
|
|
459
|
+
/** Those a member of the knot takes in, by their index in `neighbours`, in order */
|
|
460
|
+
var joined = /* @__PURE__ */ new Int32Array(256);
|
|
461
|
+
/**
|
|
462
|
+
* The neighbours filed by cells a metre wide (`fileNear`): the cell of each, and the indices of those in each cell, in
|
|
463
|
+
* order, from `cellStart[cell]` to `cellStart[cell + 1]`; the corner the cells start from, how many there are across
|
|
464
|
+
* and down, and the widest neighbour
|
|
465
|
+
*/
|
|
466
|
+
var cellItems = /* @__PURE__ */ new Int32Array(256);
|
|
467
|
+
var cellStart = /* @__PURE__ */ new Int32Array(257);
|
|
468
|
+
var cellFill = /* @__PURE__ */ new Int32Array(257);
|
|
469
|
+
var nearCell = /* @__PURE__ */ new Int32Array(256);
|
|
470
|
+
var nearMinX = 0;
|
|
471
|
+
var nearMinZ = 0;
|
|
472
|
+
var nearCols = 0;
|
|
473
|
+
var nearRows = 0;
|
|
474
|
+
var nearWidest = 0;
|
|
475
|
+
/**
|
|
476
|
+
* Files the `count` neighbours (`nearX`, `nearZ`, `nearRadius`) by cells a metre wide, for the knot to find those
|
|
477
|
+
* against each member among a few of them. False, and nothing filed, where it would take more cells than it is worth
|
|
478
|
+
* (a few neighbours far apart), or a place or a radius is no number
|
|
479
|
+
*/
|
|
480
|
+
function fileNear(count) {
|
|
481
|
+
let minX = Infinity;
|
|
482
|
+
let minZ = Infinity;
|
|
483
|
+
let maxX = -Infinity;
|
|
484
|
+
let maxZ = -Infinity;
|
|
485
|
+
let widest = 0;
|
|
486
|
+
let sum = 0;
|
|
487
|
+
for (let j = 0; j < count; j++) {
|
|
488
|
+
const x = nearX[j];
|
|
489
|
+
const z = nearZ[j];
|
|
490
|
+
sum += x + z + nearRadius[j];
|
|
491
|
+
if (x < minX) minX = x;
|
|
492
|
+
if (x > maxX) maxX = x;
|
|
493
|
+
if (z < minZ) minZ = z;
|
|
494
|
+
if (z > maxZ) maxZ = z;
|
|
495
|
+
if (nearRadius[j] > widest) widest = nearRadius[j];
|
|
496
|
+
}
|
|
497
|
+
const cols = Math.floor(maxX - minX) + 1;
|
|
498
|
+
const rows = Math.floor(maxZ - minZ) + 1;
|
|
499
|
+
const cells = cols * rows;
|
|
500
|
+
if (Number.isNaN(sum) || !(cells <= count * 4)) return false;
|
|
501
|
+
if (cellStart.length < cells + 1) {
|
|
502
|
+
cellStart = new Int32Array((cells + 1) * 2);
|
|
503
|
+
cellFill = new Int32Array((cells + 1) * 2);
|
|
504
|
+
}
|
|
505
|
+
cellStart.fill(0, 0, cells + 1);
|
|
506
|
+
for (let j = 0; j < count; j++) {
|
|
507
|
+
const cell = Math.floor(nearZ[j] - minZ) * cols + Math.floor(nearX[j] - minX);
|
|
508
|
+
nearCell[j] = cell;
|
|
509
|
+
cellStart[cell + 1]++;
|
|
510
|
+
}
|
|
511
|
+
for (let cell = 0; cell < cells; cell++) cellStart[cell + 1] += cellStart[cell];
|
|
512
|
+
cellFill.set(cellStart.subarray(0, cells));
|
|
513
|
+
for (let j = 0; j < count; j++) cellItems[cellFill[nearCell[j]]++] = j;
|
|
514
|
+
nearMinX = minX;
|
|
515
|
+
nearMinZ = minZ;
|
|
516
|
+
nearCols = cols;
|
|
517
|
+
nearRows = rows;
|
|
518
|
+
nearWidest = widest;
|
|
519
|
+
return true;
|
|
520
|
+
}
|
|
521
|
+
/**
|
|
522
|
+
* Grows the knot of the unit looking ahead (`lookAhead`) from those in its way (`knot`, `knotAt`): each member in turn
|
|
523
|
+
* takes in the neighbours that stand against it, in their order, until the knot is too big to go round. Those against
|
|
524
|
+
* a member are looked for in the cells round it (`fileNear`), as far as it reaches the widest neighbour: one further
|
|
525
|
+
* off touches it not. Where the neighbours are not filed, among them all
|
|
526
|
+
*/
|
|
527
|
+
function growKnot(world, entity, count) {
|
|
528
|
+
for (let i = 0; i < count; i++) {
|
|
529
|
+
const other = neighbours[i];
|
|
530
|
+
nearX[i] = other.pos.x;
|
|
531
|
+
nearZ[i] = other.pos.z;
|
|
532
|
+
nearRadius[i] = other.def.radius;
|
|
533
|
+
}
|
|
534
|
+
const filed = fileNear(count);
|
|
535
|
+
for (let i = 0; i < knot.length && knot.length < knotMost; i++) {
|
|
536
|
+
const member = knotAt[i];
|
|
537
|
+
const memberX = nearX[member];
|
|
538
|
+
const memberZ = nearZ[member];
|
|
539
|
+
const memberRadius = nearRadius[member];
|
|
540
|
+
let added = 0;
|
|
541
|
+
const take = (j) => {
|
|
542
|
+
const mark = standing[j];
|
|
543
|
+
if (mark === KNOTTED || mark === CLEAR) return;
|
|
544
|
+
if (hypot(nearX[j] - memberX, nearZ[j] - memberZ) >= memberRadius + nearRadius[j] + .3) return;
|
|
545
|
+
if (!standsThere(world, entity, j)) return;
|
|
546
|
+
standing[j] = KNOTTED;
|
|
547
|
+
let place = added++;
|
|
548
|
+
for (; place > 0 && joined[place - 1] > j; place--) joined[place] = joined[place - 1];
|
|
549
|
+
joined[place] = j;
|
|
550
|
+
};
|
|
551
|
+
if (filed) {
|
|
552
|
+
const touch = memberRadius + nearWidest + .3 + .01;
|
|
553
|
+
const fromCol = Math.max(Math.floor(memberX - touch - nearMinX), 0);
|
|
554
|
+
const toCol = Math.min(Math.floor(memberX + touch - nearMinX), nearCols - 1);
|
|
555
|
+
const fromRow = Math.max(Math.floor(memberZ - touch - nearMinZ), 0);
|
|
556
|
+
const toRow = Math.min(Math.floor(memberZ + touch - nearMinZ), nearRows - 1);
|
|
557
|
+
for (let row = fromRow; row <= toRow; row++) for (let k = cellStart[row * nearCols + fromCol], end = cellStart[row * nearCols + toCol + 1]; k < end; k++) take(cellItems[k]);
|
|
558
|
+
} else for (let j = 0; j < count; j++) take(j);
|
|
559
|
+
for (let k = 0; k < added; k++) {
|
|
560
|
+
knotAt[knot.length] = joined[k];
|
|
561
|
+
knot.push(neighbours[joined[k]]);
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
var UNASKED = 0;
|
|
566
|
+
var CLEAR = 1;
|
|
567
|
+
var STANDING = 2;
|
|
568
|
+
var KNOTTED = 3;
|
|
569
|
+
var direction = {
|
|
570
|
+
x: 0,
|
|
571
|
+
z: 0
|
|
572
|
+
};
|
|
573
|
+
var agent = {
|
|
574
|
+
x: 0,
|
|
575
|
+
z: 0,
|
|
576
|
+
vx: 0,
|
|
577
|
+
vz: 0,
|
|
578
|
+
cx: 0,
|
|
579
|
+
cz: 0,
|
|
580
|
+
nx: 0,
|
|
581
|
+
nz: 0
|
|
582
|
+
};
|
|
583
|
+
/**
|
|
584
|
+
* Asks friendly units that are standing around in front of a unit to step aside.
|
|
585
|
+
* Avoidance alone cannot get a unit out of a tight group of idle ones: they would have to move, and nothing tells them to.
|
|
586
|
+
*
|
|
587
|
+
* @beta
|
|
588
|
+
*/
|
|
589
|
+
function makeWay(world, entity) {
|
|
590
|
+
const m = movementOf(entity);
|
|
591
|
+
if (!world.nav.readAgent(entity.id, agent)) return;
|
|
592
|
+
const to = m.detour ?? m.navGoal;
|
|
593
|
+
let dx = to.x - entity.pos.x;
|
|
594
|
+
let dz = to.z - entity.pos.z;
|
|
595
|
+
const length = hypot(dx, dz);
|
|
596
|
+
if (length < .01) return;
|
|
597
|
+
dx /= length;
|
|
598
|
+
dz /= length;
|
|
599
|
+
direction.x = dx;
|
|
600
|
+
direction.z = dz;
|
|
601
|
+
world.spatial.query(entity.pos.x, entity.pos.z, entity.def.radius + 1.5, neighbours);
|
|
602
|
+
let against;
|
|
603
|
+
for (const other of neighbours) {
|
|
604
|
+
const rx = other.pos.x - entity.pos.x;
|
|
605
|
+
const rz = other.pos.z - entity.pos.z;
|
|
606
|
+
const reach = entity.def.radius + other.def.radius;
|
|
607
|
+
const ahead = rx * dx + rz * dz;
|
|
608
|
+
if (ahead < -.1 || ahead > reach + 1) continue;
|
|
609
|
+
const offset = rx * dz - rz * dx;
|
|
610
|
+
if (Math.abs(offset) > reach) continue;
|
|
611
|
+
against ??= [];
|
|
612
|
+
against.push(other);
|
|
613
|
+
}
|
|
614
|
+
if (!against) return;
|
|
615
|
+
for (const other of against) if (standsInWay(world, entity, other)) stepAside(world, entity, other, direction, agent);
|
|
616
|
+
}
|
|
617
|
+
/** Whether a unit walking a segment would touch any of the knot */
|
|
618
|
+
function segmentClear(radius, ax, az, bx, bz) {
|
|
619
|
+
for (const other of knot) if (segmentDistance(other.pos.x, other.pos.z, ax, az, bx, bz) < radius + other.def.radius + .05) return false;
|
|
620
|
+
return true;
|
|
621
|
+
}
|
|
622
|
+
var wayFrom = {
|
|
623
|
+
x: 0,
|
|
624
|
+
z: 0
|
|
625
|
+
};
|
|
626
|
+
var wayTo = {
|
|
627
|
+
x: 0,
|
|
628
|
+
z: 0
|
|
629
|
+
};
|
|
630
|
+
/**
|
|
631
|
+
* Whether the way from a point to another is straight, as far as the navigation is concerned: its path is no longer
|
|
632
|
+
* than the line, give or take. A way round a knot that bends round a building is no way round the knot
|
|
633
|
+
*/
|
|
634
|
+
function straightWay(nav, fromX, fromZ, toX, toZ) {
|
|
635
|
+
const from = wayFrom;
|
|
636
|
+
const to = wayTo;
|
|
637
|
+
from.x = fromX;
|
|
638
|
+
from.z = fromZ;
|
|
639
|
+
to.x = toX;
|
|
640
|
+
to.z = toZ;
|
|
641
|
+
const path = nav.findPath(from, to);
|
|
642
|
+
if (!path || path.length === 0) return false;
|
|
643
|
+
let length = dist(from, path[0]);
|
|
644
|
+
for (let i = 1; i < path.length; i++) length += dist(path[i - 1], path[i]);
|
|
645
|
+
length += dist(path[path.length - 1], to);
|
|
646
|
+
return length <= dist(from, to) * 1.05 + .3;
|
|
647
|
+
}
|
|
648
|
+
var standingThere = [];
|
|
649
|
+
/**
|
|
650
|
+
* Whether a unit could stand at a point: walkable there, and nobody standing on it, or stepping aside onto it. Null
|
|
651
|
+
* when it could; otherwise the unit in the way there, or the mover itself for ground it cannot walk
|
|
652
|
+
*/
|
|
653
|
+
function standable(world, nav, entity, x, z) {
|
|
654
|
+
if (!walkableAt(nav, x, z)) return entity;
|
|
655
|
+
world.spatial.query(x, z, entity.def.radius + 1, standingThere);
|
|
656
|
+
for (const other of standingThere) {
|
|
657
|
+
if (other === entity || !other.get(moving) || other.hidden) continue;
|
|
658
|
+
const room = entity.def.radius + other.def.radius + .05;
|
|
659
|
+
if (hypot(other.pos.x - x, other.pos.z - z) < room && standsInWay(world, entity, other)) return other;
|
|
660
|
+
const om = other.get(moving);
|
|
661
|
+
if (om.aside && om.status === "moving" && hypot(om.goal.x - x, om.goal.z - z) < room) return other;
|
|
662
|
+
}
|
|
663
|
+
return null;
|
|
664
|
+
}
|
|
665
|
+
/** Whether the neighbour at `i` stands in the way of the unit looking ahead: asked of `standsInWay` the first time only */
|
|
666
|
+
function standsThere(world, entity, i) {
|
|
667
|
+
if (standing[i] === UNASKED) standing[i] = standsInWay(world, entity, neighbours[i]) ? STANDING : CLEAR;
|
|
668
|
+
return standing[i] !== CLEAR;
|
|
669
|
+
}
|
|
670
|
+
/**
|
|
671
|
+
* Looks ahead of a unit on its way for units standing in it (within `RuleSettings.movement.lookAhead`): a way round the knot
|
|
672
|
+
* they make is taken where it is not much longer (`RuleSettings.movement.goesAround`, the `detour` hook); otherwise those of
|
|
673
|
+
* them that make way (`RuleSettings.movement.makesWay`) are asked to step aside before the unit reaches them. The way round is
|
|
674
|
+
* beside the knot, on the side it sticks out less, at the knot's middle; the unit heads there, and on to its path
|
|
675
|
+
* from there. The number of units sent to this per tick is spread by their ids (`LOOK_AHEAD_INTERVAL`)
|
|
676
|
+
*
|
|
677
|
+
* @beta
|
|
678
|
+
*/
|
|
679
|
+
function lookAhead(world, entity, agent) {
|
|
680
|
+
lookFurther(world, entity, agent, false);
|
|
681
|
+
}
|
|
682
|
+
/**
|
|
683
|
+
* The look ahead (`lookAhead`); `held` for a unit held up a while (`tryAgain`): it looks a few cells ahead, whatever the
|
|
684
|
+
* rules say, takes in the whole knot, however big, and goes round it however long the way round, where there is one
|
|
685
|
+
*/
|
|
686
|
+
function lookFurther(world, entity, agent, held) {
|
|
687
|
+
const m = movementOf(entity);
|
|
688
|
+
const look = held ? Math.max(world.settings.movement.lookAhead(world, entity), 3) : world.settings.movement.lookAhead(world, entity);
|
|
689
|
+
if (look <= 0) return;
|
|
690
|
+
knotMost = held ? KNOT_HELD : KNOT_MOST;
|
|
691
|
+
const { pos } = entity;
|
|
692
|
+
const radius = entity.def.radius;
|
|
693
|
+
let dx = agent.cx - pos.x;
|
|
694
|
+
let dz = agent.cz - pos.z;
|
|
695
|
+
const toCorner = hypot(dx, dz);
|
|
696
|
+
if (toCorner < radius) return;
|
|
697
|
+
dx /= toCorner;
|
|
698
|
+
dz /= toCorner;
|
|
699
|
+
const reach = Math.min(toCorner, look);
|
|
700
|
+
world.spatial.query(pos.x + dx * reach / 2, pos.z + dz * reach / 2, reach / 2 + (held ? HELD_REACH : 3), neighbours);
|
|
701
|
+
const count = neighbours.length;
|
|
702
|
+
if (standing.length < count) {
|
|
703
|
+
standing = new Uint8Array(count * 2);
|
|
704
|
+
nearX = new Float64Array(count * 2);
|
|
705
|
+
nearZ = new Float64Array(count * 2);
|
|
706
|
+
nearRadius = new Float64Array(count * 2);
|
|
707
|
+
knotAt = new Int32Array(count * 2);
|
|
708
|
+
joined = new Int32Array(count * 2);
|
|
709
|
+
nearCell = new Int32Array(count * 2);
|
|
710
|
+
cellItems = new Int32Array(count * 2);
|
|
711
|
+
}
|
|
712
|
+
standing.fill(UNASKED, 0, count);
|
|
713
|
+
inWay.length = 0;
|
|
714
|
+
knot.length = 0;
|
|
715
|
+
for (let i = 0; i < count; i++) {
|
|
716
|
+
const other = neighbours[i];
|
|
717
|
+
const rx = other.pos.x - pos.x;
|
|
718
|
+
const rz = other.pos.z - pos.z;
|
|
719
|
+
const touch = radius + other.def.radius;
|
|
720
|
+
const ahead = rx * dx + rz * dz;
|
|
721
|
+
if (ahead < radius || ahead > reach + touch) continue;
|
|
722
|
+
const offset = rx * dz - rz * dx;
|
|
723
|
+
if (Math.abs(offset) > touch - .05) continue;
|
|
724
|
+
if (!standsThere(world, entity, i)) continue;
|
|
725
|
+
standing[i] = KNOTTED;
|
|
726
|
+
knotAt[inWay.length] = i;
|
|
727
|
+
inWay.push(other);
|
|
728
|
+
}
|
|
729
|
+
if (inWay.length === 0) return;
|
|
730
|
+
for (const other of inWay) knot.push(other);
|
|
731
|
+
if (knot.length < knotMost) growKnot(world, entity, count);
|
|
732
|
+
let detour = null;
|
|
733
|
+
if (knot.length < knotMost) {
|
|
734
|
+
const nav = world.navFor(entity);
|
|
735
|
+
let aimX = agent.cx;
|
|
736
|
+
let aimZ = agent.cz;
|
|
737
|
+
for (let grown = 0; grown < 4 && !detour; grown++) {
|
|
738
|
+
let left = -Infinity;
|
|
739
|
+
let right = Infinity;
|
|
740
|
+
let along = 0;
|
|
741
|
+
for (const other of knot) {
|
|
742
|
+
const rx = other.pos.x - pos.x;
|
|
743
|
+
const rz = other.pos.z - pos.z;
|
|
744
|
+
const offset = rx * dz - rz * dx;
|
|
745
|
+
left = Math.max(left, offset + other.def.radius);
|
|
746
|
+
right = Math.min(right, offset - other.def.radius);
|
|
747
|
+
along += rx * dx + rz * dz;
|
|
748
|
+
}
|
|
749
|
+
along = Math.max(along / knot.length, radius);
|
|
750
|
+
const leftFirst = Math.abs(left) <= Math.abs(right);
|
|
751
|
+
let blocker = null;
|
|
752
|
+
for (let pass = 0; pass < 2; pass++) {
|
|
753
|
+
const side = leftFirst === (pass === 0) ? left : right;
|
|
754
|
+
const out = side > 0 ? 1 : -1;
|
|
755
|
+
for (let push = 0; push < 3 && !detour; push++) {
|
|
756
|
+
const offset = side + out * (radius + DETOUR_CLEARANCE + push * .5);
|
|
757
|
+
const x = pos.x + dx * along + dz * offset;
|
|
758
|
+
const z = pos.z + dz * along - dx * offset;
|
|
759
|
+
const there = standable(world, nav, entity, x, z);
|
|
760
|
+
if (there) {
|
|
761
|
+
if (there !== entity && !knot.includes(there)) blocker ??= there;
|
|
762
|
+
continue;
|
|
763
|
+
}
|
|
764
|
+
if (!segmentClear(radius, pos.x, pos.z, x, z) || !straightWay(nav, pos.x, pos.z, x, z)) continue;
|
|
765
|
+
if (segmentClear(radius, x, z, agent.cx, agent.cz) && straightWay(nav, x, z, agent.cx, agent.cz)) {
|
|
766
|
+
aimX = agent.cx;
|
|
767
|
+
aimZ = agent.cz;
|
|
768
|
+
} else if ((agent.nx !== agent.cx || agent.nz !== agent.cz) && segmentClear(radius, x, z, agent.nx, agent.nz) && straightWay(nav, x, z, agent.nx, agent.nz)) {
|
|
769
|
+
aimX = agent.nx;
|
|
770
|
+
aimZ = agent.nz;
|
|
771
|
+
} else continue;
|
|
772
|
+
detour = {
|
|
773
|
+
x,
|
|
774
|
+
z
|
|
775
|
+
};
|
|
776
|
+
}
|
|
777
|
+
if (detour) break;
|
|
778
|
+
}
|
|
779
|
+
if (!detour && blocker && knot.length < knotMost) knot.push(blocker);
|
|
780
|
+
else if (!detour) break;
|
|
781
|
+
}
|
|
782
|
+
if (detour) {
|
|
783
|
+
const straight = aimX === agent.cx && aimZ === agent.cz ? toCorner : toCorner + hypot(agent.nx - agent.cx, agent.nz - agent.cz);
|
|
784
|
+
const longer = hypot(detour.x - pos.x, detour.z - pos.z) + hypot(aimX - detour.x, aimZ - detour.z) - straight;
|
|
785
|
+
const around = [...knot];
|
|
786
|
+
if (!held && !world.settings.movement.goesAround(world, entity, around, longer, straight)) detour = null;
|
|
787
|
+
if (world.hooks.has("detour")) detour = world.hooks.run("detour", {
|
|
788
|
+
entity,
|
|
789
|
+
around,
|
|
790
|
+
straight,
|
|
791
|
+
longer,
|
|
792
|
+
point: detour
|
|
793
|
+
}).point;
|
|
794
|
+
if (detour) {
|
|
795
|
+
m.detour = detour;
|
|
796
|
+
m.detourAim = {
|
|
797
|
+
x: aimX,
|
|
798
|
+
z: aimZ
|
|
799
|
+
};
|
|
800
|
+
m.detourPast = false;
|
|
801
|
+
world.nav.setDestination(entity.id, detour);
|
|
802
|
+
return;
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
direction.x = dx;
|
|
807
|
+
direction.z = dz;
|
|
808
|
+
for (const other of [...inWay]) stepAside(world, entity, other, direction, agent);
|
|
809
|
+
}
|
|
810
|
+
/**
|
|
811
|
+
* Over how many ticks the chasers look for new paths after the navigation changed: an eighth of them each tick
|
|
812
|
+
*
|
|
813
|
+
* @beta
|
|
814
|
+
*/
|
|
815
|
+
var REPATH_SPREAD = 8;
|
|
816
|
+
/** Keeps chasers pointed at targets that moved, and lets go of the ones gone out of reach */
|
|
817
|
+
function followTargets(world) {
|
|
818
|
+
const { nav } = world;
|
|
819
|
+
for (const entity of world.index.with(moving)) {
|
|
820
|
+
const m = entity.get(moving);
|
|
821
|
+
if (!m || m.status !== "moving" || !m.goalEntity) continue;
|
|
822
|
+
const target = world.get(m.goalEntity);
|
|
823
|
+
if (!target || target.hidden) {
|
|
824
|
+
nav.clearDestination(entity.id);
|
|
825
|
+
m.status = "failed";
|
|
826
|
+
continue;
|
|
827
|
+
}
|
|
828
|
+
const point = approachPoint(world, entity, target);
|
|
829
|
+
const stale = m.navVersion !== nav.version && (entity.id + world.tick) % 8 === 0;
|
|
830
|
+
if (dist(point, m.navGoal) > .75 || stale) beginMove(world, entity, point);
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
/** Where the navigation moved each unit to, read back into the world: and from there, how each is getting on */
|
|
834
|
+
function readAgents(world, dt) {
|
|
835
|
+
for (const entity of world.index.with(moving)) {
|
|
836
|
+
const m = entity.get(moving);
|
|
837
|
+
if (!m || !entity.alive || entity.hidden) continue;
|
|
838
|
+
if (!world.nav.readAgent(entity.id, agent)) continue;
|
|
839
|
+
moveAlong(world, entity, m, dt);
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
/** A unit the navigation moved (`agent`, just read): where it is, which way it faces, and how it is getting on */
|
|
843
|
+
function moveAlong(world, entity, m, dt) {
|
|
844
|
+
entity.moveTo(agent.x, agent.z);
|
|
845
|
+
entity.velocity.x = agent.vx;
|
|
846
|
+
entity.velocity.z = agent.vz;
|
|
847
|
+
if (m.status !== "moving") {
|
|
848
|
+
if (m.place) backToPlace(world, entity, m, dt);
|
|
849
|
+
return lineUp(world, entity, m, dt);
|
|
850
|
+
}
|
|
851
|
+
if (agent.vx * agent.vx + agent.vz * agent.vz > .2) {
|
|
852
|
+
const desired = atan2(agent.vx, agent.vz);
|
|
853
|
+
entity.facing = rotateTowards(entity.facing, desired, turnRateOf(world, entity) * dt);
|
|
854
|
+
}
|
|
855
|
+
const distance = distanceLeft(world, entity, m);
|
|
856
|
+
if (distance === void 0) return;
|
|
857
|
+
if (distance <= m.range) return arrive(world, entity);
|
|
858
|
+
steerAround(world, entity, m);
|
|
859
|
+
followRoute(world, entity, m);
|
|
860
|
+
watchProgress(world, entity, m, distance, dt);
|
|
861
|
+
}
|
|
862
|
+
/** How far off its place in a formation a unit that stands there goes back to it */
|
|
863
|
+
var PLACE_OFF = .35;
|
|
864
|
+
/** Seconds it stands off its place before it goes back: the one it stepped aside for gone by */
|
|
865
|
+
var PLACE_WAIT = .75;
|
|
866
|
+
/** How many times it goes back to its place without getting there before it lets it go: jostling for ever is no good */
|
|
867
|
+
var BACK_TRIES = 5;
|
|
868
|
+
/**
|
|
869
|
+
* A unit of a formation standing off its place (stepped aside for another, or pushed off it) walks back to it once it
|
|
870
|
+
* has stood off it a while (`PLACE_WAIT`), as one of the formation: it swaps, passes on and trades places on the way,
|
|
871
|
+
* and makes its own room by it (`nudge`), but does not try again: held up `HELD_UP` near it, it stops, its place kept.
|
|
872
|
+
* Where another of the formation stands there, off its own, that one keeps this place and this one goes to the
|
|
873
|
+
* other's; where one stands at its own there it waits. After a few walks back (`BACK_TRIES`) without getting there
|
|
874
|
+
* it lets the place go, and stays where it is
|
|
875
|
+
*/
|
|
876
|
+
function backToPlace(world, entity, m, dt) {
|
|
877
|
+
const place = m.place;
|
|
878
|
+
if (m.anchored || entity.orders.length > 0 || dist(entity.pos, place) <= PLACE_OFF) return;
|
|
879
|
+
m.stalledTime += dt;
|
|
880
|
+
if (m.stalledTime < PLACE_WAIT || (world.tick + entity.id) % LOOK_AHEAD_INTERVAL !== 0) return;
|
|
881
|
+
m.stalledTime = 0;
|
|
882
|
+
const tries = (m.backTries ?? 0) + 1;
|
|
883
|
+
if (tries > BACK_TRIES) return leavePlace(m);
|
|
884
|
+
const theirs = m.formation !== void 0 ? takeOver(world, entity, place, m.formation) : void 0;
|
|
885
|
+
if (theirs) m.place = theirs;
|
|
886
|
+
const to = m.place;
|
|
887
|
+
if (theirs || !standingOn(world, entity, to)) {
|
|
888
|
+
if (m.formation !== void 0) toPlace(world, entity, to, m.formation, m.finalFacing ?? entity.facing);
|
|
889
|
+
else moveTo(world, entity, to, {
|
|
890
|
+
facing: m.finalFacing ?? entity.facing,
|
|
891
|
+
aside: true
|
|
892
|
+
});
|
|
893
|
+
m.place = to;
|
|
894
|
+
}
|
|
895
|
+
if (theirs) delete m.backTries;
|
|
896
|
+
else m.backTries = tries;
|
|
897
|
+
if (m.status === "moving") m.asideDepth = ASIDE_DEPTH;
|
|
898
|
+
}
|
|
899
|
+
/** Groups bump into each other on arrival and end up looking anywhere: a unit that stopped turns to face the way it was told */
|
|
900
|
+
function lineUp(world, entity, m, dt) {
|
|
901
|
+
if (m.finalFacing === null) return;
|
|
902
|
+
entity.facing = rotateTowards(entity.facing, m.finalFacing, turnRateOf(world, entity) * dt);
|
|
903
|
+
if (entity.facing === m.finalFacing) m.finalFacing = null;
|
|
904
|
+
}
|
|
905
|
+
/** How far a unit on its way has still to go: to the edge of what it goes to, or to its point. None for a target gone */
|
|
906
|
+
function distanceLeft(world, entity, m) {
|
|
907
|
+
if (!m.goalEntity) return dist(entity.pos, m.goal);
|
|
908
|
+
const target = world.get(m.goalEntity);
|
|
909
|
+
return target ? edgeDistance(entity, target) : void 0;
|
|
910
|
+
}
|
|
911
|
+
/**
|
|
912
|
+
* Round a knot of standing units: sent on past the point beside them as it nears it, and back on its way once it is
|
|
913
|
+
* past that point, or held up there
|
|
914
|
+
*/
|
|
915
|
+
function steerAround(world, entity, m) {
|
|
916
|
+
if (!m.detour) return;
|
|
917
|
+
const near = dist(entity.pos, m.detour);
|
|
918
|
+
const aim = m.detourAim ?? m.navGoal;
|
|
919
|
+
const passed = (entity.pos.x - m.detour.x) * (aim.x - m.detour.x) + (entity.pos.z - m.detour.z) * (aim.z - m.detour.z) > 0;
|
|
920
|
+
if (m.detourPast && passed || near <= .5 || m.stalledTime > .5 || (m.slowTime ?? 0) > .3) {
|
|
921
|
+
m.detour = void 0;
|
|
922
|
+
walk(world, entity);
|
|
923
|
+
} else if (!m.detourPast && near <= DETOUR_PAST_AT) {
|
|
924
|
+
m.detourPast = true;
|
|
925
|
+
const to = m.detourAim ?? m.stretch ?? m.navGoal;
|
|
926
|
+
let px = to.x - m.detour.x;
|
|
927
|
+
let pz = to.z - m.detour.z;
|
|
928
|
+
const past = hypot(px, pz);
|
|
929
|
+
if (past > DETOUR_PAST) {
|
|
930
|
+
px *= DETOUR_PAST / past;
|
|
931
|
+
pz *= DETOUR_PAST / past;
|
|
932
|
+
}
|
|
933
|
+
world.nav.setDestination(entity.id, {
|
|
934
|
+
x: m.detour.x + px,
|
|
935
|
+
z: m.detour.z + pz
|
|
936
|
+
});
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
/**
|
|
940
|
+
* On a route its side planned: planned again once the side knows more (a few units a tick, by their ids), and sent on
|
|
941
|
+
* a stretch further once halfway along the one it is on
|
|
942
|
+
*/
|
|
943
|
+
function followRoute(world, entity, m) {
|
|
944
|
+
if (m.detour || !(m.route || m.routeVersion !== void 0)) return;
|
|
945
|
+
const team = sideOf(world, entity);
|
|
946
|
+
let again = false;
|
|
947
|
+
if (team !== void 0 && m.routeVersion !== world.sidePaths.version(team) && (entity.id + world.tick) % 8 === 0) {
|
|
948
|
+
planRoute(world, entity, team);
|
|
949
|
+
again = true;
|
|
950
|
+
}
|
|
951
|
+
if (again || m.stretch && dist(entity.pos, m.stretch) < stretchOf(entity) / 2) {
|
|
952
|
+
const next = m.route ? stretchPoint(entity) : m.navGoal;
|
|
953
|
+
if (again || !m.stretch || dist(next, m.stretch) > .5) walk(world, entity);
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
/**
|
|
957
|
+
* Whether a unit on its way gets anywhere: held up by others (asked aside, gone round), stalled (arrived where close is
|
|
958
|
+
* good enough, or given up after a while)
|
|
959
|
+
*/
|
|
960
|
+
function watchProgress(world, entity, m, distance, dt) {
|
|
961
|
+
const progress = hypot(entity.pos.x - agent.cx, entity.pos.z - agent.cz);
|
|
962
|
+
if (agent.cx !== m.corner.x || agent.cz !== m.corner.z) {
|
|
963
|
+
m.corner.x = agent.cx;
|
|
964
|
+
m.corner.z = agent.cz;
|
|
965
|
+
m.bestDistance = progress;
|
|
966
|
+
}
|
|
967
|
+
m.slowTime = m.speed > 0 && hypot(agent.vx, agent.vz) < m.speed * SLOW_PART && distance > m.range + entity.def.radius * 2 + .3 && m.bestDistance < Infinity ? (m.slowTime ?? 0) + dt : 0;
|
|
968
|
+
if (!m.detour && !m.aside && (world.tick + entity.id) % LOOK_AHEAD_INTERVAL === 0) lookAhead(world, entity, agent);
|
|
969
|
+
if (progress < m.bestDistance - .1) {
|
|
970
|
+
m.bestDistance = progress;
|
|
971
|
+
m.stalledTime = 0;
|
|
972
|
+
if (m.tries && distance < (m.triedAt ?? Infinity) - TRIED_FAR) {
|
|
973
|
+
delete m.tries;
|
|
974
|
+
delete m.triedAt;
|
|
975
|
+
}
|
|
976
|
+
if (!m.aside && (m.slowTime ?? 0) > MAKE_WAY_AFTER && (world.tick + entity.id) % MAKE_WAY_INTERVAL === 0) makeWay(world, entity);
|
|
977
|
+
return;
|
|
978
|
+
}
|
|
979
|
+
m.stalledTime += dt;
|
|
980
|
+
if ((!m.aside || (m.asideDepth ?? 1) < ASIDE_DEPTH) && m.stalledTime > MAKE_WAY_AFTER && (world.tick + entity.id) % MAKE_WAY_INTERVAL === 0) makeWay(world, entity);
|
|
981
|
+
if (!m.goalEntity) {
|
|
982
|
+
const formed = m.groupId && m.formation === m.groupId && !m.aside;
|
|
983
|
+
if (formed && m.stalledTime > .25 && distance < m.range + 4 && swapPlaces(world, entity, m)) return;
|
|
984
|
+
if (formed && m.stalledTime > .25 && (world.tick + entity.id) % LOOK_AHEAD_INTERVAL === 0 && passOn(world, entity, m)) return;
|
|
985
|
+
if (formed && m.stalledTime > .25 && (world.tick + entity.id) % LOOK_AHEAD_INTERVAL === 0 && tradeGoals(world, entity, m)) return;
|
|
986
|
+
if (formed && m.stalledTime > MAKE_WAY_AFTER && distance < NUDGE_NEAR && (world.tick + entity.id) % MAKE_WAY_INTERVAL === 0) {
|
|
987
|
+
nudge(world, entity, m);
|
|
988
|
+
clearPlace(world, entity, m);
|
|
989
|
+
}
|
|
990
|
+
const taken = m.aside || m.stalledTime > .25 && distance < m.range + 4 && goalTaken(world, entity, m);
|
|
991
|
+
if (taken && m.stalledTime > .25 && distance < m.range + 4 && blockedByArrivedGroupMate(world, entity)) arrive(world, entity);
|
|
992
|
+
else if (taken && m.stalledTime > .6 && distance < 1.25) arrive(world, entity);
|
|
993
|
+
}
|
|
994
|
+
if (m.status === "moving" && m.stalledTime > HELD_UP) {
|
|
995
|
+
if (!m.goalEntity && distance < 3 && (m.aside || m.place || goalTaken(world, entity, m))) arrive(world, entity);
|
|
996
|
+
else if (!m.aside && (m.tries ?? 0) < TRIES && !wayEndsShort(entity, m) && heldByUnits(world, entity)) tryAgain(world, entity, m, distance);
|
|
997
|
+
else if (!m.goalEntity && distance < 3) arrive(world, entity);
|
|
998
|
+
else {
|
|
999
|
+
world.nav.clearDestination(entity.id);
|
|
1000
|
+
m.status = "failed";
|
|
1001
|
+
m.stuck = true;
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
/** Seconds a unit on its way gets nowhere before it tries again (`tryAgain`), or, out of tries, gives up */
|
|
1006
|
+
var HELD_UP = 3;
|
|
1007
|
+
/** How many times a unit held up tries again before it gives up: 4, after 15 seconds held up in all */
|
|
1008
|
+
var TRIES = 4;
|
|
1009
|
+
/** How much nearer a unit that tried again has to get to have its tries again */
|
|
1010
|
+
var TRIED_FAR = 2;
|
|
1011
|
+
/**
|
|
1012
|
+
* Whether another unit stands where a unit on its way is going: then near is as good as there, rather than push it
|
|
1013
|
+
* off (a group sent to one point, a unit sent where another stands)
|
|
1014
|
+
*/
|
|
1015
|
+
function goalTaken(world, entity, m) {
|
|
1016
|
+
return !!standingOn(world, entity, m.goal, true);
|
|
1017
|
+
}
|
|
1018
|
+
/**
|
|
1019
|
+
* The unit standing on a point, where another would stand, the nearest it: none where nobody does. `sameGoal` counts
|
|
1020
|
+
* one on its way to that very point, there already, as standing there: several sent to one point
|
|
1021
|
+
*/
|
|
1022
|
+
function standingOn(world, entity, point, sameGoal = false) {
|
|
1023
|
+
world.spatial.query(point.x, point.z, entity.def.radius + 1, roomNear);
|
|
1024
|
+
let nearest;
|
|
1025
|
+
let best = Infinity;
|
|
1026
|
+
for (const other of roomNear) {
|
|
1027
|
+
if (other === entity || other.hidden || other.flying !== entity.flying || !other.get(moving)) continue;
|
|
1028
|
+
const om = other.get(moving);
|
|
1029
|
+
const room = entity.def.radius + other.def.radius;
|
|
1030
|
+
if (om.status === "moving" && !(sameGoal && hypot(om.goal.x - point.x, om.goal.z - point.z) < room)) continue;
|
|
1031
|
+
const d = hypot(other.pos.x - point.x, other.pos.z - point.z);
|
|
1032
|
+
if (d < room && d < best) {
|
|
1033
|
+
best = d;
|
|
1034
|
+
nearest = other;
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
return nearest;
|
|
1038
|
+
}
|
|
1039
|
+
/**
|
|
1040
|
+
* A unit of a formation held up near its place, with another of the formation standing on it, off its own (it stopped
|
|
1041
|
+
* short of it, or stepped aside onto this one): they swap. The one standing there has its place where it stands, and
|
|
1042
|
+
* this one goes to the other's. The formation is whole all the same, and neither pushes the other. Only those of a
|
|
1043
|
+
* type: a formation that places each by who it is (`FormationDef.points`) keeps them so. True when they do
|
|
1044
|
+
*/
|
|
1045
|
+
function swapPlaces(world, entity, m) {
|
|
1046
|
+
const theirs = takeOver(world, entity, m.goal, m.groupId);
|
|
1047
|
+
if (!theirs) return false;
|
|
1048
|
+
toPlace(world, entity, theirs, m.groupId, m.finalFacing);
|
|
1049
|
+
return true;
|
|
1050
|
+
}
|
|
1051
|
+
/**
|
|
1052
|
+
* The one of formation `group` standing on a place, off its own, given that place where it stands, as `swapPlaces`
|
|
1053
|
+
* has it: its own place, which is the other one's now, or none where nobody such stands there
|
|
1054
|
+
*/
|
|
1055
|
+
function takeOver(world, entity, place, group) {
|
|
1056
|
+
const other = standingOn(world, entity, place);
|
|
1057
|
+
const om = other?.get(moving);
|
|
1058
|
+
if (!other || !om?.place || om.formation !== group || other.def.id !== entity.def.id || other.orders.length > 0) return;
|
|
1059
|
+
if (dist(other.pos, om.place) <= PLACE_OFF || dist(om.place, place) <= PLACE_OFF) return;
|
|
1060
|
+
const theirs = om.place;
|
|
1061
|
+
om.place = {
|
|
1062
|
+
x: place.x,
|
|
1063
|
+
z: place.z
|
|
1064
|
+
};
|
|
1065
|
+
delete om.backTries;
|
|
1066
|
+
return theirs;
|
|
1067
|
+
}
|
|
1068
|
+
/** How near its place one of a formation is for those of it it touches, ahead, to make it room (`nudge`) */
|
|
1069
|
+
var NUDGE_NEAR = 1.5;
|
|
1070
|
+
/** How far they step to make room, from where they stand: back to their places after (`backToPlace`) */
|
|
1071
|
+
var NUDGE = .4;
|
|
1072
|
+
/**
|
|
1073
|
+
* One of a formation held up right by its place, those of it at theirs touching it on the way there: they step a
|
|
1074
|
+
* little away from it to make it room, as a crowd parts, and go back to their places once it is in its own. The last
|
|
1075
|
+
* of a ring to come finds the gap left for it narrowed by those either side, each stopped up to `ARRIVE_RANGE` short
|
|
1076
|
+
*/
|
|
1077
|
+
function nudge(world, entity, m) {
|
|
1078
|
+
const dx = m.goal.x - entity.pos.x;
|
|
1079
|
+
const dz = m.goal.z - entity.pos.z;
|
|
1080
|
+
world.spatial.query(entity.pos.x, entity.pos.z, entity.def.radius + 1.5, roomNear);
|
|
1081
|
+
const near = [...roomNear];
|
|
1082
|
+
for (const other of near) {
|
|
1083
|
+
const om = other.get(moving);
|
|
1084
|
+
if (other === entity || !om?.place || om.formation !== m.groupId || om.status === "moving" || other.orders.length > 0 || om.anchored) continue;
|
|
1085
|
+
const rx = other.pos.x - entity.pos.x;
|
|
1086
|
+
const rz = other.pos.z - entity.pos.z;
|
|
1087
|
+
const apart = hypot(rx, rz);
|
|
1088
|
+
if (rx * dx + rz * dz <= 0 || apart - entity.def.radius - other.def.radius > .25 || apart < .01) continue;
|
|
1089
|
+
const x = other.pos.x + rx / apart * NUDGE;
|
|
1090
|
+
const z = other.pos.z + rz / apart * NUDGE;
|
|
1091
|
+
if (!walkableAt(world.navFor(other), x, z)) continue;
|
|
1092
|
+
moveTo(world, other, {
|
|
1093
|
+
x,
|
|
1094
|
+
z
|
|
1095
|
+
}, {
|
|
1096
|
+
facing: om.finalFacing ?? other.facing,
|
|
1097
|
+
aside: true
|
|
1098
|
+
});
|
|
1099
|
+
om.asideDepth = ASIDE_DEPTH;
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
/**
|
|
1103
|
+
* One of a formation held up by its place, an ally of none of it standing there: asked aside, as the rules have it
|
|
1104
|
+
* (`stepAside`). A formation is laid out where it is sent, whoever stood there
|
|
1105
|
+
*/
|
|
1106
|
+
function clearPlace(world, entity, m) {
|
|
1107
|
+
const other = standingOn(world, entity, m.goal);
|
|
1108
|
+
if (!other || other.get(moving).formation === m.groupId) return;
|
|
1109
|
+
const dx = m.goal.x - entity.pos.x;
|
|
1110
|
+
const dz = m.goal.z - entity.pos.z;
|
|
1111
|
+
const length = hypot(dx, dz);
|
|
1112
|
+
if (length < .01 || !world.nav.readAgent(entity.id, agent)) return;
|
|
1113
|
+
direction.x = dx / length;
|
|
1114
|
+
direction.z = dz / length;
|
|
1115
|
+
stepAside(world, entity, other, direction, agent);
|
|
1116
|
+
}
|
|
1117
|
+
/** Sends one of a formation to a place in it, as its order did: it keeps the place once there */
|
|
1118
|
+
function toPlace(world, entity, place, groupId, facing) {
|
|
1119
|
+
moveTo(world, entity, place, {
|
|
1120
|
+
groupId,
|
|
1121
|
+
facing: facing ?? void 0
|
|
1122
|
+
});
|
|
1123
|
+
movementOf(entity).formation = groupId;
|
|
1124
|
+
}
|
|
1125
|
+
/** How much nearer its place the one standing in the way is than the one held up, for it to be passed on (`passOn`) */
|
|
1126
|
+
var PASS_NEARER = .25;
|
|
1127
|
+
/**
|
|
1128
|
+
* A unit of a formation held up by another of it standing at its place, on the way to its own further in: the one
|
|
1129
|
+
* standing goes on to that place, nearer it, and this one takes the one it leaves, right by it. The places of a ring
|
|
1130
|
+
* deep in the formation are filled through those already standing, a step at a time, rather than each pushing through
|
|
1131
|
+
* those that came first. Each pass has the one going on to the place nearer it (`PASS_NEARER`), so that it comes to an
|
|
1132
|
+
* end. Only to one of its type, as `swapPlaces`. True when it is passed on
|
|
1133
|
+
*/
|
|
1134
|
+
function passOn(world, entity, m) {
|
|
1135
|
+
const left = dist(entity.pos, m.goal);
|
|
1136
|
+
world.spatial.query(entity.pos.x, entity.pos.z, entity.def.radius + 1.5, roomNear);
|
|
1137
|
+
let best;
|
|
1138
|
+
let nearest = left - PASS_NEARER;
|
|
1139
|
+
for (const other of roomNear) {
|
|
1140
|
+
const om = other.get(moving);
|
|
1141
|
+
if (other === entity || !om?.place || om.formation !== m.groupId || other.def.id !== entity.def.id || om.status === "moving" || other.orders.length > 0 || om.anchored) continue;
|
|
1142
|
+
if (distanceToEdge(entity.pos, other) - entity.def.radius > .35 || dist(other.pos, om.place) > PLACE_OFF) continue;
|
|
1143
|
+
if (dist(entity.pos, om.place) > entity.def.radius + other.def.radius + .6) continue;
|
|
1144
|
+
const d = dist(other.pos, m.goal);
|
|
1145
|
+
if (d < nearest) {
|
|
1146
|
+
nearest = d;
|
|
1147
|
+
best = other;
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
if (!best) return false;
|
|
1151
|
+
const theirs = best.get(moving).place;
|
|
1152
|
+
toPlace(world, best, {
|
|
1153
|
+
x: m.goal.x,
|
|
1154
|
+
z: m.goal.z
|
|
1155
|
+
}, m.groupId, m.finalFacing);
|
|
1156
|
+
toPlace(world, entity, theirs, m.groupId, m.finalFacing);
|
|
1157
|
+
return true;
|
|
1158
|
+
}
|
|
1159
|
+
/** How much shorter the two ways together are for two of a formation to trade places on the way (`tradeGoals`) */
|
|
1160
|
+
var TRADE_SHORTER = .5;
|
|
1161
|
+
/**
|
|
1162
|
+
* Two of a formation on their way, holding each other up, each nearer the other's place than its own (they meet head
|
|
1163
|
+
* on, or cross): they trade places, when the two ways together are shorter by `TRADE_SHORTER`, rather than each push
|
|
1164
|
+
* round the other. Only with one of its type that does nothing but walk to its place, as `swapPlaces`. True when they do
|
|
1165
|
+
*/
|
|
1166
|
+
function tradeGoals(world, entity, m) {
|
|
1167
|
+
const mine = dist(entity.pos, m.goal);
|
|
1168
|
+
world.spatial.query(entity.pos.x, entity.pos.z, entity.def.radius + 1.5, roomNear);
|
|
1169
|
+
let best;
|
|
1170
|
+
let most = TRADE_SHORTER;
|
|
1171
|
+
for (const other of roomNear) {
|
|
1172
|
+
const om = other.get(moving);
|
|
1173
|
+
if (other === entity || !om || om.status !== "moving" || om.aside || om.goalEntity || om.groupId !== m.groupId || om.formation !== m.groupId || other.def.id !== entity.def.id || other.orders.length > 1 || other.orders.length === 1 && other.orders[0].type !== "move" || distanceToEdge(entity.pos, other) - entity.def.radius > .35) continue;
|
|
1174
|
+
const shorter = mine + dist(other.pos, om.goal) - dist(entity.pos, om.goal) - dist(other.pos, m.goal);
|
|
1175
|
+
if (shorter > most) {
|
|
1176
|
+
most = shorter;
|
|
1177
|
+
best = other;
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
if (!best) return false;
|
|
1181
|
+
const goal = best.get(moving).goal;
|
|
1182
|
+
const theirs = {
|
|
1183
|
+
x: goal.x,
|
|
1184
|
+
z: goal.z
|
|
1185
|
+
};
|
|
1186
|
+
toPlace(world, best, {
|
|
1187
|
+
x: m.goal.x,
|
|
1188
|
+
z: m.goal.z
|
|
1189
|
+
}, m.groupId, m.finalFacing);
|
|
1190
|
+
toPlace(world, entity, theirs, m.groupId, m.finalFacing);
|
|
1191
|
+
return true;
|
|
1192
|
+
}
|
|
1193
|
+
/**
|
|
1194
|
+
* Whether the unit stands at the end of its path, and that end is short of where it goes: the navigation knows no way
|
|
1195
|
+
* further (across a wood, up a cliff). Then trying again is no good
|
|
1196
|
+
*/
|
|
1197
|
+
function wayEndsShort(entity, m) {
|
|
1198
|
+
const to = m.stretch ?? m.navGoal;
|
|
1199
|
+
return hypot(entity.pos.x - agent.cx, entity.pos.z - agent.cz) < entity.def.radius + .5 && hypot(agent.cx - to.x, agent.cz - to.z) > .5;
|
|
1200
|
+
}
|
|
1201
|
+
/**
|
|
1202
|
+
* Whether others that may yet go are what hold a unit up: one against it that is not anchored (an ally that makes way,
|
|
1203
|
+
* one on its way, an enemy that moves on). Not the ground, a wood, nor those holding their ground: trying again is no
|
|
1204
|
+
* good against them
|
|
1205
|
+
*/
|
|
1206
|
+
function heldByUnits(world, entity) {
|
|
1207
|
+
world.spatial.query(entity.pos.x, entity.pos.z, entity.def.radius + 1.5, roomNear);
|
|
1208
|
+
for (const other of roomNear) {
|
|
1209
|
+
const om = other.get(moving);
|
|
1210
|
+
if (other === entity || !om || om.anchored || om.ghost || om.phased || other.hidden || !other.alive || other.flying !== entity.flying) continue;
|
|
1211
|
+
if (distanceToEdge(entity.pos, other) - entity.def.radius < .6) return true;
|
|
1212
|
+
}
|
|
1213
|
+
return false;
|
|
1214
|
+
}
|
|
1215
|
+
/**
|
|
1216
|
+
* A unit held up on its way (`HELD_UP`), where its goal is not taken, tries again rather than give up: it is sent on
|
|
1217
|
+
* its way anew, looks round the whole knot it is held up by for a way round, however long, and asks those of it that
|
|
1218
|
+
* make way aside. Out of tries (`TRIES`) it gives up: a crowd of others, or enemies, that will not let it through
|
|
1219
|
+
*/
|
|
1220
|
+
function tryAgain(world, entity, m, distance) {
|
|
1221
|
+
m.tries = (m.tries ?? 0) + 1;
|
|
1222
|
+
m.triedAt = distance;
|
|
1223
|
+
m.stalledTime = 0;
|
|
1224
|
+
m.slowTime = 0;
|
|
1225
|
+
m.detour = void 0;
|
|
1226
|
+
walk(world, entity);
|
|
1227
|
+
if (!world.nav.readAgent(entity.id, agent)) return;
|
|
1228
|
+
m.corner.x = agent.cx;
|
|
1229
|
+
m.corner.z = agent.cz;
|
|
1230
|
+
m.bestDistance = hypot(entity.pos.x - agent.cx, entity.pos.z - agent.cz);
|
|
1231
|
+
lookFurther(world, entity, agent, true);
|
|
1232
|
+
if (!m.detour) makeWay(world, entity);
|
|
1233
|
+
}
|
|
1234
|
+
var movementSystem = {
|
|
1235
|
+
name: "movement",
|
|
1236
|
+
phase: "move",
|
|
1237
|
+
update(world, dt) {
|
|
1238
|
+
seeToPhasing(world);
|
|
1239
|
+
followTargets(world);
|
|
1240
|
+
world.nav.update(dt);
|
|
1241
|
+
readAgents(world, dt);
|
|
1242
|
+
}
|
|
1243
|
+
};
|
|
1244
|
+
//#endregion
|
|
1245
|
+
export { ARRIVE_RANGE, REPATH_SPREAD, approachPoint, faceTowards, halt, isMovingTo, joinFormation, lookAhead, makeWay, moveTo, moveToEntity, movementSystem, setAnchored, setGhost, standsInWay, stepAside, walkOn };
|
|
1246
|
+
|
|
1247
|
+
//# sourceMappingURL=movement.js.map
|