@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/hooks.js
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { engineMessage } from "./messages.js";
|
|
2
|
+
//#region src/hooks.ts
|
|
3
|
+
/**
|
|
4
|
+
* A hook of a game's own: `const lifeLost = defineHookType<{ invader: Entity; lives: number } & Cancellable>({ id: 'td.lifeLost' })`.
|
|
5
|
+
* The game runs it where the moment is (`world.hooks.run(lifeLost, { ... })`) and reads back what the handlers made
|
|
6
|
+
* of the event; handlers are written with `defineHook({ hook: lifeLost, ... })`, by the game or by a mod on it.
|
|
7
|
+
* Ids are shared by every game: give them a prefix of the game's
|
|
8
|
+
*
|
|
9
|
+
* @beta
|
|
10
|
+
*/
|
|
11
|
+
function defineHookType(def) {
|
|
12
|
+
return { id: def.id };
|
|
13
|
+
}
|
|
14
|
+
/** What `cancellable` gives an event: one function and one description for all, so that a hook run makes neither */
|
|
15
|
+
var CANCEL = {
|
|
16
|
+
value(reason) {
|
|
17
|
+
this.cancelled = true;
|
|
18
|
+
if (reason !== void 0) this.reason = reason;
|
|
19
|
+
},
|
|
20
|
+
enumerable: false,
|
|
21
|
+
configurable: true,
|
|
22
|
+
writable: true
|
|
23
|
+
};
|
|
24
|
+
/** Gives an event `cancel` (not enumerable: a save, a snapshot or a clone leaves it out), unless it has one @internal */
|
|
25
|
+
function cancellable(event) {
|
|
26
|
+
if (typeof event.cancel !== "function") Object.defineProperty(event, "cancel", CANCEL);
|
|
27
|
+
return event;
|
|
28
|
+
}
|
|
29
|
+
/** What a hook that tells the player refuses with: its reason, or the engine's word where a handler gave none; nothing where it lets through @beta */
|
|
30
|
+
function refusalOf(event) {
|
|
31
|
+
return event.cancelled ? event.reason ?? engineMessage("cannotDoThat") : void 0;
|
|
32
|
+
}
|
|
33
|
+
function defineHook(def) {
|
|
34
|
+
return def;
|
|
35
|
+
}
|
|
36
|
+
/** The name a hook goes by in the lists */
|
|
37
|
+
var nameOf = (hook) => typeof hook === "string" ? hook : hook.id;
|
|
38
|
+
/**
|
|
39
|
+
* The handlers of every hook of one world
|
|
40
|
+
*
|
|
41
|
+
* @beta
|
|
42
|
+
*/
|
|
43
|
+
var Hooks = class {
|
|
44
|
+
world;
|
|
45
|
+
lists = /* @__PURE__ */ new Map();
|
|
46
|
+
constructor(world) {
|
|
47
|
+
this.world = world;
|
|
48
|
+
}
|
|
49
|
+
/** Adds a handler. One with the same id on the same hook is replaced */
|
|
50
|
+
add(def) {
|
|
51
|
+
const name = nameOf(def.hook);
|
|
52
|
+
let list = this.lists.get(name);
|
|
53
|
+
if (!list) this.lists.set(name, list = []);
|
|
54
|
+
const index = list.findIndex((entry) => entry.id === def.id);
|
|
55
|
+
const entry = {
|
|
56
|
+
id: def.id,
|
|
57
|
+
priority: def.priority ?? 0,
|
|
58
|
+
run: def.run
|
|
59
|
+
};
|
|
60
|
+
if (index >= 0) list[index] = entry;
|
|
61
|
+
else list.push(entry);
|
|
62
|
+
list.sort((a, b) => a.priority - b.priority);
|
|
63
|
+
}
|
|
64
|
+
/** Takes the handler with the id off the hook; nothing happens when there is none */
|
|
65
|
+
remove(hook, id) {
|
|
66
|
+
const list = this.lists.get(nameOf(hook));
|
|
67
|
+
const index = list?.findIndex((entry) => entry.id === id) ?? -1;
|
|
68
|
+
if (index >= 0) list.splice(index, 1);
|
|
69
|
+
}
|
|
70
|
+
/** Whether a hook has any handlers. For hooks run very often, to not even put the event together when nobody listens */
|
|
71
|
+
has(hook) {
|
|
72
|
+
return (this.lists.get(nameOf(hook))?.length ?? 0) > 0;
|
|
73
|
+
}
|
|
74
|
+
/** Ids of the handlers of a hook, in the order they run */
|
|
75
|
+
handlers(hook) {
|
|
76
|
+
return (this.lists.get(nameOf(hook)) ?? []).map((entry) => entry.id);
|
|
77
|
+
}
|
|
78
|
+
run(hook, event) {
|
|
79
|
+
const list = this.lists.get(nameOf(hook));
|
|
80
|
+
if (!list) return event;
|
|
81
|
+
if (typeof event === "object" && event !== null && "cancelled" in event) cancellable(event);
|
|
82
|
+
const name = nameOf(hook);
|
|
83
|
+
this.world.trace?.hook(name, list, typeof hook !== "string", event);
|
|
84
|
+
for (let i = 0; i < list.length; i++) {
|
|
85
|
+
const entry = list[i];
|
|
86
|
+
try {
|
|
87
|
+
entry.run(this.world, event);
|
|
88
|
+
} catch (error) {
|
|
89
|
+
this.world.caught(error, {
|
|
90
|
+
kind: "hook",
|
|
91
|
+
id: entry.id,
|
|
92
|
+
hook: name
|
|
93
|
+
});
|
|
94
|
+
const at = list.indexOf(entry);
|
|
95
|
+
if (at >= 0) list.splice(at, 1);
|
|
96
|
+
i = Math.min(i, at) - 1;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return event;
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
//#endregion
|
|
103
|
+
export { Hooks, cancellable, defineHook, defineHookType, refusalOf };
|
|
104
|
+
|
|
105
|
+
//# sourceMappingURL=hooks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks.js","names":[],"sources":["../src/hooks.ts"],"sourcesContent":["import type { ChatAudience } from './talk'\nimport type { AbilityDef, BuffDef, Cost, DamageType, EffectDef, StatChange, Stats, UnitTypeDef } from './defs'\nimport type { Camp } from './camps'\nimport type { BuffInstance, Entity, EntityId, ItemInstance, Order, PlayerId } from './entity'\nimport type { FormationDef } from './formation'\nimport type { AreaDef } from './areas'\nimport type { GameMap, MapCamp, MapObject, MapRegion } from './map'\nimport type { Rect, Vec2 } from './math'\nimport { engineMessage, type MessageRef } from './messages'\nimport type { DeathCause, DeathReason, Missile, World } from './world'\n\n/**\n * Hooks are how game modules and mods take part in what the engine does, while it does it: make an attack\n * hit harder, keep a unit from dying, pay for a kill, refuse an order. A hook is a list of handlers that run\n * in order, each getting the same event object; handlers before damage or death can change it or call it off.\n *\n * Events (`World.events`) are different: they tell whoever watches (a player's session, a test) what has\n * happened, once the tick is over, and cannot change anything. Code that is part of the rules uses hooks.\n */\n\n/**\n * Damage about to be dealt, before armor and shields. Change `amount` or `type`, or `cancel()`\n *\n * @beta\n */\nexport interface BeforeDamage {\n\t/** The entity about to take the damage */\n\treadonly target: Entity\n\t/** The entity that deals it, left out when nothing does (the rules, a trap) */\n\treadonly source?: Entity\n\t/** The damage in hit points before armor and shields; a handler may change it */\n\tamount: number\n\t/** The damage type, which armor and resistance read; a handler may change it */\n\ttype: DamageType\n\t/** A basic attack, not an ability */\n\treadonly attack: boolean\n\t/** Whether the blow is a critical hit */\n\treadonly crit: boolean\n\t/** The ability that deals it, by id. Left out for a basic attack */\n\treadonly ability?: string\n\t/** Words of the game's own about it, see `DamageOptions.tags` */\n\treadonly tags?: readonly string[]\n\t/** Whether a handler has called it off; set by `cancel()` */\n\tcancelled: boolean\n\t/** Stops it. The reason is what the player is told, where this hook tells them (`reason`) */\n\tcancel(reason?: MessageRef): void\n}\n\n/**\n * Damage that was dealt. The target may have died of it\n *\n * @beta\n */\nexport interface AfterDamage {\n\t/** The entity that took the damage */\n\treadonly target: Entity\n\t/** The entity that dealt it, left out when nothing did */\n\treadonly source?: Entity\n\t/** What came off its health, after armor and shields */\n\treadonly dealt: number\n\t/** The part of that it had health for: overkill left out */\n\treadonly taken: number\n\t/** The damage type it was dealt as */\n\treadonly type: DamageType\n\t/** Whether it was a basic attack, not an ability */\n\treadonly attack: boolean\n\t/** Whether the blow was a critical hit */\n\treadonly crit: boolean\n\t/** The ability that dealt it, by id; left out for a basic attack */\n\treadonly ability?: string\n\t/** Words of the game's own about it (`DamageOptions.tags`) */\n\treadonly tags?: readonly string[]\n}\n\n/**\n * Health about to be given back. Change `amount`, or `cancel()`\n *\n * @beta\n */\nexport interface BeforeHeal {\n\t/** The entity about to be healed */\n\treadonly target: Entity\n\t/** The entity that heals it, left out when nothing does */\n\treadonly source?: Entity\n\t/** How much health is given; a handler may change it */\n\tamount: number\n\t/** Whether a handler has called it off; set by `cancel()` */\n\tcancelled: boolean\n\t/** Stops it. The reason is what the player is told, where this hook tells them (`reason`) */\n\tcancel(reason?: MessageRef): void\n}\n\n/**\n * Something is about to die. `cancel()` keeps it alive: it is then up to the handler what health it has\n *\n * @beta\n */\nexport interface BeforeDeath {\n\t/** The entity about to die */\n\treadonly entity: Entity\n\t/** The entity that killed it, left out when nothing did */\n\treadonly killer?: Entity\n\t/** An attack of the killer did it */\n\treadonly attack: boolean\n\t/** It ran out of health, rather than being removed by the rules (felled, expired, cancelled) */\n\treadonly fromDamage: boolean\n\t/** The blow that did it, when it ran out of health */\n\treadonly cause?: DeathCause\n\t/** Why it dies (`DeathReason`): `damage`, or what the rules said (`cancelled`, `expired`, a game's own word) */\n\treadonly reason: DeathReason\n\t/** Whether a handler has called it off; set by `cancel()` */\n\tcancelled: boolean\n\t/** Stops it. The reason is what the player is told, where this hook tells them (`reason`) */\n\tcancel(reason?: MessageRef): void\n}\n\n/**\n * Something dies. In `death` it still stands where it was; in `afterDeath` it is gone from the world\n *\n * @beta\n */\nexport interface Death {\n\t/** The entity that died */\n\treadonly entity: Entity\n\t/** The entity that killed it, left out when nothing did */\n\treadonly killer?: Entity\n\t/** Whether an attack of the killer did it */\n\treadonly attack: boolean\n\t/** The blow that did it, when it ran out of health: its damage type, the ability, how much too much */\n\treadonly cause?: DeathCause\n\t/** Why it dies (`DeathReason`): `damage`, or what the rules said (`cancelled`, `expired`, a game's own word) */\n\treadonly reason: DeathReason\n\t/**\n\t * What the rules make of the death, for the screen (`'exploded'`, `'burned'`): what the blow says (`AttackDef.how`,\n\t * `AbilityDef.how`) to start with, changed in the `death` hook as the game likes. The view gets it with the death\n\t * (`SessionEvent` `death`) to show it its way (`UnitLook.death`). Nothing when left out\n\t */\n\thow?: string\n\t/**\n\t * The buffs it carried as it fell, in `afterDeath` (where they are taken off it already): an `onKill`'s effects ask\n\t * them of the one killed (B44). Left out when it carried none\n\t */\n\treadonly carried?: readonly BuffInstance[]\n}\n\n/**\n * An order about to be given to a unit. Set `rejected` to refuse it. A cast that goes off at once, in the middle of\n * what the unit is doing (a potion drunk on the way, a leap), is asked here too, as the cast order it stands for\n *\n * @beta\n */\nexport interface BeforeOrder {\n\t/** The entity the order is for */\n\treadonly entity: Entity\n\t/** The order about to be given */\n\treadonly order: Order\n\t/** Added to the end of what it does, rather than in place of it */\n\treadonly queued: boolean\n\t/** Whether a handler refuses the order; it is then not given */\n\trejected: boolean\n}\n\n/**\n * How much a unit wants to attack something, as it looks for a target by itself. Higher is picked first:\n * raise or lower `score`, or make it `-Infinity` to pass the target over. Towers of a tower defense go for\n * the creep furthest along its way like this; a taunt makes everyone go for one unit.\n *\n * Runs for every candidate of every search, which is often: the same object is handed out again and again,\n * so keep nothing of it.\n *\n * @beta\n */\nexport interface TargetScore {\n\t/** The unit looking for a target */\n\tattacker: Entity\n\t/** The candidate it is scoring */\n\ttarget: Entity\n\t/** Edge to edge */\n\tdistance: number\n\t/** Attackers like this one (its layer, its reach) the target has already, and how many it has room for (`RuleSettings.combat.engageRoom`) */\n\tengaged: number\n\t/** How many attackers like it the target has already (`RuleSettings.combat.engageRoom`) */\n\troom: number\n\t/** What the engine makes of it: things that fight back first, then the closest, and a full one only when nothing else is near */\n\tscore: number\n}\n\n/**\n * Where an attacker goes to fight a target from: its spot around it (see `engagement.ts`), or the target itself, in\n * `point`, to change. A flank for cavalry, behind for assassins. Asked every time the target moves a little: keep it cheap\n */\nexport interface Approach {\n\treadonly attacker: Entity\n\treadonly target: Entity\n\tpoint: Vec2\n}\n\n/**\n * An ally standing in a unit's way is asked to step aside, to `point` (see `RuleSettings.movement.makesWay`, `lookAhead`): change\n * where it goes, or make it null to leave it standing. `mover` is on its way, heading the way of `direction`\n *\n * @beta\n */\nexport interface MakeWay {\n\t/** The unit that is on its way */\n\treadonly mover: Entity\n\t/** The ally standing in its way, asked to step aside */\n\treadonly other: Entity\n\t/** Where the mover is heading, a unit long */\n\treadonly direction: Vec2\n\t/** Where the other unit goes; change it, or null to leave it standing */\n\tpoint: Vec2 | null\n}\n\n/**\n * A unit is about to go round units standing in its way (`around`), by `point`, which is `longer` ground units more\n * than the `straight` way to the next corner of its path (see `RuleSettings.movement.goesAround`): change the point, or make it\n * null to have it go straight through, asking them aside. Asked as it comes up to them: keep it cheap\n *\n * @beta\n */\nexport interface Detour {\n\t/** The unit about to go round the others */\n\treadonly entity: Entity\n\t/** The units standing in its way */\n\treadonly around: readonly Entity[]\n\t/** The distance of the straight way to the next corner of its path, in ground units */\n\treadonly straight: number\n\t/** How many ground units longer the way by `point` is than the straight way */\n\treadonly longer: number\n\t/** The point it goes by round the others; change it, or null to go straight through */\n\tpoint: Vec2 | null\n}\n\n/**\n * Units ordered to a point together have their places in a formation worked out (`FormationDef`, `formationPoints`):\n * change any in `points`, by the unit's id, or add or remove some. `units` are those that walk, or those that fly:\n * each is laid out apart\n *\n * @beta\n */\nexport interface Formation {\n\t/** The units ordered, those that walk or those that fly, each laid out apart */\n\treadonly units: readonly Entity[]\n\t/** The point they are ordered to */\n\treadonly target: Vec2\n\t/** The formation the units are laid out in */\n\treadonly formation: FormationDef\n\t/** Where each unit goes, by entity id; a handler may change, add or remove places */\n\treadonly points: Map<EntityId, Vec2>\n}\n\n/**\n * Whether a structure may be placed. `cancel(reason)` refuses it, with what the player is told\n *\n * @beta\n */\nexport interface CanPlace {\n\t/** The unit type of the structure to be placed */\n\treadonly def: UnitTypeDef\n\t/** The ground it would cover */\n\treadonly site: Rect\n\t/** Who would build it. Left out when the engine asks for itself */\n\treadonly player?: PlayerId\n\t/** Whether a handler has refused the placing; set by `cancel()` */\n\tcancelled: boolean\n\t/** Stops it. The reason is what the player is told, where this hook tells them (`reason`) */\n\tcancel(reason?: MessageRef): void\n\t/** What the player is told of why it was refused */\n\treason?: MessageRef\n}\n\n/**\n * An ability about to go off, before it is paid for. Change what it costs, or call it off with a `reason`.\n * Whether the caster has the mana was already checked against the ability's own cost before it wound up:\n * a lower cost here does not let it cast with less than that\n *\n * @beta\n */\nexport interface BeforeCast {\n\t/** The unit that casts */\n\treadonly caster: Entity\n\t/** The ability being cast */\n\treadonly ability: AbilityDef\n\t/** The level of the ability it is cast at */\n\treadonly level: number\n\t/** The unit it is cast on, left out for a point or no target */\n\treadonly target?: Entity\n\t/** The point it is cast at (the target's place for a unit target) */\n\treadonly point: Vec2\n\t/** What it is cast from, for an item's ability */\n\treadonly item?: ItemInstance\n\t/** The mana it costs; a handler may change it */\n\tmanaCost: number\n\t/** Seconds until it can be used again */\n\tcooldown: number\n\t/** Whether a handler has called the cast off; set by `cancel()` */\n\tcancelled: boolean\n\t/** Stops it. The reason is what the player is told, where this hook tells them (`reason`) */\n\tcancel(reason?: MessageRef): void\n\t/** What the player is told of why it was called off */\n\treason?: MessageRef\n}\n\n/**\n * An ability that went off\n *\n * @beta\n */\nexport interface AfterCast {\n\t/** The unit that cast */\n\treadonly caster: Entity\n\t/** The ability that went off */\n\treadonly ability: AbilityDef\n\t/** The level it was cast at */\n\treadonly level: number\n\t/** The unit it was cast on, left out for a point or no target */\n\treadonly target?: Entity\n\t/** The point it was cast at */\n\treadonly point: Vec2\n\t/** The item it was cast from, for an item's ability */\n\treadonly item?: ItemInstance\n\t/** It went off charged, and spent the charge */\n\treadonly charged: boolean\n}\n\n/**\n * A buff about to be put on, or put on again. Change how long it lasts or how strong it is, or call it off (immunity)\n *\n * @beta\n */\nexport interface BeforeBuff {\n\t/** The unit about to get the buff */\n\treadonly target: Entity\n\t/** The buff to be put on */\n\treadonly buff: BuffDef\n\t/** The unit that puts it on, left out when nothing does */\n\treadonly source?: Entity\n\t/** The level the buff is put on at; a handler may change it */\n\tlevel: number\n\t/** Seconds, after tenacity. Infinity for one that stays */\n\tduration: number\n\t/** Whether a handler has called it off; set by `cancel()` */\n\tcancelled: boolean\n\t/** Stops it. The reason is what the player is told, where this hook tells them (`reason`) */\n\tcancel(reason?: MessageRef): void\n}\n\n/**\n * A buff that came off: it ran out (`expired`), or was taken off. Not called for the buffs of something that dies\n *\n * @beta\n */\nexport interface BuffEnd {\n\t/** The entity the buff was on */\n\treadonly entity: Entity\n\t/** The buff instance that ended, with its level and source */\n\treadonly buff: BuffInstance\n\t/** Whether the buff ran out its duration; false when it was taken off */\n\treadonly expired: boolean\n}\n\n/**\n * One of the five things that are made: a unit trained, an upgrade researched, a building morphed, a hero revived, a structure put down\n *\n * @beta\n */\nexport type ProductionKind = 'unit' | 'upgrade' | 'morph' | 'revive' | 'structure'\n\n/**\n * Something about to be made: a unit trained, an upgrade researched, a building upgraded, a hero brought back,\n * a structure put down by a worker. Change what it costs and how long it takes, or call it off with a `reason`\n *\n * @beta\n */\nexport interface BeforeProduce {\n\t/** The player the production is for */\n\treadonly player: PlayerId\n\t/** The building it is made in, or the worker putting down a structure */\n\treadonly producer: Entity\n\t/** What is being made: `unit`, `upgrade`, `morph`, `revive` or `structure` */\n\treadonly kind: ProductionKind\n\t/** Unit type, upgrade, the type a building becomes, the id of a hero, or a structure type */\n\treadonly id: string\n\t/** What it costs the player; a handler may change it */\n\tcost: Cost\n\t/** Seconds it takes */\n\ttime: number\n\t/** Whether a handler has called it off; set by `cancel()` */\n\tcancelled: boolean\n\t/** Stops it. The reason is what the player is told, where this hook tells them (`reason`) */\n\tcancel(reason?: MessageRef): void\n\t/** What the player is told of why it was called off */\n\treason?: MessageRef\n}\n\n/** Every hook, and what its handlers get */\n/**\n * A unit with nothing to do, this tick: no orders. Set `handled` and do what it does instead of what idle units do\n * (fight back, go for enemies that come close, which is only for those that fight): a healer that goes to the\n * wounded, a worker that goes back to work. Asked often: keep it cheap\n *\n * @beta\n */\nexport interface Idle {\n\t/** The unit with nothing to do */\n\treadonly entity: Entity\n\t/** Seconds the tick lasts */\n\treadonly dt: number\n\t/** Whether it fights by itself: it has an attack and is not told to stand down. The engine only does that */\n\treadonly fights: boolean\n\t/** Whether a handler took over the idle unit; set it to stop the engine's own idle behaviour */\n\thandled: boolean\n}\n\n/**\n * Whether an attacker may attack a target: what the engine makes of it (its attack's targets, whether they are\n * enemies) is in `cancelled`, to change. A buff that lets a unit hit what flies; a truce. Asked very often, the same\n * object handed out again and again: keep nothing of it\n */\nexport interface CanAttack {\n\tattacker: Entity\n\ttarget: Entity\n\tcancelled: boolean\n\t/** Stops it. The reason is what the player is told, where this hook tells them (`reason`) */\n\tcancel(reason?: MessageRef): void\n\t/**\n\t * Whether a player told the attacker to attack this one (an attack order): what a game lets of its own side, as a\n\t * deny (`denying`). Never when a unit picks a target by itself or fights back, so nothing turns on its own side\n\t * unless told: a unit looking for a target by itself is not asked about its own side's at all (they are passed over\n\t * before the hook, as most of what stands around a unit in a crowd is its own)\n\t */\n\tordered: boolean\n}\n\n/**\n * An attack going off, as the engine has it: change what it does, or call it off. `target` is left out for an attack\n * at the ground. `splash` is the radius of an attack that hits an area; `projectileSpeed` 0 is a blow, more a shot\n * (`look` what the shot looks like, for the screen). Damage, the critical strike and the miss are already rolled\n */\nexport interface BeforeAttack {\n\treadonly attacker: Entity\n\treadonly target?: Entity\n\treadonly point: Vec2\n\t/** Which of the attacker's attacks goes off, by place (`UnitTypeDef.attacks`) */\n\treadonly weapon: number\n\tdamage: number\n\ttype: DamageType\n\tcrit: boolean\n\tmiss: boolean\n\tsplash?: number\n\tprojectileSpeed: number\n\tlook?: string\n\t/** Words of the game's own about it, which the damage carries, see `DamageOptions.tags` */\n\ttags?: string[]\n\t/** How what it kills dies, for the screen (`AttackDef.how`, worked out for this blow): changed as the game likes */\n\thow?: string\n\tcancelled: boolean\n\t/** Stops it. The reason is what the player is told, where this hook tells them (`reason`) */\n\tcancel(reason?: MessageRef): void\n}\n\n/**\n * The stats of an entity being added up, once what the engine knows of (its type, levels, research, items, buffs) is\n * in: `add` more, as a stat change (`{ stats: { armor: 2 } }`, `{ percent: { moveSpeed: 0.1 } }`). Asked only when\n * something they come from changed: call `invalidateStats` when what a handler reads changes\n */\nexport interface StatsHook {\n\treadonly entity: Entity\n\t/** What its type starts with */\n\treadonly base: Readonly<Stats>\n\tadd(change: StatChange, times?: number): void\n}\n\n/**\n * Whether an ability can be used now: what the engine makes of it (level, cooldown, mana, silence) is `cancelled` with its\n * `reason`: `cancelled = false` clears it (\"free while Clearcasting\"), `cancel(reason)` sets it (\"not while carrying the flag\"). The cost itself is `beforeCast`'s: one\n * that is let through for free sets its `manaCost` to 0 there too. The player's screen is told what this decided for\n * the abilities of their own units\n */\nexport interface CanCast {\n\treadonly caster: Entity\n\treadonly ability: AbilityDef\n\treadonly level: number\n\t/** What it is used from, for an item's ability */\n\treadonly item?: ItemInstance\n\treason?: MessageRef\n\tcancelled: boolean\n\t/** Stops it. The reason is what the player is told, where this hook tells them (`reason`) */\n\tcancel(reason?: MessageRef): void\n}\n\n/**\n * Whether an ability may be used on a target: what the engine makes of it (the ability's `targets`) is `cancelled`, with its `reason`: `cancelled = false` to\n * clear (\"can target allied buildings below half health\") or to set. The screen only knows the declared targets: what\n * this changes, the simulation says when the order comes\n */\nexport interface CanTarget {\n\treadonly caster: Entity\n\treadonly ability: AbilityDef\n\treadonly target: Entity\n\treason?: MessageRef\n\tcancelled: boolean\n\t/** Stops it. The reason is what the player is told, where this hook tells them (`reason`) */\n\tcancel(reason?: MessageRef): void\n}\n\n/**\n * An effect of an ability about to reach one target (`beforeEffect`): who it is from, the effect, whom it reaches, where\n * it went off from. Cancelled, it does not reach that one, and only that one: the rest of an area are reached, a missile\n * passes it by (it is in its `hit`, so it is not asked again). Asked wherever any effect reaches any target: who an\n * effect applies to (`effectTargets`, so a `damage`, `heal`, `buff`, `knockback`, `pull`, `dispel`, a game's own that\n * asks), a missile's hit (with `missile`: a shield that eats it takes it out with `removeMissile`), what a game's own\n * effect asks (`mayReach`). Not for an aura's buff, which is kept up rather than landed. Asked only where a handler\n * is there: a game without one pays nothing\n *\n * @beta\n */\nexport interface BeforeEffect {\n\t/** Whose the effect is */\n\treadonly caster: Entity\n\t/** The ability the effect belongs to */\n\treadonly ability: AbilityDef\n\t/** The level it was cast at */\n\treadonly level: number\n\t/** The effect, as it runs (a chain lowered: `lowerChain`) */\n\treadonly effect: EffectDef\n\t/** Whom it is about to reach */\n\treadonly target: Entity\n\t/** What it went off from, when not the caster (`EffectContext.origin`) */\n\treadonly origin?: Entity | Vec2\n\t/** Where it landed */\n\treadonly point: Vec2\n\t/** The missile that reached the target, for a missile's hit */\n\treadonly missile?: Missile\n\t/** Whether a handler has called it off for this target; set by `cancel()` */\n\tcancelled: boolean\n\t/** It does not reach this target */\n\tcancel(): void\n}\n\n/**\n * An effect of an ability has reached one target (`effectLanded`), after its handler ran: what a game does with each\n * one an ability reached (a passive's stack for each hit, an execute below a threshold). For every target the\n * handler's `effectTargets` gave; asked only where a handler is there\n *\n * @beta\n */\nexport interface EffectLanded {\n\t/** The unit that cast the ability the effect is from */\n\treadonly caster: Entity\n\t/** The ability the effect is from */\n\treadonly ability: AbilityDef\n\t/** The level the ability was cast at */\n\treadonly level: number\n\t/** The effect that reached the target, as it runs */\n\treadonly effect: EffectDef\n\t/** Whom it reached: dead now, maybe, of it */\n\treadonly target: Entity\n\t/** What it went off from, when not the caster: an entity or a point */\n\treadonly origin?: Entity | Vec2\n\t/** Where the effect landed */\n\treadonly point: Vec2\n}\n\n/**\n * Whether a team sees an entity of someone else's: what the fog and invisibility make of it in `visible`, to change.\n * Units in brush seen only from up close; a watchtower. Asked very often: keep it cheap\n */\nexport interface Visible {\n\treadonly entity: Entity\n\treadonly team: number\n\tvisible: boolean\n}\n\n/**\n * Whether a player may make something, as far as what it requires goes: a unit, a level of research (`level`), what a\n * building upgrades to, a structure. What the engine makes of it (the finished buildings it requires: `missing`) is in\n * `cancelled` with its `reason`, to clear (`cancelled = false`) or set (`cancel(reason)`): \"needs Blacksmith upgrade 2\", \"needs a level 5 hero\", \"locked until the objective\". The\n * player's screen is told what this decided, for what they could make\n */\nexport interface Requirement {\n\treadonly player: PlayerId\n\treadonly kind: 'unit' | 'upgrade'\n\treadonly id: string\n\t/** The level being researched, for an upgrade */\n\treadonly level?: number\n\t/** Required building types the player does not have */\n\treadonly missing: readonly string[]\n\treason?: MessageRef\n\tcancelled: boolean\n\t/** Stops it. The reason is what the player is told, where this hook tells them (`reason`) */\n\tcancel(reason?: MessageRef): void\n}\n\n/**\n * Whether a player may make a unit type or research an upgrade at all, before what it requires (see `isAvailable`):\n * by default (`available`), what is of no race or of theirs (`race`). Set it otherwise for a game's own way: what a\n * mode takes away, a roster that grows as a campaign goes, a unit only one player may have. What is not available is\n * not on the player's buttons, and an order for it is refused; their screen is told where this decided otherwise\n *\n * @beta\n */\nexport interface Available {\n\t/** The player who would make it */\n\treadonly player: PlayerId\n\t/** Whether it is for a `unit` type or an `upgrade` */\n\treadonly kind: 'unit' | 'upgrade'\n\t/** The unit type or upgrade being asked about */\n\treadonly id: string\n\t/** The race the player plays, if the game has races */\n\treadonly race: string | undefined\n\t/** Whether the player may make it at all; the engine sets it from the race, a handler may change it */\n\tavailable: boolean\n}\n\n/**\n * A player about to ping the map or say a line (see `ping`, `chat`): change the words (`text`) or who hears them (`to`),\n * or call it off: a muted player, a word filter, no talking in a cinematic. On the rules' side, for every screen alike\n */\nexport interface BeforeTalk {\n\treadonly player: PlayerId\n\treadonly kind: 'ping' | 'chat'\n\t/** A line's words */\n\ttext?: string\n\t/** Who a line or a ping is for */\n\tto?: ChatAudience\n\t/** Where a ping is, and of what kind */\n\treadonly point?: Vec2\n\treadonly pingKind?: string\n\tcancelled: boolean\n\t/** Stops it. The reason is what the player is told, where this hook tells them (`reason`) */\n\tcancel(reason?: MessageRef): void\n}\n\n/**\n * Resources about to be given to an ally (see `give`): change how much arrives (`received`), or call it off with a\n * `reason`: no trading in the first minutes, a cap on what goes to one player\n */\nexport interface BeforeTrade {\n\treadonly from: PlayerId\n\treadonly to: PlayerId\n\treadonly resource: string\n\treadonly sent: number\n\treceived: number\n\tcancelled: boolean\n\t/** Stops it. The reason is what the player is told, where this hook tells them (`reason`) */\n\tcancel(reason?: MessageRef): void\n\treason?: MessageRef\n}\n\n/**\n * A player is about to give up (see `surrender`): call it off with a `reason`, as a game that does not let them before a time\n *\n * @beta\n */\nexport interface BeforeSurrender {\n\t/** The player about to give up */\n\treadonly player: PlayerId\n\t/** Whether a handler has called it off; set by `cancel()` */\n\tcancelled: boolean\n\t/** Stops it. The reason is what the player is told, where this hook tells them (`reason`) */\n\tcancel(reason?: MessageRef): void\n\t/** What the player is told of why they cannot give up */\n\treason?: MessageRef\n}\n\n/**\n * A player asks for a pause (see `askPause`): how many they have left before this one (`left`), and how long it lasts\n * at most (`seconds`, which can be changed); call it off with a `reason`\n *\n * @beta\n */\nexport interface BeforePause {\n\t/** The player asking for the pause */\n\treadonly player: PlayerId\n\t/** How many pauses the player has left before this one */\n\treadonly left: number\n\t/** How long the pause lasts at most, in seconds; a handler may change it */\n\tseconds: number\n\t/** Whether a handler has called it off; set by `cancel()` */\n\tcancelled: boolean\n\t/** Stops it. The reason is what the player is told, where this hook tells them (`reason`) */\n\tcancel(reason?: MessageRef): void\n\t/** What the player is told of why the pause was refused */\n\treason?: MessageRef\n}\n\n/**\n * A player's cap of a pool of supply, once what their buildings provide is added up (see the supply system): change\n * `cap` (a starting amount, an upgrade, a rule of the game's own). The game's most (`RuleSettings.supply.max`, a pool's\n * `max`) still holds after\n *\n * @beta\n */\nexport interface SupplyCap {\n\t/** The player whose supply cap it is */\n\treadonly player: PlayerId\n\t/** `supply` for the one there always is, or the name of one of the game's own (`RuleSettings.supply.pools`) */\n\treadonly pool: string\n\t/** The cap of the pool in supply points, once buildings are added up; a handler may change it */\n\tcap: number\n}\n\n/**\n * Whether a worker may gather from a resource: by default, a resource of a kind it gathers (`harvester.ids`). Refuse\n * it for a game's own rule: a mine only its owner's cursed mine stands on, a tree of a sacred grove. Asked when it is\n * told to, and of every resource it would go on to by itself\n *\n * @beta\n */\nexport interface CanHarvest {\n\t/** The worker that would gather */\n\treadonly worker: Entity\n\t/** The resource entity it would gather from */\n\treadonly source: Entity\n\t/** Whether a handler has refused it; set by `cancel()` */\n\tcancelled: boolean\n\t/** Stops it. The reason is what the player is told, where this hook tells them (`reason`) */\n\tcancel(reason?: MessageRef): void\n\t/** What the player is told when it is refused */\n\treason?: MessageRef\n}\n\n/** Resources a worker hands in: change `amount` (more from mines near the keep), or call it off */\nexport interface BeforeDeposit {\n\treadonly worker: Entity\n\treadonly player: PlayerId\n\treadonly kind: string\n\tamount: number\n\tcancelled: boolean\n\t/** Stops it. The reason is what the player is told, where this hook tells them (`reason`) */\n\tcancel(reason?: MessageRef): void\n}\n\n/** An item about to be bought at a shop: change what it costs, or call it off with a `reason` */\nexport interface BeforeBuy {\n\treadonly buyer: Entity\n\treadonly shop: Entity\n\treadonly item: string\n\tcost: Cost\n\tcancelled: boolean\n\t/** Stops it. The reason is what the player is told, where this hook tells them (`reason`) */\n\tcancel(reason?: MessageRef): void\n\treason?: MessageRef\n}\n\n/** An item about to be picked up off the ground (`ground` its id there): call it off with a `reason` */\nexport interface BeforePickUp {\n\treadonly entity: Entity\n\treadonly item: string\n\treadonly ground: number\n\tcancelled: boolean\n\t/** Stops it. The reason is what the player is told, where this hook tells them (`reason`) */\n\tcancel(reason?: MessageRef): void\n\treason?: MessageRef\n}\n\n/** An item about to be put down: call it off with a `reason` (a cursed blade) */\nexport interface BeforeDrop {\n\treadonly entity: Entity\n\treadonly item: ItemInstance\n\tcancelled: boolean\n\t/** Stops it. The reason is what the player is told, where this hook tells them (`reason`) */\n\tcancel(reason?: MessageRef): void\n\treason?: MessageRef\n}\n\n/** Experience about to go to a hero: change `amount` (the killer gets more), or make it 0. `from` is what was killed, when that is where it comes from */\nexport interface BeforeXp {\n\treadonly hero: Entity\n\treadonly from?: Entity\n\tamount: number\n}\n\n/** Whether a hero may put a point into an ability: what the engine makes of it in `cancelled`, to change. The screen hears of it with what the hero can learn */\nexport interface CanLearn {\n\treadonly hero: Entity\n\treadonly ability: string\n\tcancelled: boolean\n\t/** Stops it. The reason is what the player is told, where this hook tells them (`reason`) */\n\tcancel(reason?: MessageRef): void\n}\n\n/** Something was made: a unit trained (`unit`), research done (`level`), a building upgraded, a hero brought back */\nexport interface Produced {\n\treadonly producer: Entity\n\treadonly kind: ProductionKind\n\treadonly id: string\n\treadonly unit?: Entity\n\treadonly level?: number\n}\n\n/**\n * Something that has just become another type where it stands (`morph`): a building upgraded, a unit transformed. Its\n * new type's parts are set (stats, abilities, slots, and every `Component.onSpawn` of a part it did not have yet): what\n * a pack gives it of its own for the type it is now, as the heroes pack makes a hero of what became a hero's type and\n * stocks what became a shop. Run before the `entityMorphed` event\n *\n * @beta\n */\nexport interface Morphed {\n\t/** What changed type, as it is now */\n\treadonly entity: Entity\n\t/** The type it was */\n\treadonly from: string\n}\n\n/**\n * What was placed on a map, and the entity it has become\n *\n * @beta\n */\nexport interface FromMapObject {\n\t/** The entity that was placed on the map and has become this entity */\n\treadonly entity: Entity\n\t/** As the map has it: where, whose, its name */\n\treadonly object: Readonly<MapObject>\n\t/** The game's own fields for it (see `defineMapField`), with what was not set at its default */\n\treadonly data: Readonly<Record<string, unknown>>\n}\n\n/**\n * A camp that was placed on a map, and the camp it has become\n *\n * @beta\n */\nexport interface FromMapCamp {\n\t/** The camp in the world that the map's camp has become */\n\treadonly camp: Camp\n\t/** The camp as the map has it: where, its units */\n\treadonly from: Readonly<MapCamp>\n\t/** The game's own fields for camps, see `FromMapObject.data` */\n\treadonly data: Readonly<Record<string, unknown>>\n}\n\n/**\n * Something that has died, before it leaves the world: whether it stays (`stays`), out of the world, in the world's\n * entities, to be brought back. No when nothing says so; the heroes pack says yes for a hero (`heroesPack`), and a\n * handler after it (a higher `priority`) can say no for a game where heroes fall for good\n *\n * @beta\n */\nexport interface FallenHero {\n\t/** What died */\n\treadonly entity: Entity\n\t/** What killed it, when something did */\n\treadonly killer?: Entity\n\t/** Whether it stays, out of the world, to be brought back: no, unless a handler says yes */\n\tstays: boolean\n}\n\n/**\n * A region of a map, and the area it has become\n *\n * @beta\n */\nexport interface FromMapRegion {\n\t/** The area of the world that the map's region has become */\n\treadonly area: AreaDef\n\t/** The region as the map has it: its name and shape */\n\treadonly region: Readonly<MapRegion>\n\t/** The game's own fields for regions, see `FromMapObject.data` */\n\treadonly data: Readonly<Record<string, unknown>>\n}\n\n/**\n * A world made from a map, everything the map places in it there and every race's start done: what a pack or the game\n * starts of its own from the map's data, as the map objectives pack gives the objectives a map gives at the start\n * (`mapObjectives`). Not for a world loaded from a save, which has them already\n *\n * @beta\n */\nexport interface FromMap {\n\t/** The map it was made from */\n\treadonly map: Readonly<GameMap>\n}\n\n/**\n * The map of hooks the engine runs, by name, to the event each one hands its handlers\n *\n * @beta\n */\nexport interface HookEvents {\n\t/** Its handlers get a `BeforeDamage`: damage about to be dealt, before armor and shields. Change `amount` or `type`, or `cancel()` */\n\tbeforeDamage: BeforeDamage\n\t/** Its handlers get a `AfterDamage`: damage that was dealt. The target may have died of it */\n\tafterDamage: AfterDamage\n\t/** Its handlers get a `BeforeHeal`: health about to be given back. Change `amount`, or `cancel()` */\n\tbeforeHeal: BeforeHeal\n\t/** Its handlers get a `BeforeDeath`: something is about to die. `cancel()` keeps it alive: it is then up to the handler what health it has */\n\tbeforeDeath: BeforeDeath\n\t/** Its handlers get a `Death`: something dies. In `death` it still stands where it was; in `afterDeath` it is gone from the world */\n\tdeath: Death\n\t/** Its handlers get a `Death`: something dies. In `death` it still stands where it was; in `afterDeath` it is gone from the world */\n\tafterDeath: Death\n\t/** Whether what died stays in the world's entities, out of the world, to be brought back (`FallenHero`). @beta */\n\tfallenHero: FallenHero\n\t/**\n\t * Something just made, its type's parts set (abilities, an inventory, an attack), not in the world yet: what a pack\n\t * gives it of its own, as the heroes pack makes a hero of a hero's type (`makeHero`) and stocks a shop. @beta\n\t */\n\tmade: Entity\n\t/** Something became another type where it stands (`morph`): what a pack gives it of its own for the new type (`Morphed`). @beta */\n\tmorphed: Morphed\n\t/** Something came into the world, and is in it now */\n\tspawn: Entity\n\t/** Something left the world for good, at the end of the tick it died in */\n\tremove: Entity\n\t/** Its handlers get a `BeforeOrder`: an order about to be given to a unit. Set `rejected` to refuse it */\n\tbeforeOrder: BeforeOrder\n\t/** Its handlers get a `TargetScore`: how much a unit wants to attack something, as it looks for a target by itself. Higher is picked first: raise or lower `score`, or make it `-Infinity` to pass the target over. Towers... */\n\ttargetScore: TargetScore\n\t/** Its handlers get a `Approach`: where an attacker goes to fight a target from: its spot around it (see `engagement.ts`), or the target itself, in `point`, to change. A flank for cavalry, behind for assassins. Asked... */\n\tapproach: Approach\n\t/** Its handlers get a `MakeWay`: an ally standing in a unit's way is asked to step aside, to `point` (see `RuleSettings.movement.makesWay`, `lookAhead`): change where it goes, or make it null to leave it standing.... */\n\tmakeWay: MakeWay\n\t/** Its handlers get a `Detour`: a unit is about to go round units standing in its way (`around`), by `point`, which is `longer` ground units more than the `straight` way to the next corner of its path (see `RuleSettings.movement.goesAround`):... */\n\tdetour: Detour\n\t/** Its handlers get a `Formation`: units ordered to a point together have their places in a formation worked out (`FormationDef`, `formationPoints`): change any in `points`, by the unit's id, or add or remove some. `units`... */\n\tformation: Formation\n\t/** Its handlers get a `CanPlace`: whether a structure may be placed. `cancel(reason)` refuses it, with what the player is told */\n\tcanPlace: CanPlace\n\t/** Its handlers get a `BeforeCast`: an ability about to go off, before it is paid for. Change what it costs, or call it off with a `reason`. Whether the caster has the mana was already checked against the ability's own... */\n\tbeforeCast: BeforeCast\n\t/** Its handlers get a `AfterCast`: an ability that went off */\n\tafterCast: AfterCast\n\t/** Its handlers get a `BeforeBuff`: a buff about to be put on, or put on again. Change how long it lasts or how strong it is, or call it off (immunity) */\n\tbeforeBuff: BeforeBuff\n\t/** Its handlers get a `BuffEnd`: a buff that came off: it ran out (`expired`), or was taken off. Not called for the buffs of something that dies */\n\tbuffEnd: BuffEnd\n\t/** Its handlers get a `BeforeProduce`: something about to be made: a unit trained, an upgrade researched, a building upgraded, a hero brought back, a structure put down by a worker. Change what it costs and how long it takes,... */\n\tbeforeProduce: BeforeProduce\n\t/** Its handlers get a `Idle`: a unit with nothing to do, this tick: no orders. Set `handled` and do what it does instead of what idle units do (fight back, go for enemies that come close, which is only for those... */\n\tidle: Idle\n\t/** Its handlers get a `CanAttack`: whether an attacker may attack a target: what the engine makes of it (its attack's targets, whether they are enemies) is in `cancelled`, to change. A buff that lets a unit hit what... */\n\tcanAttack: CanAttack\n\t/** Its handlers get a `BeforeAttack`: an attack going off, as the engine has it: change what it does, or call it off. `target` is left out for an attack at the ground. `splash` is the radius of an attack that hits an area;... */\n\tbeforeAttack: BeforeAttack\n\t/** Its handlers get a `StatsHook`: the stats of an entity being added up, once what the engine knows of (its type, levels, research, items, buffs) is in: `add` more, as a stat change (`{ stats: { armor: 2 } }`, `{ percent:... */\n\tstats: StatsHook\n\t/** Its handlers get a `CanCast`: whether an ability can be used now: what the engine makes of it (level, cooldown, mana, silence) is `cancelled` with its `reason`: `cancelled = false` clears it (\"free while Clearcasting\"),... */\n\tcanCast: CanCast\n\t/** Its handlers get a `CanTarget`: whether an ability may be used on a target: what the engine makes of it (the ability's `targets`) is `cancelled`, with its `reason`: `cancelled = false` to clear (\"can target allied... */\n\tcanTarget: CanTarget\n\t/** An effect about to reach one target: cancel it for that one (`BeforeEffect`). @beta */\n\tbeforeEffect: BeforeEffect\n\t/** An effect reached one target, its handler done (`EffectLanded`). @beta */\n\teffectLanded: EffectLanded\n\t/** Its handlers get a `Visible`: whether a team sees an entity of someone else's: what the fog and invisibility make of it in `visible`, to change. Units in brush seen only from up close; a watchtower. Asked very often: keep it cheap */\n\tvisible: Visible\n\t/** Its handlers get a `Requirement`: whether a player may make something, as far as what it requires goes: a unit, a level of research (`level`), what a building upgrades to, a structure. What the engine makes of it (the... */\n\trequirement: Requirement\n\t/** Its handlers get a `Available`: whether a player may make a unit type or research an upgrade at all, before what it requires (see `isAvailable`): by default (`available`), what is of no race or of theirs (`race`).... */\n\tavailable: Available\n\t/** Its handlers get a `BeforeDeposit`: resources a worker hands in: change `amount` (more from mines near the keep), or call it off */\n\tbeforeDeposit: BeforeDeposit\n\t/** Its handlers get a `CanHarvest`: whether a worker may gather from a resource: by default, a resource of a kind it gathers (`harvester.ids`). Refuse it for a game's own rule: a mine only its owner's cursed mine stands... */\n\tcanHarvest: CanHarvest\n\t/** Its handlers get a `BeforeTalk`: a player about to ping the map or say a line (see `ping`, `chat`): change the words (`text`) or who hears them (`to`), or call it off: a muted player, a word filter, no talking in a... */\n\tbeforeTalk: BeforeTalk\n\t/** Its handlers get a `BeforeTrade`: resources about to be given to an ally (see `give`): change how much arrives (`received`), or call it off with a `reason`: no trading in the first minutes, a cap on what goes to one player */\n\tbeforeTrade: BeforeTrade\n\t/** Its handlers get a `BeforeSurrender`: a player is about to give up (see `surrender`): call it off with a `reason`, as a game that does not let them before a time */\n\tbeforeSurrender: BeforeSurrender\n\t/** Its handlers get a `SupplyCap`: a player's cap of a pool of supply, once what their buildings provide is added up (see the supply system): change `cap` (a starting amount, an upgrade, a rule of the game's own). The... */\n\tsupplyCap: SupplyCap\n\t/** Its handlers get a `BeforePause`: a player asks for a pause (see `askPause`): how many they have left before this one (`left`), and how long it lasts at most (`seconds`, which can be changed); call it off with a `reason` */\n\tbeforePause: BeforePause\n\t/** Its handlers get a `BeforeBuy`: an item about to be bought at a shop: change what it costs, or call it off with a `reason` */\n\tbeforeBuy: BeforeBuy\n\t/** Its handlers get a `BeforePickUp`: an item about to be picked up off the ground (`ground` its id there): call it off with a `reason` */\n\tbeforePickUp: BeforePickUp\n\t/** Its handlers get a `BeforeDrop`: an item about to be put down: call it off with a `reason` (a cursed blade) */\n\tbeforeDrop: BeforeDrop\n\t/** Its handlers get a `BeforeXp`: experience about to go to a hero: change `amount` (the killer gets more), or make it 0. `from` is what was killed, when that is where it comes from */\n\tbeforeXp: BeforeXp\n\t/** Its handlers get a `CanLearn`: whether a hero may put a point into an ability: what the engine makes of it in `cancelled`, to change. The screen hears of it with what the hero can learn */\n\tcanLearn: CanLearn\n\t/** Its handlers get a `Produced`: something was made: a unit trained (`unit`), research done (`level`), a building upgraded, a hero brought back */\n\tproduced: Produced\n\t/** Something placed on a map has become an entity, as the world is made from the map: what the game does with its own fields */\n\tmapObject: FromMapObject\n\t/** A camp placed on a map is in the world, see `mapObject` */\n\tmapCamp: FromMapCamp\n\t/** A region of a map is an area of the world, see `mapObject` */\n\tmapRegion: FromMapRegion\n\t/** The world made from a map is all there, about to start (`FromMap`): what a pack starts from the map's own data. @beta */\n\tmapStart: FromMap\n}\n\n/**\n * The name of one of the engine's hooks, a key of `HookEvents`\n *\n * @beta\n */\nexport type HookName = keyof HookEvents\n\n/**\n * The function a handler for the hook `K` is, taking the world and the hook's event\n *\n * @beta\n */\nexport type HookHandler<K extends HookName> = (world: World, event: HookEvents[K]) => void\n\n/**\n * A hook of a game's own, made with `defineHookType`: a moment of its rules others can take part in, the way the\n * engine's hooks are for its own\n *\n * @beta\n */\nexport interface HookKey<T> {\n\t/** The hook's id, shared by every game, which `Hooks` lists it by */\n\treadonly id: string\n\t/** Only there for the type of the event */\n\treadonly event?: T\n}\n\n/**\n * A hook of a game's own: `const lifeLost = defineHookType<{ invader: Entity; lives: number } & Cancellable>({ id: 'td.lifeLost' })`.\n * The game runs it where the moment is (`world.hooks.run(lifeLost, { ... })`) and reads back what the handlers made\n * of the event; handlers are written with `defineHook({ hook: lifeLost, ... })`, by the game or by a mod on it.\n * Ids are shared by every game: give them a prefix of the game's\n *\n * @beta\n */\nexport function defineHookType<T>(def: { id: string }): HookKey<T> {\n\treturn { id: def.id }\n}\n\n/**\n * A hook: one of the engine's by name, or a game's own\n *\n * @beta\n */\nexport type AnyHook = HookName | HookKey<any>\n\n/**\n * What a hook that may be stopped carries: `cancel(reason?)` stops it, `cancelled` says whether it was, and `reason` is\n * what the player is told, for the hooks that tell them (`canPlace`, `canHarvest`, `canCast`, `canTarget`,\n * `requirement`). The engine's own refusal comes in as `cancelled` already true, with its `reason`: `cancelled = false`\n * lets it through\n *\n * @beta\n */\nexport interface Cancellable {\n\t/** Whether a handler has stopped the event; `cancel()` sets it */\n\tcancelled: boolean\n\t/** What the player is told of why it was stopped, for the hooks that tell them */\n\treason?: MessageRef\n\t/** Stops the event, with the `reason` the player is told when given */\n\tcancel(reason?: MessageRef): void\n}\n\n/** An event of a hook that may be stopped, as whoever runs the hook puts it together: `cancel` is given as it runs (`Hooks.run`) @beta */\nexport type Uncancelled<T> = T extends Cancellable ? Omit<T, 'cancel'> & { cancel?: Cancellable['cancel'] } : T\n\n/** What `cancellable` gives an event: one function and one description for all, so that a hook run makes neither */\nconst CANCEL: PropertyDescriptor = {\n\tvalue(this: Cancellable, reason?: MessageRef) {\n\t\tthis.cancelled = true\n\t\tif (reason !== undefined) this.reason = reason\n\t},\n\tenumerable: false,\n\tconfigurable: true,\n\twritable: true\n}\n\n/** Gives an event `cancel` (not enumerable: a save, a snapshot or a clone leaves it out), unless it has one @internal */\nexport function cancellable<T extends { cancelled: boolean }>(event: T): T & Cancellable {\n\tif (typeof (event as { cancel?: unknown }).cancel !== 'function') Object.defineProperty(event, 'cancel', CANCEL)\n\treturn event as T & Cancellable\n}\n\n/** What a hook that tells the player refuses with: its reason, or the engine's word where a handler gave none; nothing where it lets through @beta */\nexport function refusalOf(event: { cancelled: boolean; reason?: MessageRef }): MessageRef | undefined {\n\treturn event.cancelled ? (event.reason ?? engineMessage('cannotDoThat')) : undefined\n}\n\n/**\n * A handler and the hook it is for. Its `id` is how others take it out or put something in its place\n *\n * @public\n */\nexport type HookDef = {\n\thook: AnyHook\n\tid: string\n\t/** Lower runs first. 0 when left out; handlers with the same priority run in the order they were added */\n\tpriority?: number\n\trun: (world: World, event: any) => void\n}\n\n/**\n * Typed help for writing a hook: `defineHook({ hook: 'death', id: 'bounty', run(world, { entity }) { ... } })`\n *\n * @public\n */\nexport function defineHook<K extends HookName>(def: { hook: K; id: string; priority?: number; run: HookHandler<K> }): HookDef\n/**\n * Typed help for a handler of a game's own hook (`HookKey`), taking the world and the hook's event\n *\n * @public\n */\nexport function defineHook<T>(def: { hook: HookKey<T>; id: string; priority?: number; run: (world: World, event: T) => void }): HookDef\nexport function defineHook(def: HookDef): HookDef {\n\treturn def\n}\n\n/** The name a hook goes by in the lists */\nconst nameOf = (hook: AnyHook): string => (typeof hook === 'string' ? hook : hook.id)\n\ninterface Entry {\n\tid: string\n\tpriority: number\n\trun: (world: World, event: never) => void\n}\n\n/**\n * The handlers of every hook of one world\n *\n * @beta\n */\nexport class Hooks {\n\tprivate readonly lists = new Map<string, Entry[]>()\n\n\tconstructor(private readonly world: World) {}\n\n\t/** Adds a handler. One with the same id on the same hook is replaced */\n\tadd(def: HookDef): void {\n\t\tconst name = nameOf(def.hook)\n\t\tlet list = this.lists.get(name)\n\t\tif (!list) this.lists.set(name, (list = []))\n\t\tconst index = list.findIndex((entry) => entry.id === def.id)\n\t\tconst entry: Entry = { id: def.id, priority: def.priority ?? 0, run: def.run as Entry['run'] }\n\t\tif (index >= 0) list[index] = entry\n\t\telse list.push(entry)\n\t\t// a stable sort: equal priorities keep the order they were added in\n\t\tlist.sort((a, b) => a.priority - b.priority)\n\t}\n\n\t/** Takes the handler with the id off the hook; nothing happens when there is none */\n\tremove(hook: AnyHook, id: string): void {\n\t\tconst list = this.lists.get(nameOf(hook))\n\t\tconst index = list?.findIndex((entry) => entry.id === id) ?? -1\n\t\tif (index >= 0) list!.splice(index, 1)\n\t}\n\n\t/** Whether a hook has any handlers. For hooks run very often, to not even put the event together when nobody listens */\n\thas(hook: AnyHook): boolean {\n\t\treturn (this.lists.get(nameOf(hook))?.length ?? 0) > 0\n\t}\n\n\t/** Ids of the handlers of a hook, in the order they run */\n\thandlers(hook: AnyHook): string[] {\n\t\treturn (this.lists.get(nameOf(hook)) ?? []).map((entry) => entry.id)\n\t}\n\n\t/** Runs the handlers of a hook on the event, in order, and hands the event back for the caller to read */\n\trun<K extends HookName>(hook: K, event: Uncancelled<HookEvents[K]>): HookEvents[K]\n\t/** Runs the handlers of a game's own hook on the event in order and returns the event */\n\trun<T>(hook: HookKey<T>, event: Uncancelled<T>): T\n\trun(hook: AnyHook, event: unknown): unknown {\n\t\tconst list = this.lists.get(nameOf(hook))\n\t\tif (!list) return event\n\t\t// a hook that may be stopped carries `cancel`, whoever put the event together\n\t\tif (typeof event === 'object' && event !== null && 'cancelled' in event) cancellable(event as { cancelled: boolean })\n\t\tconst name = nameOf(hook)\n\t\tthis.world.trace?.hook(name, list, typeof hook !== 'string', event)\n\t\tfor (let i = 0; i < list.length; i++) {\n\t\t\tconst entry = list[i]\n\t\t\ttry {\n\t\t\t\t;(entry.run as (world: World, event: unknown) => void)(this.world, event)\n\t\t\t} catch (error) {\n\t\t\t\t// what the world says of errors (`World.caught`): it throws, or the handler is switched off and the rest run\n\t\t\t\tthis.world.caught(error, { kind: 'hook', id: entry.id, hook: name })\n\t\t\t\tconst at = list.indexOf(entry)\n\t\t\t\tif (at >= 0) list.splice(at, 1)\n\t\t\t\ti = Math.min(i, at) - 1\n\t\t\t}\n\t\t}\n\t\treturn event\n\t}\n}\n"],"mappings":";;;;;;;;;;AAkgCA,SAAgB,eAAkB,KAAiC;CAClE,OAAO,EAAE,IAAI,IAAI,GAAG;AACrB;;AA8BA,IAAM,SAA6B;CAClC,MAAyB,QAAqB;EAC7C,KAAK,YAAY;EACjB,IAAI,WAAW,KAAA,GAAW,KAAK,SAAS;CACzC;CACA,YAAY;CACZ,cAAc;CACd,UAAU;AACX;;AAGA,SAAgB,YAA8C,OAA2B;CACxF,IAAI,OAAQ,MAA+B,WAAW,YAAY,OAAO,eAAe,OAAO,UAAU,MAAM;CAC/G,OAAO;AACR;;AAGA,SAAgB,UAAU,OAA4E;CACrG,OAAO,MAAM,YAAa,MAAM,UAAU,cAAc,cAAc,IAAK,KAAA;AAC5E;AA2BA,SAAgB,WAAW,KAAuB;CACjD,OAAO;AACR;;AAGA,IAAM,UAAU,SAA2B,OAAO,SAAS,WAAW,OAAO,KAAK;;;;;;AAalF,IAAa,QAAb,MAAmB;CAGW;CAF7B,wBAAyB,IAAI,IAAqB;CAElD,YAAY,OAA+B;EAAd,KAAA,QAAA;CAAe;;CAG5C,IAAI,KAAoB;EACvB,MAAM,OAAO,OAAO,IAAI,IAAI;EAC5B,IAAI,OAAO,KAAK,MAAM,IAAI,IAAI;EAC9B,IAAI,CAAC,MAAM,KAAK,MAAM,IAAI,MAAO,OAAO,CAAC,CAAE;EAC3C,MAAM,QAAQ,KAAK,WAAW,UAAU,MAAM,OAAO,IAAI,EAAE;EAC3D,MAAM,QAAe;GAAE,IAAI,IAAI;GAAI,UAAU,IAAI,YAAY;GAAG,KAAK,IAAI;EAAoB;EAC7F,IAAI,SAAS,GAAG,KAAK,SAAS;OACzB,KAAK,KAAK,KAAK;EAEpB,KAAK,MAAM,GAAG,MAAM,EAAE,WAAW,EAAE,QAAQ;CAC5C;;CAGA,OAAO,MAAe,IAAkB;EACvC,MAAM,OAAO,KAAK,MAAM,IAAI,OAAO,IAAI,CAAC;EACxC,MAAM,QAAQ,MAAM,WAAW,UAAU,MAAM,OAAO,EAAE,KAAK;EAC7D,IAAI,SAAS,GAAG,KAAM,OAAO,OAAO,CAAC;CACtC;;CAGA,IAAI,MAAwB;EAC3B,QAAQ,KAAK,MAAM,IAAI,OAAO,IAAI,CAAC,CAAC,EAAE,UAAU,KAAK;CACtD;;CAGA,SAAS,MAAyB;EACjC,QAAQ,KAAK,MAAM,IAAI,OAAO,IAAI,CAAC,KAAK,CAAC,EAAA,CAAG,KAAK,UAAU,MAAM,EAAE;CACpE;CAMA,IAAI,MAAe,OAAyB;EAC3C,MAAM,OAAO,KAAK,MAAM,IAAI,OAAO,IAAI,CAAC;EACxC,IAAI,CAAC,MAAM,OAAO;EAElB,IAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,eAAe,OAAO,YAAY,KAA+B;EACpH,MAAM,OAAO,OAAO,IAAI;EACxB,KAAK,MAAM,OAAO,KAAK,MAAM,MAAM,OAAO,SAAS,UAAU,KAAK;EAClE,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;GACrC,MAAM,QAAQ,KAAK;GACnB,IAAI;IACF,MAAO,IAA+C,KAAK,OAAO,KAAK;GACzE,SAAS,OAAO;IAEf,KAAK,MAAM,OAAO,OAAO;KAAE,MAAM;KAAQ,IAAI,MAAM;KAAI,MAAM;IAAK,CAAC;IACnE,MAAM,KAAK,KAAK,QAAQ,KAAK;IAC7B,IAAI,MAAM,GAAG,KAAK,OAAO,IAAI,CAAC;IAC9B,IAAI,KAAK,IAAI,GAAG,EAAE,IAAI;GACvB;EACD;EACA,OAAO;CACR;AACD"}
|
package/dist/hotReload.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type Rules } from './game';
|
|
2
2
|
import type { ModDef } from './mods';
|
|
3
3
|
import type { World } from './world';
|
|
4
4
|
/**
|
|
@@ -19,13 +19,14 @@ export declare const gameReloaded: import("./events").EventKey<{
|
|
|
19
19
|
*
|
|
20
20
|
* @beta
|
|
21
21
|
*/
|
|
22
|
-
export declare function reloadGame(world: World, game:
|
|
22
|
+
export declare function reloadGame(world: World, game: Rules): void;
|
|
23
23
|
/**
|
|
24
24
|
* What a module's `import.meta.hot` gives for hot reload, as Vite has it: what loads the page again
|
|
25
25
|
*
|
|
26
26
|
* @beta
|
|
27
27
|
*/
|
|
28
28
|
export interface HotContext {
|
|
29
|
+
/** Asks Vite to load the page again, with the reason given; called when a new module cannot be taken by the running game */
|
|
29
30
|
invalidate(message?: string): void;
|
|
30
31
|
}
|
|
31
32
|
/**
|
|
@@ -33,7 +34,7 @@ export interface HotContext {
|
|
|
33
34
|
*
|
|
34
35
|
* @beta
|
|
35
36
|
*/
|
|
36
|
-
export declare function onNewGameVersion(listener: (game:
|
|
37
|
+
export declare function onNewGameVersion(listener: (game: Rules) => void): () => void;
|
|
37
38
|
/**
|
|
38
39
|
* Hears of every new version of a mod taken in the page (`hotMod`). Returns what stops it
|
|
39
40
|
*
|
|
@@ -71,6 +72,6 @@ export declare function replaceIn(current: object, next: object): void;
|
|
|
71
72
|
* running world keeps as it was made (its `systems`, `hooks`, `components`, `resources`, and `withoutSystems` and
|
|
72
73
|
* `withoutHooks`, compared by their code and values). No client is pulled into the rules, which a server reads too
|
|
73
74
|
*
|
|
74
|
-
* @
|
|
75
|
+
* @public
|
|
75
76
|
*/
|
|
76
|
-
export declare function hotRules(hot: HotContext | undefined, current:
|
|
77
|
+
export declare function hotRules(hot: HotContext | undefined, current: Rules, next: unknown): void;
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { defineEngineEvent } from "./events.js";
|
|
2
|
+
import { rootLogger } from "./log.js";
|
|
3
|
+
import { redefinitions, restoreRedefinitions } from "./gameData.js";
|
|
4
|
+
import { createRegistry } from "./game.js";
|
|
5
|
+
//#region src/hotReload.ts
|
|
6
|
+
/**
|
|
7
|
+
* A world took a new version of its game while it ran (`reloadGame`, hot reload): what the rules hear
|
|
8
|
+
* (`world.events.on(gameReloaded, …)`), and every screen (`GameView.on`), to make again what it made of the old one
|
|
9
|
+
*
|
|
10
|
+
* @beta
|
|
11
|
+
*/
|
|
12
|
+
var gameReloaded = defineEngineEvent({
|
|
13
|
+
id: "core.gameReloaded",
|
|
14
|
+
replicate: "everyone"
|
|
15
|
+
});
|
|
16
|
+
/**
|
|
17
|
+
* Puts a new version of a world's game into it while it runs, as a game's files are saved during development (hot
|
|
18
|
+
* reload): its unit types, abilities, buffs, items, upgrades and races, the code of their effects and of its orders,
|
|
19
|
+
* and its rules. What `world.redefine` changed while it ran stays over them, and its units take their types as they
|
|
20
|
+
* are now. What the world was made of otherwise (its systems, hooks, components, resources) is not: a change to those
|
|
21
|
+
* wants a new game, which is said (`hotRules` loads the page again for one). Throws for another game, or a module that is no game (as `createRegistry`)
|
|
22
|
+
*
|
|
23
|
+
* @beta
|
|
24
|
+
*/
|
|
25
|
+
function reloadGame(world, game) {
|
|
26
|
+
const { registry } = world;
|
|
27
|
+
if (game.id !== registry.game) throw new Error(`The world plays "${registry.game}", not "${game.id}"`);
|
|
28
|
+
registry.takeFrom(createRegistry(game));
|
|
29
|
+
if (world.states.has(redefinitions)) restoreRedefinitions(registry, world.state(redefinitions));
|
|
30
|
+
world.retype();
|
|
31
|
+
world.score.listen();
|
|
32
|
+
try {
|
|
33
|
+
game.onReload?.(world);
|
|
34
|
+
} catch (error) {
|
|
35
|
+
world.log.error("game", `${game.id}'s onReload threw: ${error instanceof Error ? error.message : String(error)}`);
|
|
36
|
+
}
|
|
37
|
+
world.log.info("game", `Took a new version of ${game.name ?? game.id}: its definitions and rules (its systems and hooks are the game's as it began)`);
|
|
38
|
+
world.events.emit(gameReloaded, { game: game.id });
|
|
39
|
+
}
|
|
40
|
+
/** What of a game a running world keeps as it was made (`reloadGame`): a new version that changes any loads the page again */
|
|
41
|
+
var NOT_RELOADED = [
|
|
42
|
+
"systems",
|
|
43
|
+
"withoutSystems",
|
|
44
|
+
"hooks",
|
|
45
|
+
"withoutHooks",
|
|
46
|
+
"components",
|
|
47
|
+
"resources"
|
|
48
|
+
];
|
|
49
|
+
/**
|
|
50
|
+
* What a part of a game is, in words, to tell a new version's from the old: its code by its source, its data by its
|
|
51
|
+
* values, so that a module evaluated again with the same code is the same
|
|
52
|
+
*/
|
|
53
|
+
function shapeOf(value, depth = 0, seen = /* @__PURE__ */ new Set()) {
|
|
54
|
+
if (typeof value === "function") return `f:${String(value)}`;
|
|
55
|
+
if (value === null || typeof value !== "object") return value === void 0 ? "u" : JSON.stringify(value);
|
|
56
|
+
if (seen.has(value) || depth > 8) return "…";
|
|
57
|
+
seen.add(value);
|
|
58
|
+
const shape = Array.isArray(value) ? `[${value.map((each) => shapeOf(each, depth + 1, seen)).join(",")}]` : `{${Object.keys(value).sort().map((key) => `${key}:${shapeOf(value[key], depth + 1, seen)}`).join(",")}}`;
|
|
59
|
+
seen.delete(value);
|
|
60
|
+
return shape;
|
|
61
|
+
}
|
|
62
|
+
/** Who hears of a new version of a game's rules or of a mod: the client, which tells the games and editors of the page */
|
|
63
|
+
var listeners = /* @__PURE__ */ new Set();
|
|
64
|
+
var modListeners = /* @__PURE__ */ new Set();
|
|
65
|
+
/**
|
|
66
|
+
* Hears of every new version of a game's rules taken in the page (`hotRules`). Returns what stops it
|
|
67
|
+
*
|
|
68
|
+
* @beta
|
|
69
|
+
*/
|
|
70
|
+
function onNewGameVersion(listener) {
|
|
71
|
+
listeners.add(listener);
|
|
72
|
+
return () => listeners.delete(listener);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Hears of every new version of a mod taken in the page (`hotMod`). Returns what stops it
|
|
76
|
+
*
|
|
77
|
+
* @beta
|
|
78
|
+
*/
|
|
79
|
+
function onNewModVersion(listener) {
|
|
80
|
+
modListeners.add(listener);
|
|
81
|
+
return () => modListeners.delete(listener);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* A mod's module's new version, taken while it runs (hot reload), as `hotRules` takes a game's: at its end,
|
|
85
|
+
*
|
|
86
|
+
* if (import.meta.hot) import.meta.hot.accept((module) => hotMod(import.meta.hot, goldRush, module?.goldRush))
|
|
87
|
+
*
|
|
88
|
+
* The mod given is made the new one in place, and every game of the page played with it is made again of its parts as
|
|
89
|
+
* they are now (`recompose`) and takes that. What does not go (no new module, another mod, mods that no longer go
|
|
90
|
+
* together) loads the page again
|
|
91
|
+
*
|
|
92
|
+
* @beta
|
|
93
|
+
*/
|
|
94
|
+
function hotMod(hot, current, next) {
|
|
95
|
+
const mod = next;
|
|
96
|
+
if (!mod || typeof mod !== "object" || mod.id !== current.id) return hot?.invalidate(`${current.id}: its module is not there as it was`);
|
|
97
|
+
try {
|
|
98
|
+
replaceIn(current, mod);
|
|
99
|
+
for (const listener of modListeners) listener(current);
|
|
100
|
+
} catch (error) {
|
|
101
|
+
rootLogger.warn("game", `The mod ${current.id}'s new version could not be taken while it runs: the page loads again`, { error: String(error) });
|
|
102
|
+
hot?.invalidate();
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Puts what `next` has into `current`, in its place: everything that holds `current` has the new version
|
|
107
|
+
*
|
|
108
|
+
* @beta
|
|
109
|
+
*/
|
|
110
|
+
function replaceIn(current, next) {
|
|
111
|
+
for (const key of Object.keys(current)) if (!(key in next)) delete current[key];
|
|
112
|
+
Object.assign(current, next);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* A game's entry module's new version, taken while it runs (hot reload). At the module's end, the call to Vite written
|
|
116
|
+
* out as it is (Vite finds a module that takes its own new versions by it):
|
|
117
|
+
*
|
|
118
|
+
* if (import.meta.hot) import.meta.hot.accept((module) => hotRules(import.meta.hot, melee, module?.melee))
|
|
119
|
+
*
|
|
120
|
+
* As it or a file it reads (its units, its `data.json`) is saved in the dev server, the module given is made the new
|
|
121
|
+
* one in place, so that what holds it has the new one, and the games and editors of the page playing it take its
|
|
122
|
+
* definitions and rules (`reloadGame`, through `onNewGameVersion`). What does not go loads the page again, saying why
|
|
123
|
+
* (`hot.invalidate(reason)`): no new module, another game, a component defined another way, or a change to what a
|
|
124
|
+
* running world keeps as it was made (its `systems`, `hooks`, `components`, `resources`, and `withoutSystems` and
|
|
125
|
+
* `withoutHooks`, compared by their code and values). No client is pulled into the rules, which a server reads too
|
|
126
|
+
*
|
|
127
|
+
* @public
|
|
128
|
+
*/
|
|
129
|
+
function hotRules(hot, current, next) {
|
|
130
|
+
const game = next;
|
|
131
|
+
if (!game || typeof game !== "object" || game.id !== current.id) return hot?.invalidate(`${current.id}: its module is not there as it was`);
|
|
132
|
+
const kept = NOT_RELOADED.filter((key) => shapeOf(current[key]) !== shapeOf(game[key]));
|
|
133
|
+
if (kept.length) return hot?.invalidate(`${current.id}: its ${kept.join(", ")} changed, which a running game does not take`);
|
|
134
|
+
try {
|
|
135
|
+
replaceIn(current, game);
|
|
136
|
+
for (const listener of listeners) listener(current);
|
|
137
|
+
} catch (error) {
|
|
138
|
+
rootLogger.warn("game", `${current.id}'s new version could not be taken while it runs: the page loads again`, { error: String(error) });
|
|
139
|
+
hot?.invalidate();
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
//#endregion
|
|
143
|
+
export { gameReloaded, hotMod, hotRules, onNewGameVersion, onNewModVersion, reloadGame, replaceIn };
|
|
144
|
+
|
|
145
|
+
//# sourceMappingURL=hotReload.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hotReload.js","names":[],"sources":["../src/hotReload.ts"],"sourcesContent":["import { defineEngineEvent } from './events'\nimport { createRegistry, type Rules } from './game'\nimport { redefinitions, restoreRedefinitions } from './gameData'\nimport { rootLogger } from './log'\nimport type { ModDef } from './mods'\nimport type { World } from './world'\n\n/**\n * A world took a new version of its game while it ran (`reloadGame`, hot reload): what the rules hear\n * (`world.events.on(gameReloaded, …)`), and every screen (`GameView.on`), to make again what it made of the old one\n *\n * @beta\n */\nexport const gameReloaded = defineEngineEvent<{ game: string }>({ id: 'core.gameReloaded', replicate: 'everyone' })\n\n/**\n * Puts a new version of a world's game into it while it runs, as a game's files are saved during development (hot\n * reload): its unit types, abilities, buffs, items, upgrades and races, the code of their effects and of its orders,\n * and its rules. What `world.redefine` changed while it ran stays over them, and its units take their types as they\n * are now. What the world was made of otherwise (its systems, hooks, components, resources) is not: a change to those\n * wants a new game, which is said (`hotRules` loads the page again for one). Throws for another game, or a module that is no game (as `createRegistry`)\n *\n * @beta\n */\nexport function reloadGame(world: World, game: Rules): void {\n\tconst { registry } = world\n\tif (game.id !== registry.game) throw new Error(`The world plays \"${registry.game}\", not \"${game.id}\"`)\n\tregistry.takeFrom(createRegistry(game))\n\t// what was changed while it ran, over the new version (looked at, not made: a world nothing was changed of has none)\n\tif (world.states.has(redefinitions)) restoreRedefinitions(registry, world.state(redefinitions))\n\tworld.retype()\n\t// the score's stats, as the new version counts them\n\tworld.score.listen()\n\t// what the game does of its own as it takes a new version: what it made of the old one, made again\n\ttry {\n\t\tgame.onReload?.(world)\n\t} catch (error) {\n\t\tworld.log.error('game', `${game.id}'s onReload threw: ${error instanceof Error ? error.message : String(error)}`)\n\t}\n\tworld.log.info(\n\t\t'game',\n\t\t`Took a new version of ${game.name ?? game.id}: its definitions and rules (its systems and hooks are the game's as it began)`\n\t)\n\tworld.events.emit(gameReloaded, { game: game.id })\n}\n\n/**\n * What a module's `import.meta.hot` gives for hot reload, as Vite has it: what loads the page again\n *\n * @beta\n */\nexport interface HotContext {\n\t/** Asks Vite to load the page again, with the reason given; called when a new module cannot be taken by the running game */\n\tinvalidate(message?: string): void\n}\n\n/** What of a game a running world keeps as it was made (`reloadGame`): a new version that changes any loads the page again */\nconst NOT_RELOADED = [\n\t'systems',\n\t'withoutSystems',\n\t'hooks',\n\t'withoutHooks',\n\t'components',\n\t'resources'\n] as const satisfies readonly (keyof Rules)[]\n\n/**\n * What a part of a game is, in words, to tell a new version's from the old: its code by its source, its data by its\n * values, so that a module evaluated again with the same code is the same\n */\nfunction shapeOf(value: unknown, depth = 0, seen = new Set<object>()): string {\n\tif (typeof value === 'function') return `f:${String(value)}`\n\tif (value === null || typeof value !== 'object') return value === undefined ? 'u' : JSON.stringify(value)\n\tif (seen.has(value) || depth > 8) return '…'\n\tseen.add(value)\n\tconst shape = Array.isArray(value)\n\t\t? `[${value.map((each) => shapeOf(each, depth + 1, seen)).join(',')}]`\n\t\t: `{${Object.keys(value)\n\t\t\t\t.sort()\n\t\t\t\t.map((key) => `${key}:${shapeOf((value as Record<string, unknown>)[key], depth + 1, seen)}`)\n\t\t\t\t.join(',')}}`\n\tseen.delete(value)\n\treturn shape\n}\n\n/** Who hears of a new version of a game's rules or of a mod: the client, which tells the games and editors of the page */\nconst listeners = new Set<(game: Rules) => void>()\nconst modListeners = new Set<(mod: ModDef) => void>()\n\n/**\n * Hears of every new version of a game's rules taken in the page (`hotRules`). Returns what stops it\n *\n * @beta\n */\nexport function onNewGameVersion(listener: (game: Rules) => void): () => void {\n\tlisteners.add(listener)\n\treturn () => listeners.delete(listener)\n}\n\n/**\n * Hears of every new version of a mod taken in the page (`hotMod`). Returns what stops it\n *\n * @beta\n */\nexport function onNewModVersion(listener: (mod: ModDef) => void): () => void {\n\tmodListeners.add(listener)\n\treturn () => modListeners.delete(listener)\n}\n\n/**\n * A mod's module's new version, taken while it runs (hot reload), as `hotRules` takes a game's: at its end,\n *\n * if (import.meta.hot) import.meta.hot.accept((module) => hotMod(import.meta.hot, goldRush, module?.goldRush))\n *\n * The mod given is made the new one in place, and every game of the page played with it is made again of its parts as\n * they are now (`recompose`) and takes that. What does not go (no new module, another mod, mods that no longer go\n * together) loads the page again\n *\n * @beta\n */\nexport function hotMod(hot: HotContext | undefined, current: ModDef, next: unknown): void {\n\tconst mod = next as ModDef | undefined\n\tif (!mod || typeof mod !== 'object' || mod.id !== current.id) return hot?.invalidate(`${current.id}: its module is not there as it was`)\n\ttry {\n\t\treplaceIn(current, mod)\n\t\tfor (const listener of modListeners) listener(current)\n\t} catch (error) {\n\t\trootLogger.warn('game', `The mod ${current.id}'s new version could not be taken while it runs: the page loads again`, { error: String(error) })\n\t\thot?.invalidate()\n\t}\n}\n\n/**\n * Puts what `next` has into `current`, in its place: everything that holds `current` has the new version\n *\n * @beta\n */\nexport function replaceIn(current: object, next: object): void {\n\tfor (const key of Object.keys(current)) if (!(key in next)) delete (current as Record<string, unknown>)[key]\n\tObject.assign(current, next)\n}\n\n/**\n * A game's entry module's new version, taken while it runs (hot reload). At the module's end, the call to Vite written\n * out as it is (Vite finds a module that takes its own new versions by it):\n *\n * if (import.meta.hot) import.meta.hot.accept((module) => hotRules(import.meta.hot, melee, module?.melee))\n *\n * As it or a file it reads (its units, its `data.json`) is saved in the dev server, the module given is made the new\n * one in place, so that what holds it has the new one, and the games and editors of the page playing it take its\n * definitions and rules (`reloadGame`, through `onNewGameVersion`). What does not go loads the page again, saying why\n * (`hot.invalidate(reason)`): no new module, another game, a component defined another way, or a change to what a\n * running world keeps as it was made (its `systems`, `hooks`, `components`, `resources`, and `withoutSystems` and\n * `withoutHooks`, compared by their code and values). No client is pulled into the rules, which a server reads too\n *\n * @public\n */\nexport function hotRules(hot: HotContext | undefined, current: Rules, next: unknown): void {\n\tconst game = next as Rules | undefined\n\tif (!game || typeof game !== 'object' || game.id !== current.id) return hot?.invalidate(`${current.id}: its module is not there as it was`)\n\t// what a running world keeps as it was made: changed, only a new game has it\n\tconst kept = NOT_RELOADED.filter((key) => shapeOf(current[key]) !== shapeOf(game[key]))\n\tif (kept.length) return hot?.invalidate(`${current.id}: its ${kept.join(', ')} changed, which a running game does not take`)\n\ttry {\n\t\treplaceIn(current, game)\n\t\tfor (const listener of listeners) listener(current)\n\t} catch (error) {\n\t\trootLogger.warn('game', `${current.id}'s new version could not be taken while it runs: the page loads again`, { error: String(error) })\n\t\thot?.invalidate()\n\t}\n}\n"],"mappings":";;;;;;;;;;;AAaA,IAAa,eAAe,kBAAoC;CAAE,IAAI;CAAqB,WAAW;AAAW,CAAC;;;;;;;;;;AAWlH,SAAgB,WAAW,OAAc,MAAmB;CAC3D,MAAM,EAAE,aAAa;CACrB,IAAI,KAAK,OAAO,SAAS,MAAM,MAAM,IAAI,MAAM,oBAAoB,SAAS,KAAK,UAAU,KAAK,GAAG,EAAE;CACrG,SAAS,SAAS,eAAe,IAAI,CAAC;CAEtC,IAAI,MAAM,OAAO,IAAI,aAAa,GAAG,qBAAqB,UAAU,MAAM,MAAM,aAAa,CAAC;CAC9F,MAAM,OAAO;CAEb,MAAM,MAAM,OAAO;CAEnB,IAAI;EACH,KAAK,WAAW,KAAK;CACtB,SAAS,OAAO;EACf,MAAM,IAAI,MAAM,QAAQ,GAAG,KAAK,GAAG,qBAAqB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAAG;CACjH;CACA,MAAM,IAAI,KACT,QACA,yBAAyB,KAAK,QAAQ,KAAK,GAAG,+EAC/C;CACA,MAAM,OAAO,KAAK,cAAc,EAAE,MAAM,KAAK,GAAG,CAAC;AAClD;;AAaA,IAAM,eAAe;CACpB;CACA;CACA;CACA;CACA;CACA;AACD;;;;;AAMA,SAAS,QAAQ,OAAgB,QAAQ,GAAG,uBAAO,IAAI,IAAY,GAAW;CAC7E,IAAI,OAAO,UAAU,YAAY,OAAO,KAAK,OAAO,KAAK;CACzD,IAAI,UAAU,QAAQ,OAAO,UAAU,UAAU,OAAO,UAAU,KAAA,IAAY,MAAM,KAAK,UAAU,KAAK;CACxG,IAAI,KAAK,IAAI,KAAK,KAAK,QAAQ,GAAG,OAAO;CACzC,KAAK,IAAI,KAAK;CACd,MAAM,QAAQ,MAAM,QAAQ,KAAK,IAC9B,IAAI,MAAM,KAAK,SAAS,QAAQ,MAAM,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,KAClE,IAAI,OAAO,KAAK,KAAK,CAAC,CACrB,KAAK,CAAC,CACN,KAAK,QAAQ,GAAG,IAAI,GAAG,QAAS,MAAkC,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,CAC3F,KAAK,GAAG,EAAE;CACd,KAAK,OAAO,KAAK;CACjB,OAAO;AACR;;AAGA,IAAM,4BAAY,IAAI,IAA2B;AACjD,IAAM,+BAAe,IAAI,IAA2B;;;;;;AAOpD,SAAgB,iBAAiB,UAA6C;CAC7E,UAAU,IAAI,QAAQ;CACtB,aAAa,UAAU,OAAO,QAAQ;AACvC;;;;;;AAOA,SAAgB,gBAAgB,UAA6C;CAC5E,aAAa,IAAI,QAAQ;CACzB,aAAa,aAAa,OAAO,QAAQ;AAC1C;;;;;;;;;;;;AAaA,SAAgB,OAAO,KAA6B,SAAiB,MAAqB;CACzF,MAAM,MAAM;CACZ,IAAI,CAAC,OAAO,OAAO,QAAQ,YAAY,IAAI,OAAO,QAAQ,IAAI,OAAO,KAAK,WAAW,GAAG,QAAQ,GAAG,oCAAoC;CACvI,IAAI;EACH,UAAU,SAAS,GAAG;EACtB,KAAK,MAAM,YAAY,cAAc,SAAS,OAAO;CACtD,SAAS,OAAO;EACf,WAAW,KAAK,QAAQ,WAAW,QAAQ,GAAG,wEAAwE,EAAE,OAAO,OAAO,KAAK,EAAE,CAAC;EAC9I,KAAK,WAAW;CACjB;AACD;;;;;;AAOA,SAAgB,UAAU,SAAiB,MAAoB;CAC9D,KAAK,MAAM,OAAO,OAAO,KAAK,OAAO,GAAG,IAAI,EAAE,OAAO,OAAO,OAAQ,QAAoC;CACxG,OAAO,OAAO,SAAS,IAAI;AAC5B;;;;;;;;;;;;;;;;AAiBA,SAAgB,SAAS,KAA6B,SAAgB,MAAqB;CAC1F,MAAM,OAAO;CACb,IAAI,CAAC,QAAQ,OAAO,SAAS,YAAY,KAAK,OAAO,QAAQ,IAAI,OAAO,KAAK,WAAW,GAAG,QAAQ,GAAG,oCAAoC;CAE1I,MAAM,OAAO,aAAa,QAAQ,QAAQ,QAAQ,QAAQ,IAAI,MAAM,QAAQ,KAAK,IAAI,CAAC;CACtF,IAAI,KAAK,QAAQ,OAAO,KAAK,WAAW,GAAG,QAAQ,GAAG,QAAQ,KAAK,KAAK,IAAI,EAAE,6CAA6C;CAC3H,IAAI;EACH,UAAU,SAAS,IAAI;EACvB,KAAK,MAAM,YAAY,WAAW,SAAS,OAAO;CACnD,SAAS,OAAO;EACf,WAAW,KAAK,QAAQ,GAAG,QAAQ,GAAG,wEAAwE,EAAE,OAAO,OAAO,KAAK,EAAE,CAAC;EACtI,KAAK,WAAW;CACjB;AACD"}
|
package/dist/ids.d.ts
CHANGED
|
@@ -11,9 +11,9 @@
|
|
|
11
11
|
* const view: GameView<TdUnit> = { units: { looks: { skeletn: ... } } } // nor does this
|
|
12
12
|
*
|
|
13
13
|
* It is a help, not a rule: plain text works wherever an id goes, and what the compiler cannot see is checked when the
|
|
14
|
-
* game is
|
|
14
|
+
* game's view is fetched in a page (the client's `loadGame`)
|
|
15
15
|
*
|
|
16
|
-
* @
|
|
16
|
+
* @public
|
|
17
17
|
*/
|
|
18
18
|
export declare function defineIds<const T extends string>(...names: T[]): {
|
|
19
19
|
readonly [K in T]: K;
|
|
@@ -21,6 +21,6 @@ export declare function defineIds<const T extends string>(...names: T[]): {
|
|
|
21
21
|
/**
|
|
22
22
|
* The ids of a list made with `defineIds`, as a type: `IdOf<typeof UNIT>`
|
|
23
23
|
*
|
|
24
|
-
* @
|
|
24
|
+
* @public
|
|
25
25
|
*/
|
|
26
26
|
export type IdOf<T extends Readonly<Record<string, string>>> = keyof T & string;
|
package/dist/ids.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
//#region src/ids.ts
|
|
2
|
+
/**
|
|
3
|
+
* Ids the compiler knows. A game's ids are text to the engine (`world.spawn('skeleton', ...)`), and a slip of the
|
|
4
|
+
* finger in one is found when the game runs, if it is found. Named once with `defineIds`, they are checked as they are
|
|
5
|
+
* written, completed by the editor, and renamed in one place:
|
|
6
|
+
*
|
|
7
|
+
* export const UNIT = defineIds('skeleton', 'runner', 'brute')
|
|
8
|
+
* export type TdUnit = IdOf<typeof UNIT> // 'skeleton' | 'runner' | 'brute'
|
|
9
|
+
*
|
|
10
|
+
* { id: UNIT.skeleton, ... } // in the unit's definition
|
|
11
|
+
* world.spawn(UNIT.skeletn, ...) // does not compile
|
|
12
|
+
* const view: GameView<TdUnit> = { units: { looks: { skeletn: ... } } } // nor does this
|
|
13
|
+
*
|
|
14
|
+
* It is a help, not a rule: plain text works wherever an id goes, and what the compiler cannot see is checked when the
|
|
15
|
+
* game's view is fetched in a page (the client's `loadGame`)
|
|
16
|
+
*
|
|
17
|
+
* @public
|
|
18
|
+
*/
|
|
19
|
+
function defineIds(...names) {
|
|
20
|
+
const out = {};
|
|
21
|
+
for (const name of names) {
|
|
22
|
+
if (name in out) throw new Error(`defineIds: "${name}" is there twice`);
|
|
23
|
+
out[name] = name;
|
|
24
|
+
}
|
|
25
|
+
return Object.freeze(out);
|
|
26
|
+
}
|
|
27
|
+
//#endregion
|
|
28
|
+
export { defineIds };
|
|
29
|
+
|
|
30
|
+
//# sourceMappingURL=ids.js.map
|
package/dist/ids.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ids.js","names":[],"sources":["../src/ids.ts"],"sourcesContent":["/**\n * Ids the compiler knows. A game's ids are text to the engine (`world.spawn('skeleton', ...)`), and a slip of the\n * finger in one is found when the game runs, if it is found. Named once with `defineIds`, they are checked as they are\n * written, completed by the editor, and renamed in one place:\n *\n * export const UNIT = defineIds('skeleton', 'runner', 'brute')\n * export type TdUnit = IdOf<typeof UNIT> // 'skeleton' | 'runner' | 'brute'\n *\n * { id: UNIT.skeleton, ... } // in the unit's definition\n * world.spawn(UNIT.skeletn, ...) // does not compile\n * const view: GameView<TdUnit> = { units: { looks: { skeletn: ... } } } // nor does this\n *\n * It is a help, not a rule: plain text works wherever an id goes, and what the compiler cannot see is checked when the\n * game's view is fetched in a page (the client's `loadGame`)\n *\n * @public\n */\nexport function defineIds<const T extends string>(...names: T[]): { readonly [K in T]: K } {\n\tconst out: Record<string, string> = {}\n\tfor (const name of names) {\n\t\tif (name in out) throw new Error(`defineIds: \"${name}\" is there twice`)\n\t\tout[name] = name\n\t}\n\treturn Object.freeze(out) as { readonly [K in T]: K }\n}\n\n/**\n * The ids of a list made with `defineIds`, as a type: `IdOf<typeof UNIT>`\n *\n * @public\n */\nexport type IdOf<T extends Readonly<Record<string, string>>> = keyof T & string\n"],"mappings":";;;;;;;;;;;;;;;;;;AAiBA,SAAgB,UAAkC,GAAG,OAAsC;CAC1F,MAAM,MAA8B,CAAC;CACrC,KAAK,MAAM,QAAQ,OAAO;EACzB,IAAI,QAAQ,KAAK,MAAM,IAAI,MAAM,eAAe,KAAK,iBAAiB;EACtE,IAAI,QAAQ;CACb;CACA,OAAO,OAAO,OAAO,GAAG;AACzB"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the game's files say, as the editor reads them: every part is optional, and what is not the shape described is
|
|
3
|
+
* passed over (a file written by hand may be wrong; it is the game's loader that says so)
|
|
4
|
+
*
|
|
5
|
+
* @beta
|
|
6
|
+
*/
|
|
7
|
+
export interface GameIdSources {
|
|
8
|
+
/** The `data.json`: definitions by kind (`units`, `abilities`, `items`, `upgrades`), the `removed` ids, `rules.resources` */
|
|
9
|
+
data?: unknown;
|
|
10
|
+
/** The `looks.json`: a look by unit type id */
|
|
11
|
+
looks?: unknown;
|
|
12
|
+
/** The `fx.json`: effects by id */
|
|
13
|
+
fx?: unknown;
|
|
14
|
+
/** The `sounds.json`: how each sound is played, by id */
|
|
15
|
+
sounds?: unknown;
|
|
16
|
+
/** The cinematics: each file's `id` and its lanes (the speakers of its dialog); `file` is its name without `.json`, the id of one that says none */
|
|
17
|
+
cinematics?: readonly {
|
|
18
|
+
file: string;
|
|
19
|
+
data: unknown;
|
|
20
|
+
}[];
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* The ids the game's files name, by what they are the ids of: the unit types (the data's and the looks'), abilities,
|
|
24
|
+
* items, upgrades, resources (`rules.resources` and what any cost is paid in), speakers (of the cinematics' dialog),
|
|
25
|
+
* cinematics, effects and sounds. Each sorted and without repeats; what the data `removed` is not there
|
|
26
|
+
*
|
|
27
|
+
* @beta
|
|
28
|
+
*/
|
|
29
|
+
export declare function gameIds(sources: GameIdSources): Record<'unit' | 'ability' | 'item' | 'upgrade' | 'resource' | 'speaker' | 'cinematic' | 'fx' | 'sound', string[]>;
|
|
30
|
+
/**
|
|
31
|
+
* The ids of a game as TypeScript, for its code to use: `UNIT.footman`, and `WardenUnit` for `GameView<WardenUnit>`.
|
|
32
|
+
* The editor writes it as `<game>.ids.ts` next to the game's files, anew with every change of the files it reads
|
|
33
|
+
*
|
|
34
|
+
* @beta
|
|
35
|
+
*/
|
|
36
|
+
export declare function gameIdsSource(game: string, sources: GameIdSources): string;
|