@v12-engine/engine 0.1.0 → 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/gameData.js
ADDED
|
@@ -0,0 +1,1690 @@
|
|
|
1
|
+
import { CORE_STAT_KEYS } from "./defs.js";
|
|
2
|
+
import { defineComponent } from "./components.js";
|
|
3
|
+
import { defineEngineEvent } from "./events.js";
|
|
4
|
+
import { replicateEvent } from "./replication.js";
|
|
5
|
+
import { callingsOf, withCallings } from "./callings.js";
|
|
6
|
+
import { COMMON_EFFECT_FIELDS } from "./abilities/effectFields.js";
|
|
7
|
+
import { dataCellLayersProblem, layCellLayerData } from "./cellLayers.js";
|
|
8
|
+
import { Invalid, string } from "./fields.js";
|
|
9
|
+
import { summonEffects } from "./summons.js";
|
|
10
|
+
import { dispelEffects } from "./abilities/dispel.js";
|
|
11
|
+
import { coreEffects } from "./abilities/effects/core.js";
|
|
12
|
+
import { dataDefaults, dataDefaultsProblem } from "./defaultSets.js";
|
|
13
|
+
import { hasPack } from "./packs/pack.js";
|
|
14
|
+
import { rootLogger } from "./log.js";
|
|
15
|
+
//#region src/gameData.ts
|
|
16
|
+
/**
|
|
17
|
+
* The kinds of definition a game's data is kept for, by the field of the game module they are listed in
|
|
18
|
+
*
|
|
19
|
+
* @beta
|
|
20
|
+
*/
|
|
21
|
+
var DATA_KINDS = [
|
|
22
|
+
"units",
|
|
23
|
+
"abilities",
|
|
24
|
+
"buffs",
|
|
25
|
+
"items",
|
|
26
|
+
"upgrades",
|
|
27
|
+
"races"
|
|
28
|
+
];
|
|
29
|
+
/**
|
|
30
|
+
* What a definition of each kind must have besides its id and its name, as the type says (`UnitTypeDef.radius`...),
|
|
31
|
+
* with what one made of nothing starts as (`NEW_DEFINITION`: the Data panel's New, from empty). A unit type is a unit
|
|
32
|
+
* unless its `kind` says otherwise
|
|
33
|
+
*
|
|
34
|
+
* @beta
|
|
35
|
+
*/
|
|
36
|
+
var REQUIRED_FIELDS = {
|
|
37
|
+
units: {
|
|
38
|
+
kind: "unit",
|
|
39
|
+
radius: .5,
|
|
40
|
+
stats: { health: 100 },
|
|
41
|
+
sight: 8
|
|
42
|
+
},
|
|
43
|
+
abilities: {
|
|
44
|
+
target: "none",
|
|
45
|
+
effects: []
|
|
46
|
+
},
|
|
47
|
+
buffs: {},
|
|
48
|
+
items: { cost: {} },
|
|
49
|
+
upgrades: {
|
|
50
|
+
cost: {},
|
|
51
|
+
researchTime: 30,
|
|
52
|
+
effects: []
|
|
53
|
+
},
|
|
54
|
+
races: {}
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* What a definition in a `data.json` says to be one of its own, made of nothing, where the game has none by its id
|
|
58
|
+
* (`{ "new": true, "name": "Peon", "stats": { "health": 220 } }`): what its kind must have (`REQUIRED_FIELDS`), its
|
|
59
|
+
* name its id until it says, with what else is said over it. A unit type's `kind` is taken from it too
|
|
60
|
+
*
|
|
61
|
+
* @beta
|
|
62
|
+
*/
|
|
63
|
+
var NEW_DEFINITION = "new";
|
|
64
|
+
/**
|
|
65
|
+
* A definition made of nothing, by an id: what its kind must have (`REQUIRED_FIELDS`), named by its id
|
|
66
|
+
*
|
|
67
|
+
* @beta
|
|
68
|
+
*/
|
|
69
|
+
function blankDefinition(kind, id, unitKind) {
|
|
70
|
+
const required = structuredClone(REQUIRED_FIELDS[kind]);
|
|
71
|
+
if (kind === "units" && unitKind) required.kind = unitKind;
|
|
72
|
+
return {
|
|
73
|
+
id,
|
|
74
|
+
name: id,
|
|
75
|
+
...required
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
/** The kinds of thing a unit type made of nothing may be (`UnitTypeDef.kind`) */
|
|
79
|
+
var UNIT_KINDS = [
|
|
80
|
+
"unit",
|
|
81
|
+
"building",
|
|
82
|
+
"resource"
|
|
83
|
+
];
|
|
84
|
+
/**
|
|
85
|
+
* What a definition in a `data.json` is a copy of, when the game has none by its id: `{ "copyOf": "footman", "name":
|
|
86
|
+
* "Champion" }` is a footman by another name. The copy is the definition it names, with what else is said over it,
|
|
87
|
+
* and knows what it is a copy of (`basedOn`)
|
|
88
|
+
*
|
|
89
|
+
* @beta
|
|
90
|
+
*/
|
|
91
|
+
var COPY_OF = "copyOf";
|
|
92
|
+
/** The fields a tag and a calling of a `data.json` may say, and what each holds */
|
|
93
|
+
var TAG_FIELDS = {
|
|
94
|
+
name: "string",
|
|
95
|
+
description: "string",
|
|
96
|
+
icon: "string",
|
|
97
|
+
color: "string",
|
|
98
|
+
filter: "boolean"
|
|
99
|
+
};
|
|
100
|
+
var CALLING_FIELDS = {
|
|
101
|
+
name: "string",
|
|
102
|
+
description: "string",
|
|
103
|
+
icon: "string",
|
|
104
|
+
color: "string"
|
|
105
|
+
};
|
|
106
|
+
/**
|
|
107
|
+
* Why what a `data.json` says of its tags or callings (`GameData.tags`, `callings`) is not right, where it first is
|
|
108
|
+
* not: nothing when it is
|
|
109
|
+
*
|
|
110
|
+
* @beta
|
|
111
|
+
*/
|
|
112
|
+
function dataEntriesProblem(section, said) {
|
|
113
|
+
if (!isRecord(said)) return `${section} is no object by id`;
|
|
114
|
+
const known = section === "tags" ? TAG_FIELDS : CALLING_FIELDS;
|
|
115
|
+
for (const [id, entry] of Object.entries(said)) {
|
|
116
|
+
if (!isRecord(entry)) return `${section}.${id} is no object`;
|
|
117
|
+
for (const [field, value] of Object.entries(entry)) {
|
|
118
|
+
if (!(field in known)) return `${section}.${id}.${field} is nothing a ${section === "tags" ? "tag" : "calling"} says (${Object.keys(known).join(", ")})`;
|
|
119
|
+
if (typeof value !== known[field]) return `${section}.${id}.${field} is no ${known[field] === "string" ? "word" : "yes or no"}`;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
/** Definitions with what a `data.json` says by id laid over them, field by field; one it says of an id they have not, added */
|
|
124
|
+
function layEntries(list, said, made) {
|
|
125
|
+
const out = list.map((def) => said[def.id] ? {
|
|
126
|
+
...def,
|
|
127
|
+
...said[def.id]
|
|
128
|
+
} : def);
|
|
129
|
+
for (const [id, entry] of Object.entries(said)) if (!list.some((def) => def.id === id)) out.push({
|
|
130
|
+
...made(id),
|
|
131
|
+
...entry
|
|
132
|
+
});
|
|
133
|
+
return out;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Why rules said as data are not, where they are first wrong: nothing for rules that are
|
|
137
|
+
*
|
|
138
|
+
* @beta
|
|
139
|
+
*/
|
|
140
|
+
function dataRulesProblem(rules) {
|
|
141
|
+
if (!isRecord(rules)) return "rules is no object";
|
|
142
|
+
const known = /* @__PURE__ */ new Set([
|
|
143
|
+
"supply",
|
|
144
|
+
"heroes",
|
|
145
|
+
"resources",
|
|
146
|
+
"upkeep"
|
|
147
|
+
]);
|
|
148
|
+
const other = Object.keys(rules).find((key) => !known.has(key));
|
|
149
|
+
if (other) return `rules.${other} is nothing the rules say as data`;
|
|
150
|
+
const number = (value) => typeof value === "number" && Number.isFinite(value);
|
|
151
|
+
for (const part of ["supply", "heroes"]) {
|
|
152
|
+
const said = rules[part];
|
|
153
|
+
if (said === void 0) continue;
|
|
154
|
+
if (!isRecord(said)) return `rules.${part} is no object`;
|
|
155
|
+
for (const [key, value] of Object.entries(said)) if (key !== "pools" && !number(value)) return `rules.${part}.${key} is no number`;
|
|
156
|
+
}
|
|
157
|
+
for (const part of ["resources", "upkeep"]) {
|
|
158
|
+
const said = rules[part];
|
|
159
|
+
if (said !== void 0 && (!Array.isArray(said) || !said.every(isRecord))) return `rules.${part} is no list`;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
/** The game with the rules a `data.json` says laid over its own */
|
|
163
|
+
function withDataRules(game, rules) {
|
|
164
|
+
const out = { ...game };
|
|
165
|
+
const own = game.settings ?? {};
|
|
166
|
+
const next = { ...own };
|
|
167
|
+
if (rules.supply) next.supply = {
|
|
168
|
+
...own.supply,
|
|
169
|
+
...rules.supply
|
|
170
|
+
};
|
|
171
|
+
if (rules.heroes) next.heroes = {
|
|
172
|
+
...own.heroes,
|
|
173
|
+
...rules.heroes
|
|
174
|
+
};
|
|
175
|
+
if (rules.supply || rules.heroes) out.settings = next;
|
|
176
|
+
if (rules.resources) out.resources = rules.resources;
|
|
177
|
+
if (rules.upkeep) out.upkeep = rules.upkeep;
|
|
178
|
+
return out;
|
|
179
|
+
}
|
|
180
|
+
/** Fields that are never changed from the editor: what a definition is known by, what kind of thing it is and of */
|
|
181
|
+
var FIXED = /* @__PURE__ */ new Set([
|
|
182
|
+
"id",
|
|
183
|
+
"kind",
|
|
184
|
+
"basedOn",
|
|
185
|
+
"new"
|
|
186
|
+
]);
|
|
187
|
+
/**
|
|
188
|
+
* The lists of ids of each kind of definition, and what they are ids of: what `all` makes editable as lists, and the
|
|
189
|
+
* kind a list field names when the game does not say. Those `always` are there to fill in though a definition has none
|
|
190
|
+
*/
|
|
191
|
+
var LISTS = {
|
|
192
|
+
units: {
|
|
193
|
+
abilities: {
|
|
194
|
+
of: "abilities",
|
|
195
|
+
always: () => true
|
|
196
|
+
},
|
|
197
|
+
requires: {
|
|
198
|
+
of: "units",
|
|
199
|
+
always: () => true
|
|
200
|
+
},
|
|
201
|
+
provides: { of: "units" },
|
|
202
|
+
builds: {
|
|
203
|
+
of: "units",
|
|
204
|
+
always: (def) => def.kind === "unit" && !!def.harvester
|
|
205
|
+
},
|
|
206
|
+
trains: {
|
|
207
|
+
of: "units",
|
|
208
|
+
always: (def) => def.kind === "building"
|
|
209
|
+
},
|
|
210
|
+
researches: {
|
|
211
|
+
of: "upgrades",
|
|
212
|
+
always: (def) => def.kind === "building"
|
|
213
|
+
},
|
|
214
|
+
sells: { of: "items" },
|
|
215
|
+
hires: { of: "units" },
|
|
216
|
+
upgradesTo: {
|
|
217
|
+
of: "units",
|
|
218
|
+
one: true
|
|
219
|
+
},
|
|
220
|
+
"hero.learns": { of: "abilities" },
|
|
221
|
+
"hero.spells": { of: "abilities" },
|
|
222
|
+
targetableBy: {
|
|
223
|
+
of: "abilities",
|
|
224
|
+
always: () => true
|
|
225
|
+
},
|
|
226
|
+
"hero.forms.*.learns": {
|
|
227
|
+
of: "abilities",
|
|
228
|
+
always: () => true
|
|
229
|
+
},
|
|
230
|
+
"hero.forms.*.keeps": {
|
|
231
|
+
of: "abilities",
|
|
232
|
+
always: () => true
|
|
233
|
+
}
|
|
234
|
+
},
|
|
235
|
+
items: { from: { of: "items" } },
|
|
236
|
+
abilities: { upgrades: { of: "abilities" } }
|
|
237
|
+
};
|
|
238
|
+
/** The lists of things whose fields are changed by place (`attacks.1.acquisitionRange`), and only by place: a unit's attacks */
|
|
239
|
+
var BY_PLACE = { units: ["attacks", "pools.*.thresholds"] };
|
|
240
|
+
/** Whether a path is that of a list by place, one with a `*` for any one part of it standing for it (`pools.*.thresholds`) */
|
|
241
|
+
var isByPlace = (byPlace, path) => byPlace.some((list) => byPath({ [list]: true }, path));
|
|
242
|
+
/**
|
|
243
|
+
* The lists of things changed whole in the editor (campaign plan RC2), each thing a row: added, taken out, put in
|
|
244
|
+
* another order, its fields by place (`effects.0.amount`). The effects of abilities, of buffs, the changes of an
|
|
245
|
+
* upgrade, the units a race's start adds. Offered where every thing in them is data (no function among them)
|
|
246
|
+
*/
|
|
247
|
+
var ROWS = {
|
|
248
|
+
abilities: {
|
|
249
|
+
effects: {
|
|
250
|
+
effects: true,
|
|
251
|
+
when: (def) => def.target !== "passive",
|
|
252
|
+
hint: "What it does, in order"
|
|
253
|
+
},
|
|
254
|
+
passive: {
|
|
255
|
+
effects: true,
|
|
256
|
+
when: (def) => def.target === "passive",
|
|
257
|
+
hint: "What it does all the time"
|
|
258
|
+
},
|
|
259
|
+
"recast.effects": {
|
|
260
|
+
effects: true,
|
|
261
|
+
when: (def) => isRecord(def.recast),
|
|
262
|
+
hint: "What a recast does: the ability’s own effects when it has none"
|
|
263
|
+
},
|
|
264
|
+
"hold.tap.effects": {
|
|
265
|
+
effects: true,
|
|
266
|
+
when: (def) => isRecord(def.hold) && isRecord(def.hold.tap),
|
|
267
|
+
hint: "What it does let go before its tap’s seconds, in place of its own effects"
|
|
268
|
+
}
|
|
269
|
+
},
|
|
270
|
+
buffs: {
|
|
271
|
+
onApply: {
|
|
272
|
+
effects: true,
|
|
273
|
+
when: () => true,
|
|
274
|
+
hint: "What happens as it is put on, in the name of who put it there"
|
|
275
|
+
},
|
|
276
|
+
"onTick.effects": {
|
|
277
|
+
effects: true,
|
|
278
|
+
when: (def) => isRecord(def.onTick),
|
|
279
|
+
hint: "What happens every so often while it lasts"
|
|
280
|
+
},
|
|
281
|
+
passive: {
|
|
282
|
+
effects: true,
|
|
283
|
+
when: () => true,
|
|
284
|
+
hint: "What the carrier’s attacks, hurts, casts and kills set off while it carries it (onHit, onDamaged…)"
|
|
285
|
+
},
|
|
286
|
+
onCarrierDeath: {
|
|
287
|
+
effects: true,
|
|
288
|
+
when: () => true,
|
|
289
|
+
hint: "What happens where its carrier dies carrying it, in the name of who put it on"
|
|
290
|
+
},
|
|
291
|
+
onMaxStacks: {
|
|
292
|
+
effects: true,
|
|
293
|
+
when: (def) => def.maxStacks !== void 0,
|
|
294
|
+
hint: "What happens to its carrier as it comes to its most stacks"
|
|
295
|
+
}
|
|
296
|
+
},
|
|
297
|
+
upgrades: { effects: {
|
|
298
|
+
row: (game) => [{
|
|
299
|
+
path: "units",
|
|
300
|
+
kind: "list",
|
|
301
|
+
of: "units",
|
|
302
|
+
hint: "The unit types that benefit: every one of the player’s when left out"
|
|
303
|
+
}, ...[...CORE_STAT_KEYS, ...(game?.stats ?? []).map((stat) => stat.id)].map((stat) => ({
|
|
304
|
+
path: `stats.${stat}`,
|
|
305
|
+
kind: "number",
|
|
306
|
+
hint: `What a level adds to ${stat}`
|
|
307
|
+
}))],
|
|
308
|
+
hint: "What each level changes"
|
|
309
|
+
} },
|
|
310
|
+
races: { "startingBase.units": {
|
|
311
|
+
row: () => [{
|
|
312
|
+
path: "type",
|
|
313
|
+
kind: "id",
|
|
314
|
+
of: "units",
|
|
315
|
+
hint: "The unit type"
|
|
316
|
+
}, {
|
|
317
|
+
path: "count",
|
|
318
|
+
kind: "integer",
|
|
319
|
+
min: 1,
|
|
320
|
+
hint: "How many"
|
|
321
|
+
}],
|
|
322
|
+
when: (def) => isRecord(def.startingBase) && typeof def.startingBase.spawn !== "function",
|
|
323
|
+
hint: "What else it starts with, by unit type"
|
|
324
|
+
} }
|
|
325
|
+
};
|
|
326
|
+
/** How deep lists of things go in a thing of a list (a missile's effects in an ability's): deeper ones stay the code's */
|
|
327
|
+
var MAX_ROWS_DEPTH = 2;
|
|
328
|
+
/**
|
|
329
|
+
* The fields that are one id of a kind of definition, by path (a `*` for a place in a list), and what they are ids of:
|
|
330
|
+
* what `all` makes an `id` field, picked in the editor from what the game has. A race's start as data (`StartingBaseData`)
|
|
331
|
+
*/
|
|
332
|
+
var IDS = {
|
|
333
|
+
races: {
|
|
334
|
+
"startingBase.hall": "units",
|
|
335
|
+
"startingBase.workers.type": "units",
|
|
336
|
+
"startingBase.onMine": "units"
|
|
337
|
+
},
|
|
338
|
+
units: {
|
|
339
|
+
"hero.forms.*.levels.*": "abilities",
|
|
340
|
+
"hero.innate": "abilities",
|
|
341
|
+
"trigger.ability": "abilities",
|
|
342
|
+
"use.ability": "abilities",
|
|
343
|
+
"burst.ability": "abilities",
|
|
344
|
+
"pools.*.thresholds.*.buff": "buffs"
|
|
345
|
+
},
|
|
346
|
+
abilities: {
|
|
347
|
+
"costGrowth.buff": "buffs",
|
|
348
|
+
"hold.buff": "buffs"
|
|
349
|
+
},
|
|
350
|
+
buffs: { "overheal.buff": "buffs" }
|
|
351
|
+
};
|
|
352
|
+
/** The ids of the engine's opt-in packs whose fields the Data panel offers (`resourcesPack`, …), as `GamePack.id` has them */
|
|
353
|
+
var RESOURCES_PACK = "core.resources";
|
|
354
|
+
var HOLDS_PACK = "core.holds";
|
|
355
|
+
var CHANGES_PACK = "core.abilityChanges";
|
|
356
|
+
var GROUND_PACK = "core.groundObjects";
|
|
357
|
+
var VISION_PACK = "core.vision";
|
|
358
|
+
var HEROES_PACK = "core.heroes";
|
|
359
|
+
var BURNING_PACK = "burning";
|
|
360
|
+
/** The pools the units of a game have (`UnitTypeDef.pools`), by id, in order: what a `<pool>` in a field's path stands for */
|
|
361
|
+
function poolsOf(game) {
|
|
362
|
+
return [...new Set((game?.units ?? []).flatMap((def) => isRecord(def.pools) ? Object.keys(def.pools) : []))].sort();
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* Fields offered though a definition has nothing there, for `all`, where `when` says: a copy of a race says what it
|
|
366
|
+
* keeps of the original's code (`RaceDef.inherits`), kept unless it says otherwise
|
|
367
|
+
*/
|
|
368
|
+
var FILLED_IN = {
|
|
369
|
+
units: [
|
|
370
|
+
{
|
|
371
|
+
path: "tags",
|
|
372
|
+
kind: "list",
|
|
373
|
+
hint: "Words of the game’s for what it is (undead, mechanical, ward): what effects and abilities may go by",
|
|
374
|
+
when: () => true
|
|
375
|
+
},
|
|
376
|
+
{
|
|
377
|
+
path: "trueSight",
|
|
378
|
+
kind: "number",
|
|
379
|
+
min: 0,
|
|
380
|
+
hint: "Finds invisible and camouflaged enemies this near, for its team: a Sentry Ward",
|
|
381
|
+
when: () => true,
|
|
382
|
+
pack: VISION_PACK
|
|
383
|
+
},
|
|
384
|
+
{
|
|
385
|
+
path: "pools.<pool>.max",
|
|
386
|
+
kind: "number",
|
|
387
|
+
min: 0,
|
|
388
|
+
hint: "The most of this pool it holds: it has the pool once this is set",
|
|
389
|
+
when: () => true,
|
|
390
|
+
pack: RESOURCES_PACK
|
|
391
|
+
},
|
|
392
|
+
...[
|
|
393
|
+
["start", "What of it it starts with: its max when left out"],
|
|
394
|
+
["regen", "What comes back each second"],
|
|
395
|
+
["decay", "What goes each second once idle"],
|
|
396
|
+
["idle", "Seconds without gaining before it decays"],
|
|
397
|
+
["moving", "What comes for each cell walked"],
|
|
398
|
+
["reload", "Seconds to fill it again once it is empty"]
|
|
399
|
+
].map(([part, hint]) => ({
|
|
400
|
+
path: `pools.*.${part}`,
|
|
401
|
+
kind: "number",
|
|
402
|
+
min: 0,
|
|
403
|
+
hint,
|
|
404
|
+
when: () => true,
|
|
405
|
+
pack: RESOURCES_PACK
|
|
406
|
+
})),
|
|
407
|
+
{
|
|
408
|
+
path: "pools.*.name",
|
|
409
|
+
kind: "text",
|
|
410
|
+
hint: "What it is called on the screen",
|
|
411
|
+
when: () => true,
|
|
412
|
+
pack: RESOURCES_PACK
|
|
413
|
+
},
|
|
414
|
+
{
|
|
415
|
+
path: "pools.*.color",
|
|
416
|
+
kind: "text",
|
|
417
|
+
hint: "The colour of its bar (#e0a030)",
|
|
418
|
+
when: () => true,
|
|
419
|
+
pack: RESOURCES_PACK
|
|
420
|
+
},
|
|
421
|
+
{
|
|
422
|
+
path: "attacks.*.recovery",
|
|
423
|
+
kind: "number",
|
|
424
|
+
min: 0,
|
|
425
|
+
hint: "Seconds it is held after the blow, the backswing, shortened by attack speed as the swing is: none when left out",
|
|
426
|
+
when: (def) => Array.isArray(def.attacks)
|
|
427
|
+
},
|
|
428
|
+
{
|
|
429
|
+
path: "attacks.*.cleave.part",
|
|
430
|
+
kind: "number",
|
|
431
|
+
min: 0,
|
|
432
|
+
hint: "A blow from up close strikes the enemies round its target too: this part of its damage each",
|
|
433
|
+
when: (def) => Array.isArray(def.attacks)
|
|
434
|
+
},
|
|
435
|
+
{
|
|
436
|
+
path: "attacks.*.cleave.radius",
|
|
437
|
+
kind: "number",
|
|
438
|
+
min: 0,
|
|
439
|
+
hint: "How far round the target the cleave reaches",
|
|
440
|
+
when: (def) => Array.isArray(def.attacks)
|
|
441
|
+
},
|
|
442
|
+
{
|
|
443
|
+
path: "attacks.*.cleave.angle",
|
|
444
|
+
kind: "number",
|
|
445
|
+
min: 0,
|
|
446
|
+
max: 6.2832,
|
|
447
|
+
hint: "How wide a cone from the attacker through the target, in radians: all round when left out",
|
|
448
|
+
when: (def) => Array.isArray(def.attacks)
|
|
449
|
+
},
|
|
450
|
+
{
|
|
451
|
+
path: "attackCost.<pool>",
|
|
452
|
+
kind: "number",
|
|
453
|
+
min: 0,
|
|
454
|
+
hint: "What each attack costs of this pool: it does not attack with less",
|
|
455
|
+
when: (def) => Array.isArray(def.attacks),
|
|
456
|
+
pack: RESOURCES_PACK
|
|
457
|
+
},
|
|
458
|
+
{
|
|
459
|
+
path: "trigger.ability",
|
|
460
|
+
kind: "id",
|
|
461
|
+
of: "abilities",
|
|
462
|
+
hint: "A trap: this ability goes off in its maker’s name as one it is for comes near",
|
|
463
|
+
when: () => true,
|
|
464
|
+
pack: GROUND_PACK
|
|
465
|
+
},
|
|
466
|
+
{
|
|
467
|
+
path: "trigger.radius",
|
|
468
|
+
kind: "number",
|
|
469
|
+
min: 0,
|
|
470
|
+
hint: "How near sets it off",
|
|
471
|
+
when: (def) => isRecord(def.trigger),
|
|
472
|
+
pack: GROUND_PACK
|
|
473
|
+
},
|
|
474
|
+
{
|
|
475
|
+
path: "trigger.by",
|
|
476
|
+
options: [
|
|
477
|
+
"enemies",
|
|
478
|
+
"allies",
|
|
479
|
+
"all",
|
|
480
|
+
"maker"
|
|
481
|
+
],
|
|
482
|
+
hint: "Who sets it off: enemies when left out",
|
|
483
|
+
when: (def) => isRecord(def.trigger),
|
|
484
|
+
pack: GROUND_PACK
|
|
485
|
+
},
|
|
486
|
+
{
|
|
487
|
+
path: "trigger.arm",
|
|
488
|
+
kind: "number",
|
|
489
|
+
min: 0,
|
|
490
|
+
hint: "Seconds before it is armed",
|
|
491
|
+
when: (def) => isRecord(def.trigger),
|
|
492
|
+
pack: GROUND_PACK
|
|
493
|
+
},
|
|
494
|
+
{
|
|
495
|
+
path: "trigger.times",
|
|
496
|
+
kind: "integer",
|
|
497
|
+
min: 1,
|
|
498
|
+
hint: "How many times it goes off before it is gone: once when left out",
|
|
499
|
+
when: (def) => isRecord(def.trigger),
|
|
500
|
+
pack: GROUND_PACK
|
|
501
|
+
},
|
|
502
|
+
{
|
|
503
|
+
path: "use.ability",
|
|
504
|
+
kind: "id",
|
|
505
|
+
of: "abilities",
|
|
506
|
+
hint: "Right-clicked, it is walked up to and used: this ability goes off (a lantern, a portal)",
|
|
507
|
+
when: () => true,
|
|
508
|
+
pack: GROUND_PACK
|
|
509
|
+
},
|
|
510
|
+
{
|
|
511
|
+
path: "use.by",
|
|
512
|
+
options: [
|
|
513
|
+
"allies",
|
|
514
|
+
"enemies",
|
|
515
|
+
"all"
|
|
516
|
+
],
|
|
517
|
+
hint: "Who may use it: allies when left out",
|
|
518
|
+
when: (def) => isRecord(def.use),
|
|
519
|
+
pack: GROUND_PACK
|
|
520
|
+
},
|
|
521
|
+
{
|
|
522
|
+
path: "use.range",
|
|
523
|
+
kind: "number",
|
|
524
|
+
min: 0,
|
|
525
|
+
hint: "How near one must come to use it",
|
|
526
|
+
when: (def) => isRecord(def.use),
|
|
527
|
+
pack: GROUND_PACK
|
|
528
|
+
},
|
|
529
|
+
{
|
|
530
|
+
path: "use.times",
|
|
531
|
+
kind: "integer",
|
|
532
|
+
min: 1,
|
|
533
|
+
hint: "How many times it may be used",
|
|
534
|
+
when: (def) => isRecord(def.use),
|
|
535
|
+
pack: GROUND_PACK
|
|
536
|
+
},
|
|
537
|
+
{
|
|
538
|
+
path: "blocksMissiles",
|
|
539
|
+
options: ["enemies", "all"],
|
|
540
|
+
hint: "Stops the missiles of its enemies, or everyone’s: a wall of wind",
|
|
541
|
+
when: () => true,
|
|
542
|
+
pack: GROUND_PACK
|
|
543
|
+
},
|
|
544
|
+
{
|
|
545
|
+
path: "burst.ability",
|
|
546
|
+
kind: "id",
|
|
547
|
+
of: "abilities",
|
|
548
|
+
hint: "This ability goes off where it dies, in its maker’s name: a barrel",
|
|
549
|
+
when: () => true,
|
|
550
|
+
pack: GROUND_PACK
|
|
551
|
+
},
|
|
552
|
+
{
|
|
553
|
+
path: "burst.chain",
|
|
554
|
+
kind: "number",
|
|
555
|
+
min: 0,
|
|
556
|
+
hint: "Those of its type and owner this near die too, and go off in turn",
|
|
557
|
+
when: (def) => isRecord(def.burst),
|
|
558
|
+
pack: GROUND_PACK
|
|
559
|
+
},
|
|
560
|
+
{
|
|
561
|
+
path: "burns.seconds",
|
|
562
|
+
kind: "number",
|
|
563
|
+
min: 0,
|
|
564
|
+
hint: "Seconds it burns before it is burnt down: 20 when left out",
|
|
565
|
+
when: (def) => def.burns !== false,
|
|
566
|
+
pack: BURNING_PACK
|
|
567
|
+
},
|
|
568
|
+
{
|
|
569
|
+
path: "burns.leaves",
|
|
570
|
+
kind: "text",
|
|
571
|
+
hint: "What is left once it has burnt down: felled (it comes down), nothing (it burns away), or a unit type put in its place (a charred stump)",
|
|
572
|
+
when: (def) => def.burns !== false,
|
|
573
|
+
pack: BURNING_PACK
|
|
574
|
+
},
|
|
575
|
+
{
|
|
576
|
+
path: "burns.wood",
|
|
577
|
+
kind: "boolean",
|
|
578
|
+
hint: "What it leaves keeps the wood it had left",
|
|
579
|
+
when: (def) => def.burns !== false,
|
|
580
|
+
pack: BURNING_PACK
|
|
581
|
+
},
|
|
582
|
+
{
|
|
583
|
+
path: "burns.how",
|
|
584
|
+
kind: "text",
|
|
585
|
+
hint: "What kind of burning it is, for its look and its death: burnt when left out",
|
|
586
|
+
when: (def) => def.burns !== false,
|
|
587
|
+
pack: BURNING_PACK
|
|
588
|
+
},
|
|
589
|
+
{
|
|
590
|
+
path: "hero.callings.<calling>",
|
|
591
|
+
kind: "integer",
|
|
592
|
+
min: 1,
|
|
593
|
+
max: 3,
|
|
594
|
+
hint: "How strong it is in this calling, 1 to 3: what the shop suggests, the tooltips and the computer players go by. None: not one of its callings",
|
|
595
|
+
when: (def) => isRecord(def.hero),
|
|
596
|
+
pack: HEROES_PACK
|
|
597
|
+
},
|
|
598
|
+
{
|
|
599
|
+
path: "hero.innate",
|
|
600
|
+
kind: "id",
|
|
601
|
+
of: "abilities",
|
|
602
|
+
hint: "Its innate: an ability it has from level 1 for no point, its level growing with the hero’s",
|
|
603
|
+
when: (def) => isRecord(def.hero)
|
|
604
|
+
},
|
|
605
|
+
{
|
|
606
|
+
path: "hero.forms.*.cooldowns",
|
|
607
|
+
hint: "Its cooldowns going in and out of the form. Left alone, what is put away runs down by the time away; keep: as left; reset: ready; shared: one with the form’s ability that takes its place",
|
|
608
|
+
when: () => true
|
|
609
|
+
}
|
|
610
|
+
],
|
|
611
|
+
abilities: [
|
|
612
|
+
{
|
|
613
|
+
path: "recast.window",
|
|
614
|
+
kind: "number",
|
|
615
|
+
min: 0,
|
|
616
|
+
hint: "Seconds after it is cast that it may be cast again",
|
|
617
|
+
when: (def) => def.target !== "passive"
|
|
618
|
+
},
|
|
619
|
+
{
|
|
620
|
+
path: "recast.count",
|
|
621
|
+
kind: "integer",
|
|
622
|
+
min: 1,
|
|
623
|
+
hint: "How many times it may be cast again in the window (once when left out)",
|
|
624
|
+
when: (def) => isRecord(def.recast)
|
|
625
|
+
},
|
|
626
|
+
{
|
|
627
|
+
path: "recast.cooldown",
|
|
628
|
+
hint: "When the cooldown starts: after the last recast or the window’s end (when left out), or at the first cast",
|
|
629
|
+
when: (def) => isRecord(def.recast)
|
|
630
|
+
},
|
|
631
|
+
{
|
|
632
|
+
path: "recast.mark",
|
|
633
|
+
kind: "id",
|
|
634
|
+
of: "buffs",
|
|
635
|
+
hint: "A recast goes to the unit carrying this buff from the caster (Sonic Wave’s mark)",
|
|
636
|
+
when: (def) => isRecord(def.recast)
|
|
637
|
+
},
|
|
638
|
+
{
|
|
639
|
+
path: "recast.range",
|
|
640
|
+
kind: "number",
|
|
641
|
+
min: 0,
|
|
642
|
+
hint: "How far a recast reaches: the ability’s range when left out",
|
|
643
|
+
when: (def) => isRecord(def.recast)
|
|
644
|
+
},
|
|
645
|
+
{
|
|
646
|
+
path: "recast.manaCost",
|
|
647
|
+
kind: "number",
|
|
648
|
+
min: 0,
|
|
649
|
+
hint: "Mana a recast costs: none when left out",
|
|
650
|
+
when: (def) => isRecord(def.recast)
|
|
651
|
+
},
|
|
652
|
+
{
|
|
653
|
+
path: "targets.tags",
|
|
654
|
+
kind: "list",
|
|
655
|
+
hint: "Only what has one of these tags of its type (undead, mechanical): everything it may target when left out",
|
|
656
|
+
when: (def) => def.target === "unit"
|
|
657
|
+
},
|
|
658
|
+
{
|
|
659
|
+
path: "castTime",
|
|
660
|
+
kind: "number",
|
|
661
|
+
min: 0,
|
|
662
|
+
hint: "Seconds from the order to its going off, the caster winding up: at once when left out",
|
|
663
|
+
when: (def) => def.target !== "passive"
|
|
664
|
+
},
|
|
665
|
+
{
|
|
666
|
+
path: "ultimate",
|
|
667
|
+
kind: "boolean",
|
|
668
|
+
hint: "A hero’s ultimate: first learned at level 6 unless its required level says otherwise",
|
|
669
|
+
when: () => true
|
|
670
|
+
},
|
|
671
|
+
{
|
|
672
|
+
path: "charges.count",
|
|
673
|
+
kind: "integer",
|
|
674
|
+
min: 1,
|
|
675
|
+
hint: "Uses it holds, for one used so many times before it waits: its cooldown is then between two uses",
|
|
676
|
+
when: (def) => def.target !== "passive"
|
|
677
|
+
},
|
|
678
|
+
{
|
|
679
|
+
path: "charges.refill",
|
|
680
|
+
kind: "number",
|
|
681
|
+
min: 0,
|
|
682
|
+
hint: "Seconds until a use is back, while it holds fewer than it can",
|
|
683
|
+
when: (def) => def.target !== "passive"
|
|
684
|
+
},
|
|
685
|
+
{
|
|
686
|
+
path: "recast.target",
|
|
687
|
+
kind: "text",
|
|
688
|
+
hint: "How a recast is aimed (none, unit, point, direction, vector): as the ability is when left out",
|
|
689
|
+
when: (def) => isRecord(def.recast)
|
|
690
|
+
},
|
|
691
|
+
{
|
|
692
|
+
path: "channel.leash",
|
|
693
|
+
kind: "number",
|
|
694
|
+
min: 0,
|
|
695
|
+
hint: "The channel breaks as its target gets farther than this, dies or hides: a tether",
|
|
696
|
+
when: (def) => isRecord(def.channel)
|
|
697
|
+
},
|
|
698
|
+
{
|
|
699
|
+
path: "channel.aimed",
|
|
700
|
+
kind: "boolean",
|
|
701
|
+
hint: "Aimed as it goes: the caster’s pointer moves where it goes off",
|
|
702
|
+
when: (def) => isRecord(def.channel),
|
|
703
|
+
pack: HOLDS_PACK
|
|
704
|
+
},
|
|
705
|
+
{
|
|
706
|
+
path: "channel.walks",
|
|
707
|
+
kind: "boolean",
|
|
708
|
+
hint: "Kept up as the caster walks",
|
|
709
|
+
when: (def) => isRecord(def.channel),
|
|
710
|
+
pack: HOLDS_PACK
|
|
711
|
+
},
|
|
712
|
+
...[
|
|
713
|
+
["hold.max", "Seconds held for it to be full: held to charge, let go to cast"],
|
|
714
|
+
["hold.upTo", "Seconds held after which it goes off by itself: as it is full when left out"],
|
|
715
|
+
["hold.range.from", "How far it reaches let go at once"],
|
|
716
|
+
["hold.range.to", "How far it reaches let go full"],
|
|
717
|
+
["hold.scale", "What its amounts come to full, times what they are let go at once (1.5: half again)"]
|
|
718
|
+
].map(([path, hint]) => ({
|
|
719
|
+
path,
|
|
720
|
+
kind: "number",
|
|
721
|
+
min: 0,
|
|
722
|
+
hint,
|
|
723
|
+
when: (def) => [
|
|
724
|
+
"none",
|
|
725
|
+
"point",
|
|
726
|
+
"direction"
|
|
727
|
+
].includes(String(def.target ?? "none")) && !def.channel,
|
|
728
|
+
pack: HOLDS_PACK
|
|
729
|
+
})),
|
|
730
|
+
{
|
|
731
|
+
path: "hold.buff",
|
|
732
|
+
kind: "id",
|
|
733
|
+
of: "buffs",
|
|
734
|
+
hint: "A buff on the caster while it holds: a slow",
|
|
735
|
+
when: (def) => isRecord(def.hold),
|
|
736
|
+
pack: HOLDS_PACK
|
|
737
|
+
},
|
|
738
|
+
{
|
|
739
|
+
path: "hold.tap.under",
|
|
740
|
+
kind: "number",
|
|
741
|
+
min: 0,
|
|
742
|
+
hint: "Let go before so many seconds, it does its tap’s effects in place of its own (Pyke’s stab, not his hook)",
|
|
743
|
+
when: (def) => isRecord(def.hold),
|
|
744
|
+
pack: HOLDS_PACK
|
|
745
|
+
},
|
|
746
|
+
{
|
|
747
|
+
path: "cost.<pool>",
|
|
748
|
+
kind: "number",
|
|
749
|
+
min: 0,
|
|
750
|
+
hint: "What it costs of the caster’s pool: not ready with less",
|
|
751
|
+
when: (def) => def.target !== "passive",
|
|
752
|
+
pack: RESOURCES_PACK
|
|
753
|
+
},
|
|
754
|
+
{
|
|
755
|
+
path: "gain.<pool>",
|
|
756
|
+
kind: "number",
|
|
757
|
+
min: 0,
|
|
758
|
+
hint: "What it gives the caster’s pool as it goes off",
|
|
759
|
+
when: (def) => def.target !== "passive",
|
|
760
|
+
pack: RESOURCES_PACK
|
|
761
|
+
},
|
|
762
|
+
{
|
|
763
|
+
path: "costGrowth.buff",
|
|
764
|
+
kind: "id",
|
|
765
|
+
of: "buffs",
|
|
766
|
+
hint: "Its costs grow with the stacks of this buff of the caster’s",
|
|
767
|
+
when: (def) => def.target !== "passive",
|
|
768
|
+
pack: RESOURCES_PACK
|
|
769
|
+
},
|
|
770
|
+
{
|
|
771
|
+
path: "costGrowth.per",
|
|
772
|
+
kind: "number",
|
|
773
|
+
min: 0,
|
|
774
|
+
hint: "How much more for each stack: 1, twice with one stack, three times with two",
|
|
775
|
+
when: (def) => def.target !== "passive",
|
|
776
|
+
pack: RESOURCES_PACK
|
|
777
|
+
},
|
|
778
|
+
{
|
|
779
|
+
path: "upgrades",
|
|
780
|
+
kind: "list",
|
|
781
|
+
of: "abilities",
|
|
782
|
+
hint: "What it may be made into for good, chosen once",
|
|
783
|
+
when: () => true,
|
|
784
|
+
pack: CHANGES_PACK
|
|
785
|
+
}
|
|
786
|
+
],
|
|
787
|
+
buffs: [
|
|
788
|
+
{
|
|
789
|
+
path: "breaksOn",
|
|
790
|
+
kind: "list",
|
|
791
|
+
hint: "What takes it off before its time: damage (its carrier hurt), attack (its attack lands), cast",
|
|
792
|
+
when: () => true
|
|
793
|
+
},
|
|
794
|
+
{
|
|
795
|
+
path: "control",
|
|
796
|
+
hint: "It takes its carrier’s orders while it lasts: fear (away from who put it on), charm (to them), taunt (attacks them)",
|
|
797
|
+
when: (def) => typeof def.control !== "function"
|
|
798
|
+
},
|
|
799
|
+
{
|
|
800
|
+
path: "suppress",
|
|
801
|
+
kind: "boolean",
|
|
802
|
+
hint: "Held like a stun, but tenacity does not shorten it and a cleanse does not take it off",
|
|
803
|
+
when: () => true
|
|
804
|
+
},
|
|
805
|
+
{
|
|
806
|
+
path: "grounded",
|
|
807
|
+
kind: "boolean",
|
|
808
|
+
hint: "Its carrier cannot dash or blink of its own",
|
|
809
|
+
when: () => true
|
|
810
|
+
},
|
|
811
|
+
{
|
|
812
|
+
path: "unstoppable",
|
|
813
|
+
kind: "boolean",
|
|
814
|
+
hint: "Nothing that holds a unit up (stun, root, silence, fear, a throw…) does anything to its carrier",
|
|
815
|
+
when: () => true
|
|
816
|
+
},
|
|
817
|
+
{
|
|
818
|
+
path: "revealed",
|
|
819
|
+
kind: "boolean",
|
|
820
|
+
hint: "Its carrier is seen by the team of whoever put it on, wherever it stands (with the vision pack)",
|
|
821
|
+
when: () => true,
|
|
822
|
+
pack: VISION_PACK
|
|
823
|
+
},
|
|
824
|
+
{
|
|
825
|
+
path: "camouflage",
|
|
826
|
+
kind: "number",
|
|
827
|
+
min: 0,
|
|
828
|
+
hint: "Its carrier is seen by its enemies only from this near, unless something finds it (with the vision pack)",
|
|
829
|
+
when: (def) => typeof def.camouflage !== "function",
|
|
830
|
+
pack: VISION_PACK
|
|
831
|
+
},
|
|
832
|
+
{
|
|
833
|
+
path: "trueSight",
|
|
834
|
+
kind: "number",
|
|
835
|
+
min: 0,
|
|
836
|
+
hint: "Its carrier finds invisible and camouflaged enemies this near (with the vision pack)",
|
|
837
|
+
when: () => true,
|
|
838
|
+
pack: VISION_PACK
|
|
839
|
+
},
|
|
840
|
+
{
|
|
841
|
+
path: "invulnerable",
|
|
842
|
+
kind: "boolean",
|
|
843
|
+
hint: "Its carrier takes no damage, and no enemy’s ability is cast on it",
|
|
844
|
+
when: (def) => typeof def.invulnerable !== "function"
|
|
845
|
+
},
|
|
846
|
+
{
|
|
847
|
+
path: "untargetable",
|
|
848
|
+
kind: "boolean",
|
|
849
|
+
hint: "Nothing of anyone else’s reaches its carrier: no ability cast on it, no attack, no area, no missile",
|
|
850
|
+
when: (def) => typeof def.untargetable !== "function"
|
|
851
|
+
},
|
|
852
|
+
{
|
|
853
|
+
path: "minHealth",
|
|
854
|
+
kind: "number",
|
|
855
|
+
min: 0,
|
|
856
|
+
hint: "The least health damage leaves its carrier with (1: it cannot die of it)",
|
|
857
|
+
when: (def) => typeof def.minHealth !== "function"
|
|
858
|
+
},
|
|
859
|
+
{
|
|
860
|
+
path: "drain.mana",
|
|
861
|
+
kind: "number",
|
|
862
|
+
min: 0,
|
|
863
|
+
hint: "Mana it takes of its carrier each second: off when there is not enough",
|
|
864
|
+
when: () => true,
|
|
865
|
+
pack: RESOURCES_PACK
|
|
866
|
+
},
|
|
867
|
+
{
|
|
868
|
+
path: "drain.<pool>",
|
|
869
|
+
kind: "number",
|
|
870
|
+
min: 0,
|
|
871
|
+
hint: "What it takes of its carrier’s pool each second: off when there is not enough",
|
|
872
|
+
when: () => true,
|
|
873
|
+
pack: RESOURCES_PACK
|
|
874
|
+
},
|
|
875
|
+
{
|
|
876
|
+
path: "tags",
|
|
877
|
+
kind: "list",
|
|
878
|
+
hint: "Words of the game’s for what it is (fire, slow, anti-heal): what a search and code find it by",
|
|
879
|
+
when: () => true
|
|
880
|
+
},
|
|
881
|
+
{
|
|
882
|
+
path: "phasing",
|
|
883
|
+
kind: "boolean",
|
|
884
|
+
hint: "Its carrier walks through other units and they through it; walls and buildings still stop it",
|
|
885
|
+
when: (def) => typeof def.phasing !== "function"
|
|
886
|
+
},
|
|
887
|
+
{
|
|
888
|
+
path: "cleave.part",
|
|
889
|
+
kind: "number",
|
|
890
|
+
min: 0,
|
|
891
|
+
hint: "Its carrier’s blows from up close strike the enemies round the target too, this part of the damage each",
|
|
892
|
+
when: () => true
|
|
893
|
+
},
|
|
894
|
+
{
|
|
895
|
+
path: "cleave.radius",
|
|
896
|
+
kind: "number",
|
|
897
|
+
min: 0,
|
|
898
|
+
hint: "How far round the target the cleave reaches",
|
|
899
|
+
when: (def) => isRecord(def.cleave)
|
|
900
|
+
},
|
|
901
|
+
{
|
|
902
|
+
path: "cleave.angle",
|
|
903
|
+
kind: "number",
|
|
904
|
+
min: 0,
|
|
905
|
+
max: 6.2832,
|
|
906
|
+
hint: "How wide a cone from the attacker through the target, in radians: all round when left out",
|
|
907
|
+
when: (def) => isRecord(def.cleave)
|
|
908
|
+
},
|
|
909
|
+
{
|
|
910
|
+
path: "overheal.buff",
|
|
911
|
+
kind: "id",
|
|
912
|
+
of: "buffs",
|
|
913
|
+
hint: "Healing past full health its carrier gives (or gets) becomes a shield: this buff, on whoever was healed",
|
|
914
|
+
when: () => true
|
|
915
|
+
},
|
|
916
|
+
{
|
|
917
|
+
path: "overheal.part",
|
|
918
|
+
kind: "number",
|
|
919
|
+
min: 0,
|
|
920
|
+
hint: "The part of what spilled over the shield holds: all of it when left out",
|
|
921
|
+
when: (def) => isRecord(def.overheal)
|
|
922
|
+
},
|
|
923
|
+
{
|
|
924
|
+
path: "overheal.most",
|
|
925
|
+
kind: "number",
|
|
926
|
+
min: 0,
|
|
927
|
+
hint: "The most the shield holds, a part of the healed one’s max health: a third when left out",
|
|
928
|
+
when: (def) => isRecord(def.overheal)
|
|
929
|
+
},
|
|
930
|
+
{
|
|
931
|
+
path: "overheal.of",
|
|
932
|
+
options: ["given", "taken"],
|
|
933
|
+
hint: "Of the healing its carrier gives (given, when left out), or gets (taken)",
|
|
934
|
+
when: (def) => isRecord(def.overheal)
|
|
935
|
+
},
|
|
936
|
+
{
|
|
937
|
+
path: "paysWithHealth",
|
|
938
|
+
kind: "either",
|
|
939
|
+
orNumber: "number",
|
|
940
|
+
min: 0,
|
|
941
|
+
hint: "Its carrier pays for its abilities with health, not mana: this much health a point of mana (1 when on)",
|
|
942
|
+
when: () => true
|
|
943
|
+
}
|
|
944
|
+
],
|
|
945
|
+
items: [
|
|
946
|
+
{
|
|
947
|
+
path: "level",
|
|
948
|
+
kind: "integer",
|
|
949
|
+
min: 1,
|
|
950
|
+
hint: "How good it is: what an item table draws by (a level)",
|
|
951
|
+
when: () => true
|
|
952
|
+
},
|
|
953
|
+
{
|
|
954
|
+
path: "class",
|
|
955
|
+
kind: "text",
|
|
956
|
+
hint: "Its kind of item, a word of the game’s: what an item table draws by (a class)",
|
|
957
|
+
when: () => true
|
|
958
|
+
},
|
|
959
|
+
{
|
|
960
|
+
path: "tier",
|
|
961
|
+
kind: "text",
|
|
962
|
+
hint: "Where it goes in a shop: consumable, starter, basic, intermediate, legendary, relic (found, not sold), or a tier of the game’s",
|
|
963
|
+
when: () => true
|
|
964
|
+
},
|
|
965
|
+
{
|
|
966
|
+
path: "tags",
|
|
967
|
+
kind: "list",
|
|
968
|
+
hint: "Words of the game’s for what it is (attack, lifesteal, early): what a search (#lifesteal) and a shop’s filters go by",
|
|
969
|
+
when: () => true
|
|
970
|
+
},
|
|
971
|
+
{
|
|
972
|
+
path: "suits",
|
|
973
|
+
kind: "list",
|
|
974
|
+
hint: "The callings of heroes it is meant for (vanguard, ranger): what a shop suggests, never a lock",
|
|
975
|
+
when: () => true
|
|
976
|
+
},
|
|
977
|
+
{
|
|
978
|
+
path: "unique",
|
|
979
|
+
kind: "text",
|
|
980
|
+
hint: "A name for its passive: two carried, of it or of items sharing the name, work once",
|
|
981
|
+
when: () => true
|
|
982
|
+
},
|
|
983
|
+
{
|
|
984
|
+
path: "group",
|
|
985
|
+
kind: "text",
|
|
986
|
+
hint: "A group a hero carries only so many of (boots: one pair)",
|
|
987
|
+
when: () => true
|
|
988
|
+
},
|
|
989
|
+
{
|
|
990
|
+
path: "groupLimit",
|
|
991
|
+
kind: "integer",
|
|
992
|
+
min: 1,
|
|
993
|
+
hint: "How many of its group one hero may carry: the game’s limit of the group, or 1, when left out",
|
|
994
|
+
when: (def) => def.group !== void 0
|
|
995
|
+
},
|
|
996
|
+
{
|
|
997
|
+
path: "stack",
|
|
998
|
+
kind: "integer",
|
|
999
|
+
min: 1,
|
|
1000
|
+
hint: "How many go in one slot, their charges added (a stack of potions)",
|
|
1001
|
+
when: (def) => def.charges !== void 0
|
|
1002
|
+
},
|
|
1003
|
+
{
|
|
1004
|
+
path: "refill.shop",
|
|
1005
|
+
kind: "boolean",
|
|
1006
|
+
hint: "Its charges all come back at a shop",
|
|
1007
|
+
when: (def) => def.charges !== void 0
|
|
1008
|
+
},
|
|
1009
|
+
{
|
|
1010
|
+
path: "refill.every",
|
|
1011
|
+
kind: "number",
|
|
1012
|
+
min: 0,
|
|
1013
|
+
hint: "Seconds for one of its charges to come back, wherever it is",
|
|
1014
|
+
when: (def) => def.charges !== void 0
|
|
1015
|
+
},
|
|
1016
|
+
{
|
|
1017
|
+
path: "sellRate",
|
|
1018
|
+
kind: "number",
|
|
1019
|
+
min: 0,
|
|
1020
|
+
max: 1,
|
|
1021
|
+
step: .05,
|
|
1022
|
+
hint: "The part of its price a shop gives back: the game’s when left out",
|
|
1023
|
+
when: () => true
|
|
1024
|
+
}
|
|
1025
|
+
],
|
|
1026
|
+
races: [{
|
|
1027
|
+
path: "inherits.hooks",
|
|
1028
|
+
kind: "boolean",
|
|
1029
|
+
hint: "Keeps the hooks of the race this is a copy of: how it gathers, where it builds. Off, it plays by the game's rules alone",
|
|
1030
|
+
when: (def) => !!def.basedOn
|
|
1031
|
+
}, {
|
|
1032
|
+
path: "inherits.onStart",
|
|
1033
|
+
kind: "boolean",
|
|
1034
|
+
hint: "Keeps the onStart of the race this is a copy of: what its players begin with that is not a unit (a ground of its own)",
|
|
1035
|
+
when: (def) => !!def.basedOn
|
|
1036
|
+
}]
|
|
1037
|
+
};
|
|
1038
|
+
/** The words a path is one of (a `choice`), by kind and path, `*` for any one part of it */
|
|
1039
|
+
var CHOICES = {
|
|
1040
|
+
units: {
|
|
1041
|
+
"hero.forms.*.cooldowns": [
|
|
1042
|
+
"keep",
|
|
1043
|
+
"reset",
|
|
1044
|
+
"shared"
|
|
1045
|
+
],
|
|
1046
|
+
"trigger.by": [
|
|
1047
|
+
"enemies",
|
|
1048
|
+
"allies",
|
|
1049
|
+
"all",
|
|
1050
|
+
"maker"
|
|
1051
|
+
],
|
|
1052
|
+
"use.by": [
|
|
1053
|
+
"allies",
|
|
1054
|
+
"enemies",
|
|
1055
|
+
"all"
|
|
1056
|
+
],
|
|
1057
|
+
blocksMissiles: ["enemies", "all"]
|
|
1058
|
+
},
|
|
1059
|
+
buffs: {
|
|
1060
|
+
control: [
|
|
1061
|
+
"fear",
|
|
1062
|
+
"charm",
|
|
1063
|
+
"taunt"
|
|
1064
|
+
],
|
|
1065
|
+
"overheal.of": ["given", "taken"]
|
|
1066
|
+
},
|
|
1067
|
+
abilities: { "recast.cooldown": ["after", "first"] }
|
|
1068
|
+
};
|
|
1069
|
+
/** The kind of definition a path is an id of, as `IDS` says, or undefined */
|
|
1070
|
+
function idKindOf(kind, path) {
|
|
1071
|
+
return byPath(IDS[kind], path);
|
|
1072
|
+
}
|
|
1073
|
+
/**
|
|
1074
|
+
* What a table by path says of a path: by the path itself, or by one with a `*` for any one part of it (a place in a
|
|
1075
|
+
* list, a form of a hero's: `hero.forms.*.keeps`)
|
|
1076
|
+
*/
|
|
1077
|
+
function byPath(table, path) {
|
|
1078
|
+
if (!table) return void 0;
|
|
1079
|
+
if (path in table) return table[path];
|
|
1080
|
+
const parts = path.split(".");
|
|
1081
|
+
for (const [key, value] of Object.entries(table)) {
|
|
1082
|
+
if (!key.includes("*")) continue;
|
|
1083
|
+
const keys = key.split(".");
|
|
1084
|
+
if (keys.length === parts.length && keys.every((each, i) => each === "*" || each === parts[i])) return value;
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
/** The paths a path with a `*` stands for in a definition: one for each key of what is there (`hero.forms.bear.keeps`) */
|
|
1088
|
+
function expandedPaths(def, path) {
|
|
1089
|
+
const star = path.indexOf(".*");
|
|
1090
|
+
if (star < 0) return [path];
|
|
1091
|
+
const head = path.slice(0, star);
|
|
1092
|
+
const there = valueAt(def, head);
|
|
1093
|
+
return (Array.isArray(there) ? there.map((_, index) => String(index)) : isRecord(there) ? Object.keys(there) : []).flatMap((key) => expandedPaths(def, `${head}.${key}${path.slice(star + 2)}`));
|
|
1094
|
+
}
|
|
1095
|
+
/** The list by place a path is in, and the place: `attacks.1.acquisitionRange` is in `attacks` at 1 */
|
|
1096
|
+
function placeOf(kind, path) {
|
|
1097
|
+
const parts = path.split(".");
|
|
1098
|
+
for (const general of BY_PLACE[kind] ?? []) {
|
|
1099
|
+
const keys = general.split(".");
|
|
1100
|
+
if (parts.length <= keys.length || !keys.every((each, i) => each === "*" || each === parts[i])) continue;
|
|
1101
|
+
const place = Number(parts[keys.length]);
|
|
1102
|
+
if (Number.isInteger(place)) return {
|
|
1103
|
+
list: parts.slice(0, keys.length).join("."),
|
|
1104
|
+
place
|
|
1105
|
+
};
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1108
|
+
var isWords = (value) => Array.isArray(value) && value.every((each) => typeof each === "string");
|
|
1109
|
+
var MAX_DEPTH = 4;
|
|
1110
|
+
var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1111
|
+
var isValue = (value) => typeof value === "boolean" || typeof value === "string" || typeof value === "number" && Number.isFinite(value);
|
|
1112
|
+
/**
|
|
1113
|
+
* What is at a path of a definition, or undefined
|
|
1114
|
+
*
|
|
1115
|
+
* @beta
|
|
1116
|
+
*/
|
|
1117
|
+
function valueAt(def, path) {
|
|
1118
|
+
let at = def;
|
|
1119
|
+
for (const part of path.split(".")) {
|
|
1120
|
+
if (typeof at !== "object" || at === null) return void 0;
|
|
1121
|
+
at = at[part];
|
|
1122
|
+
}
|
|
1123
|
+
return at;
|
|
1124
|
+
}
|
|
1125
|
+
/**
|
|
1126
|
+
* Values with one field set, nested as the path says: `nested('stats.health', 420)` is `{ stats: { health: 420 } }`
|
|
1127
|
+
*
|
|
1128
|
+
* @beta
|
|
1129
|
+
*/
|
|
1130
|
+
function nested(path, value) {
|
|
1131
|
+
const parts = path.split(".");
|
|
1132
|
+
let out = { [parts.pop()]: value };
|
|
1133
|
+
while (parts.length) out = { [parts.pop()]: out };
|
|
1134
|
+
return out;
|
|
1135
|
+
}
|
|
1136
|
+
/**
|
|
1137
|
+
* Every number, word and yes or no of a definition, by path, and its lists of ids as lists: what `all` makes editable.
|
|
1138
|
+
* A list of numbers (a bounty's two ends) is by place, and so are the things of a list `byPlace` names (a unit's
|
|
1139
|
+
* attacks); another list of things (drops) or of lists stays the code's
|
|
1140
|
+
*/
|
|
1141
|
+
function leaves(def, lists = {}, prefix = "", depth = 0, byPlace = []) {
|
|
1142
|
+
if (depth > MAX_DEPTH) return [];
|
|
1143
|
+
const out = [];
|
|
1144
|
+
const entries = Array.isArray(def) ? def.map((value, i) => [String(i), value]) : Object.entries(def);
|
|
1145
|
+
for (const [key, value] of entries) {
|
|
1146
|
+
if (depth === 0 && FIXED.has(key)) continue;
|
|
1147
|
+
const path = prefix ? `${prefix}.${key}` : key;
|
|
1148
|
+
if (isValue(value)) out.push(path);
|
|
1149
|
+
else if (byPath(lists, path) && isWords(value)) out.push(path);
|
|
1150
|
+
else if (Array.isArray(value) ? value.every((each) => typeof each === "number") || isByPlace(byPlace, path) && value.every(isRecord) : isRecord(value)) out.push(...leaves(value, lists, path, depth + 1, byPlace));
|
|
1151
|
+
}
|
|
1152
|
+
return out;
|
|
1153
|
+
}
|
|
1154
|
+
var kindOf = (value) => typeof value === "boolean" ? "boolean" : typeof value === "string" ? "text" : "number";
|
|
1155
|
+
function fieldOf(kind, def, field) {
|
|
1156
|
+
const said = typeof field === "string" ? { path: field } : field;
|
|
1157
|
+
const options = said.options ?? byPath(CHOICES[kind], said.path);
|
|
1158
|
+
const given = options ? {
|
|
1159
|
+
...said,
|
|
1160
|
+
options
|
|
1161
|
+
} : said;
|
|
1162
|
+
const parts = given.path.split(".");
|
|
1163
|
+
const list = byPath(LISTS[kind], given.path);
|
|
1164
|
+
const value = valueAt(def, given.path);
|
|
1165
|
+
const listed = given.kind === "list" || given.kind === void 0 && (isWords(value) || value === void 0 && !!list || !!list?.one && typeof value === "string");
|
|
1166
|
+
const idOf = (given.kind === "id" || given.kind === void 0) && typeof value !== "number" ? idKindOf(kind, given.path) : void 0;
|
|
1167
|
+
const place = placeOf(kind, given.path);
|
|
1168
|
+
const form = kind === "units" && parts.length > 3 && parts[0] === "hero" && parts[1] === "forms";
|
|
1169
|
+
return {
|
|
1170
|
+
...given,
|
|
1171
|
+
name: given.name ?? (place ? given.path.slice(`${place.list}.${place.place}.`.length) : form ? parts.slice(3).join(" ") : parts[parts.length - 1]),
|
|
1172
|
+
kind: given.kind ?? (given.options ? "choice" : listed ? "list" : idOf ? "id" : kindOf(value)),
|
|
1173
|
+
group: given.group ?? (place ? `${place.list.split(".").join(" ")} ${place.place + 1}` : form ? `form ${parts[2]}` : parts.length > 1 ? parts[0] : listed ? "lists" : ""),
|
|
1174
|
+
...listed && (given.of ?? list?.of) && { of: given.of ?? list.of },
|
|
1175
|
+
...listed && (given.one ?? list?.one) && { one: true },
|
|
1176
|
+
...!listed && (given.of ?? idOf) && { of: given.of ?? idOf }
|
|
1177
|
+
};
|
|
1178
|
+
}
|
|
1179
|
+
/** Whether a value is data all through, no function anywhere in it: as a list must be to be changed whole and kept in a file */
|
|
1180
|
+
var isData = (value, depth = 0) => depth <= 8 && (value === void 0 || isValue(value) || Array.isArray(value) && value.every((each) => isData(each, depth + 1)) || isRecord(value) && Object.values(value).every((each) => isData(each, depth + 1)));
|
|
1181
|
+
/** The kinds of effect a game has, by type: the engine's, its packs' and its own (`Rules.effects`), one of its own over the engine's of its type */
|
|
1182
|
+
function effectTypesByType(game) {
|
|
1183
|
+
const kinds = /* @__PURE__ */ new Map();
|
|
1184
|
+
for (const kind of [
|
|
1185
|
+
...coreEffects,
|
|
1186
|
+
...summonEffects,
|
|
1187
|
+
...dispelEffects,
|
|
1188
|
+
...(game?.packs ?? []).flatMap((pack) => pack.effects ?? []),
|
|
1189
|
+
...game?.effects ?? []
|
|
1190
|
+
]) kinds.set(kind.type, kind);
|
|
1191
|
+
return kinds;
|
|
1192
|
+
}
|
|
1193
|
+
/**
|
|
1194
|
+
* The fields an effect of a type has, by their path in it: those its type reads (`defineEffect`'s `fields`), then those
|
|
1195
|
+
* every effect may have (`EffectCommon`). Only those every effect may have, for a type the game has not
|
|
1196
|
+
*
|
|
1197
|
+
* @beta
|
|
1198
|
+
*/
|
|
1199
|
+
function effectFields(game, type) {
|
|
1200
|
+
return [...effectTypesByType(game).get(type)?.fields ?? [], ...Object.values(COMMON_EFFECT_FIELDS).flat()];
|
|
1201
|
+
}
|
|
1202
|
+
/**
|
|
1203
|
+
* The types of effect a game has (`defineEffect`): the engine's and its own, in order of their names
|
|
1204
|
+
*
|
|
1205
|
+
* @beta
|
|
1206
|
+
*/
|
|
1207
|
+
function effectTypesOf(game) {
|
|
1208
|
+
return [...effectTypesByType(game).keys()].sort();
|
|
1209
|
+
}
|
|
1210
|
+
/**
|
|
1211
|
+
* A list of things changed whole (`ROWS`), and the fields of each of its things by place under a heading of its own
|
|
1212
|
+
* (`effects 1`): its type for an effect, then what it has, then what its type or the list says it may have. The lists
|
|
1213
|
+
* inside a thing (a missile's effects) the same, a few deep
|
|
1214
|
+
*/
|
|
1215
|
+
function rowsFields(game, spec, path, heading, rows, depth = 0) {
|
|
1216
|
+
const types = spec.effects ? effectTypesOf(game) : void 0;
|
|
1217
|
+
const out = [{
|
|
1218
|
+
path,
|
|
1219
|
+
name: path.split(".").pop(),
|
|
1220
|
+
kind: "rows",
|
|
1221
|
+
group: heading,
|
|
1222
|
+
...types && { types },
|
|
1223
|
+
...spec.hint && { hint: spec.hint }
|
|
1224
|
+
}];
|
|
1225
|
+
rows.forEach((row, place) => {
|
|
1226
|
+
if (!isRecord(row)) return;
|
|
1227
|
+
const at = `${path}.${place}`;
|
|
1228
|
+
const group = `${heading} ${place + 1}`;
|
|
1229
|
+
const declared = spec.effects ? effectFields(game, String(row.type)) : spec.row?.(game) ?? [];
|
|
1230
|
+
const lists = Object.fromEntries(declared.filter((field) => field.kind === "list").map((field) => [field.path, field]));
|
|
1231
|
+
const own = (field, value) => ({
|
|
1232
|
+
...field,
|
|
1233
|
+
path: `${at}.${field.path}`,
|
|
1234
|
+
name: field.name ?? field.path,
|
|
1235
|
+
kind: field.kind ?? (field.options ? "choice" : isWords(value) ? "list" : kindOf(value)),
|
|
1236
|
+
group: field.group ?? group
|
|
1237
|
+
});
|
|
1238
|
+
if (spec.effects) out.push({
|
|
1239
|
+
path: `${at}.type`,
|
|
1240
|
+
name: "type",
|
|
1241
|
+
kind: "text",
|
|
1242
|
+
group,
|
|
1243
|
+
hint: "What kind of effect it is"
|
|
1244
|
+
});
|
|
1245
|
+
const present = leaves(row, lists).filter((each) => !spec.effects || each !== "type");
|
|
1246
|
+
for (const each of present) out.push(own(declared.find((field) => field.path === each) ?? { path: each }, valueAt(row, each)));
|
|
1247
|
+
for (const field of declared) {
|
|
1248
|
+
const value = valueAt(row, field.path);
|
|
1249
|
+
if (field.kind !== "rows") {
|
|
1250
|
+
const byLevel = (field.kind === "number" || field.kind === "integer") && Array.isArray(value);
|
|
1251
|
+
if (value === void 0 || byLevel) out.push(own(field, void 0));
|
|
1252
|
+
} else if (depth < MAX_ROWS_DEPTH && (value === void 0 || Array.isArray(value) && isData(value))) out.push(...rowsFields(game, {
|
|
1253
|
+
effects: true,
|
|
1254
|
+
hint: field.hint
|
|
1255
|
+
}, `${at}.${field.path}`, `${group} ${field.path}`, value ?? [], depth + 1));
|
|
1256
|
+
}
|
|
1257
|
+
});
|
|
1258
|
+
return out;
|
|
1259
|
+
}
|
|
1260
|
+
/** The lists of things changed whole of a definition (`ROWS`), with their things' fields: those it has, all data, and those offered empty */
|
|
1261
|
+
function allRows(game, kind, def) {
|
|
1262
|
+
return Object.entries(ROWS[kind] ?? {}).flatMap(([path, spec]) => {
|
|
1263
|
+
const rows = valueAt(def, path);
|
|
1264
|
+
return (rows === void 0 ? !!spec.when?.(def) : Array.isArray(rows) && isData(rows)) ? rowsFields(game, spec, path, path.split(".").join(" "), rows ?? []) : [];
|
|
1265
|
+
});
|
|
1266
|
+
}
|
|
1267
|
+
/**
|
|
1268
|
+
* An upgrade's requirements by level (`UpgradeDef.requires`, a list for each): a list of ids for each of its levels,
|
|
1269
|
+
* those it has and up to its last
|
|
1270
|
+
*/
|
|
1271
|
+
function levelLists(def) {
|
|
1272
|
+
const levels = Math.max(def.maxLevel ?? 1, def.requires?.length ?? 0);
|
|
1273
|
+
return Array.from({ length: Math.min(levels, MAX_LIST) }, (_, level) => ({
|
|
1274
|
+
path: `requires.${level}`,
|
|
1275
|
+
name: `level ${level + 1}`,
|
|
1276
|
+
kind: "list",
|
|
1277
|
+
of: "units",
|
|
1278
|
+
group: "requires",
|
|
1279
|
+
hint: `The buildings needed for level ${level + 1}: all of them`
|
|
1280
|
+
}));
|
|
1281
|
+
}
|
|
1282
|
+
/**
|
|
1283
|
+
* The fields of a definition the editor may change, as the game says (`Rules.editable`), each with what it
|
|
1284
|
+
* holds and the heading it goes under. None for a game that says nothing of that kind
|
|
1285
|
+
*
|
|
1286
|
+
* @beta
|
|
1287
|
+
*/
|
|
1288
|
+
function editableFields(game, kind, def) {
|
|
1289
|
+
const editable = game?.editable;
|
|
1290
|
+
if (!editable) return [];
|
|
1291
|
+
let said = editable === "all" ? "all" : editable[kind];
|
|
1292
|
+
if (typeof said === "function") said = said(def);
|
|
1293
|
+
if (!said) return [];
|
|
1294
|
+
if (said === "all") {
|
|
1295
|
+
const lists = LISTS[kind] ?? {};
|
|
1296
|
+
const paths = leaves(def, lists, "", 0, BY_PLACE[kind]);
|
|
1297
|
+
for (const [general, list] of Object.entries(lists)) for (const path of expandedPaths(def, general)) if (!paths.includes(path) && valueAt(def, path) === void 0 && list.always?.(def)) paths.push(path);
|
|
1298
|
+
const fields = paths.map((path) => fieldOf(kind, def, path));
|
|
1299
|
+
for (const { when, pack, ...field } of FILLED_IN[kind] ?? []) {
|
|
1300
|
+
if (pack && !hasPack(game, pack)) continue;
|
|
1301
|
+
const general = field.path.includes("<pool>") ? poolsOf(game).map((pool) => field.path.replace("<pool>", pool)) : field.path.includes("<calling>") ? callingsOf({ packs: game?.packs }).map((calling) => field.path.replace("<calling>", calling.id)) : [field.path];
|
|
1302
|
+
for (const path of general.flatMap((each) => expandedPaths(def, each))) if (!paths.includes(path) && !fields.some((each) => each.path === path) && when(def)) fields.push(fieldOf(kind, def, {
|
|
1303
|
+
...field,
|
|
1304
|
+
path
|
|
1305
|
+
}));
|
|
1306
|
+
}
|
|
1307
|
+
fields.push(...allRows(game, kind, def));
|
|
1308
|
+
if (kind === "upgrades") fields.push(...levelLists(def));
|
|
1309
|
+
return fields;
|
|
1310
|
+
}
|
|
1311
|
+
return said.flatMap((field) => {
|
|
1312
|
+
const path = typeof field === "string" ? field : field.path;
|
|
1313
|
+
const spec = ROWS[kind]?.[path];
|
|
1314
|
+
if (!spec) return [fieldOf(kind, def, field)];
|
|
1315
|
+
const rows = valueAt(def, path);
|
|
1316
|
+
if (rows !== void 0 && !(Array.isArray(rows) && isData(rows))) return [];
|
|
1317
|
+
return rowsFields(game, spec, path, path.split(".").join(" "), rows ?? []);
|
|
1318
|
+
});
|
|
1319
|
+
}
|
|
1320
|
+
/** How many words a list field holds at most, and how long each is */
|
|
1321
|
+
var MAX_LIST = 64;
|
|
1322
|
+
var MAX_WORD = 100;
|
|
1323
|
+
/** Whether something is values as a data file has them: numbers, words, yes or no, lists of them and of things, a few deep */
|
|
1324
|
+
function isValues(value, depth = 0) {
|
|
1325
|
+
return isRecord(value) && depth <= 6 && Object.entries(value).every(([key, each]) => /^[\w$]+$/.test(key) && isEntry(each, depth + 1));
|
|
1326
|
+
}
|
|
1327
|
+
var isEntry = (value, depth) => isValue(value) && (typeof value !== "string" || value.length <= 200) || Array.isArray(value) && value.length <= MAX_LIST && value.every((each) => isEntry(each, depth + 1)) || isValues(value, depth);
|
|
1328
|
+
/** Whether something is a list of things as a `rows` field takes it whole */
|
|
1329
|
+
var isRows = (value) => Array.isArray(value) && value.length <= MAX_LIST && value.every((row) => isValues(row));
|
|
1330
|
+
/**
|
|
1331
|
+
* A value as a field takes it, or the reason it does not
|
|
1332
|
+
*
|
|
1333
|
+
* @beta
|
|
1334
|
+
*/
|
|
1335
|
+
function fitValue(field, value) {
|
|
1336
|
+
switch (field.kind) {
|
|
1337
|
+
case "rows": return isRows(value) && (!field.types || value.every((row) => typeof row.type === "string")) ? { value: value.map((row) => ({ ...row })) } : { error: `${field.path} is a list of things${field.types ? ", each of a type" : ""}` };
|
|
1338
|
+
case "list": {
|
|
1339
|
+
const words = field.one && typeof value === "string" ? [value] : value;
|
|
1340
|
+
return isWords(words) && words.length <= MAX_LIST && words.every((each) => each.length <= MAX_WORD) ? { value: field.one && words.length === 1 ? words[0] : [...words] } : { error: `${field.path} is a list of words` };
|
|
1341
|
+
}
|
|
1342
|
+
case "boolean": return typeof value === "boolean" ? { value } : { error: `${field.path} is yes or no` };
|
|
1343
|
+
case "text": return typeof value === "string" ? { value } : { error: `${field.path} is words` };
|
|
1344
|
+
case "id": return typeof value === "string" && value.length <= MAX_WORD ? { value } : { error: `${field.path} is an id${field.of ? ` of the ${field.of}` : ""}` };
|
|
1345
|
+
case "choice": return typeof value === "string" && (!field.options || field.options.includes(value)) ? { value } : { error: `${field.path} is one of ${(field.options ?? []).join(", ")}` };
|
|
1346
|
+
case "either":
|
|
1347
|
+
if (typeof value === "boolean" || typeof value === "string" && field.options?.includes(value)) return { value };
|
|
1348
|
+
if (field.orNumber && typeof value === "number" && Number.isFinite(value)) return { value: fitNumber(field, field.orNumber, value) };
|
|
1349
|
+
return { error: `${field.path} is ${[
|
|
1350
|
+
"yes or no",
|
|
1351
|
+
...field.options ?? [],
|
|
1352
|
+
...field.orNumber ? ["a number"] : []
|
|
1353
|
+
].join(", ")}` };
|
|
1354
|
+
default: return typeof value === "number" && Number.isFinite(value) ? { value: fitNumber(field, field.kind, value) } : { error: `${field.path} is a number` };
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
/** A number within a field's ends, whole where it is an integer */
|
|
1358
|
+
function fitNumber(field, kind, value) {
|
|
1359
|
+
let set = kind === "integer" ? Math.round(value) : value;
|
|
1360
|
+
if (field.min !== void 0) set = Math.max(set, field.min);
|
|
1361
|
+
if (field.max !== void 0) set = Math.min(set, field.max);
|
|
1362
|
+
return set;
|
|
1363
|
+
}
|
|
1364
|
+
/** Whether a list in the data is one of things by place (a unit's attacks) or of numbers (a bounty's two ends): walked by place, as a record of indices is */
|
|
1365
|
+
var byPlace = (value) => Array.isArray(value) && value.length > 0 && (value.every(isRecord) || value.every((each) => typeof each === "number"));
|
|
1366
|
+
/**
|
|
1367
|
+
* Every path of values, with what is there: a list of things or numbers by place (`attacks.0.damagePoint`), a list of
|
|
1368
|
+
* words whole, and a list of things whole where `whole` says (a `rows` field's)
|
|
1369
|
+
*/
|
|
1370
|
+
function pathsOf(values, whole = () => false, prefix = "") {
|
|
1371
|
+
return Object.entries(values).flatMap(([key, value]) => {
|
|
1372
|
+
const path = prefix ? `${prefix}.${key}` : key;
|
|
1373
|
+
return isRecord(value) || byPlace(value) && !whole(path) ? pathsOf(value, whole, path) : [{
|
|
1374
|
+
path,
|
|
1375
|
+
value
|
|
1376
|
+
}];
|
|
1377
|
+
});
|
|
1378
|
+
}
|
|
1379
|
+
/** Whether a record is one of places in a list: every key a whole number */
|
|
1380
|
+
var places = (value) => Object.keys(value).length > 0 && Object.keys(value).every((key) => /^\d+$/.test(key));
|
|
1381
|
+
/**
|
|
1382
|
+
* A definition with values over it: a copy, the parts the values go into copied too, the rest (its functions, its
|
|
1383
|
+
* lists of things) shared with the one it was made from. Values by place (`{ attacks: { 0: { damagePoint: 0.5 } } }`)
|
|
1384
|
+
* go into the list there, or make one where there is none. Nothing of the definition given is changed
|
|
1385
|
+
*
|
|
1386
|
+
* @beta
|
|
1387
|
+
*/
|
|
1388
|
+
function layValues(def, values) {
|
|
1389
|
+
const over = (into, from) => {
|
|
1390
|
+
const copy = Array.isArray(into) ? [...into] : { ...into };
|
|
1391
|
+
for (const [key, value] of Object.entries(from)) {
|
|
1392
|
+
if (!isRecord(value)) {
|
|
1393
|
+
copy[key] = value;
|
|
1394
|
+
continue;
|
|
1395
|
+
}
|
|
1396
|
+
const there = copy[key];
|
|
1397
|
+
const inner = isRecord(there) || Array.isArray(there) ? there : places(value) ? [] : {};
|
|
1398
|
+
copy[key] = over(inner, value);
|
|
1399
|
+
}
|
|
1400
|
+
return copy;
|
|
1401
|
+
};
|
|
1402
|
+
return over(def, values);
|
|
1403
|
+
}
|
|
1404
|
+
/**
|
|
1405
|
+
* Values merged: what `b` says over what `a` says, at any depth. Places said over a list go into it (`{ 0: { amount:
|
|
1406
|
+
* 50 } }` over a list of effects); a list said is the list
|
|
1407
|
+
*
|
|
1408
|
+
* @beta
|
|
1409
|
+
*/
|
|
1410
|
+
function mergeValues(a, b) {
|
|
1411
|
+
const out = { ...a };
|
|
1412
|
+
for (const [key, value] of Object.entries(b)) {
|
|
1413
|
+
const before = out[key];
|
|
1414
|
+
if (isRecord(value) && isRecord(before)) out[key] = mergeValues(before, value);
|
|
1415
|
+
else if (isRecord(value) && Array.isArray(before) && places(value)) {
|
|
1416
|
+
const list = [...before];
|
|
1417
|
+
for (const [place, each] of Object.entries(value)) list[Number(place)] = isRecord(each) && isRecord(list[Number(place)]) ? mergeValues(list[Number(place)], each) : each;
|
|
1418
|
+
out[key] = list;
|
|
1419
|
+
} else out[key] = value;
|
|
1420
|
+
}
|
|
1421
|
+
return out;
|
|
1422
|
+
}
|
|
1423
|
+
/**
|
|
1424
|
+
* Only the values of the fields that can be changed, each as its field takes it. What is not is left out and said:
|
|
1425
|
+
* a field the game no longer lets be changed, a value of another kind
|
|
1426
|
+
*
|
|
1427
|
+
* @beta
|
|
1428
|
+
*/
|
|
1429
|
+
function editableValues(fields, values, said = () => {}) {
|
|
1430
|
+
let out = {};
|
|
1431
|
+
const rows = new Set(fields.filter((field) => field.kind === "rows").map((field) => field.path));
|
|
1432
|
+
for (const { path, value } of pathsOf(values, (path) => rows.has(path))) {
|
|
1433
|
+
const field = fields.find((each) => each.path === path);
|
|
1434
|
+
if (!field) {
|
|
1435
|
+
said(`${path} cannot be changed from the data`);
|
|
1436
|
+
continue;
|
|
1437
|
+
}
|
|
1438
|
+
const fit = fitValue(field, value);
|
|
1439
|
+
if ("error" in fit) said(fit.error);
|
|
1440
|
+
else out = mergeValues(out, nested(path, fit.value));
|
|
1441
|
+
}
|
|
1442
|
+
return out;
|
|
1443
|
+
}
|
|
1444
|
+
/**
|
|
1445
|
+
* The game with what its `data.json` says over what its code says: `export default layData(game, dataFile)`. Only
|
|
1446
|
+
* the fields the game lets be changed (`Rules.editable`) are taken, and of the kind each holds; anything else in
|
|
1447
|
+
* the file is left out, and said in the log. The game given is not changed
|
|
1448
|
+
*
|
|
1449
|
+
* @beta
|
|
1450
|
+
*/
|
|
1451
|
+
function layData(game, file) {
|
|
1452
|
+
if (!isRecord(file)) return game;
|
|
1453
|
+
const warn = (why) => rootLogger.warn("game", `${game.id}'s data.json: ${why}`);
|
|
1454
|
+
if (file.defaults !== void 0) {
|
|
1455
|
+
const wrong = dataDefaultsProblem(file.defaults, game);
|
|
1456
|
+
if (wrong) warn(wrong);
|
|
1457
|
+
else game = dataDefaults(game, file.defaults);
|
|
1458
|
+
}
|
|
1459
|
+
let out = { ...game };
|
|
1460
|
+
if (file.tags !== void 0) {
|
|
1461
|
+
const wrong = dataEntriesProblem("tags", file.tags);
|
|
1462
|
+
if (wrong) warn(wrong);
|
|
1463
|
+
else out.tags = layEntries(out.tags ?? [], file.tags, (id) => ({ id }));
|
|
1464
|
+
}
|
|
1465
|
+
if (file.callings !== void 0) {
|
|
1466
|
+
const wrong = dataEntriesProblem("callings", file.callings);
|
|
1467
|
+
if (wrong) warn(wrong);
|
|
1468
|
+
else out = withCallings(out, layEntries(callingsOf(out), file.callings, (id) => ({
|
|
1469
|
+
id,
|
|
1470
|
+
name: id
|
|
1471
|
+
})));
|
|
1472
|
+
}
|
|
1473
|
+
if (file.cellLayers !== void 0) {
|
|
1474
|
+
const wrong = dataCellLayersProblem(file.cellLayers);
|
|
1475
|
+
if (wrong) warn(wrong);
|
|
1476
|
+
else {
|
|
1477
|
+
const said = file.cellLayers;
|
|
1478
|
+
if (out.cellLayers) out.cellLayers = layCellLayerData(out.cellLayers, said);
|
|
1479
|
+
for (const layer of Object.keys(said)) if (!out.cellLayers?.some((def) => def.id === layer)) warn(`cellLayers: the game has no layer of cells "${layer}"`);
|
|
1480
|
+
}
|
|
1481
|
+
}
|
|
1482
|
+
for (const kind of DATA_KINDS) {
|
|
1483
|
+
const values = file[kind];
|
|
1484
|
+
if (values === void 0) continue;
|
|
1485
|
+
const defs = game[kind];
|
|
1486
|
+
if (!isRecord(values) || !defs) {
|
|
1487
|
+
warn(`there are no ${kind} to set`);
|
|
1488
|
+
continue;
|
|
1489
|
+
}
|
|
1490
|
+
const seen = new Set(Object.keys(values));
|
|
1491
|
+
/** What is said of a definition as its fields take it, what it is a copy of (or that it is new) left out */
|
|
1492
|
+
const over = (def, own) => {
|
|
1493
|
+
const { [COPY_OF]: _, ["new"]: isNew, ...rest } = own;
|
|
1494
|
+
if (isNew === true) delete rest.kind;
|
|
1495
|
+
return layValues(def, editableValues(editableFields(game, kind, def), rest, (why) => warn(`${kind}.${def.id}: ${why}`)));
|
|
1496
|
+
};
|
|
1497
|
+
const made = defs.map((def) => {
|
|
1498
|
+
const own = values[def.id];
|
|
1499
|
+
if (!isRecord(own)) return def;
|
|
1500
|
+
seen.delete(def.id);
|
|
1501
|
+
return over(def, own);
|
|
1502
|
+
});
|
|
1503
|
+
for (const id of seen) {
|
|
1504
|
+
const own = values[id];
|
|
1505
|
+
if (!isRecord(own) || own["new"] !== true) continue;
|
|
1506
|
+
made.push(over(blankDefinition(kind, id, unitKindOf(own.kind)), own));
|
|
1507
|
+
seen.delete(id);
|
|
1508
|
+
}
|
|
1509
|
+
for (let progress = true; progress;) {
|
|
1510
|
+
progress = false;
|
|
1511
|
+
for (const id of seen) {
|
|
1512
|
+
const own = values[id];
|
|
1513
|
+
const from = isRecord(own) ? own[COPY_OF] : void 0;
|
|
1514
|
+
const base = typeof from === "string" ? made.find((def) => def.id === from) : void 0;
|
|
1515
|
+
if (!base) continue;
|
|
1516
|
+
made.push(over({
|
|
1517
|
+
...base,
|
|
1518
|
+
id,
|
|
1519
|
+
basedOn: from
|
|
1520
|
+
}, own));
|
|
1521
|
+
seen.delete(id);
|
|
1522
|
+
progress = true;
|
|
1523
|
+
}
|
|
1524
|
+
}
|
|
1525
|
+
out[kind] = made;
|
|
1526
|
+
for (const id of seen) {
|
|
1527
|
+
const from = isRecord(values[id]) ? values[id][COPY_OF] : void 0;
|
|
1528
|
+
warn(typeof from === "string" ? `${kind}.${id} is a copy of "${from}", which the game has not` : `the game has no ${kind} "${id}"`);
|
|
1529
|
+
}
|
|
1530
|
+
}
|
|
1531
|
+
const ai = file.ai;
|
|
1532
|
+
if (ai !== void 0) {
|
|
1533
|
+
const races = isRecord(ai) ? ai.races : void 0;
|
|
1534
|
+
if (!isRecord(ai) || races !== void 0 && !isRecord(races)) warn("ai is no { races: { <race>: <profile> } }");
|
|
1535
|
+
else if (isRecord(races)) {
|
|
1536
|
+
const own = { ...game.ai?.races };
|
|
1537
|
+
for (const [race, profile] of Object.entries(races)) {
|
|
1538
|
+
if (!isRecord(profile)) {
|
|
1539
|
+
warn(`ai.races.${race} is no profile`);
|
|
1540
|
+
continue;
|
|
1541
|
+
}
|
|
1542
|
+
if (!(out.races ?? []).some((def) => def.id === race)) warn(`ai.races: the game has no race "${race}"`);
|
|
1543
|
+
own[race] = profile;
|
|
1544
|
+
}
|
|
1545
|
+
out.ai = {
|
|
1546
|
+
...game.ai,
|
|
1547
|
+
races: own
|
|
1548
|
+
};
|
|
1549
|
+
}
|
|
1550
|
+
}
|
|
1551
|
+
if (file.rules !== void 0) {
|
|
1552
|
+
const wrong = dataRulesProblem(file.rules);
|
|
1553
|
+
if (wrong) warn(wrong);
|
|
1554
|
+
else Object.assign(out, withDataRules(out, file.rules));
|
|
1555
|
+
}
|
|
1556
|
+
const removed = file.removed;
|
|
1557
|
+
if (isRecord(removed)) for (const [kind, ids] of Object.entries(removed)) {
|
|
1558
|
+
const list = out[kind];
|
|
1559
|
+
if (!DATA_KINDS.includes(kind) || !list || !isWords(ids)) {
|
|
1560
|
+
warn(`removed.${kind} is no list of ${kind} of the game`);
|
|
1561
|
+
continue;
|
|
1562
|
+
}
|
|
1563
|
+
for (const id of ids) if (!list.some((def) => def.id === id)) warn(`removed.${kind}: the game has no ${kind} "${id}"`);
|
|
1564
|
+
out[kind] = list.filter((def) => !ids.includes(def.id));
|
|
1565
|
+
}
|
|
1566
|
+
return out;
|
|
1567
|
+
}
|
|
1568
|
+
/** The kind of thing a unit type made of nothing is, as its data says: a unit when it says none the game knows */
|
|
1569
|
+
var unitKindOf = (said) => typeof said === "string" && UNIT_KINDS.includes(said) ? said : void 0;
|
|
1570
|
+
/**
|
|
1571
|
+
* What a world's definitions were changed to while it runs (`world.redefine`), by kind and id: kept with the world
|
|
1572
|
+
* and in its save, so that a load has them again
|
|
1573
|
+
*
|
|
1574
|
+
* @beta
|
|
1575
|
+
*/
|
|
1576
|
+
var redefinitions = defineComponent({
|
|
1577
|
+
id: "core.redefinitions",
|
|
1578
|
+
default: () => ({})
|
|
1579
|
+
});
|
|
1580
|
+
/**
|
|
1581
|
+
* A definition changed while the game runs: what it is now
|
|
1582
|
+
*
|
|
1583
|
+
* @beta
|
|
1584
|
+
*/
|
|
1585
|
+
var definitionChanged = defineEngineEvent({ id: "core.definitionChanged" });
|
|
1586
|
+
/**
|
|
1587
|
+
* Puts a definition with values over it into the registry, in the place of the one there: what is made of it from
|
|
1588
|
+
* then on is made of the new one. False for a definition the game does not have
|
|
1589
|
+
*
|
|
1590
|
+
* @beta
|
|
1591
|
+
*/
|
|
1592
|
+
function redefineIn(registry, kind, id, values) {
|
|
1593
|
+
const copyOf = values[COPY_OF];
|
|
1594
|
+
if (typeof copyOf === "string" && !definitionIn(registry, kind, id)) {
|
|
1595
|
+
if (!copyDefinition(registry, kind, copyOf, id)) return false;
|
|
1596
|
+
const { [COPY_OF]: _, ...rest } = values;
|
|
1597
|
+
return Object.keys(rest).length ? redefineIn(registry, kind, id, rest) : true;
|
|
1598
|
+
}
|
|
1599
|
+
if (values["new"] === true && !definitionIn(registry, kind, id)) {
|
|
1600
|
+
if (!id) return false;
|
|
1601
|
+
registry.kinds[kind].define(blankDefinition(kind, id, unitKindOf(values.kind)));
|
|
1602
|
+
const { ["new"]: _, kind: __, ...rest } = values;
|
|
1603
|
+
return Object.keys(rest).length ? redefineIn(registry, kind, id, rest) : true;
|
|
1604
|
+
}
|
|
1605
|
+
if ("copyOf" in values || "new" in values) {
|
|
1606
|
+
const { [COPY_OF]: _, ["new"]: __, ...rest } = values;
|
|
1607
|
+
values = rest;
|
|
1608
|
+
}
|
|
1609
|
+
const defs = registry.kinds[kind];
|
|
1610
|
+
const def = defs.find(id);
|
|
1611
|
+
if (!def) return false;
|
|
1612
|
+
defs.define(layValues(def, values));
|
|
1613
|
+
return true;
|
|
1614
|
+
}
|
|
1615
|
+
/**
|
|
1616
|
+
* A new definition, a copy of one the registry has, by an id it has nothing by: what it is drawn as is the one it is
|
|
1617
|
+
* a copy of (`basedOn`) until the game gives it a look of its own. False for one it does not have, or an id it has
|
|
1618
|
+
*
|
|
1619
|
+
* @beta
|
|
1620
|
+
*/
|
|
1621
|
+
function copyDefinition(registry, kind, from, id) {
|
|
1622
|
+
const base = definitionIn(registry, kind, from);
|
|
1623
|
+
if (!base || definitionIn(registry, kind, id) || !id) return false;
|
|
1624
|
+
const copy = {
|
|
1625
|
+
...base,
|
|
1626
|
+
id,
|
|
1627
|
+
basedOn: from
|
|
1628
|
+
};
|
|
1629
|
+
registry.kinds[kind].define(copy);
|
|
1630
|
+
return true;
|
|
1631
|
+
}
|
|
1632
|
+
/**
|
|
1633
|
+
* Takes a definition out of the registry (the Data panel's Delete): what is made of it from then on is not. False for
|
|
1634
|
+
* one it has not. Not for a world that runs: its units of the type are there
|
|
1635
|
+
*
|
|
1636
|
+
* @beta
|
|
1637
|
+
*/
|
|
1638
|
+
function removeDefinition(registry, kind, id) {
|
|
1639
|
+
return registry.kinds[kind].remove(id);
|
|
1640
|
+
}
|
|
1641
|
+
/**
|
|
1642
|
+
* The definition of a kind and id in the registry, as it is now, or undefined
|
|
1643
|
+
*
|
|
1644
|
+
* @beta
|
|
1645
|
+
*/
|
|
1646
|
+
function definitionIn(registry, kind, id) {
|
|
1647
|
+
return registry.kinds[kind].find(id);
|
|
1648
|
+
}
|
|
1649
|
+
/**
|
|
1650
|
+
* Every definition of a kind the registry has
|
|
1651
|
+
*
|
|
1652
|
+
* @beta
|
|
1653
|
+
*/
|
|
1654
|
+
function definitionsIn(registry, kind) {
|
|
1655
|
+
return registry.kinds[kind].all();
|
|
1656
|
+
}
|
|
1657
|
+
/** Puts what a save kept of the definitions changed while it ran back into the registry: before its entities are made */
|
|
1658
|
+
function restoreRedefinitions(registry, kept) {
|
|
1659
|
+
if (!isRecord(kept)) return;
|
|
1660
|
+
for (const kind of DATA_KINDS) {
|
|
1661
|
+
const byId = kept[kind];
|
|
1662
|
+
if (!isRecord(byId)) continue;
|
|
1663
|
+
for (const [id, values] of Object.entries(byId)) if (isRecord(values)) redefineIn(registry, kind, id, values);
|
|
1664
|
+
}
|
|
1665
|
+
}
|
|
1666
|
+
/** A path into a definition: names and places, joined by dots */
|
|
1667
|
+
/** A path into a definition, as the Data panel names a field: `stats.health` */
|
|
1668
|
+
var pathCheck = (value, path) => {
|
|
1669
|
+
const text = string(value, path);
|
|
1670
|
+
if (!/^[A-Za-z_$][\w$]*(\.[\w$]+)*$/.test(text)) throw new Invalid(`${path} is a path like stats.health`);
|
|
1671
|
+
return text;
|
|
1672
|
+
};
|
|
1673
|
+
/** A value of a field the Data panel may set: a number, words, yes or no, a list of words, or a list of things whole */
|
|
1674
|
+
var valueCheck = (value, path) => {
|
|
1675
|
+
if (isValue(value) && (typeof value !== "string" || value.length <= 200)) return value;
|
|
1676
|
+
if (isWords(value) && value.length <= MAX_LIST && value.every((each) => each.length <= MAX_WORD)) return value;
|
|
1677
|
+
if (isRows(value)) return value;
|
|
1678
|
+
throw new Invalid(`${path} is a number, words, yes or no, a list of words, or a list of things`);
|
|
1679
|
+
};
|
|
1680
|
+
/** A definition changed while the game runs (`world.redefine`): to everyone, whose screens read the definitions */
|
|
1681
|
+
var toldRedefined = replicateEvent(definitionChanged, "redefined", ({ kind, id, values }) => values ? {
|
|
1682
|
+
type: "redefined",
|
|
1683
|
+
kind,
|
|
1684
|
+
definition: id,
|
|
1685
|
+
values: structuredClone(values)
|
|
1686
|
+
} : void 0);
|
|
1687
|
+
//#endregion
|
|
1688
|
+
export { COPY_OF, DATA_KINDS, NEW_DEFINITION, REQUIRED_FIELDS, blankDefinition, copyDefinition, dataEntriesProblem, dataRulesProblem, definitionChanged, definitionIn, definitionsIn, editableFields, editableValues, effectFields, effectTypesOf, fitValue, layData, layValues, mergeValues, nested, pathCheck, redefineIn, redefinitions, removeDefinition, restoreRedefinitions, toldRedefined, valueAt, valueCheck };
|
|
1689
|
+
|
|
1690
|
+
//# sourceMappingURL=gameData.js.map
|