@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 @@
|
|
|
1
|
+
{"version":3,"file":"harvest.js","names":[],"sources":["../../src/orders/harvest.ts"],"sourcesContent":["import { chopped, resourcesDeposited } from '#engine/engineEvents'\nimport { defineComponent } from '#engine/components'\nimport type { ResourceId } from '#engine/defs'\nimport { edgeDistance, type Entity, type EntityId, type HarvesterState, type Order, type ResourceState } from '#engine/entity'\nimport type { GatheringInfo } from '#engine/session/protocol'\nimport { closestPointOnRect, dist, distSq, type Vec2 } from '#engine/math'\nimport type { OrderBehavior, OrderInits, OrderStatus } from '#engine/registry'\nimport { faceTowards, halt, moveTo, moveToEntity, setAnchored, setGhost } from '#engine/systems/movement'\nimport { earn } from '#engine/player'\nimport type { World } from '#engine/world'\nimport { engineMessage, type MessageRef, toMessage } from '#engine/messages'\nimport { cos, hypot, sin } from '#engine/exactMath'\nimport { moving, deposit } from '../entity'\n\n/** Edge distance at which a worker can get to work on a resource or hand in what it carries */\nconst REACH = 0.7\nconst RESOURCE_SEARCH_RADIUS = 30\n/** How close to its spot a worker has to be to start on a tree */\nconst SPOT_RANGE = 0.45\n/** How near a tree's spot a worker whose walk is over has to be to work it: next to it, where someone stands on the spot */\nconst NEXT_TO_SPOT = 1.3\n/** How many trees out of reach an order remembers, not to go for them again */\nconst OUT_OF_REACH_KEPT = 8\n/** Places to wait at a full mine, side by side: workers past that many share them */\nconst WAITING_PLACES = 5\n/** How close to its place a worker waits: on it, nearly, or it would stand in the next one's */\nconst WAIT_RANGE = 0.15\n/** Seconds between two blows of the axe */\nconst CHOP_INTERVAL = 1\n\n/**\n * The step a worker is at: walking to its resource, gathering, bringing the load home\n *\n * @internal\n */\nexport type HarvestPhase = 'toResource' | 'gathering' | 'toDropOff'\n\n/**\n * What a worker carries and where it gathers (`UnitTypeDef.harvester`): set as it is spawned (and as its type changes),\n * for a type that gathers. Its owner and their allies are told what it carries (`GatheringInfo`)\n *\n * @beta\n */\nexport const gathering = defineComponent<HarvesterState, GatheringInfo>({ id: 'core.harvester', // a worker's load, nothing carried yet\n\tonSpawn: (entity) => {\n\t\tif (entity.def.kind === 'unit' && entity.def.harvester) entity.set(gathering, { carrying: 0, kind: null, resource: 0 })\n\t},\n\treplicate: 'allies',\n\tsnapshot: (state) => ({ carrying: state.carrying, kind: state.kind }),\n\tsame: (a, b) => a.carrying === b.carrying && a.kind === b.kind })\n\n/**\n * What a worker carries and where it gathers: none for a type that does not gather (`gathering`)\n *\n * @beta\n */\nexport const harvesterOf = (entity: Entity): HarvesterState | undefined => entity.get(gathering)\n\n/** Whether a building takes in a resource. Any drop-off will do for a worker that has not gathered anything yet */\nconst accepts = (building: Entity, kind: ResourceId | null | undefined) => {\n\tconst { dropOff } = building.def\n\tif (!kind) return !!dropOff\n\treturn dropOff === true || (Array.isArray(dropOff) && dropOff.includes(kind))\n}\n\n/** Closest building of the player that takes the resource */\nexport function findDropOff(world: World, entity: Entity, kind: ResourceId | null | undefined = harvesterOf(entity)?.kind): Entity | undefined {\n\tlet best: Entity | undefined\n\tlet bestDistance = Infinity\n\tfor (const other of world.index.ownedBy(entity.owner)) {\n\t\tif (!other.operational || !accepts(other, kind)) continue\n\t\tconst d = distSq(entity.pos, other.pos)\n\t\tif (d < bestDistance) {\n\t\t\tbestDistance = d\n\t\t\tbest = other\n\t\t}\n\t}\n\treturn best\n}\n\n/**\n * Whether a worker may gather from a resource: one of a kind it gathers (`harvester.ids`), and then as the game's\n * `canHarvest` hook says\n *\n * @beta\n */\nexport function canHarvest(world: World, worker: Entity, source: Entity): boolean {\n\treturn harvestRefusal(world, worker, source) === null\n}\n\n/** Why a worker may not gather from a resource (`canHarvest`): null where it may, and undefined where nothing is said */\nfunction harvestRefusal(world: World, worker: Entity, source: Entity): MessageRef | undefined | null {\n\tconst kind = source.def.resource?.id\n\tconst kinds = worker.def.harvester?.ids\n\tif (!kind || !worker.def.harvester) return undefined\n\t// a resource someone has built on is theirs alone (`UnitTypeDef.builtOn`)\n\tconst above = world.get(source.get(deposit)?.under)\n\tconst allowed = (!kinds || kinds.includes(kind)) && (!above?.alive || above.owner === worker.owner)\n\tif (!world.hooks.has('canHarvest')) return allowed ? null : engineMessage('cannotGather', { resource: kind })\n\tconst decided = world.hooks.run('canHarvest', {\n\t\tworker,\n\t\tsource,\n\t\tcancelled: !allowed,\n\t\t...(!allowed && { reason: engineMessage('cannotGather', { resource: kind }) })\n\t})\n\treturn decided.cancelled ? (decided.reason ?? engineMessage('cannotGather', { resource: kind })) : null\n}\n/** Whether another worker fits. Resources that are worked on from outside, like trees, are claimed by whoever is on their way */\nconst hasRoom = (source: Entity) => source.get(deposit)!.occupants < Math.max(source.def.resource!.slots, 1)\n\n/** Whether a worker can get next to it. Trees inside a forest have to wait for the ones around them to fall */\nfunction reachable(world: World, source: Entity): boolean {\n\tconst cell = source.cell\n\tconst fp = source.def.footprint\n\tif (!cell || !fp) return true\n\tfor (let i = 0; i < fp.w; i++)\n\t\tif (world.grid.occupantAt(cell.x + i, cell.z - 1) === 0 || world.grid.occupantAt(cell.x + i, cell.z + fp.d) === 0) return true\n\tfor (let j = 0; j < fp.d; j++)\n\t\tif (world.grid.occupantAt(cell.x - 1, cell.z + j) === 0 || world.grid.occupantAt(cell.x + fp.w, cell.z + j) === 0) return true\n\treturn false\n}\n\n/** Where to stand to work on a source from outside: in front of its free side that is closest to the worker */\nfunction workSpot(world: World, entity: Entity, source: Entity): Vec2 {\n\tconst { cell, pos } = source\n\tconst fp = source.def.footprint\n\tconst reach = entity.def.radius + 0.2\n\tlet best: Vec2 | undefined\n\tlet bestDistance = Infinity\n\tif (cell && fp) {\n\t\tconst sides = [\n\t\t\t{ x: -1, z: 0, free: world.grid.occupantAt(cell.x - 1, cell.z) === 0 },\n\t\t\t{ x: 1, z: 0, free: world.grid.occupantAt(cell.x + fp.w, cell.z) === 0 },\n\t\t\t{ x: 0, z: -1, free: world.grid.occupantAt(cell.x, cell.z - 1) === 0 },\n\t\t\t{ x: 0, z: 1, free: world.grid.occupantAt(cell.x, cell.z + fp.d) === 0 }\n\t\t]\n\t\tfor (const side of sides) {\n\t\t\tif (!side.free) continue\n\t\t\tconst spot = { x: pos.x + side.x * (fp.w / 2 + reach), z: pos.z + side.z * (fp.d / 2 + reach) }\n\t\t\tconst distance = distSq(entity.pos, spot)\n\t\t\tif (distance < bestDistance) {\n\t\t\t\tbestDistance = distance\n\t\t\t\tbest = spot\n\t\t\t}\n\t\t}\n\t}\n\tbest ??= closestPointOnRect(entity.pos, source.rect, reach)\n\treturn world.nav.closestPoint(best, 3) ?? best\n}\n\n/** How far `findResource` looks at first. Most of the time the next tree is right there */\nconst RESOURCE_SEARCH_STEPS = [6, 12]\nconst nearby: Entity[] = []\n\n/**\n * Closest resource with something left within `radius` of the point, of a kind when one is named.\n * `free` only takes what another worker can still get at. Among equally close ones, the oldest.\n */\nexport function findResource(\n\tworld: World,\n\tnear: Vec2,\n\tradius: number,\n\tkind?: ResourceId,\n\tfree = false,\n\tworker?: Entity,\n\tskip?: readonly EntityId[]\n): Entity | undefined {\n\t// look close by first and further only when there is nothing: everything within the distance looked at comes back,\n\t// so whatever is found within it is the closest there is\n\tfor (const step of RESOURCE_SEARCH_STEPS) {\n\t\tif (step >= radius) break\n\t\tconst found = closestResource(world, near, step, kind, free, worker, skip)\n\t\tif (found) return found\n\t}\n\treturn closestResource(world, near, radius, kind, free, worker, skip)\n}\n\nfunction closestResource(\n\tworld: World,\n\tnear: Vec2,\n\tradius: number,\n\tkind: ResourceId | undefined,\n\tfree: boolean,\n\tworker?: Entity,\n\tskip?: readonly EntityId[]\n): Entity | undefined {\n\tlet best: Entity | undefined\n\tlet bestDistance = radius * radius\n\tfor (const other of world.spatial.query(near.x, near.z, radius, nearby)) {\n\t\tif (!other.alive || !other.get(deposit) || other.get(deposit)!.amount <= 0) continue\n\t\tif (kind && other.def.resource!.id !== kind) continue\n\t\tif (skip?.includes(other.id)) continue\n\t\tif (free && !other.def.resource!.entered && (!hasRoom(other) || !reachable(world, other))) continue\n\t\tconst d = distSq(near, other.pos)\n\t\tif (d > bestDistance || (d === bestDistance && best && other.id > best.id)) continue\n\t\t// what this worker may gather from, asked last: it can be a game's hook\n\t\tif (worker && !canHarvest(world, worker, other)) continue\n\t\tif (d < bestDistance || (d === bestDistance && best && other.id < best.id)) {\n\t\t\tbestDistance = d\n\t\t\tbest = other\n\t\t}\n\t}\n\treturn best\n}\n\n/**\n * What a worker hands in at where it gathers: the building of its owner's that stands on the resource and takes it\n * (`UnitTypeDef.builtOn`, a cursed mine), finished. None for a resource gathered the ordinary way\n */\nfunction gatheringAt(world: World, worker: Entity, source: Entity): Entity | undefined {\n\tconst above = world.get(source.get(deposit)?.under)\n\tif (!above?.alive || !above.operational || above.owner !== worker.owner) return undefined\n\treturn accepts(above, source.def.resource!.id) ? above : undefined\n}\n\n/** Where the `slot`th of `of` workers gathering at a building stands: round its edge, spread out evenly */\nfunction spotAround(world: World, worker: Entity, building: Entity, slot: number, of: number): Vec2 {\n\tconst angle = (slot / Math.max(of, 1)) * Math.PI * 2\n\tconst far = { x: building.pos.x + sin(angle) * 50, z: building.pos.z + cos(angle) * 50 }\n\tconst spot = closestPointOnRect(far, building.rect, worker.def.radius + 0.2)\n\treturn world.nav.closestPoint(spot, 3) ?? spot\n}\n\n/** Hands in what a worker carries: cut by upkeep for what has it, then as the game's `beforeDeposit` says */\nfunction dropOff(world: World, entity: Entity): void {\n\tconst harvester = harvesterOf(entity)!\n\t// what it carries came from somewhere, so it knows what it is\n\tconst kind = harvester.kind!\n\t// upkeep is taken at the door, from the resources that have it\n\tconst income = world.registry.resource(kind)?.upkeep ? world.settings.economy.upkeep(world, entity.owner).income : 1\n\tlet amount = Math.round(harvester.carrying * income)\n\tconst upkeep = income < 1 ? Math.round(harvester.carrying) - amount : 0\n\t// what the game makes of it: more from a mine near the keep, nothing in a famine\n\tif (world.hooks.has('beforeDeposit')) {\n\t\tconst before = world.hooks.run('beforeDeposit', { worker: entity, player: entity.owner, kind, amount, cancelled: false })\n\t\tamount = before.cancelled ? 0 : before.amount\n\t}\n\tearn(world.player(entity.owner).resources, kind, amount)\n\tworld.events.emit(resourcesDeposited, { entity, player: entity.owner, kind, amount, ...(upkeep > 0 && { upkeep }) })\n\tharvester.carrying = 0\n}\n\n/**\n * What harvesting keeps through every step of it, and from one load to the next: the kind it gathers and where it last\n * did, the resource it holds a place at (`claimed`, a tree, a place round a building on a resource), the building it\n * gathers at (`inPlace`), the place it walks to and the one it waits at, whether it walked to its place already, the\n * seconds to its next swing (`chop`: the rhythm goes on from one load to the next), the hall it brings its loads to\n *\n * @beta\n */\nexport interface HarvestKept {\n\t/** The resource kind the worker gathers, set once it knows what it works */\n\tkind?: ResourceId\n\t/** Where the resource it last gathered from stands, to look for the next of its kind near */\n\tat?: Vec2\n\t/** The resource whose place at it the worker holds (a tree, or a place round a building on a resource); 0 or unset when none */\n\tclaimed?: EntityId\n\t/** The building of its owner's that stands on the resource it gathers, where it works round that building; 0 or unset otherwise */\n\tinPlace?: EntityId\n\t/** The place it walks to and works from, in front of its tree or round the building */\n\tspot?: Vec2\n\t/** The place it waits at, beside a mine or building with no room; cleared once it gets a place */\n\twaitSpot?: Vec2\n\t/** Whether it has already set off for its `spot`, so a spot someone stands on is told from one not yet walked to */\n\twalked?: boolean\n\t/** The trees it walked to and could not get next to, the last few: not gone for again by this order */\n\toutOfReach?: EntityId[]\n\t/** Seconds to its next swing at a tree; the rhythm goes on from one load to the next */\n\tchop?: number\n\t/** The building it last brought, or is bringing, its load to; reset to 0 after each hand-in so the closest is chosen again */\n\tdropOff?: EntityId\n}\n\n/**\n * Walking to its resource, and to its place at it (`HarvestState`)\n *\n * @beta\n */\nexport interface HarvestToResource extends HarvestKept {\n\t/** The step this state is in, `'toResource'` */\n\tphase: 'toResource'\n}\n\n/**\n * At work (`HarvestState`): the seconds of it left, and what it works (`working`) or is inside of (a mine's, `inside`)\n *\n * @beta\n */\nexport interface HarvestGathering extends HarvestKept {\n\t/** The step this state is in, `'gathering'` */\n\tphase: 'gathering'\n\t/** Seconds of work left before the load is taken */\n\ttimer: number\n\t/** The resource it works from outside, like a tree */\n\tworking?: EntityId\n\t/** The mine it is inside of, hidden, while it works there */\n\tinside?: EntityId\n}\n\n/**\n * Bringing the load home (`HarvestState`): whether it is its last, the resource used up\n *\n * @beta\n */\nexport interface HarvestToDropOff extends HarvestKept {\n\t/** The step this state is in, `'toDropOff'` */\n\tphase: 'toDropOff'\n\t/** Whether this is the last load, the resource used up: the order is done once it is handed in */\n\tlast?: boolean\n}\n\n/**\n * What `harvest` and `return` keep in their orders: the step it is at, with what that step keeps beside what every\n * step does (`HarvestKept`). A step's own fields stay in the order as it goes on to the next (a save has them as they\n * were), and are read only in their step\n *\n * @beta\n */\nexport type HarvestState = HarvestToResource | HarvestGathering | HarvestToDropOff\n\n/** The fields a step has of its own, beside its phase and what every step keeps */\ntype OwnOf<P extends HarvestPhase> = Omit<Extract<HarvestState, { phase: P }>, 'phase' | keyof HarvestKept>\n\n/** On to the next step, with what it starts with: in the order, where its fields were */\nfunction goOn<P extends HarvestPhase>(state: HarvestState, phase: P, own: OwnOf<P>): void {\n\tObject.assign(state, own)\n\tstate.phase = phase\n}\n\n/** Gives up the tree the worker had for itself */\nfunction release(world: World, state: HarvestKept): void {\n\tconst claimed = world.entities.get(state.claimed ?? 0)\n\tstate.claimed = 0\n\tconst resource = claimed?.get(deposit)\n\tif (resource) resource.occupants = Math.max(resource.occupants - 1, 0)\n}\n\n/**\n * Where a worker waits for a mine with no room: next to its edge on the side of the town hall, a place each (by the\n * worker's id: the one in front of the hall, then one side, then the other), so that waiting workers stand side by side\n */\nfunction waitingSpot(world: World, entity: Entity, mine: Entity): Vec2 {\n\tconst margin = entity.def.radius + 0.2\n\tconst towards = findDropOff(world, entity)?.pos ?? entity.pos\n\tconst front = closestPointOnRect(towards, mine.rect, margin)\n\tconst slot = entity.id % WAITING_PLACES\n\tconst along = (slot % 2 ? 1 : -1) * Math.ceil(slot / 2) * (entity.def.radius * 2 + 0.15)\n\tconst outX = front.x - mine.pos.x\n\tconst outZ = front.z - mine.pos.z\n\tconst length = hypot(outX, outZ) || 1\n\t// along the edge, and back onto it where that goes round a corner\n\treturn closestPointOnRect({ x: front.x - (outZ / length) * along, z: front.z + (outX / length) * along }, mine.rect, margin)\n}\n\n/** Into a mine: out of sight, a place in it taken */\nfunction enter(world: World, entity: Entity, state: HarvestToResource, resource: ResourceState): void {\n\tstate.waitSpot = undefined\n\tresource.occupants++\n\tworld.setHidden(entity, true)\n}\n\nfunction leave(world: World, entity: Entity, state: HarvestGathering): void {\n\tconst mine = world.entities.get(state.inside ?? 0)\n\tstate.inside = 0\n\tconst resource = mine?.get(deposit)\n\tif (resource) resource.occupants = Math.max(resource.occupants - 1, 0)\n\n\t// come out on the side facing the town hall\n\tconst towards = findDropOff(world, entity)?.pos ?? entity.pos\n\tconst exit = mine ? closestPointOnRect(towards, mine.rect, entity.def.radius + 0.2) : entity.pos\n\tworld.setHidden(entity, false, exit)\n}\n\n/** Stops where it stands, if it was on its way */\nfunction stop(world: World, entity: Entity): void {\n\tif (entity.get(moving)!.status === 'moving') halt(world, entity)\n}\n\n/** Walks to a spot to wait at, and waits there: what a worker does for a place that has no room */\nfunction wait(world: World, entity: Entity, spot: Vec2): void {\n\tif (dist(entity.pos, spot) > WAIT_RANGE) {\n\t\tif (entity.get(moving)!.status !== 'moving') moveTo(world, entity, spot, { range: WAIT_RANGE * 0.5 })\n\t} else stop(world, entity)\n}\n\n/**\n * To the spot in front of a tree and nowhere else, or workers on neighbouring trees end up in each other: still on its\n * way (`true`), or there, or next to it where someone stands on it (`false`)\n */\nfunction walkingToSpot(world: World, entity: Entity, state: HarvestKept, spot: Vec2): boolean {\n\tconst away = dist(entity.pos, spot)\n\tif (away <= SPOT_RANGE) return false\n\tif (entity.get(moving)!.status === 'moving') return true\n\t// someone is standing there: next to it will do\n\tif (state.walked && away < NEXT_TO_SPOT) return false\n\tstate.walked = true\n\tmoveTo(world, entity, spot, { range: SPOT_RANGE * 0.6 })\n\treturn true\n}\n\n/** At work from here on: in the way like anyone else (it is on the road that workers pass through each other) */\nfunction setToWork(world: World, entity: Entity): void {\n\tstop(world, entity)\n\tsetGhost(world, entity, false)\n\tsetAnchored(world, entity, true)\n}\n\n/**\n * A worker at a resource its owner's building stands on (`UnitTypeDef.builtOn`): a place round the building, as many\n * as it has room for (`gatherers`), waited for in line beside it when they are all taken; then to work\n */\nfunction gatherInPlace(world: World, entity: Entity, state: HarvestToResource, source: Entity, resource: ResourceState, at: Entity): OrderStatus {\n\tconst most = at.def.gatherers ?? 5\n\tif (state.claimed !== source.id) {\n\t\trelease(world, state)\n\t\tif (resource.occupants >= most) {\n\t\t\twait(world, entity, (state.waitSpot ??= waitingSpot(world, entity, at)))\n\t\t\treturn 'running'\n\t\t}\n\t\tstate.waitSpot = undefined\n\t\tstate.spot = spotAround(world, entity, at, resource.occupants, most)\n\t\tresource.occupants++\n\t\tstate.claimed = source.id\n\t\tstate.walked = false\n\t}\n\tstate.inPlace = at.id\n\tif (walkingToSpot(world, entity, state, state.spot!)) return 'running'\n\tsetToWork(world, entity)\n\tfaceTowards(world, entity, at.pos, 1)\n\tconst working = source.id\n\tharvesterOf(entity)!.resource = source.id\n\tgoOn(state, 'gathering', { working, timer: source.def.resource!.gatherTime ?? entity.def.harvester!.gatherTime })\n\treturn 'running'\n}\n\n/** Walking to the resource and to its place at it, then to work; on to the next of its kind where it is used up */\nfunction toResource(world: World, entity: Entity, order: Order<HarvestState>, state: HarvestToResource, harvester: HarvesterState): OrderStatus {\n\tconst source = world.get(order.init.target)\n\tconst resource = source?.get(deposit)\n\tif (!source || !resource || resource.amount <= 0) {\n\t\trelease(world, state)\n\t\t// used up: on to the next one of the same kind\n\t\tconst kind = state.kind ?? source?.def.resource?.id\n\t\tconst near = state.at ?? source?.pos ?? entity.pos\n\t\tconst next =\n\t\t\tfindResource(world, near, RESOURCE_SEARCH_RADIUS, kind, true, entity) ?? findResource(world, near, RESOURCE_SEARCH_RADIUS, kind, false, entity)\n\t\tif (next) {\n\t\t\torder.init.target = next.id\n\t\t\treturn 'running'\n\t\t}\n\t\tif (harvester.carrying > 0) {\n\t\t\tgoOn(state, 'toDropOff', { last: true })\n\t\t\treturn 'running'\n\t\t}\n\t\treturn 'done'\n\t}\n\tconst def = source.def.resource!\n\tconst gatherTime = def.gatherTime ?? entity.def.harvester!.gatherTime\n\tstate.kind = def.id\n\t// every tick of every worker on its way: the point it has, written over\n\tconst where = (state.at ??= { x: 0, z: 0 })\n\twhere.x = source.pos.x\n\twhere.z = source.pos.z\n\t// gathered where its owner's building stands on it: from round it, handed in on the spot\n\tconst at = gatheringAt(world, entity, source)\n\tif (at) return gatherInPlace(world, entity, state, source, resource, at)\n\tstate.inPlace = 0\n\t// a place round a building that has gone is given up\n\tif (def.entered && state.claimed) release(world, state)\n\tif (!def.entered) {\n\t\tif (state.claimed !== source.id) {\n\t\t\t// a tree each: whoever finds theirs taken goes for the next one\n\t\t\trelease(world, state)\n\t\t\tif (!hasRoom(source)) {\n\t\t\t\tconst next = findResource(world, source.pos, RESOURCE_SEARCH_RADIUS, def.id, true, entity)\n\t\t\t\tif (next) {\n\t\t\t\t\torder.init.target = next.id\n\t\t\t\t\treturn 'running'\n\t\t\t\t}\n\t\t\t}\n\t\t\tresource.occupants++\n\t\t\tstate.claimed = source.id\n\t\t\tstate.spot = workSpot(world, entity, source)\n\t\t\tstate.walked = false\n\t\t}\n\t\t// the walk over, the tree not reached, and nobody else at it to wait behind: it cannot be got to from here (behind\n\t\t// a cliff, deep in the wood). The nearest other one to where it stands, those it gave up on left out; nothing of\n\t\t// the kind within reach, it stops\n\t\tconst walk = entity.get(moving)!\n\t\tif (\n\t\t\tstate.walked &&\n\t\t\tresource.occupants <= 1 &&\n\t\t\twalk.status !== 'moving' &&\n\t\t\twalk.goalEntity === 0 &&\n\t\t\tdist(walk.goal, state.spot!) < 0.01 &&\n\t\t\tdist(entity.pos, state.spot!) >= NEXT_TO_SPOT\n\t\t) {\n\t\t\trelease(world, state)\n\t\t\tconst skipped = (state.outOfReach ??= [])\n\t\t\tskipped.push(source.id)\n\t\t\tif (skipped.length > OUT_OF_REACH_KEPT) skipped.shift()\n\t\t\tconst next = findResource(world, entity.pos, RESOURCE_SEARCH_RADIUS, def.id, true, entity, skipped)\n\t\t\tif (next) {\n\t\t\t\torder.init.target = next.id\n\t\t\t\treturn 'running'\n\t\t\t}\n\t\t\tif (harvester.carrying > 0) {\n\t\t\t\tgoOn(state, 'toDropOff', { last: true })\n\t\t\t\treturn 'running'\n\t\t\t}\n\t\t\treturn 'done'\n\t\t}\n\t\tif (walkingToSpot(world, entity, state, state.spot!)) return 'running'\n\t\t// trees and the like are worked on from next to them\n\t\tsetToWork(world, entity)\n\t\tconst working = source.id\n\t\tharvester.resource = source.id\n\t\tgoOn(state, 'gathering', { working, timer: gatherTime })\n\t\treturn 'running'\n\t}\n\tif (edgeDistance(entity, source) > REACH) {\n\t\tmoveToEntity(world, entity, source, REACH - 0.2)\n\t\treturn 'running'\n\t}\n\tif (resource.occupants >= def.slots) {\n\t\t// busy, wait in line: beside the others, not on top of them. Workers pass through each other on the road,\n\t\t// so nothing would push them apart, and the screen would draw them all in one place\n\t\twait(world, entity, (state.waitSpot ??= waitingSpot(world, entity, source)))\n\t\treturn 'running'\n\t}\n\tenter(world, entity, state, resource)\n\tharvester.resource = source.id\n\tgoOn(state, 'gathering', { inside: source.id, timer: gatherTime })\n\treturn 'running'\n}\n\n/** At work: a swing now and then, a load once the time is up; then home with it, or back for more */\nfunction gather(world: World, entity: Entity, state: HarvestGathering, harvester: HarvesterState, dt: number): OrderStatus {\n\tconst source = world.get(state.inside || state.working)\n\tif (source && !state.inside && !state.inPlace) {\n\t\tfaceTowards(world, entity, source.pos, dt)\n\t\t// every blow can be seen and heard\n\t\tstate.chop = (state.chop ?? CHOP_INTERVAL * 0.5) - dt\n\t\tif (state.chop <= 0) {\n\t\t\tstate.chop += CHOP_INTERVAL\n\t\t\tworld.events.emit(chopped, { worker: entity, source })\n\t\t}\n\t}\n\tstate.timer -= dt\n\tconst resource = source?.get(deposit)\n\tif (resource && state.timer > 0) return 'running'\n\tif (source && resource) {\n\t\tconst kind = source.def.resource!.id\n\t\t// a load of one thing: what was carried of the other is dropped\n\t\tif (harvester.kind !== kind) harvester.carrying = 0\n\t\tconst amount = Math.min(entity.def.harvester!.capacity - harvester.carrying, resource.amount)\n\t\tresource.amount -= amount\n\t\tharvester.carrying += amount\n\t\tharvester.kind = kind\n\t}\n\t// at a building on the resource: handed in where it stands, and on to the next load\n\tconst at = state.inPlace && source ? gatheringAt(world, entity, source) : undefined\n\tif (at && harvester.carrying > 0) dropOff(world, entity)\n\tif (state.inside) leave(world, entity, state)\n\telse if (!at) {\n\t\tsetAnchored(world, entity, false)\n\t\tsetGhost(world, entity, true)\n\t}\n\tstate.working = 0\n\tif (source && resource && resource.amount <= 0) world.kill(source, undefined, false, 'depleted')\n\tif (harvester.carrying > 0) goOn(state, 'toDropOff', {})\n\telse goOn(state, 'toResource', {})\n\treturn 'running'\n}\n\n/** Home with the load, to the nearest hall that takes it; then back for more, or done where it was the last */\nfunction toDropOff(world: World, entity: Entity, state: HarvestToDropOff, harvester: HarvesterState): OrderStatus {\n\tlet hall = world.get(state.dropOff)\n\tif (!hall?.operational || !accepts(hall, harvester.kind)) {\n\t\thall = findDropOff(world, entity)\n\t\tstate.dropOff = hall?.id ?? 0\n\t}\n\tif (!hall) {\n\t\tworld.message(entity.owner, engineMessage('nowhereToReturn', { resource: harvester.kind ?? '' }))\n\t\treturn 'failed'\n\t}\n\tif (edgeDistance(entity, hall) > REACH) {\n\t\tmoveToEntity(world, entity, hall, REACH - 0.2)\n\t\treturn 'running'\n\t}\n\tdropOff(world, entity)\n\t// the closest place to hand in may be another one next time\n\tstate.dropOff = 0\n\tif (state.last) return 'done'\n\tgoOn(state, 'toResource', {})\n\treturn 'running'\n}\n\nfunction update(world: World, entity: Entity, order: Order<HarvestState>, dt: number): OrderStatus {\n\tconst { state } = order\n\tconst harvester = harvesterOf(entity)!\n\tswitch (state.phase) {\n\t\tcase 'toResource':\n\t\t\treturn toResource(world, entity, order, state, harvester)\n\t\tcase 'gathering':\n\t\t\treturn gather(world, entity, state, harvester, dt)\n\t\tcase 'toDropOff':\n\t\t\treturn toDropOff(world, entity, state, harvester)\n\t}\n}\n\nfunction end(world: World, entity: Entity, order: Order<HarvestState>): void {\n\tconst { state } = order\n\trelease(world, state)\n\t// inside a mine only while at work there\n\tif (state.phase === 'gathering' && state.inside) leave(world, entity, state)\n\tsetAnchored(world, entity, false)\n\tsetGhost(world, entity, false)\n}\n\n/** Gather from a resource, bring it home, repeat */\nexport const harvestOrder: OrderBehavior<HarvestState, OrderInits['harvest']> = {\n\ttype: 'harvest',\n\taccepts(world, entity, init) {\n\t\tconst source = world.get(init.target)\n\t\tif (!entity.has(gathering) || !source?.get(deposit)) return false\n\t\tconst refusal = harvestRefusal(world, entity, source)\n\t\tif (refusal === null) return true\n\t\t// told why, where the game says\n\t\tif (refusal) world.message(entity.owner, toMessage(refusal))\n\t\treturn false\n\t},\n\tstart(world, entity, order) {\n\t\tconst harvester = harvesterOf(entity)\n\t\tconst kind = world.get(order.init.target)?.def.resource?.id\n\t\t// full hands are emptied first. A full load of something else is handed in rather than thrown away\n\t\tconst full = harvester!.carrying >= entity.def.harvester!.capacity\n\t\torder.state.phase = full ? 'toDropOff' : 'toResource'\n\t\torder.state.kind = kind\n\t\tsetGhost(world, entity, true)\n\t},\n\tupdate,\n\tend\n}\n\n/** Hand in what the worker carries, then go back to gathering */\nexport const returnOrder: OrderBehavior<HarvestState, OrderInits['return']> = {\n\ttype: 'return',\n\taccepts: (_world, entity) => (harvesterOf(entity)?.carrying ?? 0) > 0,\n\tstart(world, entity, order) {\n\t\torder.init.target ??= harvesterOf(entity)!.resource\n\t\torder.state.phase = 'toDropOff'\n\t\tsetGhost(world, entity, true)\n\t},\n\tupdate,\n\tend\n}\n"],"mappings":"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"}
|
package/dist/orders/idle.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type Entity } from '#engine/entity';
|
|
2
2
|
import type { World } from '#engine/world';
|
|
3
3
|
/**
|
|
4
4
|
* What units do without orders: attack enemies that come close, fight back
|
|
5
5
|
* when attacked, and return to where they stood afterwards.
|
|
6
6
|
*/
|
|
7
7
|
export declare function idle(world: World, entity: Entity, dt: number): void;
|
|
8
|
+
/** How far from the ally hit an ally is looked for at most (`RuleSettings.combat.helpRange` is cut to it) */
|
|
9
|
+
export declare const HELP_SEARCH = 20;
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import { dist } from "../math.js";
|
|
2
|
+
import { defineListener } from "../events.js";
|
|
3
|
+
import { damaged, entityDied } from "../engineEvents.js";
|
|
4
|
+
import { edgeDistance, fighting, moving } from "../entity.js";
|
|
5
|
+
import { farthestAcquisition } from "../attacks.js";
|
|
6
|
+
import { engageWith, isBlocked, shun } from "../engagement.js";
|
|
7
|
+
import { moveTo, moveToEntity } from "../systems/movement.js";
|
|
8
|
+
import { summoned } from "../summoned.js";
|
|
9
|
+
import { acquireInRange, acquireTarget, canAttack, canSee, disengage, engage, scoreTarget } from "../systems/combat.js";
|
|
10
|
+
//#region src/orders/idle.ts
|
|
11
|
+
/** How far past its acquisition range an idle unit chases before walking back */
|
|
12
|
+
var LEASH = 6;
|
|
13
|
+
/**
|
|
14
|
+
* What units do without orders: attack enemies that come close, fight back
|
|
15
|
+
* when attacked, and return to where they stood afterwards.
|
|
16
|
+
*/
|
|
17
|
+
function idle(world, entity, dt) {
|
|
18
|
+
const combat = entity.get(fighting);
|
|
19
|
+
const fights = !!combat && !!entity.def.attacks?.length && !combat.passive;
|
|
20
|
+
if (world.hooks.has("idle") && world.hooks.run("idle", {
|
|
21
|
+
entity,
|
|
22
|
+
dt,
|
|
23
|
+
fights,
|
|
24
|
+
handled: false
|
|
25
|
+
}).handled) return;
|
|
26
|
+
const summon = entity.get(summoned);
|
|
27
|
+
const master = summon?.follow ? world.get(summon.by) : void 0;
|
|
28
|
+
if (!fights || !combat) {
|
|
29
|
+
if (master) followMaster(world, entity, master);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
const m = entity.get(moving);
|
|
33
|
+
if (combat.autoTarget) {
|
|
34
|
+
const target = world.get(combat.autoTarget);
|
|
35
|
+
const tooFar = !!combat.guard && dist(entity.pos, combat.guard) > world.settings.combat.acquisitionRange(world, entity) + LEASH;
|
|
36
|
+
let result = tooFar ? "invalid" : engage(world, entity, target, dt, !!m);
|
|
37
|
+
if (result === "chasing" && target && isBlocked(world, entity, target)) {
|
|
38
|
+
shun(world, entity, target);
|
|
39
|
+
result = "invalid";
|
|
40
|
+
}
|
|
41
|
+
if (result === "attacking" || result === "chasing") return;
|
|
42
|
+
combat.autoTarget = 0;
|
|
43
|
+
disengage(world, entity);
|
|
44
|
+
const next = tooFar ? void 0 : acquireTarget(world, entity);
|
|
45
|
+
if (next) {
|
|
46
|
+
engageWith(world, entity, next);
|
|
47
|
+
combat.autoTarget = next.id;
|
|
48
|
+
} else if (master) followMaster(world, entity, master);
|
|
49
|
+
else if (m && combat.guard && dist(entity.pos, combat.guard) > 1) moveTo(world, entity, combat.guard);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
if ((world.tick + entity.id) % 4 !== 0) return;
|
|
53
|
+
const returning = !!combat.guard && m?.status === "moving";
|
|
54
|
+
let found = returning ? acquireInRange(world, entity, 1) : acquireTarget(world, entity);
|
|
55
|
+
if (!found && combat.lastAttacker) {
|
|
56
|
+
const attacker = world.get(combat.lastAttacker);
|
|
57
|
+
if (attacker && canAttack(world, entity, attacker) && canSee(world, entity, attacker)) found = attacker;
|
|
58
|
+
combat.lastAttacker = 0;
|
|
59
|
+
}
|
|
60
|
+
if (found) {
|
|
61
|
+
engageWith(world, entity, found);
|
|
62
|
+
if (!master) combat.guard ??= {
|
|
63
|
+
x: entity.pos.x,
|
|
64
|
+
z: entity.pos.z
|
|
65
|
+
};
|
|
66
|
+
combat.autoTarget = found.id;
|
|
67
|
+
} else if (!returning) {
|
|
68
|
+
combat.guard = null;
|
|
69
|
+
if (master) followMaster(world, entity, master);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/** How far from its master (edge to edge) a following summon lets itself get, and how near it comes back to */
|
|
73
|
+
var FOLLOW_AWAY = 2;
|
|
74
|
+
var FOLLOW_NEAR = 1.2;
|
|
75
|
+
/** Walks a summon to its master when it is past `FOLLOW_AWAY`: asked every few ticks, it follows the master as it moves */
|
|
76
|
+
function followMaster(world, entity, master) {
|
|
77
|
+
if ((world.tick + entity.id) % 4 !== 0 || !master.alive || master.hidden || master === entity) return;
|
|
78
|
+
if (edgeDistance(entity, master) > FOLLOW_AWAY) moveToEntity(world, entity, master, FOLLOW_NEAR);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Whether a unit is free to take up a fight it is called to (a camp's creep when another is hit): one that fights, is
|
|
82
|
+
* not standing down (`CombatState.passive`) and has no order of its player's (a hold, a move). What it may attack is
|
|
83
|
+
* still the `canAttack` hook's to say (a stance)
|
|
84
|
+
*
|
|
85
|
+
* @internal
|
|
86
|
+
*/
|
|
87
|
+
function freeToHelp(entity) {
|
|
88
|
+
const combat = entity.get(fighting);
|
|
89
|
+
return !!combat && !combat.passive && !!entity.def.attacks?.length && entity.orders.length === 0 && !entity.hidden;
|
|
90
|
+
}
|
|
91
|
+
/** Seconds between two calls for help on behalf of the same attacker: it recruits at its first blow, and later ones find no one new but the late */
|
|
92
|
+
var HELP_EVERY = 3;
|
|
93
|
+
/** How far the search goes by world: the longest acquisition range of its unit types and 4, kept for as long as it has as many */
|
|
94
|
+
var searches = /* @__PURE__ */ new WeakMap();
|
|
95
|
+
function searchRadius(world) {
|
|
96
|
+
const types = world.registry.units.size;
|
|
97
|
+
let kept = searches.get(world);
|
|
98
|
+
if (kept?.types !== types) {
|
|
99
|
+
let most = 0;
|
|
100
|
+
for (const def of world.registry.units.all()) most = Math.max(most, farthestAcquisition(def));
|
|
101
|
+
searches.set(world, kept = {
|
|
102
|
+
types,
|
|
103
|
+
radius: Math.min(most + 4, 20)
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
return kept.radius;
|
|
107
|
+
}
|
|
108
|
+
/** By world: the idle units of an owner as they stood when its first ally was hit in a tick, kept for the rest of that tick (a fight of thousands asks it hundreds of times a tick, and almost no one in it is idle) */
|
|
109
|
+
var idleOf = /* @__PURE__ */ new WeakMap();
|
|
110
|
+
var helpers = [];
|
|
111
|
+
function idleUnits(world, owner) {
|
|
112
|
+
let kept = idleOf.get(world);
|
|
113
|
+
if (!kept) idleOf.set(world, kept = {
|
|
114
|
+
tick: world.tick,
|
|
115
|
+
owners: /* @__PURE__ */ new Map()
|
|
116
|
+
});
|
|
117
|
+
else if (kept.tick !== world.tick) {
|
|
118
|
+
kept.tick = world.tick;
|
|
119
|
+
kept.owners.clear();
|
|
120
|
+
}
|
|
121
|
+
let units = kept.owners.get(owner);
|
|
122
|
+
if (!units) {
|
|
123
|
+
kept.owners.set(owner, units = []);
|
|
124
|
+
for (const helper of world.index.ownedBy(owner)) {
|
|
125
|
+
const state = helper.get(fighting);
|
|
126
|
+
if (state && !state.autoTarget && !state.passive && !helper.asleep && helper.alive && freeToHelp(helper)) units.push(helper);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return units;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* An ally is hit: each idle unit of the same owner within `RuleSettings.combat.helpRange` of it (the lowest id first) takes
|
|
133
|
+
* the attacker, as a camp's creeps do. The fight is the idle unit's own from then on, with its leash from where it stood
|
|
134
|
+
* (`idle`): it walks back when the attacker is gone or led it too far. Left alone: a unit with an order of its
|
|
135
|
+
* player's (a hold), one standing down, one that does not fight, one already fighting, creeps (the camp's own list does
|
|
136
|
+
* it), and an attacker its `canAttack` hook lets it leave (a stance that fires back only, or reaches near), cannot
|
|
137
|
+
* see, or a `targetScore` handler rules out
|
|
138
|
+
*
|
|
139
|
+
* @internal
|
|
140
|
+
*/
|
|
141
|
+
function helpAlly(world, victim, attacker) {
|
|
142
|
+
if (!attacker?.alive || attacker === victim || !victim.alive || !world.areEnemies(attacker.owner, victim.owner)) return;
|
|
143
|
+
if (world.player(victim.owner).creeps) return;
|
|
144
|
+
const blows = attacker.get(fighting);
|
|
145
|
+
if (blows) {
|
|
146
|
+
if (blows.helpedAt !== void 0 && world.tick - blows.helpedAt < HELP_EVERY * world.tickRate && world.tick >= blows.helpedAt) return;
|
|
147
|
+
blows.helpedAt = world.tick;
|
|
148
|
+
}
|
|
149
|
+
const { owner } = victim;
|
|
150
|
+
helpers.length = 0;
|
|
151
|
+
const reachMost = Math.min(searchRadius(world), 20);
|
|
152
|
+
for (const helper of idleUnits(world, owner)) {
|
|
153
|
+
if (helper === victim) continue;
|
|
154
|
+
const state = helper.get(fighting);
|
|
155
|
+
if (!state || state.autoTarget || state.passive || helper.asleep || !helper.alive || !freeToHelp(helper)) continue;
|
|
156
|
+
if (dist(helper.pos, victim.pos) > reachMost) continue;
|
|
157
|
+
helpers.push(helper);
|
|
158
|
+
}
|
|
159
|
+
if (!helpers.length) return;
|
|
160
|
+
helpers.sort((a, b) => a.id - b.id);
|
|
161
|
+
const { combat } = world.settings;
|
|
162
|
+
for (const helper of helpers) {
|
|
163
|
+
const reach = Math.min(combat.helpRange(world, helper, victim), 20);
|
|
164
|
+
if (!(reach > 0) || dist(helper.pos, victim.pos) > reach) continue;
|
|
165
|
+
if (!canAttack(world, helper, attacker) || !canSee(world, helper, attacker) || scoreTarget(world, helper, attacker) === -Infinity) continue;
|
|
166
|
+
const state = helper.get(fighting);
|
|
167
|
+
engageWith(world, helper, attacker);
|
|
168
|
+
state.guard ??= {
|
|
169
|
+
x: helper.pos.x,
|
|
170
|
+
z: helper.pos.z
|
|
171
|
+
};
|
|
172
|
+
state.autoTarget = attacker.id;
|
|
173
|
+
}
|
|
174
|
+
helpers.length = 0;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* A unit is hit: its summons with `aggro: 'mastersAttacker'` take the attacker at once, whatever they were at (unless
|
|
178
|
+
* their player gave them an order), through the same asking as `helpAlly` (`canAttack`, `canSee`, `targetScore`).
|
|
179
|
+
* Whoever it was counts for more to them when they look for a target themselves, for a while (`FOE_MEMORY`)
|
|
180
|
+
*
|
|
181
|
+
* @internal
|
|
182
|
+
*/
|
|
183
|
+
function summonsAnswer(world, master, attacker) {
|
|
184
|
+
const all = world.index.with(summoned);
|
|
185
|
+
if (!all.size || !attacker?.alive || attacker === master || !world.areEnemies(attacker.owner, master.owner)) return;
|
|
186
|
+
for (const brought of all) {
|
|
187
|
+
const data = brought.get(summoned);
|
|
188
|
+
if (data.by !== master.id || data.aggro !== "mastersAttacker" || brought === attacker) continue;
|
|
189
|
+
data.foe = attacker.id;
|
|
190
|
+
data.foeUntil = world.time + 6;
|
|
191
|
+
const state = brought.get(fighting);
|
|
192
|
+
if (!state || state.passive || state.autoTarget === attacker.id || !brought.alive || brought.asleep || brought.hidden) continue;
|
|
193
|
+
if (!brought.def.attacks?.length || brought.orders.length) continue;
|
|
194
|
+
if (!canAttack(world, brought, attacker) || !canSee(world, brought, attacker) || scoreTarget(world, brought, attacker) === -Infinity) continue;
|
|
195
|
+
engageWith(world, brought, attacker);
|
|
196
|
+
state.autoTarget = attacker.id;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
/** A master dies: what it summoned with `diesWithMaster` goes with it */
|
|
200
|
+
function summonsFollowMaster(world, master) {
|
|
201
|
+
const all = world.index.with(summoned);
|
|
202
|
+
if (!all.size) return;
|
|
203
|
+
for (const brought of [...all]) {
|
|
204
|
+
const data = brought.get(summoned);
|
|
205
|
+
if (data.by === master.id && data.diesWithMaster && brought.alive) world.kill(brought, void 0, false, "masterDied");
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* What makes idle allies answer a hit on a unit near them (`helpAlly`), with the engine's own: the core's, heard ahead
|
|
210
|
+
* of the game's
|
|
211
|
+
*
|
|
212
|
+
* @internal
|
|
213
|
+
*/
|
|
214
|
+
var helpListeners = [
|
|
215
|
+
defineListener({
|
|
216
|
+
event: damaged,
|
|
217
|
+
id: "core.helpAlly",
|
|
218
|
+
run: (world, { target, source }) => helpAlly(world, target, source)
|
|
219
|
+
}),
|
|
220
|
+
defineListener({
|
|
221
|
+
event: damaged,
|
|
222
|
+
id: "core.summonsAnswer",
|
|
223
|
+
run: (world, { target, source }) => summonsAnswer(world, target, source)
|
|
224
|
+
}),
|
|
225
|
+
defineListener({
|
|
226
|
+
event: entityDied,
|
|
227
|
+
id: "core.summonsDie",
|
|
228
|
+
run: (world, { entity }) => summonsFollowMaster(world, entity)
|
|
229
|
+
})
|
|
230
|
+
];
|
|
231
|
+
//#endregion
|
|
232
|
+
export { freeToHelp, helpAlly, helpListeners, idle, summonsAnswer };
|
|
233
|
+
|
|
234
|
+
//# sourceMappingURL=idle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"idle.js","names":[],"sources":["../../src/orders/idle.ts"],"sourcesContent":["import { edgeDistance, type Entity, type PlayerId } from '#engine/entity'\nimport { farthestAcquisition } from '#engine/attacks'\nimport { summoned, FOE_MEMORY } from '#engine/summoned'\nimport { dist } from '#engine/math'\nimport { acquireInRange, acquireTarget, canAttack, canSee, disengage, engage, scoreTarget } from '#engine/systems/combat'\nimport { damaged, entityDied } from '#engine/engineEvents'\nimport { defineListener, type ListenerDef } from '#engine/events'\nimport { moveTo, moveToEntity } from '#engine/systems/movement'\nimport type { World } from '#engine/world'\nimport { engageWith, isBlocked, shun } from '#engine/engagement'\nimport { moving, fighting } from '../entity'\n\n/** How far past its acquisition range an idle unit chases before walking back */\nconst LEASH = 6\n\n/**\n * What units do without orders: attack enemies that come close, fight back\n * when attacked, and return to where they stood afterwards.\n */\nexport function idle(world: World, entity: Entity, dt: number): void {\n\tconst combat = entity.get(fighting)\n\tconst fights = !!combat && !!entity.def.attacks?.length && !combat.passive\n\t// a game can have units of its own idle their own way, like creeps that guard their camp, or a healer that goes\n\t// to the wounded: those that do not fight too\n\tif (world.hooks.has('idle') && world.hooks.run('idle', { entity, dt, fights, handled: false }).handled) return\n\t// a summon with nothing to do walks with its master (`Summoned.follow`)\n\tconst summon = entity.get(summoned)\n\tconst master = summon?.follow ? world.get(summon.by) : undefined\n\tif (!fights || !combat) {\n\t\tif (master) followMaster(world, entity, master)\n\t\treturn\n\t}\n\tconst m = entity.get(moving)\n\n\tif (combat.autoTarget) {\n\t\tconst target = world.get(combat.autoTarget)\n\t\tconst tooFar = !!combat.guard && dist(entity.pos, combat.guard) > world.settings.combat.acquisitionRange(world, entity) + LEASH\n\t\tlet result = tooFar ? 'invalid' : engage(world, entity, target, dt, !!m)\n\t\t// held up on the way to it: something else then\n\t\tif (result === 'chasing' && target && isBlocked(world, entity, target)) {\n\t\t\tshun(world, entity, target)\n\t\t\tresult = 'invalid'\n\t\t}\n\t\tif (result === 'attacking' || result === 'chasing') return\n\n\t\tcombat.autoTarget = 0\n\t\tdisengage(world, entity)\n\t\tconst next = tooFar ? undefined : acquireTarget(world, entity)\n\t\tif (next) {\n\t\t\tengageWith(world, entity, next)\n\t\t\tcombat.autoTarget = next.id\n\t\t} else if (master) followMaster(world, entity, master)\n\t\telse if (m && combat.guard && dist(entity.pos, combat.guard) > 1) moveTo(world, entity, combat.guard)\n\t\treturn\n\t}\n\n\tif ((world.tick + entity.id) % 4 !== 0) return\n\n\tconst returning = !!combat.guard && m?.status === 'moving'\n\t// on the way back only react to what is right in its face, or it would never get home\n\tlet found = returning ? acquireInRange(world, entity, 1) : acquireTarget(world, entity)\n\tif (!found && combat.lastAttacker) {\n\t\tconst attacker = world.get(combat.lastAttacker)\n\t\tif (attacker && canAttack(world, entity, attacker) && canSee(world, entity, attacker)) found = attacker\n\t\tcombat.lastAttacker = 0\n\t}\n\tif (found) {\n\t\tengageWith(world, entity, found)\n\t\t// a summon has no post to go back to: it goes back to its master\n\t\tif (!master) combat.guard ??= { x: entity.pos.x, z: entity.pos.z }\n\t\tcombat.autoTarget = found.id\n\t} else if (!returning) {\n\t\tcombat.guard = null\n\t\tif (master) followMaster(world, entity, master)\n\t}\n}\n\n/** How far from its master (edge to edge) a following summon lets itself get, and how near it comes back to */\nconst FOLLOW_AWAY = 2\nconst FOLLOW_NEAR = 1.2\n\n/** Walks a summon to its master when it is past `FOLLOW_AWAY`: asked every few ticks, it follows the master as it moves */\nfunction followMaster(world: World, entity: Entity, master: Entity): void {\n\tif ((world.tick + entity.id) % 4 !== 0 || !master.alive || master.hidden || master === entity) return\n\tif (edgeDistance(entity, master) > FOLLOW_AWAY) moveToEntity(world, entity, master, FOLLOW_NEAR)\n}\n\n/**\n * Whether a unit is free to take up a fight it is called to (a camp's creep when another is hit): one that fights, is\n * not standing down (`CombatState.passive`) and has no order of its player's (a hold, a move). What it may attack is\n * still the `canAttack` hook's to say (a stance)\n *\n * @internal\n */\nexport function freeToHelp(entity: Entity): boolean {\n\tconst combat = entity.get(fighting)\n\treturn !!combat && !combat.passive && !!entity.def.attacks?.length && entity.orders.length === 0 && !entity.hidden\n}\n\n/** How far from the ally hit an ally is looked for at most (`RuleSettings.combat.helpRange` is cut to it) */\nexport const HELP_SEARCH = 20\n\n/** Seconds between two calls for help on behalf of the same attacker: it recruits at its first blow, and later ones find no one new but the late */\nconst HELP_EVERY = 3\n\n/** How far the search goes by world: the longest acquisition range of its unit types and 4, kept for as long as it has as many */\nconst searches = new WeakMap<World, { types: number; radius: number }>()\n\nfunction searchRadius(world: World): number {\n\tconst types = world.registry.units.size\n\tlet kept = searches.get(world)\n\tif (kept?.types !== types) {\n\t\tlet most = 0\n\t\tfor (const def of world.registry.units.all()) most = Math.max(most, farthestAcquisition(def))\n\t\tsearches.set(world, (kept = { types, radius: Math.min(most + 4, HELP_SEARCH) }))\n\t}\n\treturn kept.radius\n}\n\n/** By world: the idle units of an owner as they stood when its first ally was hit in a tick, kept for the rest of that tick (a fight of thousands asks it hundreds of times a tick, and almost no one in it is idle) */\nconst idleOf = new WeakMap<World, { tick: number; owners: Map<PlayerId, Entity[]> }>()\nconst helpers: Entity[] = []\n\nfunction idleUnits(world: World, owner: PlayerId): Entity[] {\n\tlet kept = idleOf.get(world)\n\tif (!kept) idleOf.set(world, (kept = { tick: world.tick, owners: new Map() }))\n\telse if (kept.tick !== world.tick) {\n\t\tkept.tick = world.tick\n\t\tkept.owners.clear()\n\t}\n\tlet units = kept.owners.get(owner)\n\tif (!units) {\n\t\tkept.owners.set(owner, (units = []))\n\t\tfor (const helper of world.index.ownedBy(owner)) {\n\t\t\tconst state = helper.get(fighting)\n\t\t\tif (state && !state.autoTarget && !state.passive && !helper.asleep && helper.alive && freeToHelp(helper)) units.push(helper)\n\t\t}\n\t}\n\treturn units\n}\n\n/**\n * An ally is hit: each idle unit of the same owner within `RuleSettings.combat.helpRange` of it (the lowest id first) takes\n * the attacker, as a camp's creeps do. The fight is the idle unit's own from then on, with its leash from where it stood\n * (`idle`): it walks back when the attacker is gone or led it too far. Left alone: a unit with an order of its\n * player's (a hold), one standing down, one that does not fight, one already fighting, creeps (the camp's own list does\n * it), and an attacker its `canAttack` hook lets it leave (a stance that fires back only, or reaches near), cannot\n * see, or a `targetScore` handler rules out\n *\n * @internal\n */\nexport function helpAlly(world: World, victim: Entity, attacker: Entity | undefined): void {\n\tif (!attacker?.alive || attacker === victim || !victim.alive || !world.areEnemies(attacker.owner, victim.owner)) return\n\tif (world.player(victim.owner).creeps) return\n\t// not by every blow of one fight: its allies are asked at its first and then every few ticks\n\tconst blows = attacker.get(fighting)\n\tif (blows) {\n\t\tif (blows.helpedAt !== undefined && world.tick - blows.helpedAt < HELP_EVERY * world.tickRate && world.tick >= blows.helpedAt) return\n\t\tblows.helpedAt = world.tick\n\t}\n\tconst { owner } = victim\n\thelpers.length = 0\n\tconst reachMost = Math.min(searchRadius(world), HELP_SEARCH)\n\tfor (const helper of idleUnits(world, owner)) {\n\t\tif (helper === victim) continue\n\t\t// they may have been given a fight or an order since the tick's list was made\n\t\tconst state = helper.get(fighting)\n\t\tif (!state || state.autoTarget || state.passive || helper.asleep || !helper.alive || !freeToHelp(helper)) continue\n\t\tif (dist(helper.pos, victim.pos) > reachMost) continue\n\t\thelpers.push(helper)\n\t}\n\tif (!helpers.length) return\n\t// the same order whatever order the index keeps them in\n\thelpers.sort((a, b) => a.id - b.id)\n\tconst { combat } = world.settings\n\tfor (const helper of helpers) {\n\t\tconst reach = Math.min(combat.helpRange(world, helper, victim), HELP_SEARCH)\n\t\tif (!(reach > 0) || dist(helper.pos, victim.pos) > reach) continue\n\t\tif (!canAttack(world, helper, attacker) || !canSee(world, helper, attacker) || scoreTarget(world, helper, attacker) === -Infinity) continue\n\t\tconst state = helper.get(fighting)!\n\t\tengageWith(world, helper, attacker)\n\t\tstate.guard ??= { x: helper.pos.x, z: helper.pos.z }\n\t\tstate.autoTarget = attacker.id\n\t}\n\thelpers.length = 0\n}\n\n/**\n * A unit is hit: its summons with `aggro: 'mastersAttacker'` take the attacker at once, whatever they were at (unless\n * their player gave them an order), through the same asking as `helpAlly` (`canAttack`, `canSee`, `targetScore`).\n * Whoever it was counts for more to them when they look for a target themselves, for a while (`FOE_MEMORY`)\n *\n * @internal\n */\nexport function summonsAnswer(world: World, master: Entity, attacker: Entity | undefined): void {\n\tconst all = world.index.with(summoned)\n\tif (!all.size || !attacker?.alive || attacker === master || !world.areEnemies(attacker.owner, master.owner)) return\n\tfor (const brought of all) {\n\t\tconst data = brought.get(summoned)!\n\t\tif (data.by !== master.id || data.aggro !== 'mastersAttacker' || brought === attacker) continue\n\t\tdata.foe = attacker.id\n\t\tdata.foeUntil = world.time + FOE_MEMORY\n\t\tconst state = brought.get(fighting)\n\t\tif (!state || state.passive || state.autoTarget === attacker.id || !brought.alive || brought.asleep || brought.hidden) continue\n\t\tif (!brought.def.attacks?.length || brought.orders.length) continue\n\t\tif (!canAttack(world, brought, attacker) || !canSee(world, brought, attacker) || scoreTarget(world, brought, attacker) === -Infinity) continue\n\t\tengageWith(world, brought, attacker)\n\t\tstate.autoTarget = attacker.id\n\t}\n}\n\n/** A master dies: what it summoned with `diesWithMaster` goes with it */\nfunction summonsFollowMaster(world: World, master: Entity): void {\n\tconst all = world.index.with(summoned)\n\tif (!all.size) return\n\tfor (const brought of [...all]) {\n\t\tconst data = brought.get(summoned)!\n\t\tif (data.by === master.id && data.diesWithMaster && brought.alive) world.kill(brought, undefined, false, 'masterDied')\n\t}\n}\n\n/**\n * What makes idle allies answer a hit on a unit near them (`helpAlly`), with the engine's own: the core's, heard ahead\n * of the game's\n *\n * @internal\n */\nexport const helpListeners: ListenerDef[] = [\n\tdefineListener({ event: damaged, id: 'core.helpAlly', run: (world, { target, source }) => helpAlly(world, target, source) }),\n\tdefineListener({ event: damaged, id: 'core.summonsAnswer', run: (world, { target, source }) => summonsAnswer(world, target, source) }),\n\tdefineListener({ event: entityDied, id: 'core.summonsDie', run: (world, { entity }) => summonsFollowMaster(world, entity) })\n]\n"],"mappings":"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"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { dist } from "../math.js";
|
|
2
|
+
import { inventorySlots } from "../inventory.js";
|
|
3
|
+
import { edgeDistance, moving } from "../entity.js";
|
|
4
|
+
import { engineMessage } from "../messages.js";
|
|
5
|
+
import { moveTo, moveToEntity } from "../systems/movement.js";
|
|
6
|
+
import { REACH, carryRefusal, dropOnGround, findItem, giveItem, hasRoomFor, pickUp, takeItem } from "../items.js";
|
|
7
|
+
//#region src/orders/items.ts
|
|
8
|
+
/** Walk to an item on the ground and take it */
|
|
9
|
+
var pickUpOrder = {
|
|
10
|
+
type: "pickUp",
|
|
11
|
+
accepts(world, entity, init) {
|
|
12
|
+
const item = world.items.find((i) => i.id === init.item);
|
|
13
|
+
if (!entity.has(inventorySlots) || !entity.get(moving) || !item) return false;
|
|
14
|
+
return world.fog.isVisible(world.player(entity.owner).team, item.x, item.z);
|
|
15
|
+
},
|
|
16
|
+
update(world, entity, order) {
|
|
17
|
+
const item = world.items.find((i) => i.id === order.init.item);
|
|
18
|
+
if (!item) return "done";
|
|
19
|
+
const m = entity.get(moving);
|
|
20
|
+
if (dist(entity.pos, item) > 1.2) {
|
|
21
|
+
if (m.status === "moving") return "running";
|
|
22
|
+
if (order.state.walked && m.status === "failed") return "failed";
|
|
23
|
+
order.state.walked = true;
|
|
24
|
+
moveTo(world, entity, item, { range: REACH * .7 });
|
|
25
|
+
return "running";
|
|
26
|
+
}
|
|
27
|
+
if (!hasRoomFor(world, entity, item.item, item.charges)) {
|
|
28
|
+
world.message(entity.owner, engineMessage("inventoryFull"));
|
|
29
|
+
return "failed";
|
|
30
|
+
}
|
|
31
|
+
return pickUp(world, entity, item.id) ? "done" : "failed";
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
/** Put an item down somewhere, or hand it to someone */
|
|
35
|
+
var dropItemOrder = {
|
|
36
|
+
type: "dropItem",
|
|
37
|
+
accepts(world, entity, init) {
|
|
38
|
+
if (!entity.get(moving) || !findItem(entity, init.item)) return false;
|
|
39
|
+
const target = world.get(init.target);
|
|
40
|
+
if (init.target) return !!target && target !== entity && target.has(inventorySlots) && world.areAllies(entity.owner, target.owner);
|
|
41
|
+
return !!init.point;
|
|
42
|
+
},
|
|
43
|
+
update(world, entity, order) {
|
|
44
|
+
if (!findItem(entity, order.init.item)) return "done";
|
|
45
|
+
const m = entity.get(moving);
|
|
46
|
+
const receiver = order.init.target ? world.get(order.init.target) : void 0;
|
|
47
|
+
if (order.init.target && !receiver) return "done";
|
|
48
|
+
if (receiver) {
|
|
49
|
+
if (edgeDistance(entity, receiver) > 1.2) {
|
|
50
|
+
moveToEntity(world, entity, receiver, REACH * .7);
|
|
51
|
+
return m.status === "failed" ? "failed" : "running";
|
|
52
|
+
}
|
|
53
|
+
const handed = findItem(entity, order.init.item);
|
|
54
|
+
if (!hasRoomFor(world, receiver, handed.item, handed.charges)) {
|
|
55
|
+
world.message(entity.owner, engineMessage("theirInventoryFull"));
|
|
56
|
+
return "failed";
|
|
57
|
+
}
|
|
58
|
+
const refused = carryRefusal(world, receiver, handed.item, [], true);
|
|
59
|
+
if (refused) {
|
|
60
|
+
world.message(entity.owner, refused);
|
|
61
|
+
return "failed";
|
|
62
|
+
}
|
|
63
|
+
giveItem(world, receiver, takeItem(world, entity, order.init.item));
|
|
64
|
+
return "done";
|
|
65
|
+
}
|
|
66
|
+
if (dist(entity.pos, order.init.point) > 1.2) {
|
|
67
|
+
if (m.status === "moving") return "running";
|
|
68
|
+
if (order.state.walked && m.status === "failed") return "failed";
|
|
69
|
+
order.state.walked = true;
|
|
70
|
+
moveTo(world, entity, order.init.point, { range: REACH * .7 });
|
|
71
|
+
return "running";
|
|
72
|
+
}
|
|
73
|
+
const held = findItem(entity, order.init.item);
|
|
74
|
+
if (held && world.hooks.has("beforeDrop")) {
|
|
75
|
+
const before = world.hooks.run("beforeDrop", {
|
|
76
|
+
entity,
|
|
77
|
+
item: held,
|
|
78
|
+
cancelled: false
|
|
79
|
+
});
|
|
80
|
+
if (before.cancelled) {
|
|
81
|
+
if (before.reason) world.message(entity.owner, before.reason);
|
|
82
|
+
return "failed";
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
dropOnGround(world, takeItem(world, entity, order.init.item), order.init.point);
|
|
86
|
+
return "done";
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
//#endregion
|
|
90
|
+
export { dropItemOrder, pickUpOrder };
|
|
91
|
+
|
|
92
|
+
//# sourceMappingURL=items.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"items.js","names":[],"sources":["../../src/orders/items.ts"],"sourcesContent":["import { edgeDistance } from '#engine/entity'\nimport { carryRefusal, dropOnGround, findItem, giveItem, pickUp, hasRoomFor, REACH, takeItem } from '#engine/items'\nimport { inventorySlots } from '#engine/inventory'\nimport { dist } from '#engine/math'\nimport type { OrderBehavior, OrderInits } from '#engine/registry'\nimport { moveTo, moveToEntity } from '#engine/systems/movement'\nimport { engineMessage } from '#engine/messages'\nimport { moving } from '../entity'\n\n/**\n * What the item orders keep: whether they walked to it already\n *\n * @beta\n */\nexport interface ItemOrderState {\n\t/** It walked to it already */\n\twalked?: boolean\n}\n\n/** Walk to an item on the ground and take it */\nexport const pickUpOrder: OrderBehavior<ItemOrderState, OrderInits['pickUp']> = {\n\ttype: 'pickUp',\n\taccepts(world, entity, init) {\n\t\tconst item = world.items.find((i) => i.id === init.item)\n\t\tif (!entity.has(inventorySlots) || !entity.get(moving) || !item) return false\n\t\t// what lies out of sight is not there to be picked up: a screen shows the items in sight alone (on a map explored\n\t\t// from the start, the dark is nowhere)\n\t\treturn world.fog.isVisible(world.player(entity.owner).team, item.x, item.z)\n\t},\n\tupdate(world, entity, order) {\n\t\tconst item = world.items.find((i) => i.id === order.init.item)\n\t\tif (!item) return 'done'\n\t\tconst m = entity.get(moving)!\n\t\tif (dist(entity.pos, item) > REACH) {\n\t\t\tif (m.status === 'moving') return 'running'\n\t\t\tif (order.state.walked && m.status === 'failed') return 'failed'\n\t\t\torder.state.walked = true\n\t\t\tmoveTo(world, entity, item, { range: REACH * 0.7 })\n\t\t\treturn 'running'\n\t\t}\n\t\tif (!hasRoomFor(world, entity, item.item, item.charges)) {\n\t\t\tworld.message(entity.owner, engineMessage('inventoryFull'))\n\t\t\treturn 'failed'\n\t\t}\n\t\t// one more of a group than it may carry, or the game's own rule: said by `pickUp`\n\t\treturn pickUp(world, entity, item.id) ? 'done' : 'failed'\n\t}\n}\n\n/** Put an item down somewhere, or hand it to someone */\nexport const dropItemOrder: OrderBehavior<ItemOrderState, OrderInits['dropItem']> = {\n\ttype: 'dropItem',\n\taccepts(world, entity, init) {\n\t\tif (!entity.get(moving) || !findItem(entity, init.item)) return false\n\t\tconst target = world.get(init.target)\n\t\tif (init.target) return !!target && target !== entity && target.has(inventorySlots) && world.areAllies(entity.owner, target.owner)\n\t\treturn !!init.point\n\t},\n\tupdate(world, entity, order) {\n\t\tif (!findItem(entity, order.init.item)) return 'done'\n\t\tconst m = entity.get(moving)!\n\t\tconst receiver = order.init.target ? world.get(order.init.target) : undefined\n\t\tif (order.init.target && !receiver) return 'done'\n\n\t\tif (receiver) {\n\t\t\tif (edgeDistance(entity, receiver) > REACH) {\n\t\t\t\tmoveToEntity(world, entity, receiver, REACH * 0.7)\n\t\t\t\treturn m.status === 'failed' ? 'failed' : 'running'\n\t\t\t}\n\t\t\tconst handed = findItem(entity, order.init.item)!\n\t\t\tif (!hasRoomFor(world, receiver, handed.item, handed.charges)) {\n\t\t\t\tworld.message(entity.owner, engineMessage('theirInventoryFull'))\n\t\t\t\treturn 'failed'\n\t\t\t}\n\t\t\tconst refused = carryRefusal(world, receiver, handed.item, [], true)\n\t\t\tif (refused) {\n\t\t\t\tworld.message(entity.owner, refused)\n\t\t\t\treturn 'failed'\n\t\t\t}\n\t\t\tgiveItem(world, receiver, takeItem(world, entity, order.init.item!)!)\n\t\t\treturn 'done'\n\t\t}\n\n\t\tif (dist(entity.pos, order.init.point!) > REACH) {\n\t\t\tif (m.status === 'moving') return 'running'\n\t\t\tif (order.state.walked && m.status === 'failed') return 'failed'\n\t\t\torder.state.walked = true\n\t\t\tmoveTo(world, entity, order.init.point!, { range: REACH * 0.7 })\n\t\t\treturn 'running'\n\t\t}\n\t\tconst held = findItem(entity, order.init.item)\n\t\tif (held && world.hooks.has('beforeDrop')) {\n\t\t\tconst before = world.hooks.run('beforeDrop', { entity, item: held, cancelled: false })\n\t\t\tif (before.cancelled) {\n\t\t\t\tif (before.reason) world.message(entity.owner, before.reason)\n\t\t\t\treturn 'failed'\n\t\t\t}\n\t\t}\n\t\tdropOnGround(world, takeItem(world, entity, order.init.item!)!, order.init.point!)\n\t\treturn 'done'\n\t}\n}\n"],"mappings":";;;;;;;;AAoBA,IAAa,cAAmE;CAC/E,MAAM;CACN,QAAQ,OAAO,QAAQ,MAAM;EAC5B,MAAM,OAAO,MAAM,MAAM,MAAM,MAAM,EAAE,OAAO,KAAK,IAAI;EACvD,IAAI,CAAC,OAAO,IAAI,cAAc,KAAK,CAAC,OAAO,IAAI,MAAM,KAAK,CAAC,MAAM,OAAO;EAGxE,OAAO,MAAM,IAAI,UAAU,MAAM,OAAO,OAAO,KAAK,CAAC,CAAC,MAAM,KAAK,GAAG,KAAK,CAAC;CAC3E;CACA,OAAO,OAAO,QAAQ,OAAO;EAC5B,MAAM,OAAO,MAAM,MAAM,MAAM,MAAM,EAAE,OAAO,MAAM,KAAK,IAAI;EAC7D,IAAI,CAAC,MAAM,OAAO;EAClB,MAAM,IAAI,OAAO,IAAI,MAAM;EAC3B,IAAI,KAAK,OAAO,KAAK,IAAI,IAAA,KAAW;GACnC,IAAI,EAAE,WAAW,UAAU,OAAO;GAClC,IAAI,MAAM,MAAM,UAAU,EAAE,WAAW,UAAU,OAAO;GACxD,MAAM,MAAM,SAAS;GACrB,OAAO,OAAO,QAAQ,MAAM,EAAE,OAAO,QAAQ,GAAI,CAAC;GAClD,OAAO;EACR;EACA,IAAI,CAAC,WAAW,OAAO,QAAQ,KAAK,MAAM,KAAK,OAAO,GAAG;GACxD,MAAM,QAAQ,OAAO,OAAO,cAAc,eAAe,CAAC;GAC1D,OAAO;EACR;EAEA,OAAO,OAAO,OAAO,QAAQ,KAAK,EAAE,IAAI,SAAS;CAClD;AACD;;AAGA,IAAa,gBAAuE;CACnF,MAAM;CACN,QAAQ,OAAO,QAAQ,MAAM;EAC5B,IAAI,CAAC,OAAO,IAAI,MAAM,KAAK,CAAC,SAAS,QAAQ,KAAK,IAAI,GAAG,OAAO;EAChE,MAAM,SAAS,MAAM,IAAI,KAAK,MAAM;EACpC,IAAI,KAAK,QAAQ,OAAO,CAAC,CAAC,UAAU,WAAW,UAAU,OAAO,IAAI,cAAc,KAAK,MAAM,UAAU,OAAO,OAAO,OAAO,KAAK;EACjI,OAAO,CAAC,CAAC,KAAK;CACf;CACA,OAAO,OAAO,QAAQ,OAAO;EAC5B,IAAI,CAAC,SAAS,QAAQ,MAAM,KAAK,IAAI,GAAG,OAAO;EAC/C,MAAM,IAAI,OAAO,IAAI,MAAM;EAC3B,MAAM,WAAW,MAAM,KAAK,SAAS,MAAM,IAAI,MAAM,KAAK,MAAM,IAAI,KAAA;EACpE,IAAI,MAAM,KAAK,UAAU,CAAC,UAAU,OAAO;EAE3C,IAAI,UAAU;GACb,IAAI,aAAa,QAAQ,QAAQ,IAAA,KAAW;IAC3C,aAAa,OAAO,QAAQ,UAAU,QAAQ,EAAG;IACjD,OAAO,EAAE,WAAW,WAAW,WAAW;GAC3C;GACA,MAAM,SAAS,SAAS,QAAQ,MAAM,KAAK,IAAI;GAC/C,IAAI,CAAC,WAAW,OAAO,UAAU,OAAO,MAAM,OAAO,OAAO,GAAG;IAC9D,MAAM,QAAQ,OAAO,OAAO,cAAc,oBAAoB,CAAC;IAC/D,OAAO;GACR;GACA,MAAM,UAAU,aAAa,OAAO,UAAU,OAAO,MAAM,CAAC,GAAG,IAAI;GACnE,IAAI,SAAS;IACZ,MAAM,QAAQ,OAAO,OAAO,OAAO;IACnC,OAAO;GACR;GACA,SAAS,OAAO,UAAU,SAAS,OAAO,QAAQ,MAAM,KAAK,IAAK,CAAE;GACpE,OAAO;EACR;EAEA,IAAI,KAAK,OAAO,KAAK,MAAM,KAAK,KAAM,IAAA,KAAW;GAChD,IAAI,EAAE,WAAW,UAAU,OAAO;GAClC,IAAI,MAAM,MAAM,UAAU,EAAE,WAAW,UAAU,OAAO;GACxD,MAAM,MAAM,SAAS;GACrB,OAAO,OAAO,QAAQ,MAAM,KAAK,OAAQ,EAAE,OAAO,QAAQ,GAAI,CAAC;GAC/D,OAAO;EACR;EACA,MAAM,OAAO,SAAS,QAAQ,MAAM,KAAK,IAAI;EAC7C,IAAI,QAAQ,MAAM,MAAM,IAAI,YAAY,GAAG;GAC1C,MAAM,SAAS,MAAM,MAAM,IAAI,cAAc;IAAE;IAAQ,MAAM;IAAM,WAAW;GAAM,CAAC;GACrF,IAAI,OAAO,WAAW;IACrB,IAAI,OAAO,QAAQ,MAAM,QAAQ,OAAO,OAAO,OAAO,MAAM;IAC5D,OAAO;GACR;EACD;EACA,aAAa,OAAO,SAAS,OAAO,QAAQ,MAAM,KAAK,IAAK,GAAI,MAAM,KAAK,KAAM;EACjF,OAAO;CACR;AACD"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { orderSays } from "./facts.js";
|
|
2
|
+
import { fighting } from "../entity.js";
|
|
3
|
+
import { isControlled } from "../abilities/buffs.js";
|
|
4
|
+
import { halt, joinFormation } from "../systems/movement.js";
|
|
5
|
+
import { disengage } from "../systems/combat.js";
|
|
6
|
+
function createOrder(world, init, groupId = 0) {
|
|
7
|
+
return {
|
|
8
|
+
id: world.newId(),
|
|
9
|
+
type: init.type,
|
|
10
|
+
init: orderParams(init),
|
|
11
|
+
groupId,
|
|
12
|
+
started: false,
|
|
13
|
+
state: {}
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* What an order keeps of what it was given: its fields as plain data of its own (a point copied, not the command's),
|
|
18
|
+
* those that are there alone, in one order (what a save and the determinism hash meet)
|
|
19
|
+
*/
|
|
20
|
+
function orderParams(init) {
|
|
21
|
+
const params = {};
|
|
22
|
+
if (init.target !== void 0) params.target = init.target;
|
|
23
|
+
if (init.point) params.point = {
|
|
24
|
+
x: init.point.x,
|
|
25
|
+
z: init.point.z
|
|
26
|
+
};
|
|
27
|
+
if (init.to) params.to = {
|
|
28
|
+
x: init.to.x,
|
|
29
|
+
z: init.to.z
|
|
30
|
+
};
|
|
31
|
+
if (init.unitType !== void 0) params.unitType = init.unitType;
|
|
32
|
+
if (init.ability !== void 0) params.ability = init.ability;
|
|
33
|
+
if (init.item !== void 0) params.item = init.item;
|
|
34
|
+
if (init.facing !== void 0) params.facing = init.facing;
|
|
35
|
+
if (init.path !== void 0) params.path = init.path;
|
|
36
|
+
if (init.towards === "first" || init.towards === "last") params.towards = init.towards;
|
|
37
|
+
if (init.speedCap !== void 0 && Number.isFinite(init.speedCap)) params.speedCap = init.speedCap;
|
|
38
|
+
return params;
|
|
39
|
+
}
|
|
40
|
+
function endOrder(world, entity, order) {
|
|
41
|
+
if (order.started) world.registry.order(order.type).end?.(world, entity, order);
|
|
42
|
+
}
|
|
43
|
+
/** Back to a neutral stance between orders: not walking, not mid swing, free to be pushed. */
|
|
44
|
+
function resetStance(world, entity) {
|
|
45
|
+
halt(world, entity);
|
|
46
|
+
disengage(world, entity);
|
|
47
|
+
if (entity.get(fighting)) {
|
|
48
|
+
entity.get(fighting).autoTarget = 0;
|
|
49
|
+
entity.get(fighting).guard = null;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/** Drops everything the entity was doing */
|
|
53
|
+
function clearOrders(world, entity) {
|
|
54
|
+
const current = entity.orders[0];
|
|
55
|
+
entity.keepOrders();
|
|
56
|
+
if (current) endOrder(world, entity, current);
|
|
57
|
+
resetStance(world, entity);
|
|
58
|
+
}
|
|
59
|
+
/** Whether the entity is in the middle of something it cannot be called away from, like casting (`OrderBehavior.committed`) */
|
|
60
|
+
var isCommitted = (world, entity) => orderSays(world, entity, "committed");
|
|
61
|
+
/**
|
|
62
|
+
* Drops what the entity was doing, as far as it lets itself be called away:
|
|
63
|
+
* what it is committed to is finished first, only what was to come after is dropped.
|
|
64
|
+
*/
|
|
65
|
+
function interrupt(world, entity) {
|
|
66
|
+
if (isCommitted(world, entity)) entity.keepOrders(1);
|
|
67
|
+
else clearOrders(world, entity);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Gives an order. Queued orders wait their turn, anything else replaces what the unit is doing,
|
|
71
|
+
* or comes right after it when the unit is committed to it.
|
|
72
|
+
*/
|
|
73
|
+
function giveOrder(world, entity, order, queue = false) {
|
|
74
|
+
if (entity.buffs.length && isControlled(world, entity)) return;
|
|
75
|
+
if (world.hooks.run("beforeOrder", {
|
|
76
|
+
entity,
|
|
77
|
+
order,
|
|
78
|
+
queued: queue,
|
|
79
|
+
rejected: false
|
|
80
|
+
}).rejected) return;
|
|
81
|
+
world.wake(entity);
|
|
82
|
+
if (entity.get(fighting)) entity.get(fighting).passive = false;
|
|
83
|
+
if (queue) {
|
|
84
|
+
if (entity.orders.length < 32) entity.addOrder(order);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const combat = entity.get(fighting);
|
|
88
|
+
const swing = combat && order.type === "attack" && order.init.target !== void 0 && combat.swingTarget === order.init.target ? combat.swing : 0;
|
|
89
|
+
if (combat && swing > 0) combat.swing = 0;
|
|
90
|
+
if (combat?.recovery !== void 0 && world.settings.combat.recoveryCancels(world, entity)) delete combat.recovery;
|
|
91
|
+
interrupt(world, entity);
|
|
92
|
+
joinFormation(entity);
|
|
93
|
+
entity.addOrder(order);
|
|
94
|
+
if (combat && swing > 0) {
|
|
95
|
+
combat.swing = swing;
|
|
96
|
+
combat.swingTarget = order.init.target;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/** Removes the order at the front of the queue once it finished */
|
|
100
|
+
function completeOrder(world, entity, order) {
|
|
101
|
+
endOrder(world, entity, order);
|
|
102
|
+
entity.removeOrder(order);
|
|
103
|
+
resetStance(world, entity);
|
|
104
|
+
}
|
|
105
|
+
//#endregion
|
|
106
|
+
export { clearOrders, completeOrder, createOrder, giveOrder, interrupt, isCommitted, resetStance };
|
|
107
|
+
|
|
108
|
+
//# sourceMappingURL=queue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queue.js","names":[],"sources":["../../src/orders/queue.ts"],"sourcesContent":["import type { Entity, Order } from '#engine/entity'\nimport { orderSays } from './facts'\nimport type { OrderInit, OrderParams } from '#engine/registry'\nimport { disengage } from '#engine/systems/combat'\nimport { halt, joinFormation } from '#engine/systems/movement'\nimport type { World } from '#engine/world'\nimport { fighting } from '../entity'\nimport { isControlled } from '#engine/abilities/buffs'\n\n/** Classic RTS games cap queues as well. Mostly a guard against runaway shift-clicking */\nexport const MAX_QUEUED_ORDERS = 32\n\nexport function createOrder(world: World, init: OrderInit, groupId = 0): Order {\n\treturn {\n\t\tid: world.newId(),\n\t\ttype: init.type,\n\t\tinit: orderParams(init),\n\t\tgroupId,\n\t\tstarted: false,\n\t\tstate: {}\n\t}\n}\n\n/**\n * What an order keeps of what it was given: its fields as plain data of its own (a point copied, not the command's),\n * those that are there alone, in one order (what a save and the determinism hash meet)\n */\nfunction orderParams(init: OrderInit): OrderParams {\n\tconst params: OrderParams = {}\n\tif (init.target !== undefined) params.target = init.target\n\tif (init.point) params.point = { x: init.point.x, z: init.point.z }\n\tif (init.to) params.to = { x: init.to.x, z: init.to.z }\n\tif (init.unitType !== undefined) params.unitType = init.unitType\n\tif (init.ability !== undefined) params.ability = init.ability\n\tif (init.item !== undefined) params.item = init.item\n\tif (init.facing !== undefined) params.facing = init.facing\n\tif (init.path !== undefined) params.path = init.path\n\tif (init.towards === 'first' || init.towards === 'last') params.towards = init.towards\n\tif (init.speedCap !== undefined && Number.isFinite(init.speedCap)) params.speedCap = init.speedCap\n\treturn params\n}\n\nfunction endOrder(world: World, entity: Entity, order: Order): void {\n\tif (order.started) world.registry.order(order.type).end?.(world, entity, order)\n}\n\n/** Back to a neutral stance between orders: not walking, not mid swing, free to be pushed. */\nexport function resetStance(world: World, entity: Entity): void {\n\thalt(world, entity)\n\tdisengage(world, entity)\n\tif (entity.get(fighting)) {\n\t\tentity.get(fighting)!.autoTarget = 0\n\t\tentity.get(fighting)!.guard = null\n\t}\n}\n\n/** Drops everything the entity was doing */\nexport function clearOrders(world: World, entity: Entity): void {\n\tconst current = entity.orders[0]\n\tentity.keepOrders()\n\tif (current) endOrder(world, entity, current)\n\tresetStance(world, entity)\n}\n\n/** Whether the entity is in the middle of something it cannot be called away from, like casting (`OrderBehavior.committed`) */\nexport const isCommitted = (world: World, entity: Entity) => orderSays(world, entity, 'committed')\n\n/**\n * Drops what the entity was doing, as far as it lets itself be called away:\n * what it is committed to is finished first, only what was to come after is dropped.\n */\nexport function interrupt(world: World, entity: Entity): void {\n\tif (isCommitted(world, entity)) entity.keepOrders(1)\n\telse clearOrders(world, entity)\n}\n\n/**\n * Gives an order. Queued orders wait their turn, anything else replaces what the unit is doing,\n * or comes right after it when the unit is committed to it.\n */\nexport function giveOrder(world: World, entity: Entity, order: Order, queue = false): void {\n\t// a buff that takes its orders (`BuffDef.control`) has them for as long as it lasts: none is taken meanwhile\n\tif (entity.buffs.length && isControlled(world, entity)) return\n\tif (world.hooks.run('beforeOrder', { entity, order, queued: queue, rejected: false }).rejected) return\n\tworld.wake(entity)\n\tif (entity.get(fighting)) entity.get(fighting)!.passive = false\n\tif (queue) {\n\t\tif (entity.orders.length < MAX_QUEUED_ORDERS) entity.addOrder(order)\n\t\treturn\n\t}\n\t// told to attack what it was already swinging at, of its own accord or on the way somewhere: the swing goes on, and\n\t// is not called off on the way (nothing is said of it)\n\tconst combat = entity.get(fighting)\n\tconst swing = combat && order.type === 'attack' && order.init.target !== undefined && combat.swingTarget === order.init.target ? combat.swing : 0\n\tif (combat && swing > 0) combat.swing = 0\n\t// in the recovery after a blow (`AttackDef.recovery`): the order waits it out, unless the rules let it cut it short\n\tif (combat?.recovery !== undefined && world.settings.combat.recoveryCancels(world, entity)) delete combat.recovery\n\tinterrupt(world, entity)\n\t// told something else: of no formation, until the command says it is of one\n\tjoinFormation(entity)\n\tentity.addOrder(order)\n\tif (combat && swing > 0) {\n\t\tcombat.swing = swing\n\t\tcombat.swingTarget = order.init.target!\n\t}\n}\n\n/** Removes the order at the front of the queue once it finished */\nexport function completeOrder(world: World, entity: Entity, order: Order): void {\n\tendOrder(world, entity, order)\n\tentity.removeOrder(order)\n\tresetStance(world, entity)\n}\n"],"mappings":";;;;;AAYA,SAAgB,YAAY,OAAc,MAAiB,UAAU,GAAU;CAC9E,OAAO;EACN,IAAI,MAAM,MAAM;EAChB,MAAM,KAAK;EACX,MAAM,YAAY,IAAI;EACtB;EACA,SAAS;EACT,OAAO,CAAC;CACT;AACD;;;;;AAMA,SAAS,YAAY,MAA8B;CAClD,MAAM,SAAsB,CAAC;CAC7B,IAAI,KAAK,WAAW,KAAA,GAAW,OAAO,SAAS,KAAK;CACpD,IAAI,KAAK,OAAO,OAAO,QAAQ;EAAE,GAAG,KAAK,MAAM;EAAG,GAAG,KAAK,MAAM;CAAE;CAClE,IAAI,KAAK,IAAI,OAAO,KAAK;EAAE,GAAG,KAAK,GAAG;EAAG,GAAG,KAAK,GAAG;CAAE;CACtD,IAAI,KAAK,aAAa,KAAA,GAAW,OAAO,WAAW,KAAK;CACxD,IAAI,KAAK,YAAY,KAAA,GAAW,OAAO,UAAU,KAAK;CACtD,IAAI,KAAK,SAAS,KAAA,GAAW,OAAO,OAAO,KAAK;CAChD,IAAI,KAAK,WAAW,KAAA,GAAW,OAAO,SAAS,KAAK;CACpD,IAAI,KAAK,SAAS,KAAA,GAAW,OAAO,OAAO,KAAK;CAChD,IAAI,KAAK,YAAY,WAAW,KAAK,YAAY,QAAQ,OAAO,UAAU,KAAK;CAC/E,IAAI,KAAK,aAAa,KAAA,KAAa,OAAO,SAAS,KAAK,QAAQ,GAAG,OAAO,WAAW,KAAK;CAC1F,OAAO;AACR;AAEA,SAAS,SAAS,OAAc,QAAgB,OAAoB;CACnE,IAAI,MAAM,SAAS,MAAM,SAAS,MAAM,MAAM,IAAI,CAAC,CAAC,MAAM,OAAO,QAAQ,KAAK;AAC/E;;AAGA,SAAgB,YAAY,OAAc,QAAsB;CAC/D,KAAK,OAAO,MAAM;CAClB,UAAU,OAAO,MAAM;CACvB,IAAI,OAAO,IAAI,QAAQ,GAAG;EACzB,OAAO,IAAI,QAAQ,CAAC,CAAE,aAAa;EACnC,OAAO,IAAI,QAAQ,CAAC,CAAE,QAAQ;CAC/B;AACD;;AAGA,SAAgB,YAAY,OAAc,QAAsB;CAC/D,MAAM,UAAU,OAAO,OAAO;CAC9B,OAAO,WAAW;CAClB,IAAI,SAAS,SAAS,OAAO,QAAQ,OAAO;CAC5C,YAAY,OAAO,MAAM;AAC1B;;AAGA,IAAa,eAAe,OAAc,WAAmB,UAAU,OAAO,QAAQ,WAAW;;;;;AAMjG,SAAgB,UAAU,OAAc,QAAsB;CAC7D,IAAI,YAAY,OAAO,MAAM,GAAG,OAAO,WAAW,CAAC;MAC9C,YAAY,OAAO,MAAM;AAC/B;;;;;AAMA,SAAgB,UAAU,OAAc,QAAgB,OAAc,QAAQ,OAAa;CAE1F,IAAI,OAAO,MAAM,UAAU,aAAa,OAAO,MAAM,GAAG;CACxD,IAAI,MAAM,MAAM,IAAI,eAAe;EAAE;EAAQ;EAAO,QAAQ;EAAO,UAAU;CAAM,CAAC,CAAC,CAAC,UAAU;CAChG,MAAM,KAAK,MAAM;CACjB,IAAI,OAAO,IAAI,QAAQ,GAAG,OAAO,IAAI,QAAQ,CAAC,CAAE,UAAU;CAC1D,IAAI,OAAO;EACV,IAAI,OAAO,OAAO,SAAA,IAA4B,OAAO,SAAS,KAAK;EACnE;CACD;CAGA,MAAM,SAAS,OAAO,IAAI,QAAQ;CAClC,MAAM,QAAQ,UAAU,MAAM,SAAS,YAAY,MAAM,KAAK,WAAW,KAAA,KAAa,OAAO,gBAAgB,MAAM,KAAK,SAAS,OAAO,QAAQ;CAChJ,IAAI,UAAU,QAAQ,GAAG,OAAO,QAAQ;CAExC,IAAI,QAAQ,aAAa,KAAA,KAAa,MAAM,SAAS,OAAO,gBAAgB,OAAO,MAAM,GAAG,OAAO,OAAO;CAC1G,UAAU,OAAO,MAAM;CAEvB,cAAc,MAAM;CACpB,OAAO,SAAS,KAAK;CACrB,IAAI,UAAU,QAAQ,GAAG;EACxB,OAAO,QAAQ;EACf,OAAO,cAAc,MAAM,KAAK;CACjC;AACD;;AAGA,SAAgB,cAAc,OAAc,QAAgB,OAAoB;CAC/E,SAAS,OAAO,QAAQ,KAAK;CAC7B,OAAO,YAAY,KAAK;CACxB,YAAY,OAAO,MAAM;AAC1B"}
|