@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
package/dist/aiTesting.d.ts
CHANGED
|
@@ -21,7 +21,7 @@ import { Brain } from './ai/brain';
|
|
|
21
21
|
import type { GoalReport } from './ai/goals';
|
|
22
22
|
import { type AiDecision, type AiReport } from './ai/report';
|
|
23
23
|
import type { PlayerId } from './entity';
|
|
24
|
-
import { type
|
|
24
|
+
import { type Rules } from './game';
|
|
25
25
|
import type { PlayerCommand, Snapshot } from './session/protocol';
|
|
26
26
|
import type { World } from './world';
|
|
27
27
|
/**
|
|
@@ -110,6 +110,7 @@ export interface FairPlay {
|
|
|
110
110
|
readonly refused: number;
|
|
111
111
|
/** Throws where it sent any command about what it did not see */
|
|
112
112
|
assert(): void;
|
|
113
|
+
/** Stops watching the brain; the violations found so far stay */
|
|
113
114
|
stop(): void;
|
|
114
115
|
}
|
|
115
116
|
/**
|
|
@@ -126,6 +127,7 @@ export declare function fairPlay(world: World, player: PlayerId): FairPlay;
|
|
|
126
127
|
* @beta
|
|
127
128
|
*/
|
|
128
129
|
export interface RecordedDecision extends AiDecision {
|
|
130
|
+
/** The player whose computer made the decision */
|
|
129
131
|
player: PlayerId;
|
|
130
132
|
/** The brain's id */
|
|
131
133
|
brain: string;
|
|
@@ -139,6 +141,7 @@ export interface RecordedDecision extends AiDecision {
|
|
|
139
141
|
export interface DecisionRecorder {
|
|
140
142
|
/** Every decision so far, in the order made */
|
|
141
143
|
readonly decisions: readonly RecordedDecision[];
|
|
144
|
+
/** Stops recording; the decisions so far stay */
|
|
142
145
|
stop(): void;
|
|
143
146
|
}
|
|
144
147
|
/**
|
|
@@ -168,12 +171,12 @@ export interface DecisionsApart {
|
|
|
168
171
|
* game seats them), runs it to `from`, saves it as a file would keep it and loads that with `game`, then runs both to
|
|
169
172
|
* `ticks` and compares what every computer decided. What lost rng, tasks or memory in a restore shows as
|
|
170
173
|
*
|
|
171
|
-
* expect(await checkComputerSave(() => duel(), { from: 600, ticks: 2400,
|
|
174
|
+
* expect(await checkComputerSave(() => duel(), { from: 600, ticks: 2400, rules: melee })).toBeNull()
|
|
172
175
|
*
|
|
173
176
|
* @beta
|
|
174
177
|
*/
|
|
175
178
|
export declare function checkComputerSave(make: () => World | Promise<World>, options: {
|
|
176
179
|
from: number;
|
|
177
180
|
ticks: number;
|
|
178
|
-
|
|
181
|
+
rules: Rules;
|
|
179
182
|
}): Promise<DecisionsApart | null>;
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import { decodeSave, encodeSave, saveWorld } from "./save.js";
|
|
2
|
+
import { loadWorld } from "./game.js";
|
|
3
|
+
import { LocalSession } from "./session/local.js";
|
|
4
|
+
import { explainGoal } from "./ai/report.js";
|
|
5
|
+
import { checkBrain } from "./ai/checks.js";
|
|
6
|
+
import { Brain } from "./ai/brain.js";
|
|
7
|
+
//#region src/aiTesting.ts
|
|
8
|
+
/**
|
|
9
|
+
* Testing a computer player (AI plan, E3): what a game's tests of its brains are written with, in
|
|
10
|
+
* `@v12-engine/engine/testing` beside `testWorld` and `run`. A brain is tested as it plays, through the world it sits in:
|
|
11
|
+
*
|
|
12
|
+
* const world = await testWorld(myGame)
|
|
13
|
+
* world.computers.seat(ENEMY, { enemyBases: [home], brain: myBrain })
|
|
14
|
+
* const watch = watchComputer(world, ENEMY) // its invariants, every think
|
|
15
|
+
* run(world, 120)
|
|
16
|
+
* expectDecision(thinkOnce(world, ENEMY), 'ai.attack')
|
|
17
|
+
* watch.assert() // no rule broken
|
|
18
|
+
*
|
|
19
|
+
* `thinkOnce` has a seated brain think now and gives its report; `expectDecision` says a goal runs, or why not in
|
|
20
|
+
* words; `watchComputer` checks the invariants of `ai/checks.ts` after every think (a unit in one squad, gold spent
|
|
21
|
+
* once, finite numbers, commands about what it sees, no churn, nothing stuck) and keeps what it decided; `fairPlay` is
|
|
22
|
+
* the one about seeing; `recordDecisions` keeps every computer's decisions for a replay's side file; `checkComputerSave`
|
|
23
|
+
* is the seventh invariant: a game saved and loaded decides the same from then on. These take the world, which a test
|
|
24
|
+
* may: the brains under test never do.
|
|
25
|
+
*/
|
|
26
|
+
/**
|
|
27
|
+
* The brain that plays a player, where one is seated (`world.computers.seat`): none where nobody is, or where what is
|
|
28
|
+
* seated is not a brain (`defineComputer`)
|
|
29
|
+
*
|
|
30
|
+
* @beta
|
|
31
|
+
*/
|
|
32
|
+
function brainOf(world, player) {
|
|
33
|
+
const computer = world.computers.get(player)?.computer;
|
|
34
|
+
return computer instanceof Brain ? computer : void 0;
|
|
35
|
+
}
|
|
36
|
+
/** The brain at a player, or an error that says what is seated there instead */
|
|
37
|
+
function seated(world, player) {
|
|
38
|
+
const brain = brainOf(world, player);
|
|
39
|
+
if (brain) return brain;
|
|
40
|
+
const system = world.computers.get(player);
|
|
41
|
+
throw new Error(system ? `The computer player at ${player} is not a brain (defineBrain): it has no report` : `No computer player is seated at ${player}`);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Has the brain at a player think now, all of it (a think its budget slices over ticks is run to its end), over a new
|
|
45
|
+
* picture of the game, and gives its report: what a test reads after setting a scene. Its commands land at the next
|
|
46
|
+
* tick, as a think's do. A think the seat would have had is not skipped: this one is beside them
|
|
47
|
+
*
|
|
48
|
+
* @beta
|
|
49
|
+
*/
|
|
50
|
+
function thinkOnce(world, player) {
|
|
51
|
+
const brain = seated(world, player);
|
|
52
|
+
do
|
|
53
|
+
brain.think();
|
|
54
|
+
while (brain.busy);
|
|
55
|
+
return brain.report();
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Says that a goal runs, as of a report (`thinkOnce`, `Brain.report`): it is picked and holds what it claimed. Throws
|
|
59
|
+
* where it does not, with its row in words (`Brain.explain`): what each consideration answered and what kept it out.
|
|
60
|
+
* Gives the goal's row. With `picked: false`, says it does not run
|
|
61
|
+
*
|
|
62
|
+
* expectDecision(thinkOnce(world, ENEMY), 'ai.defend')
|
|
63
|
+
*
|
|
64
|
+
* @beta
|
|
65
|
+
*/
|
|
66
|
+
function expectDecision(report, goal, options = {}) {
|
|
67
|
+
const wanted = options.picked ?? true;
|
|
68
|
+
const row = report.goals.find((each) => each.id === goal);
|
|
69
|
+
if (!row) throw new Error(`The brain ${report.brain} has no goal "${goal}": its goals are ${report.goals.map((each) => each.id).join(", ") || "none"}`);
|
|
70
|
+
if (row.picked === wanted) return row;
|
|
71
|
+
const seconds = (tick) => tick / report.tickRate;
|
|
72
|
+
throw new Error(`Expected ${goal} ${wanted ? "to run" : "not to run"} at ${report.time.toFixed(1)} s, and it ${wanted ? "does not" : "does"}. ${explainGoal(row, seconds, report.time)}${report.goal && report.goal !== goal ? ` The best goal is ${report.goal}.` : ""}`);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Follows the brain at a player from now on: after every think, the invariants of `ai/checks.ts` (a unit in one squad
|
|
76
|
+
* and one hold, gold spent once, finite numbers, commands about what it sees, no order sent again to a unit still at
|
|
77
|
+
* it, builders, tasks, holds and wants that end), with what it decided and sent. A broken rule is kept, not thrown,
|
|
78
|
+
* unless `onViolation` throws: `assert` at the end says them all
|
|
79
|
+
*
|
|
80
|
+
* @beta
|
|
81
|
+
*/
|
|
82
|
+
function watchComputer(world, player, options = {}) {
|
|
83
|
+
const brain = seated(world, player);
|
|
84
|
+
const violations = [];
|
|
85
|
+
const decisions = [];
|
|
86
|
+
let thinks = 0;
|
|
87
|
+
let commands = 0;
|
|
88
|
+
const { stop: unchecked } = checkBrain(brain, {
|
|
89
|
+
...options,
|
|
90
|
+
onViolation: (violation) => {
|
|
91
|
+
violations.push(violation);
|
|
92
|
+
options.onViolation?.(violation);
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
const observer = options.observe ? new LocalSession(world, player, { observer: true }) : void 0;
|
|
96
|
+
const unwatched = brain.watch({
|
|
97
|
+
sent: (command) => {
|
|
98
|
+
commands++;
|
|
99
|
+
options.sent?.(command, brain);
|
|
100
|
+
},
|
|
101
|
+
decided: (decision) => void decisions.push(decision),
|
|
102
|
+
thought: () => {
|
|
103
|
+
thinks++;
|
|
104
|
+
if (observer) options.observe(observer.snapshot(), brain);
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
return {
|
|
108
|
+
brain,
|
|
109
|
+
violations,
|
|
110
|
+
decisions,
|
|
111
|
+
get thinks() {
|
|
112
|
+
return thinks;
|
|
113
|
+
},
|
|
114
|
+
get commands() {
|
|
115
|
+
return commands;
|
|
116
|
+
},
|
|
117
|
+
assert() {
|
|
118
|
+
if (!violations.length) return;
|
|
119
|
+
const lines = violations.slice(0, 20).map((each) => ` ${each.invariant} at tick ${each.tick}: ${each.message}`);
|
|
120
|
+
const more = violations.length > 20 ? `\n and ${violations.length - 20} more` : "";
|
|
121
|
+
throw new Error(`The computer player at ${player} broke ${violations.length} rule${violations.length === 1 ? "" : "s"}:\n${lines.join("\n")}${more}`);
|
|
122
|
+
},
|
|
123
|
+
stop() {
|
|
124
|
+
unchecked();
|
|
125
|
+
unwatched();
|
|
126
|
+
observer?.dispose();
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Follows the brain at a player from now on for fair play: that it never sends a command about an entity its snapshot
|
|
132
|
+
* did not have (a fog leak: its seat's session would drop the command, so a game shows nothing; this says it), and
|
|
133
|
+
* counts what the game refused
|
|
134
|
+
*
|
|
135
|
+
* @beta
|
|
136
|
+
*/
|
|
137
|
+
function fairPlay(world, player) {
|
|
138
|
+
const watch = watchComputer(world, player, { invariants: ["commands"] });
|
|
139
|
+
const brain = watch.brain;
|
|
140
|
+
const refusedBefore = brain.stats.refused;
|
|
141
|
+
return {
|
|
142
|
+
get unfair() {
|
|
143
|
+
return watch.violations;
|
|
144
|
+
},
|
|
145
|
+
get refused() {
|
|
146
|
+
return brain.stats.refused - refusedBefore;
|
|
147
|
+
},
|
|
148
|
+
assert: () => watch.assert(),
|
|
149
|
+
stop: () => watch.stop()
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
/** How many recorders were made: each one's system a name of its own */
|
|
153
|
+
var recorders = 0;
|
|
154
|
+
/**
|
|
155
|
+
* Keeps the decisions of every brain seated at a world, from now on, those seated later included (looked for at each
|
|
156
|
+
* tick, by a system of its own that keeps nothing in a save)
|
|
157
|
+
*
|
|
158
|
+
* @beta
|
|
159
|
+
*/
|
|
160
|
+
function recordDecisions(world) {
|
|
161
|
+
const decisions = [];
|
|
162
|
+
const watched = /* @__PURE__ */ new Map();
|
|
163
|
+
const look = () => {
|
|
164
|
+
for (const player of world.computers.list()) {
|
|
165
|
+
const brain = brainOf(world, player);
|
|
166
|
+
if (!brain || watched.has(brain)) continue;
|
|
167
|
+
watched.set(brain, brain.watch({ decided: (decision) => void decisions.push({
|
|
168
|
+
...decision,
|
|
169
|
+
player: brain.playerId,
|
|
170
|
+
brain: brain.def.id
|
|
171
|
+
}) }));
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
look();
|
|
175
|
+
const name = `core.ai.recordDecisions.${++recorders}`;
|
|
176
|
+
world.addSystem({
|
|
177
|
+
name,
|
|
178
|
+
update: look
|
|
179
|
+
});
|
|
180
|
+
return {
|
|
181
|
+
decisions,
|
|
182
|
+
stop() {
|
|
183
|
+
world.removeSystem(name);
|
|
184
|
+
for (const unwatch of watched.values()) unwatch();
|
|
185
|
+
watched.clear();
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* The seventh invariant of a computer player: a game saved at tick `from` and loaded makes the same decisions from then
|
|
191
|
+
* on as the game it was saved from, under the same commands. Makes the world with `make` (its computers seated, as a
|
|
192
|
+
* game seats them), runs it to `from`, saves it as a file would keep it and loads that with `game`, then runs both to
|
|
193
|
+
* `ticks` and compares what every computer decided. What lost rng, tasks or memory in a restore shows as
|
|
194
|
+
*
|
|
195
|
+
* expect(await checkComputerSave(() => duel(), { from: 600, ticks: 2400, rules: melee })).toBeNull()
|
|
196
|
+
*
|
|
197
|
+
* @beta
|
|
198
|
+
*/
|
|
199
|
+
async function checkComputerSave(make, options) {
|
|
200
|
+
const saved = await make();
|
|
201
|
+
let loaded;
|
|
202
|
+
try {
|
|
203
|
+
while (saved.tick < options.from) saved.step();
|
|
204
|
+
loaded = await loadWorld(decodeSave(encodeSave(saveWorld(saved))), { rules: options.rules });
|
|
205
|
+
const before = recordDecisions(saved);
|
|
206
|
+
const after = recordDecisions(loaded);
|
|
207
|
+
while (saved.tick < options.ticks) {
|
|
208
|
+
saved.step();
|
|
209
|
+
loaded.step();
|
|
210
|
+
}
|
|
211
|
+
before.stop();
|
|
212
|
+
after.stop();
|
|
213
|
+
const a = before.decisions;
|
|
214
|
+
const b = after.decisions;
|
|
215
|
+
for (let i = 0; i < Math.max(a.length, b.length); i++) if (JSON.stringify(a[i]) !== JSON.stringify(b[i])) return {
|
|
216
|
+
index: i,
|
|
217
|
+
...a[i] && { saved: a[i] },
|
|
218
|
+
...b[i] && { loaded: b[i] }
|
|
219
|
+
};
|
|
220
|
+
return null;
|
|
221
|
+
} finally {
|
|
222
|
+
saved.dispose();
|
|
223
|
+
loaded?.dispose();
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
//#endregion
|
|
227
|
+
export { brainOf, checkComputerSave, expectDecision, fairPlay, recordDecisions, thinkOnce, watchComputer };
|
|
228
|
+
|
|
229
|
+
//# sourceMappingURL=aiTesting.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aiTesting.js","names":[],"sources":["../src/aiTesting.ts"],"sourcesContent":["/**\n * Testing a computer player (AI plan, E3): what a game's tests of its brains are written with, in\n * `@v12-engine/engine/testing` beside `testWorld` and `run`. A brain is tested as it plays, through the world it sits in:\n *\n * const world = await testWorld(myGame)\n * world.computers.seat(ENEMY, { enemyBases: [home], brain: myBrain })\n * const watch = watchComputer(world, ENEMY) // its invariants, every think\n * run(world, 120)\n * expectDecision(thinkOnce(world, ENEMY), 'ai.attack')\n * watch.assert() // no rule broken\n *\n * `thinkOnce` has a seated brain think now and gives its report; `expectDecision` says a goal runs, or why not in\n * words; `watchComputer` checks the invariants of `ai/checks.ts` after every think (a unit in one squad, gold spent\n * once, finite numbers, commands about what it sees, no churn, nothing stuck) and keeps what it decided; `fairPlay` is\n * the one about seeing; `recordDecisions` keeps every computer's decisions for a replay's side file; `checkComputerSave`\n * is the seventh invariant: a game saved and loaded decides the same from then on. These take the world, which a test\n * may: the brains under test never do.\n */\nimport { type AiCheckOptions, type AiViolation, checkBrain } from './ai/checks'\nimport { Brain } from './ai/brain'\nimport type { GoalReport } from './ai/goals'\nimport { type AiDecision, type AiReport, explainGoal } from './ai/report'\nimport type { PlayerId } from './entity'\nimport { type Rules, loadWorld } from './game'\nimport { decodeSave, encodeSave, saveWorld } from './save'\nimport { LocalSession } from './session/local'\nimport type { PlayerCommand, Snapshot } from './session/protocol'\nimport type { World } from './world'\n\n/**\n * The brain that plays a player, where one is seated (`world.computers.seat`): none where nobody is, or where what is\n * seated is not a brain (`defineComputer`)\n *\n * @beta\n */\nexport function brainOf(world: World, player: PlayerId): Brain | undefined {\n\tconst computer = world.computers.get(player)?.computer\n\treturn computer instanceof Brain ? computer : undefined\n}\n\n/** The brain at a player, or an error that says what is seated there instead */\nfunction seated(world: World, player: PlayerId): Brain {\n\tconst brain = brainOf(world, player)\n\tif (brain) return brain\n\tconst system = world.computers.get(player)\n\tthrow new Error(\n\t\tsystem ? `The computer player at ${player} is not a brain (defineBrain): it has no report` : `No computer player is seated at ${player}`\n\t)\n}\n\n/**\n * Has the brain at a player think now, all of it (a think its budget slices over ticks is run to its end), over a new\n * picture of the game, and gives its report: what a test reads after setting a scene. Its commands land at the next\n * tick, as a think's do. A think the seat would have had is not skipped: this one is beside them\n *\n * @beta\n */\nexport function thinkOnce(world: World, player: PlayerId): AiReport {\n\tconst brain = seated(world, player)\n\tdo brain.think()\n\twhile (brain.busy)\n\treturn brain.report()\n}\n\n/**\n * Says that a goal runs, as of a report (`thinkOnce`, `Brain.report`): it is picked and holds what it claimed. Throws\n * where it does not, with its row in words (`Brain.explain`): what each consideration answered and what kept it out.\n * Gives the goal's row. With `picked: false`, says it does not run\n *\n * expectDecision(thinkOnce(world, ENEMY), 'ai.defend')\n *\n * @beta\n */\nexport function expectDecision(report: AiReport, goal: string, options: { picked?: boolean } = {}): GoalReport {\n\tconst wanted = options.picked ?? true\n\tconst row = report.goals.find((each) => each.id === goal)\n\tif (!row)\n\t\tthrow new Error(`The brain ${report.brain} has no goal \"${goal}\": its goals are ${report.goals.map((each) => each.id).join(', ') || 'none'}`)\n\tif (row.picked === wanted) return row\n\tconst seconds = (tick: number) => tick / report.tickRate\n\tthrow new Error(\n\t\t`Expected ${goal} ${wanted ? 'to run' : 'not to run'} at ${report.time.toFixed(1)} s, and it ${wanted ? 'does not' : 'does'}. ${explainGoal(row, seconds, report.time)}${\n\t\t\treport.goal && report.goal !== goal ? ` The best goal is ${report.goal}.` : ''\n\t\t}`\n\t)\n}\n\n/**\n * A computer player followed over a run (`watchComputer`): the rules it broke, what it decided and sent, and, where\n * asked, what an observer saw at each of its thinks\n *\n * @beta\n */\nexport interface ComputerWatch {\n\t/** The brain watched */\n\treadonly brain: Brain\n\t/** Every invariant it broke, in the order found (`ai/checks.ts`) */\n\treadonly violations: readonly AiViolation[]\n\t/** What it decided while watched, oldest first: every line, not only the last fifty its log keeps */\n\treadonly decisions: readonly AiDecision[]\n\t/** Its thinks while watched */\n\treadonly thinks: number\n\t/** Commands it sent while watched */\n\treadonly commands: number\n\t/** Throws, listing them, where it broke any rule */\n\tassert(): void\n\t/** Stops watching */\n\tstop(): void\n}\n\n/**\n * How a computer player is watched (`watchComputer`): which invariants and how long things may go on (`AiCheckOptions`),\n * and what to be shown at each think\n *\n * @beta\n */\nexport interface WatchOptions extends AiCheckOptions {\n\t/**\n\t * Shown, at the end of each of its thinks, the game as an observer sees it (everything, no fog) and the brain: for a\n\t * look at what it does (a test that writes frames, a page that draws them). An observer's seat is made only when given\n\t */\n\tobserve?: (snapshot: Snapshot, brain: Brain) => void\n\t/** Each command as it sends it */\n\tsent?: (command: PlayerCommand, brain: Brain) => void\n}\n\n/**\n * Follows the brain at a player from now on: after every think, the invariants of `ai/checks.ts` (a unit in one squad\n * and one hold, gold spent once, finite numbers, commands about what it sees, no order sent again to a unit still at\n * it, builders, tasks, holds and wants that end), with what it decided and sent. A broken rule is kept, not thrown,\n * unless `onViolation` throws: `assert` at the end says them all\n *\n * @beta\n */\nexport function watchComputer(world: World, player: PlayerId, options: WatchOptions = {}): ComputerWatch {\n\tconst brain = seated(world, player)\n\tconst violations: AiViolation[] = []\n\tconst decisions: AiDecision[] = []\n\tlet thinks = 0\n\tlet commands = 0\n\tconst { stop: unchecked } = checkBrain(brain, {\n\t\t...options,\n\t\tonViolation: (violation) => {\n\t\t\tviolations.push(violation)\n\t\t\toptions.onViolation?.(violation)\n\t\t}\n\t})\n\tconst observer = options.observe ? new LocalSession(world, player, { observer: true }) : undefined\n\tconst unwatched = brain.watch({\n\t\tsent: (command) => {\n\t\t\tcommands++\n\t\t\toptions.sent?.(command, brain)\n\t\t},\n\t\tdecided: (decision) => void decisions.push(decision),\n\t\tthought: () => {\n\t\t\tthinks++\n\t\t\tif (observer) options.observe!(observer.snapshot(), brain)\n\t\t}\n\t})\n\treturn {\n\t\tbrain,\n\t\tviolations,\n\t\tdecisions,\n\t\tget thinks() {\n\t\t\treturn thinks\n\t\t},\n\t\tget commands() {\n\t\t\treturn commands\n\t\t},\n\t\tassert() {\n\t\t\tif (!violations.length) return\n\t\t\tconst lines = violations.slice(0, 20).map((each) => ` ${each.invariant} at tick ${each.tick}: ${each.message}`)\n\t\t\tconst more = violations.length > 20 ? `\\n and ${violations.length - 20} more` : ''\n\t\t\tthrow new Error(\n\t\t\t\t`The computer player at ${player} broke ${violations.length} rule${violations.length === 1 ? '' : 's'}:\\n${lines.join('\\n')}${more}`\n\t\t\t)\n\t\t},\n\t\tstop() {\n\t\t\tunchecked()\n\t\t\tunwatched()\n\t\t\tobserver?.dispose()\n\t\t}\n\t}\n}\n\n/**\n * Whether a computer player played fair over a run (`fairPlay`): every command it sent named what its own snapshot\n * had, and how many the game refused\n *\n * @beta\n */\nexport interface FairPlay {\n\t/** Commands that named an entity it did not see, or a place off the map */\n\treadonly unfair: readonly AiViolation[]\n\t/** Commands the game refused while watched (a unit that could not do it, a place it could not build at) */\n\treadonly refused: number\n\t/** Throws where it sent any command about what it did not see */\n\tassert(): void\n\t/** Stops watching the brain; the violations found so far stay */\n\tstop(): void\n}\n\n/**\n * Follows the brain at a player from now on for fair play: that it never sends a command about an entity its snapshot\n * did not have (a fog leak: its seat's session would drop the command, so a game shows nothing; this says it), and\n * counts what the game refused\n *\n * @beta\n */\nexport function fairPlay(world: World, player: PlayerId): FairPlay {\n\tconst watch = watchComputer(world, player, { invariants: ['commands'] })\n\tconst brain = watch.brain\n\tconst refusedBefore = brain.stats.refused\n\treturn {\n\t\tget unfair() {\n\t\t\treturn watch.violations\n\t\t},\n\t\tget refused() {\n\t\t\treturn brain.stats.refused - refusedBefore\n\t\t},\n\t\tassert: () => watch.assert(),\n\t\tstop: () => watch.stop()\n\t}\n}\n\n/**\n * One thing a computer player decided, with whose: a line of a replay's side file (`recordDecisions`)\n *\n * @beta\n */\nexport interface RecordedDecision extends AiDecision {\n\t/** The player whose computer made the decision */\n\tplayer: PlayerId\n\t/** The brain's id */\n\tbrain: string\n}\n\n/**\n * The decisions of every computer of a world, as they are made (`recordDecisions`): plain data, for a side file beside a\n * replay of commands, read back by whoever wonders why the computer did what the replay shows\n *\n * @beta\n */\nexport interface DecisionRecorder {\n\t/** Every decision so far, in the order made */\n\treadonly decisions: readonly RecordedDecision[]\n\t/** Stops recording; the decisions so far stay */\n\tstop(): void\n}\n\n/** How many recorders were made: each one's system a name of its own */\nlet recorders = 0\n\n/**\n * Keeps the decisions of every brain seated at a world, from now on, those seated later included (looked for at each\n * tick, by a system of its own that keeps nothing in a save)\n *\n * @beta\n */\nexport function recordDecisions(world: World): DecisionRecorder {\n\tconst decisions: RecordedDecision[] = []\n\tconst watched = new Map<Brain, () => void>()\n\tconst look = () => {\n\t\tfor (const player of world.computers.list()) {\n\t\t\tconst brain = brainOf(world, player)\n\t\t\tif (!brain || watched.has(brain)) continue\n\t\t\twatched.set(brain, brain.watch({ decided: (decision) => void decisions.push({ ...decision, player: brain.playerId, brain: brain.def.id }) }))\n\t\t}\n\t}\n\tlook()\n\tconst name = `core.ai.recordDecisions.${++recorders}`\n\tworld.addSystem({ name, update: look })\n\treturn {\n\t\tdecisions,\n\t\tstop() {\n\t\t\tworld.removeSystem(name)\n\t\t\tfor (const unwatch of watched.values()) unwatch()\n\t\t\twatched.clear()\n\t\t}\n\t}\n}\n\n/**\n * Where a game saved and loaded first decided otherwise than the game it was saved from (`checkComputerSave`): the\n * decision each made at that place in their logs. `null` where they decided alike to the end\n *\n * @beta\n */\nexport interface DecisionsApart {\n\t/** How many decisions since the save they shared before this one */\n\tindex: number\n\t/** The game that went on from the save */\n\tsaved?: RecordedDecision\n\t/** The game loaded from it */\n\tloaded?: RecordedDecision\n}\n\n/**\n * The seventh invariant of a computer player: a game saved at tick `from` and loaded makes the same decisions from then\n * on as the game it was saved from, under the same commands. Makes the world with `make` (its computers seated, as a\n * game seats them), runs it to `from`, saves it as a file would keep it and loads that with `game`, then runs both to\n * `ticks` and compares what every computer decided. What lost rng, tasks or memory in a restore shows as\n *\n * expect(await checkComputerSave(() => duel(), { from: 600, ticks: 2400, rules: melee })).toBeNull()\n *\n * @beta\n */\nexport async function checkComputerSave(\n\tmake: () => World | Promise<World>,\n\toptions: { from: number; ticks: number; rules: Rules }\n): Promise<DecisionsApart | null> {\n\tconst saved = await make()\n\tlet loaded: World | undefined\n\ttry {\n\t\twhile (saved.tick < options.from) saved.step()\n\t\tloaded = await loadWorld(decodeSave(encodeSave(saveWorld(saved))), { rules: options.rules })\n\t\tconst before = recordDecisions(saved)\n\t\tconst after = recordDecisions(loaded)\n\t\twhile (saved.tick < options.ticks) {\n\t\t\tsaved.step()\n\t\t\tloaded.step()\n\t\t}\n\t\tbefore.stop()\n\t\tafter.stop()\n\t\tconst a = before.decisions\n\t\tconst b = after.decisions\n\t\tfor (let i = 0; i < Math.max(a.length, b.length); i++)\n\t\t\tif (JSON.stringify(a[i]) !== JSON.stringify(b[i])) return { index: i, ...(a[i] && { saved: a[i] }), ...(b[i] && { loaded: b[i] }) }\n\t\treturn null\n\t} finally {\n\t\tsaved.dispose()\n\t\tloaded?.dispose()\n\t}\n}\n"],"mappings":"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"}
|
package/dist/areas.d.ts
CHANGED
|
@@ -77,13 +77,14 @@ export declare function areaShapeOf(ref: AreaRef, regions: readonly MapRegion[])
|
|
|
77
77
|
/**
|
|
78
78
|
* A named part of the map that the rules watch: who walks into it and out of it (`enteredArea`, `leftArea` events),
|
|
79
79
|
* and who is in it now (`world.areas`). Units count, by where their middle is; buildings, scenery and units inside
|
|
80
|
-
* something do not. Given in `
|
|
80
|
+
* something do not. Given in `Rules.areas`
|
|
81
81
|
*
|
|
82
82
|
* @beta
|
|
83
83
|
*/
|
|
84
84
|
export interface AreaDef {
|
|
85
85
|
/** Shared by every game, like other ids: give it a prefix of the game's (`'td.gate'`) */
|
|
86
86
|
id: string;
|
|
87
|
+
/** The area's shape in cells, one of the `AreaShape`s */
|
|
87
88
|
shape: AreaShape;
|
|
88
89
|
}
|
|
89
90
|
/**
|
|
@@ -122,7 +123,9 @@ export declare class Areas {
|
|
|
122
123
|
constructor(world: World, defs: readonly AreaDef[]);
|
|
123
124
|
/** The areas of the game, then those added while it runs */
|
|
124
125
|
get all(): Iterable<AreaDef>;
|
|
126
|
+
/** How many areas there are: the game's and those added while it runs */
|
|
125
127
|
get size(): number;
|
|
128
|
+
/** Gives the area with the id; throws when there is none */
|
|
126
129
|
get(id: string): AreaDef;
|
|
127
130
|
/** Whether there is an area of that id */
|
|
128
131
|
has(id: string): boolean;
|
package/dist/areas.js
ADDED
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
import { hypot } from "./exactMath.js";
|
|
2
|
+
import { defineComponent } from "./components.js";
|
|
3
|
+
import { enteredArea, leftArea } from "./engineEvents.js";
|
|
4
|
+
//#region src/areas.ts
|
|
5
|
+
/**
|
|
6
|
+
* The box round a shape: its least and greatest x and z on the map
|
|
7
|
+
*
|
|
8
|
+
* @beta
|
|
9
|
+
*/
|
|
10
|
+
function shapeBounds(shape) {
|
|
11
|
+
if (shape.kind === "circle") return {
|
|
12
|
+
x0: shape.x - shape.radius,
|
|
13
|
+
z0: shape.z - shape.radius,
|
|
14
|
+
x1: shape.x + shape.radius,
|
|
15
|
+
z1: shape.z + shape.radius
|
|
16
|
+
};
|
|
17
|
+
if (shape.kind === "rect") return {
|
|
18
|
+
x0: shape.x - shape.width / 2,
|
|
19
|
+
z0: shape.z - shape.depth / 2,
|
|
20
|
+
x1: shape.x + shape.width / 2,
|
|
21
|
+
z1: shape.z + shape.depth / 2
|
|
22
|
+
};
|
|
23
|
+
let x0 = Infinity;
|
|
24
|
+
let z0 = Infinity;
|
|
25
|
+
let x1 = -Infinity;
|
|
26
|
+
let z1 = -Infinity;
|
|
27
|
+
for (const point of shape.points) {
|
|
28
|
+
x0 = Math.min(x0, shape.x + point.x);
|
|
29
|
+
z0 = Math.min(z0, shape.z + point.z);
|
|
30
|
+
x1 = Math.max(x1, shape.x + point.x);
|
|
31
|
+
z1 = Math.max(z1, shape.z + point.z);
|
|
32
|
+
}
|
|
33
|
+
return shape.points.length ? {
|
|
34
|
+
x0,
|
|
35
|
+
z0,
|
|
36
|
+
x1,
|
|
37
|
+
z1
|
|
38
|
+
} : {
|
|
39
|
+
x0: shape.x,
|
|
40
|
+
z0: shape.z,
|
|
41
|
+
x1: shape.x,
|
|
42
|
+
z1: shape.z
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* How much ground a shape covers, in cells
|
|
47
|
+
*
|
|
48
|
+
* @beta
|
|
49
|
+
*/
|
|
50
|
+
function shapeArea(shape) {
|
|
51
|
+
if (shape.kind === "circle") return Math.PI * shape.radius * shape.radius;
|
|
52
|
+
if (shape.kind === "rect") return shape.width * shape.depth;
|
|
53
|
+
let twice = 0;
|
|
54
|
+
const { points } = shape;
|
|
55
|
+
for (let i = 0, j = points.length - 1; i < points.length; j = i++) twice += points[j].x * points[i].z - points[i].x * points[j].z;
|
|
56
|
+
return Math.abs(twice) / 2;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* A shape as a circle or a rectangle: a polygon as the rectangle round it. For what draws only those (mist, clouds and
|
|
60
|
+
* weather in a region of the map)
|
|
61
|
+
*
|
|
62
|
+
* @beta
|
|
63
|
+
*/
|
|
64
|
+
function shapeAsBox(shape) {
|
|
65
|
+
if (shape.kind !== "polygon") return shape;
|
|
66
|
+
const { x0, z0, x1, z1 } = shapeBounds(shape);
|
|
67
|
+
return {
|
|
68
|
+
kind: "rect",
|
|
69
|
+
x: (x0 + x1) / 2,
|
|
70
|
+
z: (z0 + z1) / 2,
|
|
71
|
+
width: x1 - x0,
|
|
72
|
+
depth: z1 - z0
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* A shape moved to stand at a point and sized `scale` times: a prefab's area where the prefab is put
|
|
77
|
+
*
|
|
78
|
+
* @beta
|
|
79
|
+
*/
|
|
80
|
+
function shapeAt(shape, at, scale = 1) {
|
|
81
|
+
if (shape.kind === "circle") return {
|
|
82
|
+
kind: "circle",
|
|
83
|
+
x: at.x,
|
|
84
|
+
z: at.z,
|
|
85
|
+
radius: shape.radius * scale
|
|
86
|
+
};
|
|
87
|
+
if (shape.kind === "rect") return {
|
|
88
|
+
kind: "rect",
|
|
89
|
+
x: at.x,
|
|
90
|
+
z: at.z,
|
|
91
|
+
width: shape.width * scale,
|
|
92
|
+
depth: shape.depth * scale
|
|
93
|
+
};
|
|
94
|
+
return {
|
|
95
|
+
kind: "polygon",
|
|
96
|
+
x: at.x,
|
|
97
|
+
z: at.z,
|
|
98
|
+
points: shape.points.map((point) => ({
|
|
99
|
+
x: point.x * scale,
|
|
100
|
+
z: point.z * scale
|
|
101
|
+
}))
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* The shape an `AreaRef` stands for: its own, or the named region's among the map's. Nothing for a region that is
|
|
106
|
+
* not there
|
|
107
|
+
*
|
|
108
|
+
* @beta
|
|
109
|
+
*/
|
|
110
|
+
function areaShapeOf(ref, regions) {
|
|
111
|
+
if ("region" in ref) return regions.find((region) => region.name === ref.region)?.shape;
|
|
112
|
+
return ref;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Typed help for writing an area
|
|
116
|
+
*
|
|
117
|
+
* @beta
|
|
118
|
+
*/
|
|
119
|
+
var defineArea = (def) => def;
|
|
120
|
+
/**
|
|
121
|
+
* Whether a point is in a shape
|
|
122
|
+
*
|
|
123
|
+
* @beta
|
|
124
|
+
*/
|
|
125
|
+
function inShape(shape, point) {
|
|
126
|
+
const dx = point.x - shape.x;
|
|
127
|
+
const dz = point.z - shape.z;
|
|
128
|
+
if (shape.kind === "circle") return dx * dx + dz * dz <= shape.radius * shape.radius;
|
|
129
|
+
if (shape.kind === "rect") return Math.abs(dx) <= shape.width / 2 && Math.abs(dz) <= shape.depth / 2;
|
|
130
|
+
const { points } = shape;
|
|
131
|
+
let odd = false;
|
|
132
|
+
for (let i = 0, j = points.length - 1; i < points.length; j = i++) {
|
|
133
|
+
const a = points[i];
|
|
134
|
+
const b = points[j];
|
|
135
|
+
if (a.z > dz !== b.z > dz && dx < (b.x - a.x) * (dz - a.z) / (b.z - a.z) + a.x) odd = !odd;
|
|
136
|
+
}
|
|
137
|
+
return odd;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* The radius of a circle round the whole shape from its middle (`x`, `z`): what the spatial index is asked for
|
|
141
|
+
*
|
|
142
|
+
* @beta
|
|
143
|
+
*/
|
|
144
|
+
function shapeReach(shape) {
|
|
145
|
+
if (shape.kind === "circle") return shape.radius;
|
|
146
|
+
if (shape.kind === "rect") return hypot(shape.width, shape.depth) / 2;
|
|
147
|
+
let most = 0;
|
|
148
|
+
for (const point of shape.points) most = Math.max(most, hypot(point.x, point.z));
|
|
149
|
+
return most;
|
|
150
|
+
}
|
|
151
|
+
var reach = shapeReach;
|
|
152
|
+
/** Who is in each area, by id: kept in the world, so that a save knows, and nobody walks in twice after loading */
|
|
153
|
+
var inside = defineComponent({
|
|
154
|
+
id: "core.areas",
|
|
155
|
+
default: () => ({})
|
|
156
|
+
});
|
|
157
|
+
/** Areas added while the game runs (`areas.add`): kept in the world, so that a save has them */
|
|
158
|
+
var added = defineComponent({
|
|
159
|
+
id: "core.areasAdded",
|
|
160
|
+
default: () => []
|
|
161
|
+
});
|
|
162
|
+
/**
|
|
163
|
+
* The areas of a world, and who is in them
|
|
164
|
+
*
|
|
165
|
+
* @beta
|
|
166
|
+
*/
|
|
167
|
+
var Areas = class {
|
|
168
|
+
world;
|
|
169
|
+
byId = /* @__PURE__ */ new Map();
|
|
170
|
+
/** Kept between ticks, not made anew */
|
|
171
|
+
found = [];
|
|
172
|
+
now = /* @__PURE__ */ new Set();
|
|
173
|
+
constructor(world, defs) {
|
|
174
|
+
this.world = world;
|
|
175
|
+
for (const def of defs) {
|
|
176
|
+
if (this.byId.has(def.id)) throw new Error(`Area "${def.id}" is there twice`);
|
|
177
|
+
this.byId.set(def.id, def);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
/** The areas of the game, then those added while it runs */
|
|
181
|
+
get all() {
|
|
182
|
+
return [...this.byId.values(), ...this.added()];
|
|
183
|
+
}
|
|
184
|
+
/** How many areas there are: the game's and those added while it runs */
|
|
185
|
+
get size() {
|
|
186
|
+
return this.byId.size + this.added().length;
|
|
187
|
+
}
|
|
188
|
+
/** Gives the area with the id; throws when there is none */
|
|
189
|
+
get(id) {
|
|
190
|
+
const def = this.find(id);
|
|
191
|
+
if (!def) throw new Error(`There is no area "${id}"`);
|
|
192
|
+
return def;
|
|
193
|
+
}
|
|
194
|
+
/** Whether there is an area of that id */
|
|
195
|
+
has(id) {
|
|
196
|
+
return !!this.find(id);
|
|
197
|
+
}
|
|
198
|
+
find(id) {
|
|
199
|
+
return this.byId.get(id) ?? this.added().find((def) => def.id === id);
|
|
200
|
+
}
|
|
201
|
+
added() {
|
|
202
|
+
return this.world.state(added);
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Adds an area while the game runs: a zone a spell leaves, a ring that closes in, a part of the map a quest opens.
|
|
206
|
+
* Who is in it is found at the end of the tick, and walks in then. One of the same id, added before, is replaced
|
|
207
|
+
*/
|
|
208
|
+
add(def) {
|
|
209
|
+
if (this.byId.has(def.id)) throw new Error(`Area "${def.id}" is one of the game's: it cannot be added again`);
|
|
210
|
+
const list = this.added();
|
|
211
|
+
const index = list.findIndex((other) => other.id === def.id);
|
|
212
|
+
const copy = {
|
|
213
|
+
id: def.id,
|
|
214
|
+
shape: { ...def.shape }
|
|
215
|
+
};
|
|
216
|
+
if (index >= 0) list[index] = copy;
|
|
217
|
+
else list.push(copy);
|
|
218
|
+
}
|
|
219
|
+
/** Takes away an area added while the game runs. Who was in it leaves it (`leftArea`). False when there was none */
|
|
220
|
+
remove(id) {
|
|
221
|
+
const list = this.added();
|
|
222
|
+
const index = list.findIndex((def) => def.id === id);
|
|
223
|
+
if (index < 0) return false;
|
|
224
|
+
list.splice(index, 1);
|
|
225
|
+
const state = this.world.state(inside);
|
|
226
|
+
for (const entityId of state[id] ?? []) {
|
|
227
|
+
const entity = this.world.get(entityId);
|
|
228
|
+
if (entity?.alive) this.world.events.emit(leftArea, {
|
|
229
|
+
area: id,
|
|
230
|
+
entity
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
delete state[id];
|
|
234
|
+
return true;
|
|
235
|
+
}
|
|
236
|
+
/** Whether the entity was in the area when the areas were last looked at: the end of the last tick's movement */
|
|
237
|
+
contains(id, entity) {
|
|
238
|
+
return this.idsIn(id).includes(entity.id);
|
|
239
|
+
}
|
|
240
|
+
/** Who is in the area, as of the last look */
|
|
241
|
+
inside(id) {
|
|
242
|
+
const result = [];
|
|
243
|
+
for (const entityId of this.idsIn(id)) {
|
|
244
|
+
const entity = this.world.get(entityId);
|
|
245
|
+
if (entity) result.push(entity);
|
|
246
|
+
}
|
|
247
|
+
return result;
|
|
248
|
+
}
|
|
249
|
+
idsIn(id) {
|
|
250
|
+
this.get(id);
|
|
251
|
+
return this.world.state(inside)[id] ?? [];
|
|
252
|
+
}
|
|
253
|
+
/** Looks who is in each area now, and tells who walked in and who walked out. What died in one is just gone */
|
|
254
|
+
update() {
|
|
255
|
+
const state = this.world.state(inside);
|
|
256
|
+
for (const area of this.byId.values()) this.look(area, state);
|
|
257
|
+
for (const area of this.added()) this.look(area, state);
|
|
258
|
+
}
|
|
259
|
+
/** Who is in one area now, against who was */
|
|
260
|
+
look(area, state) {
|
|
261
|
+
const { world, found, now } = this;
|
|
262
|
+
const { shape } = area;
|
|
263
|
+
now.clear();
|
|
264
|
+
for (const entity of world.spatial.query(shape.x, shape.z, reach(shape), found)) {
|
|
265
|
+
if (entity.def.kind !== "unit" || !entity.alive || entity.hidden || !inShape(shape, entity.pos)) continue;
|
|
266
|
+
now.add(entity.id);
|
|
267
|
+
}
|
|
268
|
+
const before = state[area.id] ?? [];
|
|
269
|
+
for (const id of before) {
|
|
270
|
+
if (now.has(id)) continue;
|
|
271
|
+
const entity = world.get(id);
|
|
272
|
+
if (entity?.alive) world.events.emit(leftArea, {
|
|
273
|
+
area: area.id,
|
|
274
|
+
entity
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
for (const id of now) if (!before.includes(id)) world.events.emit(enteredArea, {
|
|
278
|
+
area: area.id,
|
|
279
|
+
entity: world.get(id)
|
|
280
|
+
});
|
|
281
|
+
if (now.size || before.length) state[area.id] = [...now];
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
/** Watches the areas, after everyone has moved. Does nothing in a game without any */
|
|
285
|
+
var areaSystem = {
|
|
286
|
+
name: "areas",
|
|
287
|
+
phase: "resolve",
|
|
288
|
+
update(world) {
|
|
289
|
+
if (world.areas.size) world.areas.update();
|
|
290
|
+
}
|
|
291
|
+
};
|
|
292
|
+
//#endregion
|
|
293
|
+
export { Areas, added, areaShapeOf, areaSystem, defineArea, inShape, inside, shapeArea, shapeAsBox, shapeAt, shapeBounds, shapeReach };
|
|
294
|
+
|
|
295
|
+
//# sourceMappingURL=areas.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"areas.js","names":["leftAreaEvent","enteredAreaEvent"],"sources":["../src/areas.ts"],"sourcesContent":["import { enteredArea as enteredAreaEvent, leftArea as leftAreaEvent } from '#engine/engineEvents'\nimport { defineComponent } from './components'\nimport type { Entity } from './entity'\nimport type { Vec2 } from './math'\nimport type { System } from './registry'\nimport type { World } from './world'\nimport { hypot } from './exactMath'\nimport type { MapRegion } from './map'\n\n/**\n * Where an area is on the map: a circle, a rectangle by its middle and size, or a polygon by its corners round a middle\n * of its own (`points`, each from `x` and `z`, three or more, in order round it: moving the middle moves it whole)\n *\n * @beta\n */\nexport type AreaShape =\n\t| { kind: 'circle'; x: number; z: number; radius: number }\n\t| { kind: 'rect'; x: number; z: number; width: number; depth: number }\n\t| { kind: 'polygon'; x: number; z: number; points: Vec2[] }\n\n/**\n * The box round a shape: its least and greatest x and z on the map\n *\n * @beta\n */\nexport function shapeBounds(shape: AreaShape): { x0: number; z0: number; x1: number; z1: number } {\n\tif (shape.kind === 'circle')\n\t\treturn { x0: shape.x - shape.radius, z0: shape.z - shape.radius, x1: shape.x + shape.radius, z1: shape.z + shape.radius }\n\tif (shape.kind === 'rect')\n\t\treturn { x0: shape.x - shape.width / 2, z0: shape.z - shape.depth / 2, x1: shape.x + shape.width / 2, z1: shape.z + shape.depth / 2 }\n\tlet x0 = Infinity\n\tlet z0 = Infinity\n\tlet x1 = -Infinity\n\tlet z1 = -Infinity\n\tfor (const point of shape.points) {\n\t\tx0 = Math.min(x0, shape.x + point.x)\n\t\tz0 = Math.min(z0, shape.z + point.z)\n\t\tx1 = Math.max(x1, shape.x + point.x)\n\t\tz1 = Math.max(z1, shape.z + point.z)\n\t}\n\treturn shape.points.length ? { x0, z0, x1, z1 } : { x0: shape.x, z0: shape.z, x1: shape.x, z1: shape.z }\n}\n\n/**\n * How much ground a shape covers, in cells\n *\n * @beta\n */\nexport function shapeArea(shape: AreaShape): number {\n\tif (shape.kind === 'circle') return Math.PI * shape.radius * shape.radius\n\tif (shape.kind === 'rect') return shape.width * shape.depth\n\tlet twice = 0\n\tconst { points } = shape\n\tfor (let i = 0, j = points.length - 1; i < points.length; j = i++) twice += points[j].x * points[i].z - points[i].x * points[j].z\n\treturn Math.abs(twice) / 2\n}\n\n/**\n * A shape as a circle or a rectangle: a polygon as the rectangle round it. For what draws only those (mist, clouds and\n * weather in a region of the map)\n *\n * @beta\n */\nexport function shapeAsBox(shape: AreaShape): Exclude<AreaShape, { kind: 'polygon' }> {\n\tif (shape.kind !== 'polygon') return shape\n\tconst { x0, z0, x1, z1 } = shapeBounds(shape)\n\treturn { kind: 'rect', x: (x0 + x1) / 2, z: (z0 + z1) / 2, width: x1 - x0, depth: z1 - z0 }\n}\n\n/**\n * A shape moved to stand at a point and sized `scale` times: a prefab's area where the prefab is put\n *\n * @beta\n */\nexport function shapeAt(shape: AreaShape, at: Vec2, scale = 1): AreaShape {\n\tif (shape.kind === 'circle') return { kind: 'circle', x: at.x, z: at.z, radius: shape.radius * scale }\n\tif (shape.kind === 'rect') return { kind: 'rect', x: at.x, z: at.z, width: shape.width * scale, depth: shape.depth * scale }\n\treturn { kind: 'polygon', x: at.x, z: at.z, points: shape.points.map((point) => ({ x: point.x * scale, z: point.z * scale })) }\n}\n\n/**\n * Where something of the map is, by a shape of its own or by a region of the map, named: mist, clouds and weather in\n * places (`MapMistArea.shape`). By the region, it is where the region is, moved with it, and is the rules' too\n *\n * @beta\n */\nexport type AreaRef = AreaShape | { region: string }\n\n/**\n * The shape an `AreaRef` stands for: its own, or the named region's among the map's. Nothing for a region that is\n * not there\n *\n * @beta\n */\nexport function areaShapeOf(ref: AreaRef, regions: readonly MapRegion[]): AreaShape | undefined {\n\tif ('region' in ref) return regions.find((region) => region.name === ref.region)?.shape\n\treturn ref\n}\n\n/**\n * A named part of the map that the rules watch: who walks into it and out of it (`enteredArea`, `leftArea` events),\n * and who is in it now (`world.areas`). Units count, by where their middle is; buildings, scenery and units inside\n * something do not. Given in `Rules.areas`\n *\n * @beta\n */\nexport interface AreaDef {\n\t/** Shared by every game, like other ids: give it a prefix of the game's (`'td.gate'`) */\n\tid: string\n\t/** The area's shape in cells, one of the `AreaShape`s */\n\tshape: AreaShape\n}\n\n/**\n * Typed help for writing an area\n *\n * @beta\n */\nexport const defineArea = (def: AreaDef): AreaDef => def\n\n/**\n * Whether a point is in a shape\n *\n * @beta\n */\nexport function inShape(shape: AreaShape, point: Vec2): boolean {\n\tconst dx = point.x - shape.x\n\tconst dz = point.z - shape.z\n\tif (shape.kind === 'circle') return dx * dx + dz * dz <= shape.radius * shape.radius\n\tif (shape.kind === 'rect') return Math.abs(dx) <= shape.width / 2 && Math.abs(dz) <= shape.depth / 2\n\t// a polygon: in where a line from the point crosses its edges an odd number of times\n\tconst { points } = shape\n\tlet odd = false\n\tfor (let i = 0, j = points.length - 1; i < points.length; j = i++) {\n\t\tconst a = points[i]\n\t\tconst b = points[j]\n\t\tif (a.z > dz !== b.z > dz && dx < ((b.x - a.x) * (dz - a.z)) / (b.z - a.z) + a.x) odd = !odd\n\t}\n\treturn odd\n}\n\n/**\n * The radius of a circle round the whole shape from its middle (`x`, `z`): what the spatial index is asked for\n *\n * @beta\n */\nexport function shapeReach(shape: AreaShape): number {\n\tif (shape.kind === 'circle') return shape.radius\n\tif (shape.kind === 'rect') return hypot(shape.width, shape.depth) / 2\n\tlet most = 0\n\tfor (const point of shape.points) most = Math.max(most, hypot(point.x, point.z))\n\treturn most\n}\nconst reach = shapeReach\n\n/** Who is in each area, by id: kept in the world, so that a save knows, and nobody walks in twice after loading */\nexport const inside = defineComponent<Record<string, number[]>>({ id: 'core.areas', default: () => ({}) })\n/** Areas added while the game runs (`areas.add`): kept in the world, so that a save has them */\nexport const added = defineComponent<AreaDef[]>({ id: 'core.areasAdded', default: () => [] })\n\n/**\n * The areas of a world, and who is in them\n *\n * @beta\n */\nexport class Areas {\n\tprivate readonly byId = new Map<string, AreaDef>()\n\t/** Kept between ticks, not made anew */\n\tprivate readonly found: Entity[] = []\n\tprivate readonly now = new Set<number>()\n\n\tconstructor(\n\t\tprivate readonly world: World,\n\t\tdefs: readonly AreaDef[]\n\t) {\n\t\tfor (const def of defs) {\n\t\t\tif (this.byId.has(def.id)) throw new Error(`Area \"${def.id}\" is there twice`)\n\t\t\tthis.byId.set(def.id, def)\n\t\t}\n\t}\n\n\t/** The areas of the game, then those added while it runs */\n\tget all(): Iterable<AreaDef> {\n\t\treturn [...this.byId.values(), ...this.added()]\n\t}\n\n\t/** How many areas there are: the game's and those added while it runs */\n\tget size(): number {\n\t\treturn this.byId.size + this.added().length\n\t}\n\n\t/** Gives the area with the id; throws when there is none */\n\tget(id: string): AreaDef {\n\t\tconst def = this.find(id)\n\t\tif (!def) throw new Error(`There is no area \"${id}\"`)\n\t\treturn def\n\t}\n\n\t/** Whether there is an area of that id */\n\thas(id: string): boolean {\n\t\treturn !!this.find(id)\n\t}\n\n\tprivate find(id: string): AreaDef | undefined {\n\t\treturn this.byId.get(id) ?? this.added().find((def) => def.id === id)\n\t}\n\n\tprivate added(): AreaDef[] {\n\t\treturn this.world.state(added)\n\t}\n\n\t/**\n\t * Adds an area while the game runs: a zone a spell leaves, a ring that closes in, a part of the map a quest opens.\n\t * Who is in it is found at the end of the tick, and walks in then. One of the same id, added before, is replaced\n\t */\n\tadd(def: AreaDef): void {\n\t\tif (this.byId.has(def.id)) throw new Error(`Area \"${def.id}\" is one of the game's: it cannot be added again`)\n\t\tconst list = this.added()\n\t\tconst index = list.findIndex((other) => other.id === def.id)\n\t\t// a copy: the shape may be moved by adding it again, not by changing what was given\n\t\tconst copy = { id: def.id, shape: { ...def.shape } }\n\t\tif (index >= 0) list[index] = copy\n\t\telse list.push(copy)\n\t}\n\n\t/** Takes away an area added while the game runs. Who was in it leaves it (`leftArea`). False when there was none */\n\tremove(id: string): boolean {\n\t\tconst list = this.added()\n\t\tconst index = list.findIndex((def) => def.id === id)\n\t\tif (index < 0) return false\n\t\tlist.splice(index, 1)\n\t\tconst state = this.world.state(inside)\n\t\tfor (const entityId of state[id] ?? []) {\n\t\t\tconst entity = this.world.get(entityId)\n\t\t\tif (entity?.alive) this.world.events.emit(leftAreaEvent, { area: id, entity })\n\t\t}\n\t\tdelete state[id]\n\t\treturn true\n\t}\n\n\t/** Whether the entity was in the area when the areas were last looked at: the end of the last tick's movement */\n\tcontains(id: string, entity: Entity): boolean {\n\t\treturn this.idsIn(id).includes(entity.id)\n\t}\n\n\t/** Who is in the area, as of the last look */\n\tinside(id: string): Entity[] {\n\t\tconst result: Entity[] = []\n\t\tfor (const entityId of this.idsIn(id)) {\n\t\t\tconst entity = this.world.get(entityId)\n\t\t\tif (entity) result.push(entity)\n\t\t}\n\t\treturn result\n\t}\n\n\tprivate idsIn(id: string): number[] {\n\t\tthis.get(id)\n\t\treturn this.world.state(inside)[id] ?? []\n\t}\n\n\t/** Looks who is in each area now, and tells who walked in and who walked out. What died in one is just gone */\n\tupdate(): void {\n\t\tconst state = this.world.state(inside)\n\t\t// the game's, then those added: no list made of both every tick\n\t\tfor (const area of this.byId.values()) this.look(area, state)\n\t\tfor (const area of this.added()) this.look(area, state)\n\t}\n\n\t/** Who is in one area now, against who was */\n\tprivate look(area: AreaDef, state: Record<string, number[]>): void {\n\t\tconst { world, found, now } = this\n\t\tconst { shape } = area\n\t\tnow.clear()\n\t\tfor (const entity of world.spatial.query(shape.x, shape.z, reach(shape), found)) {\n\t\t\tif (entity.def.kind !== 'unit' || !entity.alive || entity.hidden || !inShape(shape, entity.pos)) continue\n\t\t\tnow.add(entity.id)\n\t\t}\n\t\tconst before = state[area.id] ?? []\n\t\tfor (const id of before) {\n\t\t\tif (now.has(id)) continue\n\t\t\tconst entity = world.get(id)\n\t\t\tif (entity?.alive) world.events.emit(leftAreaEvent, { area: area.id, entity })\n\t\t}\n\t\tfor (const id of now) {\n\t\t\tif (!before.includes(id)) world.events.emit(enteredAreaEvent, { area: area.id, entity: world.get(id)! })\n\t\t}\n\t\tif (now.size || before.length) state[area.id] = [...now]\n\t}\n}\n\n/** Watches the areas, after everyone has moved. Does nothing in a game without any */\nexport const areaSystem: System = {\n\tname: 'areas',\n\tphase: 'resolve',\n\tupdate(world) {\n\t\tif (world.areas.size) world.areas.update()\n\t}\n}\n"],"mappings":"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"}
|