@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":"commands.js","names":["commandRejectedEvent","commandHandledEvent"],"sources":["../src/commands.ts"],"sourcesContent":["import { commandHandled as commandHandledEvent, commandRejected as commandRejectedEvent, constructionCancelled } from '#engine/engineEvents'\nimport { aimKind } from './targeting'\nimport type { Message } from './messages'\nimport type { RejectedKind } from './errors'\nimport { productionOf } from './systems/productionQueue'\nimport { statsOf } from './stats'\nimport { constructionSite, underConstruction } from './systems/construction'\nimport { isStunned } from './abilities/buffs'\nimport { steerMissile } from './abilities/effects'\nimport { dashing } from './dashing'\nimport type { Entity, EntityId, PlayerId } from './entity'\nimport { bool, type Checked, type Fields, id, ids, index, Invalid, number, object, oneOf, optional, point, string } from './fields'\nimport { formationPoints } from './formation'\nimport { distSq, type Vec2 } from './math'\nimport { castAside, notReady } from './orders/cast'\nimport { createOrder, giveOrder, interrupt } from './orders/queue'\nimport { giveBack } from './player'\nimport type { OrderInit } from './registry'\nimport { smartOrder } from './smart'\nimport { chat, ping } from './talk'\nimport { give, shareWith } from './trade'\nimport { askPause, surrender } from './endings'\nimport { canAttack } from './systems/combat'\nimport { runOrder } from './systems/orders'\nimport { joinFormation } from './systems/movement'\nimport { cameraCommanded, cameraCommandFields } from './cameraOrders'\nimport { CINEMATIC_OUTCOMES, cinematicChose, cinematicEnded } from './cinematics'\nimport { cancelProduction, enqueueMorph, enqueueProduction, enqueueResearch } from './systems/production'\nimport type { World } from './world'\nimport { atan2 } from './exactMath'\nimport { fighting, moving } from './entity'\nimport { replicateEvent } from './replication'\n\n/**\n * Commands are everything a player can ask for: plain data, and the only way input reaches the simulation,\n * which keeps the door open for replays, the AI and multiplayer.\n *\n * A command type is a `CommandDef`: the fields it carries, and what it does. What arrives is checked against the\n * fields before anything happens, because on a server it is whatever anyone sends. The engine's own commands are\n * defined the same way as a game module's (`Rules.commands`).\n *\n * @beta\n */\nexport interface CommandDef<F extends Fields = Fields> {\n\t/** The command's name, which a sent command carries as its `type` */\n\ttype: string\n\t/** What it carries, besides its type and the player who sent it. See `fields.ts` for the checkers */\n\tfields: F\n\t/** Carries it out, for `player`. Whether the player owns or can see what it names is for this to check */\n\texecute(world: World, player: PlayerId, command: Checked<F>): void\n\t/**\n\t * Carried out at once when given between two ticks, a paused game's too, not at the start of the next (`World.issue`):\n\t * talk, a line of chat or a ping, which a game that waits is still to hear. Counted by the talk's own rate, not the\n\t * commands a tick may have; a replay keeps it where it was given (RV14)\n\t */\n\toutsideTick?: boolean\n}\n\ndeclare const modCommandBrand: unique symbol\n\n/**\n * A command of a game module, as its definition's `make` puts it together. Sessions send it like the engine's own\n *\n * @beta\n */\nexport type ModCommand = { readonly type: string; readonly [modCommandBrand]: true }\n\n/**\n * A command type, with `make` to put one together for a session to send\n *\n * @beta\n */\nexport type DefinedCommand<T extends string, F extends Fields> = CommandDef<F> & {\n\ttype: T\n\tmake(fields: Checked<F>): ModCommand\n}\n\n/**\n * Defines a command type, for a game module's `commands`: its type, its fields (see `fields.ts`), and what it does.\n * `command` is typed by the fields.\n *\n * ```ts\n * const sellTower = defineCommand('sellTower', { tower: id }, (world, player, command) => { ... })\n * session.send(sellTower.make({ tower: 12 }))\n * ```\n *\n * @public\n */\nexport function defineCommand<const T extends string, F extends Fields>(\n\ttype: T,\n\tfields: F,\n\texecute: (world: World, player: PlayerId, command: Checked<F>) => void,\n\toptions: { outsideTick?: boolean } = {}\n): DefinedCommand<T, F> {\n\t// what every command carries of its own: a field of the same name would be written over on the way in\n\tfor (const own of ['type', 'player', 'seq']) {\n\t\tif (own in fields)\n\t\t\tthrow new Error(`Command \"${type}\": \"${own}\" is what every command carries (who sent it, and the like), name the field otherwise`)\n\t}\n\treturn {\n\t\ttype,\n\t\tfields,\n\t\texecute,\n\t\t...(options.outsideTick && { outsideTick: true }),\n\t\tmake: (values) => ({ ...values, type }) as unknown as ModCommand\n\t}\n}\n\n/** What a command looks like on its way in: its type, who sent it, and its fields */\ntype CommandOf<D> = D extends DefinedCommand<infer T, infer F> ? { type: T; player: PlayerId } & Checked<F> : never\n\n/** Part of the cost returned when a construction site is cancelled */\n\n/** The buildings something is to be made in: the selected ones, of which the least busy gets it. `building` for just one */\n/** @internal */\nexport const producers = { building: optional(id), buildings: optional(ids) }\n\n/**\n * Of the player's buildings that were named, the one that will get to something first: finished, able to make it,\n * and with the shortest queue that has room. As in classic RTS games, a group of barracks shares the work. When none has\n * room, the first that could make it, which then says its queue is full\n *\n * @internal\n */\nexport function leastBusy(\n\tworld: World,\n\tplayer: PlayerId,\n\tcommand: { building?: EntityId; buildings?: EntityId[] },\n\tfits: (entity: Entity) => boolean\n): Entity | undefined {\n\tconst named = [...(command.building !== undefined ? [command.building] : []), ...(command.buildings ?? [])]\n\tlet best: Entity | undefined\n\tlet first: Entity | undefined\n\tfor (const entity of owned(world, player, named)) {\n\t\tconst production = productionOf(entity)\n\t\tif (!production || !entity.operational || !fits(entity)) continue\n\t\tfirst ??= entity\n\t\tconst length = production.queue.length\n\t\tif (length < world.settings.production.queue && (!best || length < productionOf(best)!.queue.length)) best = entity\n\t}\n\treturn best ?? first\n}\n\n/**\n * The units a command names that the player may command: their own, and what another shares control of with them\n * (`world.mayCommand`). One of another's, or one there never was, is what their own client never sends: it is\n * turned away (`commandRejected`), and the rest goes on. One that has died meanwhile is let be\n *\n * @internal\n */\nexport function owned(world: World, player: PlayerId, ids: EntityId[]): Entity[] {\n\tconst result: Entity[] = []\n\tfor (const id of ids) {\n\t\tconst entity = world.get(id)\n\t\tif (entity && world.mayCommand(player, entity)) result.push(entity)\n\t\telse if (entity) world.events.emit(commandRejectedEvent, { player, kind: 'notTheirs', reason: `unit ${id} is not theirs` })\n\t\telse if (!world.made(id)) world.events.emit(commandRejectedEvent, { player, kind: 'noSuchUnit', reason: `there is no unit ${id}` })\n\t}\n\treturn result\n}\n\n/** Direction from the middle of a group to where it was sent, so the whole group ends up facing the same way */\nfunction travelDirection(entities: Entity[], point: Vec2): number | undefined {\n\tlet x = 0\n\tlet z = 0\n\tfor (const entity of entities) {\n\t\tx += entity.pos.x\n\t\tz += entity.pos.z\n\t}\n\tx = point.x - x / entities.length\n\tz = point.z - z / entities.length\n\treturn x * x + z * z > 0.04 ? atan2(x, z) : undefined\n}\n\n/**\n * Entity a player may point at: one their team sees, a structure they have seen before, or, on a map explored from\n * the start, a structure of nobody's (a tree, a mine). Commands naming anything else are probing for what the player\n * cannot know.\n *\n * @internal\n */\nexport function known(world: World, player: PlayerId, id: EntityId | undefined): Entity | undefined {\n\tconst entity = world.get(id)\n\tif (!entity) return undefined\n\tconst { team } = world.player(player)\n\tif (world.areAllies(entity.owner, player) || world.isVisibleTo(entity, team)) return entity\n\tif (!entity.isStructure) return undefined\n\tif (world.sight.hasSeen(entity, team)) return entity\n\t// on a map explored from the start, what stands on it and is no player's (trees, mines, the creeps' own) is known\n\t// from the first snapshot, out of sight, as the session tells it (`TeamMemory.startKnown`): an order on it stands\n\tconst owner = world.players.get(entity.owner)\n\treturn world.fog.exploredFromStart && (owner?.neutral || owner?.creeps) ? entity : undefined\n}\n\n/** What a unit is told to do, as a command carries it. See `OrderInit` */\nconst orderInit = object({\n\ttype: string,\n\ttarget: optional(id),\n\tpoint: optional(point),\n\tunitType: optional(string),\n\tability: optional(string),\n\titem: optional(index),\n\tfacing: optional(number),\n\tpath: optional(string),\n\ttowards: optional(oneOf('first', 'last')),\n\tformation: optional(string),\n\ttogether: optional(bool)\n})\n\n// ---- the engine's commands\n\n/**\n * The engine's `order` command: gives an order to entities the player owns, replacing theirs or queued after them\n *\n * @internal\n */\nexport const orderCommand = defineCommand(\n\t'order',\n\t{ entities: ids, order: orderInit, queue: optional(bool) },\n\t(world, player, { entities: chosen, order: init, queue = false }) => {\n\t\tif (!world.registry.orders.has(init.type)) return\n\t\tif (init.target && !known(world, player, init.target)) return\n\t\tconst behavior = world.registry.order(init.type)\n\t\tlet entities = owned(world, player, chosen).filter((entity) => !entity.has(constructionSite) && behavior.accepts(world, entity, init))\n\t\t// what is carried and used on the spot does not stop whoever carries it\n\t\tif (init.type === 'cast' && init.item !== undefined && !queue) entities = entities.filter((entity) => !castAside(world, entity, init))\n\t\t// told to attack what it is attacking already: it goes on as it was, and only what was to come after is dropped\n\t\tif (init.type === 'attack' && init.target !== undefined && !queue) {\n\t\t\tentities = entities.filter((entity) => {\n\t\t\t\tconst current = entity.orders[0]\n\t\t\t\tif (current?.type !== 'attack' || current.init.target !== init.target) return true\n\t\t\t\tentity.keepOrders(1)\n\t\t\t\treturn false\n\t\t\t})\n\t\t}\n\t\tif (entities.length === 0) return\n\n\t\tconst groupId = world.newId()\n\t\tconst facing = init.facing ?? (init.point && !init.target ? travelDirection(entities, init.point) : undefined)\n\t\t// those who walk line up on the ground, those who fly above it\n\t\tconst points = new Map<EntityId, Vec2>()\n\t\tif (behavior.formation && init.point && !init.target && entities.length > 1) {\n\t\t\tconst id = init.formation ?? world.settings.movement.formation(world, entities, init)\n\t\t\t// a formation nobody knows is no formation: the units go as the rules have them, rather than nowhere\n\t\t\tconst formation = world.registry.formations.has(id)\n\t\t\t\t? world.registry.formation(id)\n\t\t\t\t: world.registry.formation(world.settings.movement.formation(world, entities, init))\n\t\t\tconst flyers = entities.filter((entity) => entity.flying)\n\t\t\tconst walkers = entities.filter((entity) => !entity.flying)\n\t\t\tfor (const [id, point] of formationPoints(world, walkers, init.point, formation, init.facing)) points.set(id, point)\n\t\t\tfor (const [id, point] of formationPoints(world, flyers, init.point, formation, init.facing)) points.set(id, point)\n\t\t}\n\t\t// a group that goes together goes at its slowest's pace: what the slowest of them goes, as they are now\n\t\tconst together = init.type === 'move' && !init.target && entities.length > 1 && (init.together ?? false)\n\t\tconst speedCap = together ? Math.min(...entities.map((entity) => statsOf(world, entity).moveSpeed)) : undefined\n\t\tfor (const entity of entities) {\n\t\t\tconst point = points.get(entity.id) ?? init.point\n\t\t\tgiveOrder(world, entity, createOrder(world, { ...init, point, facing, ...(speedCap !== undefined && { speedCap }) }, groupId), queue)\n\t\t\t// one of a formation: it keeps its place in it, and swaps places with the others on the way (`MovementState.formation`)\n\t\t\tif (points.has(entity.id) && entity.orders.at(-1)?.groupId === groupId) joinFormation(entity, groupId)\n\t\t}\n\t}\n)\n\n/**\n * The engine's `rally` command: sets where the units a building makes go, a point or an entity\n *\n * @internal\n */\nexport const rallyCommand = defineCommand('rally', { buildings: ids, point, target: optional(id) }, (world, player, command) => {\n\tconst target = known(world, player, command.target)\n\tfor (const building of owned(world, player, command.buildings)) {\n\t\tconst production = productionOf(building)\n\t\tif (!production) continue\n\t\t// clicking the building itself clears the rally point\n\t\tif (target === building) production.rally = null\n\t\telse production.rally = { point: { x: command.point.x, z: command.point.z }, target: target?.id ?? 0 }\n\t}\n})\n\n/**\n * The right-click: every unit does what makes sense for it, buildings set their rally point\n *\n * @internal\n */\nexport const smartCommand = defineCommand(\n\t'smart',\n\t{ entities: ids, point, target: optional(id), queue: optional(bool), formation: optional(string), facing: optional(number) },\n\t(world, player, { point, queue, formation, facing, ...command }) => {\n\t\tconst target = known(world, player, command.target)\n\t\tconst entities = owned(world, player, command.entities)\n\t\tconst units = entities.filter((entity) => entity.get(moving))\n\t\tif (units.length === 0) {\n\t\t\trallyCommand.execute(world, player, { buildings: entities.map((entity) => entity.id), point, target: target?.id })\n\t\t\treturn\n\t\t}\n\t\t// units that end up with the same order are commanded together, so they move as a group\n\t\tconst groups = new Map<string, { order: OrderInit; ids: EntityId[] }>()\n\t\tfor (const unit of units) {\n\t\t\tconst order = smartOrder(world, unit, point, target)\n\t\t\tif (!order) continue\n\t\t\tif (formation !== undefined) order.formation = formation\n\t\t\tif (facing !== undefined && !target) order.facing = facing\n\t\t\t// moves of a group together, where the rules say (not attack-moves: those fight their way, each as it can)\n\t\t\tif (order.type === 'move' && world.settings.movement.together) order.together = true\n\t\t\tconst key = `${order.type}:${order.target ?? ''}`\n\t\t\tlet group = groups.get(key)\n\t\t\tif (!group) groups.set(key, (group = { order, ids: [] }))\n\t\t\tgroup.ids.push(unit.id)\n\t\t}\n\t\tfor (const group of groups.values()) orderCommand.execute(world, player, { entities: group.ids, order: group.order, queue })\n\t}\n)\n\n/**\n * Attack the target, for whoever can. Everyone else, or without a target: attack-move to the point\n *\n * @internal\n */\nexport const attackCommand = defineCommand(\n\t'attack',\n\t{ entities: ids, point, target: optional(id), queue: optional(bool), formation: optional(string) },\n\t(world, player, { point, queue, formation, ...command }) => {\n\t\tconst target = known(world, player, command.target)\n\t\tconst units = owned(world, player, command.entities).filter((entity) => entity.get(moving) || entity.get(fighting))\n\t\tconst attackers = target ? units.filter((unit) => canAttack(world, unit, target, true)) : []\n\t\tif (target && attackers.length) {\n\t\t\torderCommand.execute(world, player, { entities: attackers.map((unit) => unit.id), order: { type: 'attack', target: target.id }, queue })\n\t\t\treturn\n\t\t}\n\t\torderCommand.execute(world, player, { entities: units.map((unit) => unit.id), order: { type: 'attackMove', point }, queue })\n\t}\n)\n\n/**\n * Use an ability. Abilities that need a target are cast by one unit, the one that can and is closest\n *\n * @internal\n */\nexport const castCommand = defineCommand(\n\t'cast',\n\t{ entities: ids, ability: string, point: optional(point), to: optional(point), target: optional(id), queue: optional(bool) },\n\t(world, player, command) => {\n\t\tconst { queue } = command\n\t\tif (!world.registry.abilities.has(command.ability)) return\n\t\tconst ability = world.registry.ability(command.ability)\n\t\tconst target = known(world, player, command.target)\n\t\tif (command.target && !target) return\n\t\tconst init: OrderInit = { type: 'cast', ability: ability.id, target: target?.id, point: command.point, ...(command.to && { to: command.to }) }\n\t\tconst kind = aimKind(world.registry, ability)\n\t\tconst behavior = world.registry.order('cast')\n\t\tconst casters = owned(world, player, command.entities).filter((entity) => behavior.accepts(world, entity, init))\n\t\tif (casters.length === 0) return\n\n\t\t// what goes off on the spot goes off now: a move given in the same breath must not get in first\n\t\tconst instant = !queue && !ability.castTime && (kind === 'none' || kind === 'direction')\n\t\tconst give = (caster: Entity) => {\n\t\t\tconst order = createOrder(world, init)\n\t\t\tgiveOrder(world, caster, order, queue)\n\t\t\t// only what it was given: an order the rules refused (`beforeOrder`), or a unit under control did not take, is in no queue\n\t\t\tif (instant && caster.orders[0] === order && !isStunned(world, caster) && !caster.get(dashing)?.pulled) runOrder(world, caster, order, 0)\n\t\t}\n\t\tif (kind === 'none') {\n\t\t\tfor (const caster of casters) {\n\t\t\t\tif (queue) give(caster)\n\t\t\t\t// on the spot, in the middle of whatever the caster is doing\n\t\t\t\telse if (!notReady(world, caster, ability) && !castAside(world, caster, { ability: ability.id })) give(caster)\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t\tconst aim = target?.pos ?? command.point\n\t\tconst ready = casters.filter((caster) => !notReady(world, caster, ability))\n\t\tconst pool = ready.length ? ready : casters\n\t\tlet best = pool[0]\n\t\tfor (const caster of pool) {\n\t\t\tif (aim && distSq(caster.pos, aim) < distSq(best.pos, aim)) best = caster\n\t\t}\n\t\t// towards somewhere, at once: in the middle of whatever the caster is doing, like the ones cast on the spot\n\t\tif (instant && !notReady(world, best, ability) && castAside(world, best, { ability: ability.id }, command.point)) return\n\t\t// with nobody ready the order still goes out, so the player hears why it failed\n\t\tgive(best)\n\t}\n)\n\n/**\n * Turns the player's missiles of an ability that are steered (`EffectFields.steer`) towards a point, as they fly\n * (`steerMissile`): what the screen sends while one is in the air, for where the pointer is\n *\n * @beta\n */\nexport const steerCommand = defineCommand('steer', { ability: string, point }, (world, player, command) => {\n\tfor (const missile of world.missiles) if (missile.owner === player && missile.ability === command.ability) steerMissile(world, missile, command.point)\n})\n\n/**\n * The engine's `autocast` command: turns an ability's autocast on or off for the entities named\n *\n * @internal\n */\nexport const autocastCommand = defineCommand('autocast', { entities: ids, ability: string, enabled: bool }, (world, player, command) => {\n\tfor (const entity of owned(world, player, command.entities)) {\n\t\tconst state = entity.abilities.find((ability) => ability.id === command.ability)\n\t\tif (state) state.autocast = command.enabled\n\t}\n})\n\n/**\n * Stops what units are doing, as the classic Stop does: a plain interrupt. They fight what comes near again at once; a\n * unit that is to stand down and take no fights is put in a stance (`stanceCommand`, `stancesPack`)\n *\n * @beta\n */\nexport const stopCommand = defineCommand('stop', { entities: ids }, (world, player, command) => {\n\tfor (const entity of owned(world, player, command.entities)) interrupt(world, entity)\n})\n\n/**\n * The engine's `train` command: queues a unit type at the least busy building that can train it\n *\n * @internal\n */\nexport const trainCommand = defineCommand('train', { ...producers, unitType: string }, (world, player, command) => {\n\tconst building = leastBusy(world, player, command, (entity) => !!entity.def.trains?.includes(command.unitType))\n\tif (building) enqueueProduction(world, building, command.unitType)\n})\n\n/**\n * The engine's `research` command: queues an upgrade at the least busy building that can research it\n *\n * @internal\n */\nexport const researchCommand = defineCommand('research', { ...producers, upgrade: string }, (world, player, command) => {\n\tconst building = leastBusy(world, player, command, (entity) => !!entity.def.researches?.includes(command.upgrade))\n\tif (building) enqueueResearch(world, building, command.upgrade)\n})\n\n/**\n * Upgrades a building into a type it can become: `into`, one of its `upgradesTo`, or the first where none is named\n *\n * @internal\n */\nexport const upgradeBuildingCommand = defineCommand('upgradeBuilding', { building: id, into: optional(string) }, (world, player, command) => {\n\tconst [building] = owned(world, player, [command.building])\n\tif (building) enqueueMorph(world, building, command.into)\n})\n\n/**\n * The engine's `cancelTrain` command: takes the item at an index out of a building's queue\n *\n * @internal\n */\nexport const cancelTrainCommand = defineCommand('cancelTrain', { building: id, index }, (world, player, command) => {\n\tconst [building] = owned(world, player, [command.building])\n\tif (building) cancelProduction(world, building, command.index)\n})\n\n/**\n * The engine's `cancelConstruction` command: stops a building under construction, refunds part of its cost and removes it\n *\n * @internal\n */\nexport const cancelConstructionCommand = defineCommand('cancelConstruction', { building: id }, (world, player, command) => {\n\tconst [building] = owned(world, player, [command.building])\n\tconst site = building && underConstruction(building)\n\tif (!site) return\n\tgiveBack(world, player, site.paid ?? building.def.cost, world.settings.production.cancelRefund, 'structure', building.def.id)\n\tworld.events.emit(constructionCancelled, building)\n\tworld.kill(building, undefined, false, 'cancelled')\n})\n\n/** The player skips the line of dialog they hear: a conversation goes on to its next line. See `world.dialog` */\nexport const skipLineCommand = defineCommand('skipLine', {}, (world, player) => world.dialog.skip(player))\n\n/** A player marks a spot of the map for their allies: `look`, `danger`, `assist` or `onMyWay` (see `ping`) */\nexport const pingCommand = defineCommand(\n\t'ping',\n\t{ point, kind: optional(string), to: optional(string), by: optional(string) },\n\t(world, player, command) => ping(world, player, command.point, command.kind, command.to, command.by),\n\t{ outsideTick: true }\n)\n\n/** A player says a line of chat: to `allies` (when left out), or to `all` (see `chat`) */\nexport const chatCommand = defineCommand(\n\t'chat',\n\t{ text: string, to: optional(string), by: optional(string) },\n\t(world, player, command) => chat(world, player, command.text, command.to, command.by),\n\t{ outsideTick: true }\n)\n\n/** A player gives an ally some of a resource they have (see `give`) */\nexport const giveCommand = defineCommand('give', { to: id, resource: string, amount: number }, (world, player, command) =>\n\tgive(world, player, command.to, command.resource, command.amount)\n)\n\n/** A player shares control of their units, or their team's sight, with an ally, or no longer (see `shareWith`) */\nexport const shareCommand = defineCommand('share', { with: id, vision: optional(bool), control: optional(bool) }, (world, player, command) =>\n\tshareWith(world, player, command.with, { vision: command.vision, control: command.control })\n)\n\n/**\n * A player gives up: out of the game, as if beaten (see `surrender`)\n *\n * @internal\n */\nexport const surrenderCommand = defineCommand('surrender', {}, (world, player) => surrender(world, player))\n\n/**\n * A player asks for the game to be paused, one of their pauses (see `askPause`): whoever runs it pauses it\n *\n * @internal\n */\nexport const pauseCommand = defineCommand('pause', {}, (world, player) => askPause(world, player))\n\n/**\n * A player's own screen says something of its camera (see `cameraFor`): being a command, a replay has it. A seat that\n * names another's (`seat`) is refused\n *\n * @internal\n */\nexport const cameraCommand = defineCommand('camera', cameraCommandFields, cameraCommanded)\n\n/**\n * A player's screen says a cinematic the rules played on it is over, and how (see `cinematic`'s `wait`): sent by the\n * client as the cinematic ends, so that the rules hear it in the same tick on every machine and in a replay\n *\n * @internal\n */\nexport const cinematicCommand = defineCommand('cinematic', { cinematic: string, outcome: oneOf(...CINEMATIC_OUTCOMES) }, (world, player, command) =>\n\tcinematicEnded(world, player, command.cinematic, command.outcome)\n)\n\n/**\n * A player's screen says which answer of a cinematic's choice they picked (C3): heard by the rules in the same tick on\n * every machine and in a replay, as `cinematicChoice`\n *\n * @internal\n */\nexport const cinematicChoiceCommand = defineCommand(\n\t'cinematicChoice',\n\t{ cinematic: string, question: string, choice: string, timedOut: optional(bool) },\n\t(world, player, command) =>\n\t\tcinematicChose(world, { player, cinematic: command.cinematic, question: command.question, choice: command.choice, timedOut: !!command.timedOut })\n)\n\n/**\n * The commands the engine knows, which every game has\n *\n * @beta\n */\nexport const coreCommands = [\n\tcameraCommand,\n\torderCommand,\n\tsmartCommand,\n\tattackCommand,\n\tcastCommand,\n\tsteerCommand,\n\tautocastCommand,\n\tstopCommand,\n\ttrainCommand,\n\tresearchCommand,\n\tupgradeBuildingCommand,\n\tcancelTrainCommand,\n\trallyCommand,\n\tcancelConstructionCommand,\n\tskipLineCommand,\n\tpingCommand,\n\tchatCommand,\n\tgiveCommand,\n\tshareCommand,\n\tsurrenderCommand,\n\tpauseCommand,\n\tcinematicCommand,\n\tcinematicChoiceCommand\n] as const\n\n/**\n * The commands a world takes, by who defines them: the engine's (`core`), and each pack's, which adds its own by\n * declaration merging, as the heroes pack does:\n *\n * ```ts\n * declare module '@v12-engine/engine' {\n * \tinterface Commands {\n * \t\tmypack: (typeof myPackCommands)[number]\n * \t}\n * }\n * ```\n *\n * @beta\n */\nexport interface Commands {\n\t/** The engine's commands, as a union of their types; a game or pack adds its own by merging into `Commands` */\n\tcore: (typeof coreCommands)[number]\n}\n\n/**\n * A command a world takes, as it comes in: its type, who sent it, and its fields. The engine's, and its packs'\n * (`Commands`)\n *\n * @beta\n */\nexport type Command = CommandOf<Commands[keyof Commands]>\n\n/**\n * Any command on its way in: the engine's own, or a game module's\n *\n * @beta\n */\nexport type IssuedCommand = (Command | (ModCommand & { player: PlayerId })) & {\n\t/** The sender's own number for it, told back with how it went (`commandHandled`): what a screen waits on */\n\tseq?: number\n}\n\n/** Type and sender, the part every command has */\nconst head = object({ type: string, player: id })\n\n/**\n * Checks a command and carries it out. A command that is not what it says it is (an unknown type, a field missing\n * or of the wrong kind, a player that is not in the game) is turned away with `commandRejected`, and changes nothing\n */\nexport function executeCommand(world: World, raw: unknown): void {\n\tlet def: CommandDef\n\tlet player: PlayerId\n\tlet fields: Checked<Fields>\n\tlet kind: RejectedKind = 'badFields'\n\ttry {\n\t\tconst { type, player: sender } = head(raw, 'command')\n\t\tconst found = world.registry.command(type)\n\t\tkind = 'unknownType'\n\t\tif (!found) throw new Invalid(`there is no command \"${type}\"`)\n\t\tkind = 'noSuchPlayer'\n\t\tif (!world.players.has(sender)) throw new Invalid(`there is no player ${sender}`)\n\t\tkind = 'badFields'\n\t\tdef = found\n\t\tplayer = sender\n\t\tfields = object(def.fields)(raw, '')\n\t} catch (error) {\n\t\tif (!(error instanceof Invalid)) throw error\n\t\tconst { type, player, seq } = (typeof raw === 'object' && raw ? raw : {}) as Record<string, unknown>\n\t\tconst sender = typeof player === 'number' ? player : undefined\n\t\tworld.events.emit(commandRejectedEvent, { player: sender, type: typeof type === 'string' ? type : undefined, kind, reason: error.message })\n\t\tif (sender !== undefined && typeof seq === 'number')\n\t\t\tworld.events.emit(commandHandledEvent, { player: sender, seq, refusal: { key: error.message } })\n\t\treturn\n\t}\n\tconst seq = (raw as { seq?: unknown }).seq\n\t// who is out has no say any more\n\tif (world.player(player).defeated) {\n\t\tif (typeof seq === 'number') world.events.emit(commandHandledEvent, { player, seq, refusal: { key: 'defeated' } })\n\t\treturn\n\t}\n\t// what the rules refuse it with as it is carried out, they tell the player: the first of it is the answer\n\tconst handling = { player, refusal: undefined as Message | undefined }\n\tworld.handling = handling\n\ttry {\n\t\tdef.execute(world, player, fields)\n\t} catch (error) {\n\t\t// what the world says of errors (`World.caught`): it throws, or the command is refused and the tick goes on\n\t\tworld.caught(error, { kind: 'command', id: def.type, player })\n\t\thandling.refusal ??= { key: 'failed' }\n\t} finally {\n\t\tworld.handling = undefined\n\t}\n\tif (typeof seq === 'number') world.events.emit(commandHandledEvent, { player, seq, refusal: handling.refusal })\n}\n\n/** What became of a command: to whoever sent it */\nexport const toldCommand = replicateEvent(commandHandledEvent, 'command', ({ player, seq, refusal }, view) =>\n\tplayer === view.player ? { type: 'command', seq, ...(refusal ? { refusal } : {}) } : undefined\n)\n"],"mappings":"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"}
|
package/dist/components.d.ts
CHANGED
|
@@ -9,7 +9,8 @@ import type { World } from './world';
|
|
|
9
9
|
* and nothing else.
|
|
10
10
|
*
|
|
11
11
|
* A component is plain data, so that it goes into a save with the rest of the world (see `saveWorld`): numbers,
|
|
12
|
-
* text, lists and plain objects, with other entities by id.
|
|
12
|
+
* text, lists and plain objects, with other entities by id. One kept otherwise while the game runs (a `Map`, bytes)
|
|
13
|
+
* says how it is saved and loaded (`save`, `load`), wherever it is held.
|
|
13
14
|
*
|
|
14
15
|
* `T` is what the component holds; `S` is what a player's snapshot carries of it (`snapshot`), `T` itself when it is
|
|
15
16
|
* sent as it is
|
|
@@ -17,6 +18,7 @@ import type { World } from './world';
|
|
|
17
18
|
* @beta
|
|
18
19
|
*/
|
|
19
20
|
export interface Component<T, S = T> {
|
|
21
|
+
/** The component's id, which saves and snapshots keep it under */
|
|
20
22
|
readonly id: string;
|
|
21
23
|
/** What it starts as. Needed for world and player state, which is there from the moment it is asked for */
|
|
22
24
|
readonly default?: () => T;
|
|
@@ -86,13 +88,19 @@ export interface Component<T, S = T> {
|
|
|
86
88
|
passable?(value: T, entity: Entity): boolean;
|
|
87
89
|
/**
|
|
88
90
|
* What a save keeps of it, where that is not its value as it is (plain data: numbers, text, lists, plain objects): a
|
|
89
|
-
* `Map` as its entries, an effect as where it is in its ability
|
|
90
|
-
* plain data then
|
|
91
|
+
* `Map` as its entries, an effect as where it is in its ability, bytes kept for speed as the record a save has always
|
|
92
|
+
* had. Its value as it is when left out, which has to be plain data then. For each of its holders: an entity, the
|
|
93
|
+
* world (`world.state`) and a player (`player.state`)
|
|
91
94
|
*
|
|
92
95
|
* @beta
|
|
93
96
|
*/
|
|
94
97
|
save?(value: T, world: World): unknown;
|
|
95
|
-
/**
|
|
98
|
+
/**
|
|
99
|
+
* It again, of what `save` gave, as a save is loaded: the save's value as it is when left out. Given a copy of the
|
|
100
|
+
* save's, its own to keep or change
|
|
101
|
+
*
|
|
102
|
+
* @beta
|
|
103
|
+
*/
|
|
96
104
|
load?(saved: unknown, registry: Registry): T;
|
|
97
105
|
/**
|
|
98
106
|
* The ids of the game's definitions a save of it names (of what `save` gave, or its value): what a save is checked
|
|
@@ -109,13 +117,22 @@ export interface Component<T, S = T> {
|
|
|
109
117
|
* @beta
|
|
110
118
|
*/
|
|
111
119
|
export interface SavedRefs {
|
|
120
|
+
/** Ids of unit types the saved value names */
|
|
112
121
|
units?: readonly string[];
|
|
122
|
+
/** Ids of abilities the saved value names */
|
|
113
123
|
abilities?: readonly string[];
|
|
124
|
+
/** Ids of buffs the saved value names */
|
|
114
125
|
buffs?: readonly string[];
|
|
126
|
+
/** Ids of items the saved value names */
|
|
115
127
|
items?: readonly string[];
|
|
128
|
+
/** Ids of upgrades the saved value names */
|
|
116
129
|
upgrades?: readonly string[];
|
|
117
130
|
}
|
|
118
|
-
/**
|
|
131
|
+
/**
|
|
132
|
+
* Who a part of a snapshot is for: the owner alone, the owner and allies, or everyone
|
|
133
|
+
*
|
|
134
|
+
* @beta
|
|
135
|
+
*/
|
|
119
136
|
export type Audience = 'owner' | 'allies' | 'everyone';
|
|
120
137
|
/**
|
|
121
138
|
* A map field of a component's: as a game's own field on a map (`MapFieldDef`), its id the component's
|
|
@@ -129,6 +146,7 @@ export type ComponentFieldDef = Omit<MapFieldDef, 'id'>;
|
|
|
129
146
|
* @beta
|
|
130
147
|
*/
|
|
131
148
|
export interface SnapshotView {
|
|
149
|
+
/** The world the snapshot is made from */
|
|
132
150
|
readonly world: World;
|
|
133
151
|
/** The player it is made for; `undefined` for an observer */
|
|
134
152
|
readonly player: PlayerId | undefined;
|
|
@@ -136,6 +154,7 @@ export interface SnapshotView {
|
|
|
136
154
|
readonly own: boolean;
|
|
137
155
|
/** Whether the entity's owner is the player, or an ally of theirs (an observer is everyone's) */
|
|
138
156
|
readonly ally: boolean;
|
|
157
|
+
/** Whether the snapshot is for an observer, who has no player */
|
|
139
158
|
readonly observer: boolean;
|
|
140
159
|
/** Whether the player's team can see another entity right now (`SessionView.knows`): what else of it the part may name */
|
|
141
160
|
readonly knows: (entity: Entity) => boolean;
|
|
@@ -151,17 +170,19 @@ export interface SnapshotView {
|
|
|
151
170
|
*/
|
|
152
171
|
export type ComponentOptions<T, S = T> = Omit<Component<T, S>, 'id' | 'slot'>;
|
|
153
172
|
/**
|
|
154
|
-
* A typed key for state of a game's own: `const wave = defineComponent<WaveState>('td.waves',
|
|
173
|
+
* A typed key for state of a game's own: `const wave = defineComponent<WaveState>({ id: 'td.waves', default: () => ... })`.
|
|
155
174
|
* Give it a prefix of the game's or the mod's: the engine's own are `core.`. A game lists its own
|
|
156
|
-
* (`
|
|
175
|
+
* (`Rules.components`), and its world finds them by id in its registry: another game of the process may have one
|
|
157
176
|
* of the same id, and a module loaded again (as a dev server does) defines it again.
|
|
158
177
|
*
|
|
159
178
|
* With `snapshot` and `same` the component shapes what players are sent of it and how a change is found; with `index`
|
|
160
179
|
* it is filed for systems to go through; with `field` the map editor sets it
|
|
161
180
|
*
|
|
162
|
-
* @
|
|
181
|
+
* @public
|
|
163
182
|
*/
|
|
164
|
-
export declare function defineComponent<T, S = T>(
|
|
183
|
+
export declare function defineComponent<T, S = T>(def: {
|
|
184
|
+
id: string;
|
|
185
|
+
} & ComponentOptions<T, S>): Component<T, S>;
|
|
165
186
|
/**
|
|
166
187
|
* What a snapshot carries of a component, typed: `snapshotOf(entity.state, shopStock)` on a screen, or in a computer
|
|
167
188
|
* player's view. `undefined` when the player was not told it
|
|
@@ -176,7 +197,7 @@ export declare function snapshotOf<T, S>(state: {
|
|
|
176
197
|
* component's default
|
|
177
198
|
*/
|
|
178
199
|
export declare class StateStore {
|
|
179
|
-
/** By component id. Plain data,
|
|
200
|
+
/** By component id. Plain data, or what its component's `save` writes as plain data (`Component.save`) */
|
|
180
201
|
readonly values: Record<string, unknown>;
|
|
181
202
|
get<T>(key: Component<T, unknown>): T;
|
|
182
203
|
set<T>(key: Component<T, unknown>, value: T): void;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
//#region src/components.ts
|
|
2
|
+
/**
|
|
3
|
+
* Each component's number by its id (`slot`): the code's, one id one number in a process, so that a module loaded
|
|
4
|
+
* again (a dev server's) reads what its world holds of it, and `entity.get` is one load. Numbers and nothing else: a
|
|
5
|
+
* world finds its game's components in its registry (`Registry.component`), which lists the engine's own and the
|
|
6
|
+
* game's (`Rules.components`), and nothing of another game of the process
|
|
7
|
+
*/
|
|
8
|
+
var slots = /* @__PURE__ */ new Map();
|
|
9
|
+
/**
|
|
10
|
+
* A typed key for state of a game's own: `const wave = defineComponent<WaveState>({ id: 'td.waves', default: () => ... })`.
|
|
11
|
+
* Give it a prefix of the game's or the mod's: the engine's own are `core.`. A game lists its own
|
|
12
|
+
* (`Rules.components`), and its world finds them by id in its registry: another game of the process may have one
|
|
13
|
+
* of the same id, and a module loaded again (as a dev server does) defines it again.
|
|
14
|
+
*
|
|
15
|
+
* With `snapshot` and `same` the component shapes what players are sent of it and how a change is found; with `index`
|
|
16
|
+
* it is filed for systems to go through; with `field` the map editor sets it
|
|
17
|
+
*
|
|
18
|
+
* @public
|
|
19
|
+
*/
|
|
20
|
+
function defineComponent(def) {
|
|
21
|
+
const { id, ...options } = def;
|
|
22
|
+
let slot = slots.get(id);
|
|
23
|
+
if (slot === void 0) slots.set(id, slot = slots.size);
|
|
24
|
+
return {
|
|
25
|
+
id,
|
|
26
|
+
slot,
|
|
27
|
+
default: void 0,
|
|
28
|
+
replicate: void 0,
|
|
29
|
+
portable: void 0,
|
|
30
|
+
snapshot: void 0,
|
|
31
|
+
same: void 0,
|
|
32
|
+
index: void 0,
|
|
33
|
+
field: void 0,
|
|
34
|
+
save: void 0,
|
|
35
|
+
load: void 0,
|
|
36
|
+
refs: void 0,
|
|
37
|
+
passable: void 0,
|
|
38
|
+
...options
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* What a snapshot carries of a component, typed: `snapshotOf(entity.state, shopStock)` on a screen, or in a computer
|
|
43
|
+
* player's view. `undefined` when the player was not told it
|
|
44
|
+
*
|
|
45
|
+
* @beta
|
|
46
|
+
*/
|
|
47
|
+
function snapshotOf(state, component) {
|
|
48
|
+
return state.components?.[component.id];
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* State kept by component, for the world or a player. Asking for one that is not there yet makes it from the
|
|
52
|
+
* component's default
|
|
53
|
+
*/
|
|
54
|
+
var StateStore = class {
|
|
55
|
+
/** By component id. Plain data, or what its component's `save` writes as plain data (`Component.save`) */
|
|
56
|
+
values = {};
|
|
57
|
+
get(key) {
|
|
58
|
+
if (!(key.id in this.values)) {
|
|
59
|
+
if (!key.default) throw new Error(`State "${key.id}" has no default: give it one in defineComponent, or set it first`);
|
|
60
|
+
this.values[key.id] = key.default();
|
|
61
|
+
}
|
|
62
|
+
return this.values[key.id];
|
|
63
|
+
}
|
|
64
|
+
set(key, value) {
|
|
65
|
+
this.values[key.id] = value;
|
|
66
|
+
}
|
|
67
|
+
has(key) {
|
|
68
|
+
return key.id in this.values;
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
//#endregion
|
|
72
|
+
export { StateStore, defineComponent, snapshotOf };
|
|
73
|
+
|
|
74
|
+
//# sourceMappingURL=components.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"components.js","names":[],"sources":["../src/components.ts"],"sourcesContent":["import type { Entity, PlayerId } from './entity'\nimport type { MapFieldDef } from './mapFields'\nimport type { Registry } from './registry'\nimport type { World } from './world'\n\n/*\n * How one of the engine's own parts becomes a component (master plan FD1, done for the shop; OB1 for the inventory\n * (`inventorySlots`) and the harvester (`gathering`); OB2 for a site (`constructionSite`) and what a building makes\n * (`productionQueue`); OB3 for the hero (`heroState`, filed by owner); OB4 follows for the hero rules, a pack):\n *\n * 1. Define it where its rules live (`shopStock` in `items.ts`): `defineComponent<State, Sent>({ id: 'core.<part>', replicate,\n * snapshot, same, index })`, the snapshot shaped for the screen (`StockInfo[]`, `InventoryInfo`), `same` comparing it\n * field by field, `index: 'owner'` where a player's own are asked for (heroes), `true` where every one is (shops).\n * 2. The entity's field goes (`Entity.shop`); `spawn` sets the component (`entity.set`); every reader is\n * `entity.get(component)` (or a reader of the part's: `slotsOf`, `harvesterOf`), every walk `world.index.with(component)`.\n * 3. The snapshot's typed fields go; readers use `snapshotOf(state, component)` (the client's entity a getter over it:\n * `inventory`, `carries`, `load`). Nothing is kept for the old shape: no alias, no deprecated field.\n * 4. Saves need nothing: an entity's components are saved with it. `checkSave`'s walk of ids reads the component. No\n * format step for saves made before: the engine and its games are still being made.\n * 5. The index's own set for the part goes (`shopSet`).\n * 6. The HUD and the computer player read the snapshot through `snapshotOf`; the inspector's parts list loses the field.\n * 7. `npm run api -- --local`, the report read; `tick.bench.ts`, `client-frame.bench.ts`, `hud.bench.ts` flat.\n */\n\n/**\n * Components are typed state a game module or a mod keeps where the engine has no field for it: on an entity\n * (`entity.get(key)`), for the whole world (`world.state(key)`) or for each player (`player.state(key)`). The engine's\n * own parts are components too (`core.`: what a shop sells, an illusion's source), so that a game pays for what it uses\n * and nothing else.\n *\n * A component is plain data, so that it goes into a save with the rest of the world (see `saveWorld`): numbers,\n * text, lists and plain objects, with other entities by id. One kept otherwise while the game runs (a `Map`, bytes)\n * says how it is saved and loaded (`save`, `load`), wherever it is held.\n *\n * `T` is what the component holds; `S` is what a player's snapshot carries of it (`snapshot`), `T` itself when it is\n * sent as it is\n *\n * @beta\n */\nexport interface Component<T, S = T> {\n\t/** The component's id, which saves and snapshots keep it under */\n\treadonly id: string\n\t/**\n\t * Where an entity keeps it (`Entity.get`): a number of its own, given as it is defined, the same for every\n\t * definition of one id\n\t *\n\t * @internal\n\t */\n\treadonly slot: number\n\t/** What it starts as. Needed for world and player state, which is there from the moment it is asked for */\n\treadonly default?: () => T\n\t/**\n\t * Who gets an entity's component in their snapshot (`EntityState.components`), for a game's view to show:\n\t * the player it belongs to, their allies too, or everyone who sees the entity. Nobody when left out\n\t */\n\treadonly replicate?: Audience\n\t/**\n\t * `false` for what is the app's, not the game's rules (where the screen is played from, a tool's own): kept in the\n\t * app's saves, but left out of a scenario (`scenarioOfWorld`), which is loaded where only the game is (a test)\n\t */\n\treadonly portable?: boolean\n\t/**\n\t * What a player's snapshot carries of it, worked out for each player told (`replicate`): a part of it, rounded,\n\t * or shaped for the screen (a shop's stock with how far the next one is, not the seconds left). A copy of the whole\n\t * value when left out. What it returns is plain data; `undefined` sends nothing to that player\n\t *\n\t * @beta\n\t */\n\tsnapshot?(value: T, entity: Entity, view: SnapshotView): S | undefined\n\t/**\n\t * Whether two snapshots of it say the same, for the delta a player is sent (`same`): field by field, as the\n\t * component knows its shape. Compared as text (`JSON.stringify`) when left out, which costs with a big value\n\t *\n\t * @beta\n\t */\n\tsame?(a: S, b: S): boolean\n\t/**\n\t * Filed in the world's index (`world.index.with(key)`, always kept), and by owner too (`'owner'`:\n\t * `world.index.with(key, player)`) for what a player asks for often (their heroes), so a system goes through what\n\t * has the component and nothing else\n\t *\n\t * @beta\n\t */\n\treadonly index?: boolean | 'owner'\n\t/**\n\t * A field of the map editor's for it: what is placed on a map starts with the component set to what the field says\n\t * (`MapObject.data[id]`, under the component's own id), the editor's Inspector shows it for what `for` names, and\n\t * the game has it from the moment the world is made, with nothing to copy over in a `mapObject` hook\n\t *\n\t * @beta\n\t */\n\treadonly field?: ComponentFieldDef\n\t/**\n\t * What an entity starts with of it, as it is made (`World.spawn`), by its type: a building that makes things gets\n\t * its queue, a unit that carries its slots. Run for every entity made, the engine's parts first and in their order,\n\t * before the `made` hook; what it does not want of an entity, it leaves alone\n\t *\n\t * @beta\n\t */\n\treadonly onSpawn?: (entity: Entity, world: World) => void\n\t/**\n\t * What is called off of it as the entity leaves its owner: it dies (before the `death` hook), or is given to\n\t * another (`World.setOwner`). Run for an entity that has it\n\t *\n\t * @beta\n\t */\n\treadonly onLeave?: (entity: Entity, world: World) => void\n\t/**\n\t * Whether a structure that has it stands open now, in nobody's way (a gate opened): what puts the world back from a\n\t * save leaves it out of the ways as it was. The part that opens and shuts it takes it out and puts it back as it\n\t * goes (`World.nav`). Run for an entity that has it\n\t *\n\t * @beta\n\t */\n\tpassable?(value: T, entity: Entity): boolean\n\t/**\n\t * What a save keeps of it, where that is not its value as it is (plain data: numbers, text, lists, plain objects): a\n\t * `Map` as its entries, an effect as where it is in its ability, bytes kept for speed as the record a save has always\n\t * had. Its value as it is when left out, which has to be plain data then. For each of its holders: an entity, the\n\t * world (`world.state`) and a player (`player.state`)\n\t *\n\t * @beta\n\t */\n\tsave?(value: T, world: World): unknown\n\t/**\n\t * It again, of what `save` gave, as a save is loaded: the save's value as it is when left out. Given a copy of the\n\t * save's, its own to keep or change\n\t *\n\t * @beta\n\t */\n\tload?(saved: unknown, registry: Registry): T\n\t/**\n\t * The ids of the game's definitions a save of it names (of what `save` gave, or its value): what a save is checked\n\t * for before a world is made of it, so that one naming what the game no longer has is refused all at once, saying\n\t * what (`SaveMissing`)\n\t *\n\t * @beta\n\t */\n\trefs?(saved: unknown): SavedRefs\n}\n\n/**\n * The ids of the game's definitions a component's saved value names, by kind (`Component.refs`)\n *\n * @beta\n */\nexport interface SavedRefs {\n\t/** Ids of unit types the saved value names */\n\tunits?: readonly string[]\n\t/** Ids of abilities the saved value names */\n\tabilities?: readonly string[]\n\t/** Ids of buffs the saved value names */\n\tbuffs?: readonly string[]\n\t/** Ids of items the saved value names */\n\titems?: readonly string[]\n\t/** Ids of upgrades the saved value names */\n\tupgrades?: readonly string[]\n}\n\n/**\n * Who a part of a snapshot is for: the owner alone, the owner and allies, or everyone\n *\n * @beta\n */\nexport type Audience = 'owner' | 'allies' | 'everyone'\n\n/**\n * A map field of a component's: as a game's own field on a map (`MapFieldDef`), its id the component's\n *\n * @beta\n */\nexport type ComponentFieldDef = Omit<MapFieldDef, 'id'>\n\n/**\n * Who a snapshot is being made for, as a component shapes its part of it\n *\n * @beta\n */\nexport interface SnapshotView {\n\t/** The world the snapshot is made from */\n\treadonly world: World\n\t/** The player it is made for; `undefined` for an observer */\n\treadonly player: PlayerId | undefined\n\t/** Whether the entity is the player's own */\n\treadonly own: boolean\n\t/** Whether the entity's owner is the player, or an ally of theirs (an observer is everyone's) */\n\treadonly ally: boolean\n\t/** Whether the snapshot is for an observer, who has no player */\n\treadonly observer: boolean\n\t/** Whether the player's team can see another entity right now (`SessionView.knows`): what else of it the part may name */\n\treadonly knows: (entity: Entity) => boolean\n\t/** Whether an owner is the player or an ally of theirs (`SessionView.isAlly`) */\n\treadonly isAlly: (owner: PlayerId) => boolean\n\t/** Whether the player's team sees a spot of the map right now (`SessionView.sees`) */\n\treadonly sees: (x: number, z: number) => boolean\n}\n\n/**\n * What `defineComponent` takes: everything of a component but its id\n *\n * @beta\n */\nexport type ComponentOptions<T, S = T> = Omit<Component<T, S>, 'id' | 'slot'>\n\n/**\n * Each component's number by its id (`slot`): the code's, one id one number in a process, so that a module loaded\n * again (a dev server's) reads what its world holds of it, and `entity.get` is one load. Numbers and nothing else: a\n * world finds its game's components in its registry (`Registry.component`), which lists the engine's own and the\n * game's (`Rules.components`), and nothing of another game of the process\n */\nconst slots = new Map<string, number>()\n\n/**\n * A typed key for state of a game's own: `const wave = defineComponent<WaveState>({ id: 'td.waves', default: () => ... })`.\n * Give it a prefix of the game's or the mod's: the engine's own are `core.`. A game lists its own\n * (`Rules.components`), and its world finds them by id in its registry: another game of the process may have one\n * of the same id, and a module loaded again (as a dev server does) defines it again.\n *\n * With `snapshot` and `same` the component shapes what players are sent of it and how a change is found; with `index`\n * it is filed for systems to go through; with `field` the map editor sets it\n *\n * @public\n */\nexport function defineComponent<T, S = T>(def: { id: string } & ComponentOptions<T, S>): Component<T, S> {\n\tconst { id, ...options } = def\n\t// every field there, in one order, whatever the options say: every component one shape, so that reading its id (as\n\t// `entity.get` does, many times a tick, with every kind of component) is one load and not a search through shapes\n\tlet slot = slots.get(id)\n\tif (slot === undefined) slots.set(id, (slot = slots.size))\n\tconst component: Component<T, S> = {\n\t\tid,\n\t\tslot,\n\t\tdefault: undefined,\n\t\treplicate: undefined,\n\t\tportable: undefined,\n\t\tsnapshot: undefined,\n\t\tsame: undefined,\n\t\tindex: undefined,\n\t\tfield: undefined,\n\t\tsave: undefined,\n\t\tload: undefined,\n\t\trefs: undefined,\n\t\tpassable: undefined,\n\t\t...options\n\t}\n\treturn component\n}\n\n/**\n * What a snapshot carries of a component, typed: `snapshotOf(entity.state, shopStock)` on a screen, or in a computer\n * player's view. `undefined` when the player was not told it\n *\n * @beta\n */\nexport function snapshotOf<T, S>(state: { components?: Record<string, unknown> }, component: Component<T, S>): S | undefined {\n\treturn state.components?.[component.id] as S | undefined\n}\n\n/**\n * State kept by component, for the world or a player. Asking for one that is not there yet makes it from the\n * component's default\n */\nexport class StateStore {\n\t/** By component id. Plain data, or what its component's `save` writes as plain data (`Component.save`) */\n\treadonly values: Record<string, unknown> = {}\n\n\tget<T>(key: Component<T, unknown>): T {\n\t\tif (!(key.id in this.values)) {\n\t\t\tif (!key.default) throw new Error(`State \"${key.id}\" has no default: give it one in defineComponent, or set it first`)\n\t\t\tthis.values[key.id] = key.default()\n\t\t}\n\t\treturn this.values[key.id] as T\n\t}\n\n\tset<T>(key: Component<T, unknown>, value: T): void {\n\t\tthis.values[key.id] = value\n\t}\n\n\thas(key: Component<unknown, unknown>): boolean {\n\t\treturn key.id in this.values\n\t}\n}\n"],"mappings":";;;;;;;AAkNA,IAAM,wBAAQ,IAAI,IAAoB;;;;;;;;;;;;AAatC,SAAgB,gBAA0B,KAA+D;CACxG,MAAM,EAAE,IAAI,GAAG,YAAY;CAG3B,IAAI,OAAO,MAAM,IAAI,EAAE;CACvB,IAAI,SAAS,KAAA,GAAW,MAAM,IAAI,IAAK,OAAO,MAAM,IAAK;CAiBzD,OAAO;EAfN;EACA;EACA,SAAS,KAAA;EACT,WAAW,KAAA;EACX,UAAU,KAAA;EACV,UAAU,KAAA;EACV,MAAM,KAAA;EACN,OAAO,KAAA;EACP,OAAO,KAAA;EACP,MAAM,KAAA;EACN,MAAM,KAAA;EACN,MAAM,KAAA;EACN,UAAU,KAAA;EACV,GAAG;CAEG;AACR;;;;;;;AAQA,SAAgB,WAAiB,OAAiD,WAA2C;CAC5H,OAAO,MAAM,aAAa,UAAU;AACrC;;;;;AAMA,IAAa,aAAb,MAAwB;;CAEvB,SAA2C,CAAC;CAE5C,IAAO,KAA+B;EACrC,IAAI,EAAE,IAAI,MAAM,KAAK,SAAS;GAC7B,IAAI,CAAC,IAAI,SAAS,MAAM,IAAI,MAAM,UAAU,IAAI,GAAG,kEAAkE;GACrH,KAAK,OAAO,IAAI,MAAM,IAAI,QAAQ;EACnC;EACA,OAAO,KAAK,OAAO,IAAI;CACxB;CAEA,IAAO,KAA4B,OAAgB;EAClD,KAAK,OAAO,IAAI,MAAM;CACvB;CAEA,IAAI,KAA2C;EAC9C,OAAO,IAAI,MAAM,KAAK;CACvB;AACD"}
|
package/dist/computers.d.ts
CHANGED
|
@@ -17,7 +17,7 @@ export type BrainSeat = (world: World, player: PlayerId, options: AiOptions) =>
|
|
|
17
17
|
* @beta
|
|
18
18
|
*/
|
|
19
19
|
export interface SeatRequest extends AiOptions {
|
|
20
|
-
/** The brain, or its id (one the game lists in `
|
|
20
|
+
/** The brain, or its id (one the game lists in `Rules.brains`): the first the game lists when left out */
|
|
21
21
|
brain?: BrainDef | string;
|
|
22
22
|
}
|
|
23
23
|
/**
|
|
@@ -55,12 +55,12 @@ export declare class Computers {
|
|
|
55
55
|
constructor(world: World);
|
|
56
56
|
/**
|
|
57
57
|
* Seats the computer at a player, and remembers it: a game loaded from a save of this one has it back, with its memory
|
|
58
|
-
* (`restore`). `request.brain` is one of the game's (`defineBrain`; one listed in `
|
|
58
|
+
* (`restore`). `request.brain` is one of the game's (`defineBrain`; one listed in `Rules.brains` is found again by
|
|
59
59
|
* its id for a load, one that is not is kept by id only, and a load without it warns and leaves the seat empty), or
|
|
60
60
|
* its id, or left out for the first brain the game lists. Of the rest of the request (`AiOptions`), the data is kept
|
|
61
61
|
* (numbers, lists, names); a function given in it is dropped from the save, said in the log, and a load has what the
|
|
62
62
|
* brain's definition gives: a game that wants its function back after a load puts it in the brain it lists in
|
|
63
|
-
* `
|
|
63
|
+
* `Rules.brains`. A player seated already is unseated first. What thinks in it is a `Brain` unless the brain was
|
|
64
64
|
* made otherwise (`defineComputer`: say which)
|
|
65
65
|
*/
|
|
66
66
|
seat<C extends ComputerPlayer = Brain>(player: PlayerId, request?: SeatRequest): ComputerSystem<C>;
|
|
@@ -97,7 +97,7 @@ export declare class Computers {
|
|
|
97
97
|
* (`GameAi.defaults.brain`). Nothing where none says: the game's first brain
|
|
98
98
|
*/
|
|
99
99
|
private brainFor;
|
|
100
|
-
/** A brain by id: one the game lists (`
|
|
100
|
+
/** A brain by id: one the game lists (`Rules.brains`) */
|
|
101
101
|
brain(id: string): BrainDef | undefined;
|
|
102
102
|
/**
|
|
103
103
|
* Seats again the computers a save remembers, in a world loaded from it: what `loadWorld` does before the game's
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { defineComponent } from "./components.js";
|
|
2
|
+
import { plainParts } from "./plain.js";
|
|
3
|
+
//#region src/computers.ts
|
|
4
|
+
/**
|
|
5
|
+
* The computer players of a world (`world.computers`): who is seated where, kept in the world so that a save has them
|
|
6
|
+
* and a loaded game seats them again. The seats alone, no brain: a brain seats itself (`BrainDef.seat`, the AI kit's
|
|
7
|
+
* `defineBrain` gives it one), so that the engine's core loads nothing of the computer player's kit
|
|
8
|
+
* (`@v12-engine/engine/ai`) a game does not list
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Who the computer plays, by player, with what they were seated with: in the world, so that a save keeps it and a
|
|
12
|
+
* loaded game seats them again by itself (`world.computers`)
|
|
13
|
+
*/
|
|
14
|
+
var computerSeats = defineComponent({
|
|
15
|
+
id: "core.computers",
|
|
16
|
+
default: () => ({})
|
|
17
|
+
});
|
|
18
|
+
/**
|
|
19
|
+
* What every seat of the world is given where its request says nothing (`world.computers.defaults`): data only, kept in
|
|
20
|
+
* the world so a save has it, and a computer seated after a load gets it too
|
|
21
|
+
*/
|
|
22
|
+
var computerDefaults = defineComponent({
|
|
23
|
+
id: "core.computerDefaults",
|
|
24
|
+
default: () => ({})
|
|
25
|
+
});
|
|
26
|
+
/**
|
|
27
|
+
* The computer players of a world: who is seated, kept in the world and in a save (`core.computers`), so that a game
|
|
28
|
+
* loaded from a save has them back without the game's doing, and how the game reaches a seated brain while it plays
|
|
29
|
+
* (`tell`, `pause`, `get`)
|
|
30
|
+
*
|
|
31
|
+
* @beta
|
|
32
|
+
*/
|
|
33
|
+
var Computers = class {
|
|
34
|
+
world;
|
|
35
|
+
/** The seats, by player, in the order they were taken */
|
|
36
|
+
seats = /* @__PURE__ */ new Map();
|
|
37
|
+
constructor(world) {
|
|
38
|
+
this.world = world;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Seats the computer at a player, and remembers it: a game loaded from a save of this one has it back, with its memory
|
|
42
|
+
* (`restore`). `request.brain` is one of the game's (`defineBrain`; one listed in `Rules.brains` is found again by
|
|
43
|
+
* its id for a load, one that is not is kept by id only, and a load without it warns and leaves the seat empty), or
|
|
44
|
+
* its id, or left out for the first brain the game lists. Of the rest of the request (`AiOptions`), the data is kept
|
|
45
|
+
* (numbers, lists, names); a function given in it is dropped from the save, said in the log, and a load has what the
|
|
46
|
+
* brain's definition gives: a game that wants its function back after a load puts it in the brain it lists in
|
|
47
|
+
* `Rules.brains`. A player seated already is unseated first. What thinks in it is a `Brain` unless the brain was
|
|
48
|
+
* made otherwise (`defineComputer`: say which)
|
|
49
|
+
*/
|
|
50
|
+
seat(player, request = {}) {
|
|
51
|
+
const { brain: asked_, ...asked } = request;
|
|
52
|
+
const options = {
|
|
53
|
+
...this.defaults,
|
|
54
|
+
...asked
|
|
55
|
+
};
|
|
56
|
+
const brain = asked_ ?? this.brainFor(player);
|
|
57
|
+
const def = typeof brain === "string" ? this.brain(brain) : brain;
|
|
58
|
+
if (typeof brain === "string" && !def) throw new Error(`No brain is called "${brain}": list it in Rules.brains, or seat the brain itself`);
|
|
59
|
+
if (this.seats.has(player)) this.unseat(player);
|
|
60
|
+
const system = this.seated(player, def, options);
|
|
61
|
+
this.world.addSystem(system);
|
|
62
|
+
this.seats.set(player, system);
|
|
63
|
+
this.world.setState(computerSeats, {
|
|
64
|
+
...this.world.state(computerSeats),
|
|
65
|
+
[player]: {
|
|
66
|
+
...def && { brain: def.id },
|
|
67
|
+
options: dataOf(options, this.world, player)
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
return system;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* What every computer seated from now on is given where its request says nothing (`AiOptions`, data only: a
|
|
74
|
+
* difficulty, a personality), over what the map says of the player (`MapPlayer.data.ai`): a campaign's difficulty,
|
|
75
|
+
* set before a mission seats its computers. Kept in the world, so a save has it. Those seated already keep what they
|
|
76
|
+
* were seated with
|
|
77
|
+
*/
|
|
78
|
+
get defaults() {
|
|
79
|
+
return this.world.states.has(computerDefaults) ? this.world.state(computerDefaults) : {};
|
|
80
|
+
}
|
|
81
|
+
set defaults(defaults) {
|
|
82
|
+
this.world.setState(computerDefaults, { ...defaults });
|
|
83
|
+
}
|
|
84
|
+
/** Takes the computer out of a player's seat, and out of what a save remembers. False where none was seated */
|
|
85
|
+
unseat(player) {
|
|
86
|
+
const system = this.seats.get(player);
|
|
87
|
+
if (this.world.states.has(computerSeats) && player in this.world.state(computerSeats)) {
|
|
88
|
+
const { [player]: _gone, ...rest } = this.world.state(computerSeats);
|
|
89
|
+
this.world.setState(computerSeats, rest);
|
|
90
|
+
}
|
|
91
|
+
if (!system) return false;
|
|
92
|
+
this.seats.delete(player);
|
|
93
|
+
this.world.removeSystem(system.name);
|
|
94
|
+
system.dispose();
|
|
95
|
+
return true;
|
|
96
|
+
}
|
|
97
|
+
/** The seat the computer plays a player from, while it does */
|
|
98
|
+
get(player) {
|
|
99
|
+
return this.seats.get(player);
|
|
100
|
+
}
|
|
101
|
+
/** The players the computer plays, in the order they were seated */
|
|
102
|
+
list() {
|
|
103
|
+
return [...this.seats.keys()];
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Tells a computer player a word, with data to go with it: what a mission's script says to its brain
|
|
107
|
+
* (`world.computers.tell(ENEMY, 'raid', { at })`), taken by a rule of the brain's (`when.told`). False where nobody is
|
|
108
|
+
* seated there, or what is seated takes no words
|
|
109
|
+
*/
|
|
110
|
+
tell(player, word, data) {
|
|
111
|
+
const computer = this.get(player)?.computer;
|
|
112
|
+
if (!computer?.tell) return false;
|
|
113
|
+
computer.tell(word, data, this.world.tick);
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
/** Has a computer player sit still until `resume`: kept in a save. False where none is seated, or it cannot be paused */
|
|
117
|
+
pause(player) {
|
|
118
|
+
return this.setPaused(player, true);
|
|
119
|
+
}
|
|
120
|
+
/** Has a paused computer player think again */
|
|
121
|
+
resume(player) {
|
|
122
|
+
return this.setPaused(player, false);
|
|
123
|
+
}
|
|
124
|
+
setPaused(player, paused) {
|
|
125
|
+
const computer = this.get(player)?.computer;
|
|
126
|
+
if (!computer || !("paused" in computer)) return false;
|
|
127
|
+
computer.paused = paused;
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
130
|
+
/** The system a player's seat is: the brain's own seat (`BrainDef.seat`), the first brain the game lists where none is named. Throws for a game that lists none */
|
|
131
|
+
seated(player, def, options) {
|
|
132
|
+
const game = this.world.registry.module;
|
|
133
|
+
const brain = def ?? game?.brains?.[0];
|
|
134
|
+
if (!brain) throw new Error(`The game "${game?.id}" gives no computer player to seat at player ${player}: list a brain in Rules.brains (meleeBrain of @v12-engine/engine/ai plays melee), or seat a brain`);
|
|
135
|
+
if (!brain.seat) throw new Error(`The brain "${brain.id}" was not made with defineBrain or defineComputer (@v12-engine/engine/ai): it has no seat`);
|
|
136
|
+
return brain.seat(this.world, player, options);
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* The brain a player is seated with where the seat names none, by id: the map's for the player (`MapAi.brain`, where
|
|
140
|
+
* the map gives the player to the computer), else its race's (`GameAi.races[race].brain`), else the game's defaults'
|
|
141
|
+
* (`GameAi.defaults.brain`). Nothing where none says: the game's first brain
|
|
142
|
+
*/
|
|
143
|
+
brainFor(player) {
|
|
144
|
+
const mapped = this.world.map.player(player);
|
|
145
|
+
const map = mapped?.controller === "computer" ? mapped.data?.ai : void 0;
|
|
146
|
+
if (map && typeof map === "object" && typeof map.brain === "string") return map.brain;
|
|
147
|
+
const ai = this.world.registry.module?.ai;
|
|
148
|
+
const race = this.world.players.get(player)?.race;
|
|
149
|
+
return (race !== void 0 ? ai?.races?.[race]?.brain : void 0) ?? ai?.defaults?.brain;
|
|
150
|
+
}
|
|
151
|
+
/** A brain by id: one the game lists (`Rules.brains`) */
|
|
152
|
+
brain(id) {
|
|
153
|
+
return this.world.registry.module?.brains?.find((brain) => brain.id === id);
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Seats again the computers a save remembers, in a world loaded from it: what `loadWorld` does before the game's
|
|
157
|
+
* `afterLoad`. One the game seated already is left as it is; one whose brain is not to be found (seated by an object
|
|
158
|
+
* the game does not list) is left empty, and the log says so
|
|
159
|
+
*/
|
|
160
|
+
restore() {
|
|
161
|
+
if (!this.world.states.has(computerSeats)) return;
|
|
162
|
+
for (const [id, seat] of Object.entries(this.world.state(computerSeats))) {
|
|
163
|
+
const player = Number(id);
|
|
164
|
+
if (this.seats.has(player)) continue;
|
|
165
|
+
const def = seat.brain === void 0 ? void 0 : this.brain(seat.brain);
|
|
166
|
+
if (seat.brain !== void 0 && !def) {
|
|
167
|
+
this.world.log.warn("ai", `the save seats the brain "${seat.brain}" at player ${player}, which the game does not list (Rules.brains): the seat is left empty`, {
|
|
168
|
+
player,
|
|
169
|
+
brain: seat.brain
|
|
170
|
+
});
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
const system = this.seated(player, def, seat.options);
|
|
174
|
+
this.world.addSystem(system);
|
|
175
|
+
this.seats.set(player, system);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
/**
|
|
180
|
+
* The data part of a seat's options, for a save: what is plain data is kept as it is, and what is not (a function, or a
|
|
181
|
+
* list with a function in it: `goals`, a flag given as a function in `settings`) is dropped, said in the log
|
|
182
|
+
*/
|
|
183
|
+
function dataOf(options, world, player) {
|
|
184
|
+
const { kept, dropped } = plainParts(options);
|
|
185
|
+
if (dropped.length) world.log.debug("ai", `the options ${dropped.map((key) => `"${key}"`).join(", ")} of the computer at player ${player} are code, and not kept in a save`, {
|
|
186
|
+
player,
|
|
187
|
+
dropped
|
|
188
|
+
});
|
|
189
|
+
return kept;
|
|
190
|
+
}
|
|
191
|
+
//#endregion
|
|
192
|
+
export { Computers, computerDefaults, computerSeats };
|
|
193
|
+
|
|
194
|
+
//# sourceMappingURL=computers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"computers.js","names":[],"sources":["../src/computers.ts"],"sourcesContent":["/**\n * The computer players of a world (`world.computers`): who is seated where, kept in the world so that a save has them\n * and a loaded game seats them again. The seats alone, no brain: a brain seats itself (`BrainDef.seat`, the AI kit's\n * `defineBrain` gives it one), so that the engine's core loads nothing of the computer player's kit\n * (`@v12-engine/engine/ai`) a game does not list\n */\nimport { defineComponent } from './components'\nimport type { PlayerId } from './entity'\nimport { plainParts } from './plain'\nimport type { World } from './world'\nimport type { AiOptions } from './ai/options'\nimport type { Brain, BrainDef } from './ai/brain'\nimport type { ComputerPlayer, ComputerSystem } from './ai/computer'\n\n/**\n * How a brain is seated at a player (`BrainDef.seat`): the system the seat is, a computer thinking in it. What\n * `defineBrain` and `defineComputer` give a brain, so that the core seats it without knowing how\n *\n * @beta\n */\nexport type BrainSeat = (world: World, player: PlayerId, options: AiOptions) => ComputerSystem\n\n/**\n * What a seat is asked for (`world.computers.seat(player, request)`): the brain (one of the game's, `defineBrain`, or\n * its id; the first the game lists when left out) and what it is seated with (`AiOptions`)\n *\n * @beta\n */\nexport interface SeatRequest extends AiOptions {\n\t/** The brain, or its id (one the game lists in `Rules.brains`): the first the game lists when left out */\n\tbrain?: BrainDef | string\n}\n\n/**\n * A seat as a save keeps it (`core.computers`): the brain by id, and the data part of its options\n *\n * @beta\n */\nexport interface ComputerSeat {\n\t/** The brain's id. Left out for the first brain the game lists */\n\tbrain?: string\n\t/** What it was seated with, the data of it (`AiOptions`) */\n\toptions: Record<string, unknown>\n}\n\n/**\n * Who the computer plays, by player, with what they were seated with: in the world, so that a save keeps it and a\n * loaded game seats them again by itself (`world.computers`)\n */\nexport const computerSeats = defineComponent<Record<string, ComputerSeat>>({ id: 'core.computers', default: () => ({}) })\n\n/**\n * What every seat of the world is given where its request says nothing (`world.computers.defaults`): data only, kept in\n * the world so a save has it, and a computer seated after a load gets it too\n */\nexport const computerDefaults = defineComponent<Record<string, unknown>>({ id: 'core.computerDefaults', default: () => ({}) })\n\n/**\n * The computer players of a world: who is seated, kept in the world and in a save (`core.computers`), so that a game\n * loaded from a save has them back without the game's doing, and how the game reaches a seated brain while it plays\n * (`tell`, `pause`, `get`)\n *\n * @beta\n */\nexport class Computers {\n\t/** The seats, by player, in the order they were taken */\n\tprivate readonly seats = new Map<PlayerId, ComputerSystem>()\n\n\tconstructor(private readonly world: World) {}\n\n\t/**\n\t * Seats the computer at a player, and remembers it: a game loaded from a save of this one has it back, with its memory\n\t * (`restore`). `request.brain` is one of the game's (`defineBrain`; one listed in `Rules.brains` is found again by\n\t * its id for a load, one that is not is kept by id only, and a load without it warns and leaves the seat empty), or\n\t * its id, or left out for the first brain the game lists. Of the rest of the request (`AiOptions`), the data is kept\n\t * (numbers, lists, names); a function given in it is dropped from the save, said in the log, and a load has what the\n\t * brain's definition gives: a game that wants its function back after a load puts it in the brain it lists in\n\t * `Rules.brains`. A player seated already is unseated first. What thinks in it is a `Brain` unless the brain was\n\t * made otherwise (`defineComputer`: say which)\n\t */\n\tseat<C extends ComputerPlayer = Brain>(player: PlayerId, request: SeatRequest = {}): ComputerSystem<C> {\n\t\tconst { brain: asked_, ...asked } = request\n\t\t// what the world gives every seat, under what the request says (and over what the map says: `mapAiOptions`)\n\t\tconst options: AiOptions = { ...this.defaults, ...asked }\n\t\t// the seat's brain, else the map's for the player, else its race's (AR3); the game's first where none says\n\t\tconst brain = asked_ ?? this.brainFor(player)\n\t\tconst def = typeof brain === 'string' ? this.brain(brain) : brain\n\t\tif (typeof brain === 'string' && !def) throw new Error(`No brain is called \"${brain}\": list it in Rules.brains, or seat the brain itself`)\n\t\tif (this.seats.has(player)) this.unseat(player)\n\t\tconst system = this.seated(player, def, options)\n\t\tthis.world.addSystem(system)\n\t\tthis.seats.set(player, system)\n\t\tthis.world.setState(computerSeats, {\n\t\t\t...this.world.state(computerSeats),\n\t\t\t[player]: { ...(def && { brain: def.id }), options: dataOf(options, this.world, player) }\n\t\t})\n\t\treturn system as ComputerSystem<C>\n\t}\n\n\t/**\n\t * What every computer seated from now on is given where its request says nothing (`AiOptions`, data only: a\n\t * difficulty, a personality), over what the map says of the player (`MapPlayer.data.ai`): a campaign's difficulty,\n\t * set before a mission seats its computers. Kept in the world, so a save has it. Those seated already keep what they\n\t * were seated with\n\t */\n\tget defaults(): Readonly<Pick<AiOptions, 'difficulty' | 'personality'>> {\n\t\treturn this.world.states.has(computerDefaults) ? (this.world.state(computerDefaults) as Pick<AiOptions, 'difficulty' | 'personality'>) : {}\n\t}\n\n\tset defaults(defaults: Pick<AiOptions, 'difficulty' | 'personality'>) {\n\t\tthis.world.setState(computerDefaults, { ...defaults })\n\t}\n\n\t/** Takes the computer out of a player's seat, and out of what a save remembers. False where none was seated */\n\tunseat(player: PlayerId): boolean {\n\t\tconst system = this.seats.get(player)\n\t\tif (this.world.states.has(computerSeats) && player in this.world.state(computerSeats)) {\n\t\t\tconst { [player]: _gone, ...rest } = this.world.state(computerSeats)\n\t\t\tthis.world.setState(computerSeats, rest)\n\t\t}\n\t\tif (!system) return false\n\t\tthis.seats.delete(player)\n\t\tthis.world.removeSystem(system.name)\n\t\tsystem.dispose()\n\t\treturn true\n\t}\n\n\t/** The seat the computer plays a player from, while it does */\n\tget(player: PlayerId): ComputerSystem | undefined {\n\t\treturn this.seats.get(player)\n\t}\n\n\t/** The players the computer plays, in the order they were seated */\n\tlist(): PlayerId[] {\n\t\treturn [...this.seats.keys()]\n\t}\n\n\t/**\n\t * Tells a computer player a word, with data to go with it: what a mission's script says to its brain\n\t * (`world.computers.tell(ENEMY, 'raid', { at })`), taken by a rule of the brain's (`when.told`). False where nobody is\n\t * seated there, or what is seated takes no words\n\t */\n\ttell(player: PlayerId, word: string, data?: unknown): boolean {\n\t\tconst computer = this.get(player)?.computer\n\t\tif (!computer?.tell) return false\n\t\tcomputer.tell(word, data, this.world.tick)\n\t\treturn true\n\t}\n\n\t/** Has a computer player sit still until `resume`: kept in a save. False where none is seated, or it cannot be paused */\n\tpause(player: PlayerId): boolean {\n\t\treturn this.setPaused(player, true)\n\t}\n\n\t/** Has a paused computer player think again */\n\tresume(player: PlayerId): boolean {\n\t\treturn this.setPaused(player, false)\n\t}\n\n\tprivate setPaused(player: PlayerId, paused: boolean): boolean {\n\t\tconst computer = this.get(player)?.computer\n\t\tif (!computer || !('paused' in computer)) return false\n\t\tcomputer.paused = paused\n\t\treturn true\n\t}\n\n\t/** The system a player's seat is: the brain's own seat (`BrainDef.seat`), the first brain the game lists where none is named. Throws for a game that lists none */\n\tprivate seated(player: PlayerId, def: BrainDef | undefined, options: AiOptions): ComputerSystem {\n\t\tconst game = this.world.registry.module\n\t\tconst brain = def ?? game?.brains?.[0]\n\t\tif (!brain)\n\t\t\tthrow new Error(\n\t\t\t\t`The game \"${game?.id}\" gives no computer player to seat at player ${player}: list a brain in Rules.brains (meleeBrain of @v12-engine/engine/ai plays melee), or seat a brain`\n\t\t\t)\n\t\tif (!brain.seat) throw new Error(`The brain \"${brain.id}\" was not made with defineBrain or defineComputer (@v12-engine/engine/ai): it has no seat`)\n\t\treturn brain.seat(this.world, player, options)\n\t}\n\n\t/**\n\t * The brain a player is seated with where the seat names none, by id: the map's for the player (`MapAi.brain`, where\n\t * the map gives the player to the computer), else its race's (`GameAi.races[race].brain`), else the game's defaults'\n\t * (`GameAi.defaults.brain`). Nothing where none says: the game's first brain\n\t */\n\tprivate brainFor(player: PlayerId): string | undefined {\n\t\tconst mapped = this.world.map.player(player)\n\t\tconst map = mapped?.controller === 'computer' ? (mapped.data?.ai as { brain?: unknown } | undefined) : undefined\n\t\tif (map && typeof map === 'object' && typeof map.brain === 'string') return map.brain\n\t\tconst ai = this.world.registry.module?.ai\n\t\tconst race = this.world.players.get(player)?.race\n\t\treturn (race !== undefined ? ai?.races?.[race]?.brain : undefined) ?? ai?.defaults?.brain\n\t}\n\n\t/** A brain by id: one the game lists (`Rules.brains`) */\n\tbrain(id: string): BrainDef | undefined {\n\t\treturn this.world.registry.module?.brains?.find((brain) => brain.id === id)\n\t}\n\n\t/**\n\t * Seats again the computers a save remembers, in a world loaded from it: what `loadWorld` does before the game's\n\t * `afterLoad`. One the game seated already is left as it is; one whose brain is not to be found (seated by an object\n\t * the game does not list) is left empty, and the log says so\n\t */\n\trestore(): void {\n\t\tif (!this.world.states.has(computerSeats)) return\n\t\tfor (const [id, seat] of Object.entries(this.world.state(computerSeats))) {\n\t\t\tconst player = Number(id)\n\t\t\tif (this.seats.has(player)) continue\n\t\t\tconst def = seat.brain === undefined ? undefined : this.brain(seat.brain)\n\t\t\tif (seat.brain !== undefined && !def) {\n\t\t\t\tthis.world.log.warn(\n\t\t\t\t\t'ai',\n\t\t\t\t\t`the save seats the brain \"${seat.brain}\" at player ${player}, which the game does not list (Rules.brains): the seat is left empty`,\n\t\t\t\t\t{\n\t\t\t\t\t\tplayer,\n\t\t\t\t\t\tbrain: seat.brain\n\t\t\t\t\t}\n\t\t\t\t)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tconst system = this.seated(player, def, seat.options as AiOptions)\n\t\t\tthis.world.addSystem(system)\n\t\t\tthis.seats.set(player, system)\n\t\t}\n\t}\n}\n\n/**\n * The data part of a seat's options, for a save: what is plain data is kept as it is, and what is not (a function, or a\n * list with a function in it: `goals`, a flag given as a function in `settings`) is dropped, said in the log\n */\nfunction dataOf(options: AiOptions, world: World, player: PlayerId): Record<string, unknown> {\n\tconst { kept, dropped } = plainParts(options)\n\tif (dropped.length)\n\t\tworld.log.debug(\n\t\t\t'ai',\n\t\t\t`the options ${dropped.map((key) => `\"${key}\"`).join(', ')} of the computer at player ${player} are code, and not kept in a save`,\n\t\t\t{\n\t\t\t\tplayer,\n\t\t\t\tdropped\n\t\t\t}\n\t\t)\n\treturn kept as Record<string, unknown>\n}\n"],"mappings":"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"}
|
package/dist/concealment.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ import type { World } from './world';
|
|
|
7
7
|
* or from close by (`reach`). An attacker in one is seen by whom it hits for a moment, as anyone is (`expose`), and
|
|
8
8
|
* what detects the invisible (`entity.detected`) sees it too. A game turns it on, on as many layers as it likes:
|
|
9
9
|
*
|
|
10
|
-
* export const rules = { ...myGame, packs: [
|
|
10
|
+
* export const rules = { ...myGame, packs: [concealmentPack({ layer: 'bush' })] }
|
|
11
11
|
*
|
|
12
12
|
* Everything that asks what a team sees (`world.isVisibleTo`) goes by it: what units pick to attack, the commands a
|
|
13
13
|
* player may give, the fog's memory, and each player's snapshots, so the computer player and the players over a wire
|
|
@@ -41,6 +41,29 @@ export interface ConcealmentOptions {
|
|
|
41
41
|
rustleEvery?: number;
|
|
42
42
|
/** The id of its hook and its system, to replace or leave out: `concealment:<layer>` when left out */
|
|
43
43
|
id?: string;
|
|
44
|
+
/**
|
|
45
|
+
* Which cells of the layer hide, by their index: every cell that is not 0 when left out. The patches are of the
|
|
46
|
+
* cells that do (those that touch), so grass that is cut or burnt neither hides nor joins two patches. What the
|
|
47
|
+
* foliage pack hides by: a style that conceals, in a state that still does (`foliagePack`). Asked as the patches are
|
|
48
|
+
* worked out, not for every unit
|
|
49
|
+
*/
|
|
50
|
+
conceals?: (world: World, cell: number) => boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Other layers whose cells decide what hides (`conceals`), by id: the patches are worked out again when one of them
|
|
53
|
+
* changes, as when the layer itself does. The foliage pack's state layer (`foliageStateLayer`)
|
|
54
|
+
*/
|
|
55
|
+
follows?: readonly string[];
|
|
56
|
+
/**
|
|
57
|
+
* Told of each unit on the map as the count goes through the units at the start of a tick (alive, not inside
|
|
58
|
+
* anything), with the cell it stands in (`unit`), and once the count is done (`done`, whether it changed cells of the
|
|
59
|
+
* layer or of one it follows: the count is made again of the patches as they are now). What the foliage pack
|
|
60
|
+
* tramples by, in the same pass over the units as the count (`FoliageStyleDef.trample`). Never told from a `visible`
|
|
61
|
+
* asked before the tick's count
|
|
62
|
+
*/
|
|
63
|
+
eachUnit?: {
|
|
64
|
+
unit(world: World, entity: Entity, cell: number): void;
|
|
65
|
+
done(world: World): boolean;
|
|
66
|
+
};
|
|
44
67
|
}
|
|
45
68
|
/**
|
|
46
69
|
* The patch of a layer an entity stands in, 1 and up, or 0 where it stands in none (`ConcealmentOptions`). For a
|
|
@@ -56,6 +79,6 @@ export declare function patchAt(world: World, layer: string, x: number, z: numbe
|
|
|
56
79
|
*
|
|
57
80
|
* @beta
|
|
58
81
|
*/
|
|
59
|
-
export declare function
|
|
82
|
+
export declare function concealmentPack(options: ConcealmentOptions): GamePack;
|
|
60
83
|
/** One hidden moving in a layer: where the player sees the ground, to whom the rules tell it, a shake of the bushes */
|
|
61
84
|
export declare const toldRustle: import("./replication").ReplicatedEvent;
|