@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/foliage.js
ADDED
|
@@ -0,0 +1,1478 @@
|
|
|
1
|
+
import { cos, exp, sin } from "./exactMath.js";
|
|
2
|
+
import { defineComponent } from "./components.js";
|
|
3
|
+
import { defineEvent } from "./events.js";
|
|
4
|
+
import { gusted } from "./engineEvents.js";
|
|
5
|
+
import { replicateEvent } from "./replication.js";
|
|
6
|
+
import { moving } from "./entity.js";
|
|
7
|
+
import { defineHookType } from "./hooks.js";
|
|
8
|
+
import { areaReach, effectArea, inArea } from "./abilities/shapes.js";
|
|
9
|
+
import { defineEffect } from "./abilities/effects.js";
|
|
10
|
+
import { areaShapeOf, inShape, shapeBounds } from "./areas.js";
|
|
11
|
+
import { concealmentPack } from "./concealment.js";
|
|
12
|
+
import { FoliageRegrowth, REGROWTH, regrowState } from "./foliageRegrowth.js";
|
|
13
|
+
import "./map/types.js";
|
|
14
|
+
import { mapInfo } from "./names.js";
|
|
15
|
+
//#region src/foliage.ts
|
|
16
|
+
/**
|
|
17
|
+
* The id of the foliage pack (`foliagePack`), for `hasPack`
|
|
18
|
+
*
|
|
19
|
+
* @beta
|
|
20
|
+
*/
|
|
21
|
+
var FOLIAGE = "foliage";
|
|
22
|
+
/**
|
|
23
|
+
* What has happened to a cell of grass or bushes, as the values of the layer's state layer (`foliageStateLayer`):
|
|
24
|
+
* `whole` (0: as it grew, and what a cell never touched is), `flattened` (crushed under what walked over it, or by
|
|
25
|
+
* `ruin`), `cut` (down to stubble: fire does not cross it), `burning`, `burnt` (charred: by a fire, or scorched by
|
|
26
|
+
* `ruin`), `growing` (coming back to whole). The style stays in the layer itself, so that what grows back is what
|
|
27
|
+
* stood there. Values past these are kept for states to come
|
|
28
|
+
*
|
|
29
|
+
* @beta
|
|
30
|
+
*/
|
|
31
|
+
var FOLIAGE_STATE = {
|
|
32
|
+
whole: 0,
|
|
33
|
+
flattened: 1,
|
|
34
|
+
cut: 2,
|
|
35
|
+
burning: 3,
|
|
36
|
+
burnt: 4,
|
|
37
|
+
growing: 5
|
|
38
|
+
};
|
|
39
|
+
var STATE_NAMES = Object.keys(FOLIAGE_STATE);
|
|
40
|
+
/**
|
|
41
|
+
* The state a value of a state layer says (`FOLIAGE_STATE`): `whole` for a value that is none of them
|
|
42
|
+
*
|
|
43
|
+
* @beta
|
|
44
|
+
*/
|
|
45
|
+
var foliageStateOf = (value) => STATE_NAMES.find((name) => FOLIAGE_STATE[name] === value) ?? "whole";
|
|
46
|
+
/** What a state layer's id ends with, after the id of the layer it is the state of */
|
|
47
|
+
var STATE = ".state";
|
|
48
|
+
/**
|
|
49
|
+
* The id of the layer of cells that keeps what happened to each cell of a layer of grass or bushes (`FOLIAGE_STATE`):
|
|
50
|
+
* `grass.state` for `grass`. A layer like any other (`Terrain.cells`, `world.setCells`): saved, told to the players who
|
|
51
|
+
* see a cell and to the others as it comes into their sight, kept with a map that starts with a field already burnt.
|
|
52
|
+
* No game lists it (`Rules.cellLayers`), so the editor does not offer it to paint
|
|
53
|
+
*
|
|
54
|
+
* @beta
|
|
55
|
+
*/
|
|
56
|
+
var foliageStateLayer = (layer) => `${layer}${STATE}`;
|
|
57
|
+
/**
|
|
58
|
+
* The layer a state layer is the state of (`foliageStateLayer`): none for a layer that is not one
|
|
59
|
+
*
|
|
60
|
+
* @beta
|
|
61
|
+
*/
|
|
62
|
+
var foliageLayerOfState = (layer) => layer.endsWith(STATE) && layer.length > 6 ? layer.slice(0, -6) : void 0;
|
|
63
|
+
/**
|
|
64
|
+
* The layers a foliage pack was made with, each with its settings: the first, then those beside it (`FoliageOptions.also`)
|
|
65
|
+
*
|
|
66
|
+
* @beta
|
|
67
|
+
*/
|
|
68
|
+
function foliageLayers(options) {
|
|
69
|
+
const { also, fire: _, ...first } = options;
|
|
70
|
+
return [first, ...also ?? []];
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* What a style of a layer is to the rules, by its value: what the value says (`CellLayerValue.foliage`, the game's
|
|
74
|
+
* code with its data and the map's over it) over the layer's own (`FoliageLayerOptions.style`). None for 0, which is
|
|
75
|
+
* no grass. A value the layer does not list is the layer's own style
|
|
76
|
+
*
|
|
77
|
+
* @beta
|
|
78
|
+
*/
|
|
79
|
+
function foliageStyle(game, layer, value) {
|
|
80
|
+
if (!value) return void 0;
|
|
81
|
+
const pack = game.packs?.find((each) => each.id === FOLIAGE);
|
|
82
|
+
const base = pack ? foliageLayers(pack.options).find((each) => each.layer === layer)?.style : void 0;
|
|
83
|
+
const own = game.cellLayers?.find((def) => def.id === layer)?.values?.find((each) => each.value === value)?.foliage;
|
|
84
|
+
return {
|
|
85
|
+
...base,
|
|
86
|
+
...own
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
/** The fields of a style, and what each holds */
|
|
90
|
+
var STYLE_FIELDS = {
|
|
91
|
+
conceals: "boolean",
|
|
92
|
+
concealsTaller: "boolean",
|
|
93
|
+
height: "number",
|
|
94
|
+
speed: "number",
|
|
95
|
+
walkable: "boolean",
|
|
96
|
+
flammable: "share",
|
|
97
|
+
burns: "number",
|
|
98
|
+
fuel: "number",
|
|
99
|
+
regrows: "regrows",
|
|
100
|
+
grows: "number",
|
|
101
|
+
trample: "trample"
|
|
102
|
+
};
|
|
103
|
+
/**
|
|
104
|
+
* Why a style said as data is not one (`FoliageStyleDef`), where it is first wrong: nothing for one that is. `what`
|
|
105
|
+
* names it in what is said
|
|
106
|
+
*
|
|
107
|
+
* @beta
|
|
108
|
+
*/
|
|
109
|
+
function foliageStyleProblem(said, what) {
|
|
110
|
+
if (typeof said !== "object" || said === null || Array.isArray(said)) return `${what} is no style of grass: { conceals, flammable, burns… }`;
|
|
111
|
+
for (const [field, value] of Object.entries(said)) {
|
|
112
|
+
const kind = STYLE_FIELDS[field];
|
|
113
|
+
if (!kind) return `${what}.${field} is nothing a style of grass says (${Object.keys(STYLE_FIELDS).join(", ")})`;
|
|
114
|
+
const number = typeof value === "number" && Number.isFinite(value) && value >= 0;
|
|
115
|
+
if (kind === "boolean" && typeof value !== "boolean") return `${what}.${field} is no yes or no`;
|
|
116
|
+
if (kind === "number" && !number) return `${what}.${field} is no number from 0`;
|
|
117
|
+
if (kind === "share" && !(number && value <= 1)) return `${what}.${field} is no number from 0 to 1`;
|
|
118
|
+
if (kind === "regrows" && value !== false && !number) return `${what}.${field} is seconds, or false for never`;
|
|
119
|
+
if (kind === "trample" && value !== "none" && value !== "crush") return `${what}.${field} is none or crush`;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Asked before a cell of grass catches fire (`FoliageIgnite`): a handler refuses it or changes its chance. For every
|
|
124
|
+
* cell a fire tries, so a handler does little
|
|
125
|
+
*
|
|
126
|
+
* @beta
|
|
127
|
+
*/
|
|
128
|
+
var foliageIgnite = /* @__PURE__ */ defineHookType({ id: "foliage.ignite" });
|
|
129
|
+
/**
|
|
130
|
+
* Cells of grass caught fire this tick, by layer and cause: what a game's rules and its computer players hear. The
|
|
131
|
+
* screens are told by the state layer's cells, each as far as it sees
|
|
132
|
+
*
|
|
133
|
+
* @beta
|
|
134
|
+
*/
|
|
135
|
+
var foliageIgnited = defineEvent({ id: "foliage.ignited" });
|
|
136
|
+
/**
|
|
137
|
+
* Cells of grass burnt out this tick: charred now, to grow back where their style says
|
|
138
|
+
*
|
|
139
|
+
* @beta
|
|
140
|
+
*/
|
|
141
|
+
var foliageBurnt = defineEvent({ id: "foliage.burnt" });
|
|
142
|
+
/**
|
|
143
|
+
* Cells of grass were ruined (`ruin`, `firebreak`, an ability, what tramples): how, and by whom where someone did
|
|
144
|
+
*
|
|
145
|
+
* @beta
|
|
146
|
+
*/
|
|
147
|
+
var foliageRuined = defineEvent({ id: "foliage.ruined" });
|
|
148
|
+
/**
|
|
149
|
+
* Cells of grass are whole again: grown back by themselves, or by `regrow` (by whom, where it said)
|
|
150
|
+
*
|
|
151
|
+
* @beta
|
|
152
|
+
*/
|
|
153
|
+
var foliageRegrown = defineEvent({ id: "foliage.regrown" });
|
|
154
|
+
/**
|
|
155
|
+
* The last burning cell of a layer went out: burnt out, put out or stopped
|
|
156
|
+
*
|
|
157
|
+
* @beta
|
|
158
|
+
*/
|
|
159
|
+
var foliageFireOut = defineEvent({ id: "foliage.fireOut" });
|
|
160
|
+
/**
|
|
161
|
+
* Grass and bushes in the rules, on a layer of cells whose values are styles (`CellLayerValue.foliage`,
|
|
162
|
+
* `FoliageStyleDef`): the styles that conceal hide who stands in them (as `concealmentPack`, patch by patch, while
|
|
163
|
+
* they stand whole), a style may slow or stop one on foot, be crushed under who walks over it, be ruined and grow
|
|
164
|
+
* back, catch fire and pass it on (`FoliageFire`). What happened to each cell is kept in the layer's state layer
|
|
165
|
+
* (`foliageStateLayer`). One a game:
|
|
166
|
+
*
|
|
167
|
+
* export const rules = { ...myGame, packs: [foliagePack({ layer: 'grass', fire: { damage: 8 } })] }
|
|
168
|
+
*
|
|
169
|
+
* A layer of the pack is not given to `concealmentPack` too: the pack hides in it by itself. Its styles are read from
|
|
170
|
+
* the game's layers as laid (`foliageStyle`: the code, the game's `data.json`, the map's definitions), so a style the
|
|
171
|
+
* editor made hides and slows as one of the code's. What it does today: hiding by style and state, a style's
|
|
172
|
+
* `speed` and `walkable`, trampling (`trample: 'crush'`, by who `tramples` says), fire (`ignite`, `FoliageFire`) with
|
|
173
|
+
* `firebreak`, `extinguish` and `stopFire`, ruin (`ruin`) and growing back (`regrow`, by itself where a style
|
|
174
|
+
* `regrows`), and the `foliage` ability effect
|
|
175
|
+
*
|
|
176
|
+
* @beta
|
|
177
|
+
*/
|
|
178
|
+
function foliagePack(options) {
|
|
179
|
+
const layers = foliageLayers(options);
|
|
180
|
+
const hooks = [];
|
|
181
|
+
const systems = [];
|
|
182
|
+
const seen = /* @__PURE__ */ new Set();
|
|
183
|
+
for (const each of layers) {
|
|
184
|
+
const { layer } = each;
|
|
185
|
+
if (!layer) throw new Error("foliagePack: a layer is named by its id (Rules.cellLayers)");
|
|
186
|
+
if (foliageLayerOfState(layer) !== void 0) throw new Error(`foliagePack: "${layer}" is the state of a layer, not a layer of grass`);
|
|
187
|
+
if (seen.has(layer)) throw new Error(`foliagePack: the layer "${layer}" is given twice`);
|
|
188
|
+
seen.add(layer);
|
|
189
|
+
const hiding = concealmentPack({
|
|
190
|
+
...foliageConcealment(each),
|
|
191
|
+
eachUnit: trampling(each)
|
|
192
|
+
});
|
|
193
|
+
hooks.push(...hiding.hooks ?? []);
|
|
194
|
+
systems.push(...hiding.systems ?? []);
|
|
195
|
+
}
|
|
196
|
+
const fire = new FoliageFireRules(options);
|
|
197
|
+
if (fire.on) systems.push(fire.system);
|
|
198
|
+
systems.push(fire.regrowth.system);
|
|
199
|
+
return {
|
|
200
|
+
id: FOLIAGE,
|
|
201
|
+
options,
|
|
202
|
+
hooks,
|
|
203
|
+
systems,
|
|
204
|
+
components: [fireState, regrowState],
|
|
205
|
+
events: [
|
|
206
|
+
foliageIgnited,
|
|
207
|
+
foliageBurnt,
|
|
208
|
+
foliageRuined,
|
|
209
|
+
foliageRegrown,
|
|
210
|
+
foliageFireOut
|
|
211
|
+
],
|
|
212
|
+
effects: [foliageEffect],
|
|
213
|
+
[FIRE]: fire,
|
|
214
|
+
[REGROWTH]: fire.regrowth
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* How a layer of the pack hides (`ConcealmentOptions`): in the cells whose style conceals and whose state is whole or
|
|
219
|
+
* growing back (`conceals`), the patches worked out again as either layer changes (`follows`); a unit taller than a
|
|
220
|
+
* style that says so seen over it (`seenBy`, asked only of who would be hidden)
|
|
221
|
+
*/
|
|
222
|
+
function foliageConcealment({ layer, conceal = {} }) {
|
|
223
|
+
const state = foliageStateLayer(layer);
|
|
224
|
+
let last;
|
|
225
|
+
const known = /* @__PURE__ */ new WeakMap();
|
|
226
|
+
/** What each value is to hiding in the world's game, worked out once for its layers of cells */
|
|
227
|
+
const stylesOf = (world) => {
|
|
228
|
+
const { cellLayers } = world.registry;
|
|
229
|
+
if (last?.of === cellLayers) return last;
|
|
230
|
+
let styles = known.get(cellLayers);
|
|
231
|
+
if (!styles) {
|
|
232
|
+
styles = {
|
|
233
|
+
of: cellLayers,
|
|
234
|
+
conceals: /* @__PURE__ */ new Uint8Array(256),
|
|
235
|
+
over: (/* @__PURE__ */ new Float32Array(256)).fill(Infinity),
|
|
236
|
+
taller: false
|
|
237
|
+
};
|
|
238
|
+
const game = {
|
|
239
|
+
cellLayers,
|
|
240
|
+
packs: world.registry.assembly?.rules.packs
|
|
241
|
+
};
|
|
242
|
+
for (let value = 1; value < 256; value++) {
|
|
243
|
+
const style = foliageStyle(game, layer, value);
|
|
244
|
+
styles.conceals[value] = style?.conceals ? 1 : 0;
|
|
245
|
+
styles.over[value] = style?.conceals && style.concealsTaller === false ? style.height ?? 1 : Infinity;
|
|
246
|
+
if (styles.over[value] !== Infinity) styles.taller = true;
|
|
247
|
+
}
|
|
248
|
+
known.set(cellLayers, styles);
|
|
249
|
+
}
|
|
250
|
+
return last = styles;
|
|
251
|
+
};
|
|
252
|
+
const { heightOf = (_world, entity) => entity.def.radius * 2, seenBy, ...rest } = conceal;
|
|
253
|
+
return {
|
|
254
|
+
...rest,
|
|
255
|
+
layer,
|
|
256
|
+
follows: [state],
|
|
257
|
+
conceals(world, cell) {
|
|
258
|
+
const { cells } = world.terrain;
|
|
259
|
+
if (!(last?.of === world.registry.cellLayers ? last : stylesOf(world)).conceals[cells[layer][cell]]) return false;
|
|
260
|
+
const states = cells[state];
|
|
261
|
+
if (!states) return true;
|
|
262
|
+
const now = states[cell];
|
|
263
|
+
return now === FOLIAGE_STATE.whole || now === FOLIAGE_STATE.growing;
|
|
264
|
+
},
|
|
265
|
+
seenBy(world, entity, team) {
|
|
266
|
+
const styles = stylesOf(world);
|
|
267
|
+
if (styles.taller) {
|
|
268
|
+
const { width } = world.terrain;
|
|
269
|
+
const over = styles.over[world.terrain.cells[layer]?.[Math.floor(entity.pos.z) * width + Math.floor(entity.pos.x)] ?? 0];
|
|
270
|
+
if (over !== Infinity && heightOf(world, entity) > over) return true;
|
|
271
|
+
}
|
|
272
|
+
return seenBy?.(world, entity, team) ?? false;
|
|
273
|
+
}
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
/** Who tramples when the layer does not say: units on the ground that walk (not structures, not what flies or sails) */
|
|
277
|
+
var onFoot = (_world, entity) => !entity.def.footprint && !entity.flying && !entity.def.naval && entity.def.kind === "unit";
|
|
278
|
+
/** Who crushed the cells put among a tick's from `had` on: one alone, or nobody named where another did too */
|
|
279
|
+
function noteBy(trampled, entity, had) {
|
|
280
|
+
if (trampled.cells.length === had) return;
|
|
281
|
+
trampled.by = trampled.by === void 0 || trampled.by === entity ? entity : null;
|
|
282
|
+
}
|
|
283
|
+
/** How a layer of the pack is trampled, told of each unit by the hiding count (`ConcealmentOptions.eachUnit`) */
|
|
284
|
+
function trampling({ layer, tramples = onFoot }) {
|
|
285
|
+
const state = foliageStateLayer(layer);
|
|
286
|
+
let last;
|
|
287
|
+
const known = /* @__PURE__ */ new WeakMap();
|
|
288
|
+
const worlds = /* @__PURE__ */ new WeakMap();
|
|
289
|
+
const stylesOf = (world) => {
|
|
290
|
+
const { cellLayers } = world.registry;
|
|
291
|
+
if (last?.of === cellLayers) return last;
|
|
292
|
+
let styles = known.get(cellLayers);
|
|
293
|
+
if (!styles) {
|
|
294
|
+
styles = {
|
|
295
|
+
of: cellLayers,
|
|
296
|
+
crushes: /* @__PURE__ */ new Uint8Array(256),
|
|
297
|
+
any: false
|
|
298
|
+
};
|
|
299
|
+
const game = {
|
|
300
|
+
cellLayers,
|
|
301
|
+
packs: world.registry.assembly?.rules.packs
|
|
302
|
+
};
|
|
303
|
+
for (let value = 1; value < 256; value++) if (foliageStyle(game, layer, value)?.trample === "crush") {
|
|
304
|
+
styles.crushes[value] = 1;
|
|
305
|
+
styles.any = true;
|
|
306
|
+
}
|
|
307
|
+
known.set(cellLayers, styles);
|
|
308
|
+
}
|
|
309
|
+
return last = styles;
|
|
310
|
+
};
|
|
311
|
+
/** A cell crushed this tick, where its style is and it stands whole or growing */
|
|
312
|
+
const crush = (world, styles, trampled, cell) => {
|
|
313
|
+
const { cells } = world.terrain;
|
|
314
|
+
if (!styles.crushes[cells[layer]?.[cell] ?? 0] || trampled.stamp[cell] === trampled.tick) return;
|
|
315
|
+
const now = cells[state]?.[cell] ?? FOLIAGE_STATE.whole;
|
|
316
|
+
if (now !== FOLIAGE_STATE.whole && now !== FOLIAGE_STATE.growing) return;
|
|
317
|
+
trampled.stamp[cell] = trampled.tick;
|
|
318
|
+
trampled.cells.push(cell);
|
|
319
|
+
};
|
|
320
|
+
return {
|
|
321
|
+
unit(world, entity, cell) {
|
|
322
|
+
const styles = last?.of === world.registry.cellLayers ? last : stylesOf(world);
|
|
323
|
+
if (!styles.any) return;
|
|
324
|
+
const { terrain } = world;
|
|
325
|
+
const cells = terrain.cells[layer];
|
|
326
|
+
const radius = entity.def.radius;
|
|
327
|
+
if (!cells || radius <= .5 && !styles.crushes[cells[cell]]) return;
|
|
328
|
+
if (entity.get(moving)?.status !== "moving" || !tramples(world, entity)) return;
|
|
329
|
+
let trampled = worlds.get(world);
|
|
330
|
+
if (!trampled || trampled.stamp.length !== cells.length) worlds.set(world, trampled = {
|
|
331
|
+
cells: [],
|
|
332
|
+
stamp: new Int32Array(cells.length).fill(-1),
|
|
333
|
+
tick: -1,
|
|
334
|
+
by: void 0
|
|
335
|
+
});
|
|
336
|
+
if (trampled.tick !== world.tick) {
|
|
337
|
+
trampled.tick = world.tick;
|
|
338
|
+
trampled.cells.length = 0;
|
|
339
|
+
trampled.by = void 0;
|
|
340
|
+
}
|
|
341
|
+
const had = trampled.cells.length;
|
|
342
|
+
crush(world, styles, trampled, cell);
|
|
343
|
+
if (radius <= .5) return noteBy(trampled, entity, had);
|
|
344
|
+
const { width, depth } = terrain;
|
|
345
|
+
const { x, z } = entity.pos;
|
|
346
|
+
for (let cz = Math.max(0, Math.floor(z - radius)); cz <= Math.min(depth - 1, Math.floor(z + radius)); cz++) for (let cx = Math.max(0, Math.floor(x - radius)); cx <= Math.min(width - 1, Math.floor(x + radius)); cx++) {
|
|
347
|
+
const dx = cx + .5 - x;
|
|
348
|
+
const dz = cz + .5 - z;
|
|
349
|
+
if (dx * dx + dz * dz <= radius * radius) crush(world, styles, trampled, cz * width + cx);
|
|
350
|
+
}
|
|
351
|
+
noteBy(trampled, entity, had);
|
|
352
|
+
},
|
|
353
|
+
done(world) {
|
|
354
|
+
const trampled = worlds.get(world);
|
|
355
|
+
if (!trampled || trampled.tick !== world.tick || !trampled.cells.length) return false;
|
|
356
|
+
const crushed = ruin(world, layer, trampled.cells, {
|
|
357
|
+
how: "crush",
|
|
358
|
+
...trampled.by && { by: trampled.by }
|
|
359
|
+
});
|
|
360
|
+
trampled.cells.length = 0;
|
|
361
|
+
trampled.by = void 0;
|
|
362
|
+
return crushed.length > 0;
|
|
363
|
+
}
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* How likely a burning cell is to light a cell beside it at a try: of a style that catches as dry grass does
|
|
368
|
+
* (`flammable` 1), lit by one that burns as hot as 1 (`fuel`), on flat ground, in still air and dry. About a cell a
|
|
369
|
+
* second at a try every quarter of a second
|
|
370
|
+
*/
|
|
371
|
+
var CATCH = .08;
|
|
372
|
+
/** What a cell across a corner catches by, of what one across a side does: it is farther, and a front of the two as round as it is wide */
|
|
373
|
+
var CORNER = .5;
|
|
374
|
+
/** How much a gale makes a try downwind likelier (`FoliageFire.wind` 1, the wind's strength 1: e² ≈ 7.4 times) and upwind less (a seventh) */
|
|
375
|
+
var WIND = 2;
|
|
376
|
+
/** How much a slope of 1 (45°) makes a try uphill likelier (`FoliageFire.slope` 1: e ≈ 2.7 times), and downhill less */
|
|
377
|
+
var SLOPE = 1;
|
|
378
|
+
/** What part of a try's chance a jump over a gap of one cell has (`FoliageFire.jump`) */
|
|
379
|
+
var JUMP = .5;
|
|
380
|
+
/** How likely a cell burning in rain or snow of amount 1 is to go out at a try */
|
|
381
|
+
var DOUSE = .25;
|
|
382
|
+
/** How often who stands in a burning cell is hurt (`FoliageFire.damage`), in seconds */
|
|
383
|
+
var SCORCH_EVERY = .5;
|
|
384
|
+
/**
|
|
385
|
+
* How likely a burning thing is to light a cell of grass beside it at a try, once a second (`BurningOptions.lightsFoliage`):
|
|
386
|
+
* of a style that catches as dry grass does (`flammable` 1), in still air and dry. A tree burning in a meadow lights a
|
|
387
|
+
* cell of its eight in about its first second, and seldom all of them at once
|
|
388
|
+
*/
|
|
389
|
+
var FROM_THING = .2;
|
|
390
|
+
/** The eight ways about a cell, row by row: the order the cells beside a burning one are tried in */
|
|
391
|
+
var WAYS_X = [
|
|
392
|
+
-1,
|
|
393
|
+
0,
|
|
394
|
+
1,
|
|
395
|
+
-1,
|
|
396
|
+
1,
|
|
397
|
+
-1,
|
|
398
|
+
0,
|
|
399
|
+
1
|
|
400
|
+
];
|
|
401
|
+
var WAYS_Z = [
|
|
402
|
+
-1,
|
|
403
|
+
-1,
|
|
404
|
+
-1,
|
|
405
|
+
0,
|
|
406
|
+
0,
|
|
407
|
+
1,
|
|
408
|
+
1,
|
|
409
|
+
1
|
|
410
|
+
];
|
|
411
|
+
/** What burns in a world (`FireState`): plain data, kept by a save */
|
|
412
|
+
var fireState = /* @__PURE__ */ defineComponent({
|
|
413
|
+
id: "foliage.fire",
|
|
414
|
+
default: () => ({
|
|
415
|
+
burning: {},
|
|
416
|
+
waiting: []
|
|
417
|
+
})
|
|
418
|
+
});
|
|
419
|
+
/** Where the pack keeps its fire's rules, on the pack, for the calls made on a world of its game */
|
|
420
|
+
var FIRE = Symbol("foliage fire");
|
|
421
|
+
/**
|
|
422
|
+
* A fire's rules, the pack's: its settings, what it worked out of the game and the map (styles, the air), and what a
|
|
423
|
+
* tick and the calls do with a world's `fireState`. One a pack, for every world of its game: what it keeps of a world
|
|
424
|
+
* is scratch, emptied as each call ends. The burning pack reaches it for its link to the grass (`foliageFireOf`)
|
|
425
|
+
*
|
|
426
|
+
* @internal
|
|
427
|
+
*/
|
|
428
|
+
var FoliageFireRules = class {
|
|
429
|
+
/** Whether anything burns in the game (`FoliageOptions.fire` not `false`) */
|
|
430
|
+
on;
|
|
431
|
+
/** The pack's layers, in order: the order a tick goes through them in */
|
|
432
|
+
layers;
|
|
433
|
+
/** Each layer's state layer (`foliageStateLayer`) */
|
|
434
|
+
states;
|
|
435
|
+
/** What `FoliageFire` says, each as it is when left out: whether a burning cell lights those about it */
|
|
436
|
+
spread;
|
|
437
|
+
/** Seconds between a burning cell's tries */
|
|
438
|
+
every;
|
|
439
|
+
/** How much the wind decides */
|
|
440
|
+
wind;
|
|
441
|
+
/** How much faster uphill */
|
|
442
|
+
slope;
|
|
443
|
+
/** The wind's strength from which a fire jumps a gap of one cell: none for never */
|
|
444
|
+
jump;
|
|
445
|
+
/** How wet everything is, 0 to 1 */
|
|
446
|
+
wet;
|
|
447
|
+
/** Whether rain and snow damp it and put it out */
|
|
448
|
+
weather;
|
|
449
|
+
/** The most cells that burn at once */
|
|
450
|
+
maxBurning;
|
|
451
|
+
/** Seconds after which a fire dies: none for never */
|
|
452
|
+
lasts;
|
|
453
|
+
/** Damage a second to who stands in a burning cell */
|
|
454
|
+
damage;
|
|
455
|
+
/** The type that damage is dealt as */
|
|
456
|
+
damageType;
|
|
457
|
+
/** Whether a burning cell may light what burns beside it (`FoliageFire.lights`), in a game with the burning pack */
|
|
458
|
+
lights;
|
|
459
|
+
/** The system that runs it */
|
|
460
|
+
system;
|
|
461
|
+
/** What grows back of the pack's layers, and when (`FoliageRegrowth`): what is ruined, and what burns out */
|
|
462
|
+
regrowth;
|
|
463
|
+
/** What each style is to the fire, as last worked out (`stylesOf`) */
|
|
464
|
+
styles;
|
|
465
|
+
/** The air as last worked out (`airOf`) */
|
|
466
|
+
air;
|
|
467
|
+
/** The road's tile of each game seen, by its tiles: 0 where it has none */
|
|
468
|
+
roads = /* @__PURE__ */ new WeakMap();
|
|
469
|
+
/** Scratch of a tick: the cells caught in it, by layer, so that one tried twice catches once */
|
|
470
|
+
caught;
|
|
471
|
+
/** Scratch of a tick, by layer: what caught (cells, by whom, when its fire was lit) */
|
|
472
|
+
fresh;
|
|
473
|
+
/** Scratch of a tick, by layer: the cells that burnt out in it */
|
|
474
|
+
out;
|
|
475
|
+
constructor(options) {
|
|
476
|
+
const fire = options.fire === false ? void 0 : options.fire ?? {};
|
|
477
|
+
this.on = !!fire;
|
|
478
|
+
this.layers = foliageLayers(options).map((each) => each.layer);
|
|
479
|
+
this.states = this.layers.map(foliageStateLayer);
|
|
480
|
+
this.spread = fire?.spread !== false;
|
|
481
|
+
this.every = Math.max(0, fire?.every ?? .25);
|
|
482
|
+
this.wind = Math.max(0, fire?.wind ?? 1);
|
|
483
|
+
this.slope = Math.max(0, fire?.slope ?? 1);
|
|
484
|
+
this.jump = fire?.jump;
|
|
485
|
+
this.wet = Math.min(1, Math.max(0, fire?.wet ?? 0));
|
|
486
|
+
this.weather = fire?.weather !== false;
|
|
487
|
+
this.maxBurning = Math.max(0, Math.floor(fire?.maxBurning ?? 4e3));
|
|
488
|
+
this.lasts = fire?.lasts;
|
|
489
|
+
this.damage = Math.max(0, fire?.damage ?? 0);
|
|
490
|
+
this.damageType = fire?.damageType ?? "magic";
|
|
491
|
+
this.lights = !!fire?.lights;
|
|
492
|
+
this.caught = this.layers.map(() => /* @__PURE__ */ new Set());
|
|
493
|
+
this.fresh = this.layers.map(() => ({
|
|
494
|
+
cells: [],
|
|
495
|
+
by: [],
|
|
496
|
+
lit: []
|
|
497
|
+
}));
|
|
498
|
+
this.out = this.layers.map(() => []);
|
|
499
|
+
this.regrowth = new FoliageRegrowth({
|
|
500
|
+
layers: this.layers,
|
|
501
|
+
states: this.states,
|
|
502
|
+
state: FOLIAGE_STATE,
|
|
503
|
+
style: foliageStyle,
|
|
504
|
+
regrown: (world, layer, cells, by) => world.events.emit(foliageRegrown, {
|
|
505
|
+
layer,
|
|
506
|
+
cells,
|
|
507
|
+
...by ? { by } : {}
|
|
508
|
+
})
|
|
509
|
+
});
|
|
510
|
+
this.system = {
|
|
511
|
+
name: "foliage.fire",
|
|
512
|
+
phase: "resolve",
|
|
513
|
+
update: (world) => {
|
|
514
|
+
if (!world.states.has(fireState)) return;
|
|
515
|
+
this.tick(world, world.state(fireState));
|
|
516
|
+
}
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
/** The index of a layer of the pack, for a call (`what`) given it: throws for one the pack has not */
|
|
520
|
+
indexOf(what, layer) {
|
|
521
|
+
const index = this.layers.indexOf(layer);
|
|
522
|
+
if (index < 0) throw new Error(`${what}: "${layer}" is no layer of the foliage pack (${this.layers.join(", ")})`);
|
|
523
|
+
return index;
|
|
524
|
+
}
|
|
525
|
+
/** How many ticks apart a cell's tries are (`every`): at least one */
|
|
526
|
+
stride(world) {
|
|
527
|
+
return Math.max(1, Math.round(this.every / world.dt));
|
|
528
|
+
}
|
|
529
|
+
/** What each style is to the fire, by layer and value, worked out once for a game's layers of cells */
|
|
530
|
+
stylesOf(world) {
|
|
531
|
+
const { cellLayers } = world.registry;
|
|
532
|
+
if (this.styles?.of === cellLayers) return this.styles;
|
|
533
|
+
const game = {
|
|
534
|
+
cellLayers,
|
|
535
|
+
packs: world.registry.assembly?.rules.packs
|
|
536
|
+
};
|
|
537
|
+
const styles = {
|
|
538
|
+
of: cellLayers,
|
|
539
|
+
flammable: [],
|
|
540
|
+
fuel: [],
|
|
541
|
+
burns: []
|
|
542
|
+
};
|
|
543
|
+
for (const layer of this.layers) {
|
|
544
|
+
const flammable = /* @__PURE__ */ new Float64Array(256);
|
|
545
|
+
const fuel = /* @__PURE__ */ new Float64Array(256);
|
|
546
|
+
const burns = /* @__PURE__ */ new Float64Array(256);
|
|
547
|
+
for (let value = 1; value < 256; value++) {
|
|
548
|
+
const style = foliageStyle(game, layer, value);
|
|
549
|
+
flammable[value] = Math.min(1, Math.max(0, style?.flammable ?? 0));
|
|
550
|
+
fuel[value] = Math.max(0, style?.fuel ?? 1);
|
|
551
|
+
burns[value] = Math.max(0, style?.burns ?? 6);
|
|
552
|
+
}
|
|
553
|
+
styles.flammable.push(flammable);
|
|
554
|
+
styles.fuel.push(fuel);
|
|
555
|
+
styles.burns.push(burns);
|
|
556
|
+
}
|
|
557
|
+
return this.styles = styles;
|
|
558
|
+
}
|
|
559
|
+
/** The index of the game's `road` tile, which never burns: 0 for a game without one */
|
|
560
|
+
roadOf(world) {
|
|
561
|
+
const { tiles } = world.registry;
|
|
562
|
+
let road = this.roads.get(tiles);
|
|
563
|
+
if (road === void 0) {
|
|
564
|
+
road = tiles.findIndex((tile) => tile.id === "road") + 1;
|
|
565
|
+
this.roads.set(tiles, road);
|
|
566
|
+
}
|
|
567
|
+
return road;
|
|
568
|
+
}
|
|
569
|
+
/** The air over the map now (`FireAir`), worked out again as the map's environment changes */
|
|
570
|
+
airOf(world) {
|
|
571
|
+
const info = world.state(mapInfo);
|
|
572
|
+
const environment = info.environment;
|
|
573
|
+
if (this.air && this.air.of === environment) return this.air;
|
|
574
|
+
const said = environment ?? {};
|
|
575
|
+
const strength = Math.min(1, Math.max(0, said.wind?.strength ?? 0));
|
|
576
|
+
const turn = (said.wind?.around ?? 0) % 360 * Math.PI / 180;
|
|
577
|
+
const wx = strength ? sin(turn) : 0;
|
|
578
|
+
const wz = strength ? -cos(turn) : 0;
|
|
579
|
+
const ways = /* @__PURE__ */ new Float64Array(8);
|
|
580
|
+
const jumps = /* @__PURE__ */ new Uint8Array(8);
|
|
581
|
+
for (let way = 0; way < 8; way++) {
|
|
582
|
+
const dx = WAYS_X[way];
|
|
583
|
+
const dz = WAYS_Z[way];
|
|
584
|
+
const corner = dx !== 0 && dz !== 0;
|
|
585
|
+
const along = (dx * wx + dz * wz) / (corner ? Math.SQRT2 : 1);
|
|
586
|
+
ways[way] = (corner ? CORNER : 1) * (strength && this.wind ? exp(WIND * this.wind * strength * along) : 1);
|
|
587
|
+
jumps[way] = this.jump !== void 0 && strength > 0 && strength >= this.jump && along >= .5 ? 1 : 0;
|
|
588
|
+
}
|
|
589
|
+
const weather = said.weather;
|
|
590
|
+
const falls = this.weather && (weather?.kind === "rain" || weather?.kind === "snow") ? Math.min(1, Math.max(0, weather?.amount ?? 0)) : 0;
|
|
591
|
+
const areas = falls && weather?.areas?.length ? weather.areas.flatMap((area) => {
|
|
592
|
+
const shape = areaShapeOf(area.shape, info.regions ?? []);
|
|
593
|
+
return shape ? [{
|
|
594
|
+
shape,
|
|
595
|
+
amount: Math.min(1, Math.max(0, area.amount ?? 1))
|
|
596
|
+
}] : [];
|
|
597
|
+
}) : void 0;
|
|
598
|
+
return this.air = {
|
|
599
|
+
of: environment,
|
|
600
|
+
strength,
|
|
601
|
+
x: wx,
|
|
602
|
+
z: wz,
|
|
603
|
+
ways,
|
|
604
|
+
jumps,
|
|
605
|
+
falls,
|
|
606
|
+
areas
|
|
607
|
+
};
|
|
608
|
+
}
|
|
609
|
+
/** How much rain or snow falls on a cell, 0 to 1 */
|
|
610
|
+
fallsOn(air, x, z) {
|
|
611
|
+
if (!air.falls || !air.areas) return air.falls;
|
|
612
|
+
let most = 0;
|
|
613
|
+
for (const area of air.areas) if (area.amount > most && inShape(area.shape, {
|
|
614
|
+
x: x + .5,
|
|
615
|
+
z: z + .5
|
|
616
|
+
})) most = area.amount;
|
|
617
|
+
return air.falls * most;
|
|
618
|
+
}
|
|
619
|
+
/**
|
|
620
|
+
* Whether a cell of a layer (`l`) may catch fire: grass of a style that burns, whole or growing back, and not on
|
|
621
|
+
* water, a road, what blocks the way or under a building
|
|
622
|
+
*/
|
|
623
|
+
mayCatch(world, styles, road, l, cell) {
|
|
624
|
+
const { terrain } = world;
|
|
625
|
+
const value = terrain.cells[this.layers[l]]?.[cell];
|
|
626
|
+
if (!value || !styles.flammable[l][value]) return false;
|
|
627
|
+
const state = terrain.cells[this.states[l]]?.[cell] ?? FOLIAGE_STATE.whole;
|
|
628
|
+
if (state !== FOLIAGE_STATE.whole && state !== FOLIAGE_STATE.growing) return false;
|
|
629
|
+
if (terrain.water[cell] || (terrain.blocked[cell] & 2) !== 0 || road && terrain.tiles[cell] === road) return false;
|
|
630
|
+
const x = cell % terrain.width;
|
|
631
|
+
return world.grid.occupantAt(x, (cell - x) / terrain.width) <= 0;
|
|
632
|
+
}
|
|
633
|
+
/** How many cells burn now, over the pack's layers */
|
|
634
|
+
burningIn(state) {
|
|
635
|
+
let count = 0;
|
|
636
|
+
for (const layer of this.layers) count += state.burning[layer]?.cells.length ?? 0;
|
|
637
|
+
return count;
|
|
638
|
+
}
|
|
639
|
+
/**
|
|
640
|
+
* Asks the game whether a cell catches (`foliageIgnite`), at a chance: the chance it says, 0 where it refuses. The
|
|
641
|
+
* chance as it is where nobody listens
|
|
642
|
+
*/
|
|
643
|
+
ask(world, l, cell, cause, from, by, chance, thing) {
|
|
644
|
+
if (!world.hooks.has(foliageIgnite)) return chance;
|
|
645
|
+
const { width } = world.terrain;
|
|
646
|
+
const x = cell % width;
|
|
647
|
+
const asked = world.hooks.run(foliageIgnite, {
|
|
648
|
+
layer: this.layers[l],
|
|
649
|
+
cell,
|
|
650
|
+
x: x + .5,
|
|
651
|
+
z: (cell - x) / width + .5,
|
|
652
|
+
cause,
|
|
653
|
+
...from !== void 0 ? { from } : {},
|
|
654
|
+
...thing ? { thing } : {},
|
|
655
|
+
...by ? { by: world.entities.get(by) } : {},
|
|
656
|
+
chance,
|
|
657
|
+
cancelled: false
|
|
658
|
+
});
|
|
659
|
+
return asked.cancelled ? 0 : Math.min(1, Math.max(0, asked.chance || 0));
|
|
660
|
+
}
|
|
661
|
+
/** Whether something with a chance happens: by the world's numbers where it is neither sure nor never */
|
|
662
|
+
happens(world, chance) {
|
|
663
|
+
return chance >= 1 || chance > 0 && world.rng.next() < chance;
|
|
664
|
+
}
|
|
665
|
+
/** Sets grass alight (`ignite`): the cells that caught, in order */
|
|
666
|
+
ignite(world, layer, cells, by) {
|
|
667
|
+
const l = this.indexOf("ignite", layer);
|
|
668
|
+
if (!this.on) return [];
|
|
669
|
+
const state = world.state(fireState);
|
|
670
|
+
const styles = this.stylesOf(world);
|
|
671
|
+
const road = this.roadOf(world);
|
|
672
|
+
const id = by?.id ?? 0;
|
|
673
|
+
const room = this.maxBurning - this.burningIn(state);
|
|
674
|
+
const lit = [];
|
|
675
|
+
const tried = /* @__PURE__ */ new Set();
|
|
676
|
+
for (const cell of cells) {
|
|
677
|
+
if (tried.has(cell)) continue;
|
|
678
|
+
tried.add(cell);
|
|
679
|
+
if (!this.mayCatch(world, styles, road, l, cell)) continue;
|
|
680
|
+
if (state.waiting.some((each) => each.cell === cell && each.layer === layer)) continue;
|
|
681
|
+
if (!this.happens(world, this.ask(world, l, cell, "ignite", void 0, id, 1))) continue;
|
|
682
|
+
if (lit.length < room) lit.push(cell);
|
|
683
|
+
else state.waiting.push({
|
|
684
|
+
layer,
|
|
685
|
+
cell,
|
|
686
|
+
lit: world.tick,
|
|
687
|
+
by: id
|
|
688
|
+
});
|
|
689
|
+
}
|
|
690
|
+
lit.sort((a, b) => a - b);
|
|
691
|
+
this.light(world, state, l, lit, () => id, () => world.tick, "ignite");
|
|
692
|
+
return lit;
|
|
693
|
+
}
|
|
694
|
+
/**
|
|
695
|
+
* Cells of a layer catch fire, in order of their indices, each once, by whom and with the tick its fire was lit:
|
|
696
|
+
* into the layer's list in order (a cell listed already, set otherwise since and lit again, is there once, with its
|
|
697
|
+
* new fire), then set burning (one `setCells`), and told (`foliageIgnited`, by whom). In the list first: a cell set
|
|
698
|
+
* burning is never outside it, whatever throws in what is told of the change (one listed whose state is not burning
|
|
699
|
+
* is dropped at the fire's next tick)
|
|
700
|
+
*/
|
|
701
|
+
light(world, state, l, cells, byOf, litOf, cause) {
|
|
702
|
+
if (!cells.length) return;
|
|
703
|
+
const layer = this.layers[l];
|
|
704
|
+
const fire = state.burning[layer] ??= {
|
|
705
|
+
cells: [],
|
|
706
|
+
ends: [],
|
|
707
|
+
lit: [],
|
|
708
|
+
by: []
|
|
709
|
+
};
|
|
710
|
+
if (fire.cells.length) {
|
|
711
|
+
let listed;
|
|
712
|
+
for (const cell of cells) if (indexIn(fire.cells, cell) >= 0) (listed ??= /* @__PURE__ */ new Set()).add(cell);
|
|
713
|
+
if (listed) {
|
|
714
|
+
let kept = 0;
|
|
715
|
+
for (let i = 0; i < fire.cells.length; i++) {
|
|
716
|
+
if (listed.has(fire.cells[i])) continue;
|
|
717
|
+
fire.cells[kept] = fire.cells[i];
|
|
718
|
+
fire.ends[kept] = fire.ends[i];
|
|
719
|
+
fire.lit[kept] = fire.lit[i];
|
|
720
|
+
fire.by[kept] = fire.by[i];
|
|
721
|
+
kept++;
|
|
722
|
+
}
|
|
723
|
+
this.shorten(fire, kept);
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
const values = world.terrain.cells[layer];
|
|
727
|
+
const burns = this.stylesOf(world).burns[l];
|
|
728
|
+
const { tick, dt } = world;
|
|
729
|
+
let i = fire.cells.length - 1;
|
|
730
|
+
let j = cells.length - 1;
|
|
731
|
+
for (let k = 0; k < cells.length; k++) {
|
|
732
|
+
fire.cells.push(0);
|
|
733
|
+
fire.ends.push(0);
|
|
734
|
+
fire.lit.push(0);
|
|
735
|
+
fire.by.push(0);
|
|
736
|
+
}
|
|
737
|
+
for (let w = fire.cells.length - 1; j >= 0; w--) if (i >= 0 && fire.cells[i] > cells[j]) {
|
|
738
|
+
fire.cells[w] = fire.cells[i];
|
|
739
|
+
fire.ends[w] = fire.ends[i];
|
|
740
|
+
fire.lit[w] = fire.lit[i];
|
|
741
|
+
fire.by[w] = fire.by[i];
|
|
742
|
+
i--;
|
|
743
|
+
} else {
|
|
744
|
+
const cell = cells[j];
|
|
745
|
+
fire.cells[w] = cell;
|
|
746
|
+
fire.ends[w] = tick + Math.max(1, Math.round(burns[values[cell]] / dt));
|
|
747
|
+
fire.lit[w] = litOf(j);
|
|
748
|
+
fire.by[w] = byOf(j);
|
|
749
|
+
j--;
|
|
750
|
+
}
|
|
751
|
+
world.setCells(this.states[l], cells, FOLIAGE_STATE.burning);
|
|
752
|
+
const first = byOf(0);
|
|
753
|
+
let whom;
|
|
754
|
+
for (let k = 1; k < cells.length && !whom; k++) if (byOf(k) !== first) whom = [first];
|
|
755
|
+
if (!whom) return void world.events.emit(foliageIgnited, {
|
|
756
|
+
layer,
|
|
757
|
+
cells: [...cells],
|
|
758
|
+
cause,
|
|
759
|
+
...first ? { by: first } : {}
|
|
760
|
+
});
|
|
761
|
+
for (let k = 0; k < cells.length; k++) if (!whom.includes(byOf(k))) whom.push(byOf(k));
|
|
762
|
+
for (const by of whom) world.events.emit(foliageIgnited, {
|
|
763
|
+
layer,
|
|
764
|
+
cells: cells.filter((_, k) => byOf(k) === by),
|
|
765
|
+
cause,
|
|
766
|
+
...by ? { by } : {}
|
|
767
|
+
});
|
|
768
|
+
}
|
|
769
|
+
/**
|
|
770
|
+
* Takes cells out of a layer's fire (those `which` holds, or all of them) and sets them to `to` (burnt, or cut by a
|
|
771
|
+
* firebreak; left as they are for none, where the caller sets them): those that burnt, in order. What waits there
|
|
772
|
+
* to be lit waits no more. Told: `foliageBurnt` for what was put out, `foliageFireOut` where nothing burns any more
|
|
773
|
+
*/
|
|
774
|
+
quench(world, state, l, which, to) {
|
|
775
|
+
const layer = this.layers[l];
|
|
776
|
+
if (state.waiting.length) state.waiting = state.waiting.filter((each) => each.layer !== layer || which !== void 0 && !which.has(each.cell));
|
|
777
|
+
const fire = state.burning[layer];
|
|
778
|
+
if (!fire) return [];
|
|
779
|
+
const out = [];
|
|
780
|
+
let kept = 0;
|
|
781
|
+
for (let i = 0; i < fire.cells.length; i++) {
|
|
782
|
+
const cell = fire.cells[i];
|
|
783
|
+
if (which === void 0 || which.has(cell)) {
|
|
784
|
+
out.push(cell);
|
|
785
|
+
continue;
|
|
786
|
+
}
|
|
787
|
+
fire.cells[kept] = cell;
|
|
788
|
+
fire.ends[kept] = fire.ends[i];
|
|
789
|
+
fire.lit[kept] = fire.lit[i];
|
|
790
|
+
fire.by[kept] = fire.by[i];
|
|
791
|
+
kept++;
|
|
792
|
+
}
|
|
793
|
+
if (!out.length) return out;
|
|
794
|
+
this.shorten(fire, kept);
|
|
795
|
+
if (to !== void 0) world.setCells(this.states[l], out, to);
|
|
796
|
+
if (to === FOLIAGE_STATE.burnt) world.events.emit(foliageBurnt, {
|
|
797
|
+
layer,
|
|
798
|
+
cells: [...out]
|
|
799
|
+
});
|
|
800
|
+
this.over(world, state, l);
|
|
801
|
+
return out;
|
|
802
|
+
}
|
|
803
|
+
/** A layer's list cut to its first `length` */
|
|
804
|
+
shorten(fire, length) {
|
|
805
|
+
fire.cells.length = length;
|
|
806
|
+
fire.ends.length = length;
|
|
807
|
+
fire.lit.length = length;
|
|
808
|
+
fire.by.length = length;
|
|
809
|
+
}
|
|
810
|
+
/** Where nothing of a layer burns any more: its list gone and told (`foliageFireOut`). Nothing where it burns, or had no list */
|
|
811
|
+
over(world, state, l) {
|
|
812
|
+
const layer = this.layers[l];
|
|
813
|
+
const fire = state.burning[layer];
|
|
814
|
+
if (!fire || fire.cells.length) return;
|
|
815
|
+
delete state.burning[layer];
|
|
816
|
+
world.events.emit(foliageFireOut, { layer });
|
|
817
|
+
}
|
|
818
|
+
/** A tick of the fire: what burns out, what catches, what waits and has room now, who is hurt */
|
|
819
|
+
tick(world, state) {
|
|
820
|
+
const { layers } = this;
|
|
821
|
+
let burning = this.burningIn(state);
|
|
822
|
+
if (!burning && !state.waiting.length) return;
|
|
823
|
+
const { tick, terrain } = world;
|
|
824
|
+
const { width, depth, heights, vertsX } = terrain;
|
|
825
|
+
const styles = this.stylesOf(world);
|
|
826
|
+
const road = this.roadOf(world);
|
|
827
|
+
const air = this.airOf(world);
|
|
828
|
+
const stride = this.stride(world);
|
|
829
|
+
const turn = tick % stride;
|
|
830
|
+
const lasts = this.lasts === void 0 ? Infinity : Math.max(1, Math.round(this.lasts / world.dt));
|
|
831
|
+
const hooked = world.hooks.has(foliageIgnite);
|
|
832
|
+
const max = this.maxBurning;
|
|
833
|
+
let fresh = 0;
|
|
834
|
+
for (let l = 0; l < layers.length; l++) {
|
|
835
|
+
this.caught[l].clear();
|
|
836
|
+
const each = this.fresh[l];
|
|
837
|
+
each.cells.length = each.by.length = each.lit.length = 0;
|
|
838
|
+
this.out[l].length = 0;
|
|
839
|
+
}
|
|
840
|
+
for (let l = 0; l < layers.length; l++) {
|
|
841
|
+
const fire = state.burning[layers[l]];
|
|
842
|
+
if (!fire) continue;
|
|
843
|
+
const out = this.out[l];
|
|
844
|
+
const values = terrain.cells[layers[l]];
|
|
845
|
+
const states = terrain.cells[this.states[l]];
|
|
846
|
+
const fuel = styles.fuel[l];
|
|
847
|
+
const { cells, ends, lit, by } = fire;
|
|
848
|
+
let kept = 0;
|
|
849
|
+
for (let i = 0; i < cells.length; i++) {
|
|
850
|
+
const cell = cells[i];
|
|
851
|
+
const from = lit[i];
|
|
852
|
+
const whose = by[i];
|
|
853
|
+
if (states?.[cell] !== FOLIAGE_STATE.burning || !values?.[cell]) {
|
|
854
|
+
burning--;
|
|
855
|
+
continue;
|
|
856
|
+
}
|
|
857
|
+
if (ends[i] <= tick || from + lasts <= tick) {
|
|
858
|
+
out.push(cell);
|
|
859
|
+
burning--;
|
|
860
|
+
continue;
|
|
861
|
+
}
|
|
862
|
+
const x = cell % width;
|
|
863
|
+
const z = (cell - x) / width;
|
|
864
|
+
if (turnOf(cell, stride) === turn) {
|
|
865
|
+
const wet = this.fallsOn(air, x, z);
|
|
866
|
+
if (wet && world.rng.next() < wet * DOUSE) {
|
|
867
|
+
out.push(cell);
|
|
868
|
+
burning--;
|
|
869
|
+
continue;
|
|
870
|
+
}
|
|
871
|
+
if (this.spread && burning + fresh < max) {
|
|
872
|
+
const dry = (1 - Math.min(1, this.wet + wet)) * fuel[values[cell]];
|
|
873
|
+
if (dry > 0) fresh += this.tryAround(world, styles, road, air, l, cell, x, z, dry, from, whose, burning + fresh, hooked, width, depth, heights, vertsX);
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
cells[kept] = cell;
|
|
877
|
+
ends[kept] = ends[i];
|
|
878
|
+
lit[kept] = from;
|
|
879
|
+
by[kept] = whose;
|
|
880
|
+
kept++;
|
|
881
|
+
}
|
|
882
|
+
this.shorten(fire, kept);
|
|
883
|
+
}
|
|
884
|
+
let waited;
|
|
885
|
+
while (state.waiting.length && burning + fresh < max) {
|
|
886
|
+
const next = state.waiting.shift();
|
|
887
|
+
const l = layers.indexOf(next.layer);
|
|
888
|
+
if (l < 0 || this.caught[l].has(next.cell) || !this.mayCatch(world, styles, road, l, next.cell)) continue;
|
|
889
|
+
this.caught[l].add(next.cell);
|
|
890
|
+
(waited ??= []).push(next);
|
|
891
|
+
fresh++;
|
|
892
|
+
}
|
|
893
|
+
for (let l = 0; l < layers.length; l++) {
|
|
894
|
+
const out = this.out[l];
|
|
895
|
+
if (out.length) {
|
|
896
|
+
world.setCells(this.states[l], out, FOLIAGE_STATE.burnt);
|
|
897
|
+
world.events.emit(foliageBurnt, {
|
|
898
|
+
layer: layers[l],
|
|
899
|
+
cells: [...out]
|
|
900
|
+
});
|
|
901
|
+
this.regrowth.ruined(world, l, out);
|
|
902
|
+
}
|
|
903
|
+
const each = this.fresh[l];
|
|
904
|
+
if (each.cells.length) {
|
|
905
|
+
const order = each.cells.map((_, k) => k).sort((a, b) => each.cells[a] - each.cells[b]);
|
|
906
|
+
const sorted = order.map((k) => each.cells[k]);
|
|
907
|
+
this.light(world, state, l, sorted, (k) => each.by[order[k]], (k) => each.lit[order[k]], "spread");
|
|
908
|
+
}
|
|
909
|
+
const lit = waited?.filter((each) => each.layer === layers[l]).sort((a, b) => a.cell - b.cell);
|
|
910
|
+
if (lit?.length) this.light(world, state, l, lit.map((each) => each.cell), (k) => lit[k].by, (k) => lit[k].lit, "ignite");
|
|
911
|
+
this.over(world, state, l);
|
|
912
|
+
}
|
|
913
|
+
if (this.damage && tick % Math.max(1, Math.round(SCORCH_EVERY / world.dt)) === 0) this.scorch(world, state);
|
|
914
|
+
}
|
|
915
|
+
/**
|
|
916
|
+
* A burning cell's try at the cells about it (and under it, of the pack's other layers): each that may catch, by a
|
|
917
|
+
* chance of its style, the burning one's (`dry`: its fuel, less what is wet), the wind's way, the slope, and what
|
|
918
|
+
* the game says (`foliageIgnite`). Across a gap of one cell downwind in a wind strong enough (`jump`). Into the
|
|
919
|
+
* tick's caught cells; how many caught
|
|
920
|
+
*/
|
|
921
|
+
tryAround(world, styles, road, air, l, cell, x, z, dry, from, by, burning, hooked, width, depth, heights, vertsX) {
|
|
922
|
+
const max = this.maxBurning;
|
|
923
|
+
let caught = 0;
|
|
924
|
+
const here = this.slope ? cellHeight(heights, vertsX, x, z) : 0;
|
|
925
|
+
for (let m = 0; m < this.layers.length; m++) {
|
|
926
|
+
const flammable = styles.flammable[m];
|
|
927
|
+
const values = world.terrain.cells[this.layers[m]];
|
|
928
|
+
if (!values) continue;
|
|
929
|
+
if (m !== l && this.catchable(world, styles, road, m, cell)) {
|
|
930
|
+
const chance = CATCH * dry * flammable[values[cell]];
|
|
931
|
+
if (this.happens(world, hooked ? this.ask(world, m, cell, "spread", cell, by, chance) : chance)) {
|
|
932
|
+
this.caught[m].add(cell);
|
|
933
|
+
this.fresh[m].cells.push(cell);
|
|
934
|
+
this.fresh[m].by.push(by);
|
|
935
|
+
this.fresh[m].lit.push(from);
|
|
936
|
+
if (burning + ++caught >= max) return caught;
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
for (let way = 0; way < 8; way++) {
|
|
940
|
+
let nx = x + WAYS_X[way];
|
|
941
|
+
let nz = z + WAYS_Z[way];
|
|
942
|
+
if (nx < 0 || nz < 0 || nx >= width || nz >= depth) continue;
|
|
943
|
+
let next = nz * width + nx;
|
|
944
|
+
let share = air.ways[way];
|
|
945
|
+
if (!this.catchable(world, styles, road, m, next)) {
|
|
946
|
+
if (!air.jumps[way] || this.caught[m].has(next) || world.terrain.cells[this.states[m]]?.[next] === FOLIAGE_STATE.burning) continue;
|
|
947
|
+
nx += WAYS_X[way];
|
|
948
|
+
nz += WAYS_Z[way];
|
|
949
|
+
if (nx < 0 || nz < 0 || nx >= width || nz >= depth) continue;
|
|
950
|
+
next = nz * width + nx;
|
|
951
|
+
if (!this.catchable(world, styles, road, m, next)) continue;
|
|
952
|
+
share *= JUMP;
|
|
953
|
+
}
|
|
954
|
+
let chance = CATCH * dry * share * flammable[values[next]];
|
|
955
|
+
if (this.slope) {
|
|
956
|
+
const rise = cellHeight(heights, vertsX, nx, nz) - here;
|
|
957
|
+
if (rise) {
|
|
958
|
+
const dx = nx - x;
|
|
959
|
+
const dz = nz - z;
|
|
960
|
+
chance *= exp(SLOPE * this.slope * Math.max(-1, Math.min(1, rise / Math.sqrt(dx * dx + dz * dz))));
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
if (!this.happens(world, hooked ? this.ask(world, m, next, "spread", cell, by, chance) : chance)) continue;
|
|
964
|
+
this.caught[m].add(next);
|
|
965
|
+
this.fresh[m].cells.push(next);
|
|
966
|
+
this.fresh[m].by.push(by);
|
|
967
|
+
this.fresh[m].lit.push(from);
|
|
968
|
+
if (burning + ++caught >= max) return caught;
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
return caught;
|
|
972
|
+
}
|
|
973
|
+
/** Whether a cell of a layer may catch now: as `mayCatch`, and not caught already this tick */
|
|
974
|
+
catchable(world, styles, road, l, cell) {
|
|
975
|
+
return !this.caught[l].has(cell) && this.mayCatch(world, styles, road, l, cell);
|
|
976
|
+
}
|
|
977
|
+
/** How many more cells may burn now, over the pack's layers (`maxBurning`) */
|
|
978
|
+
room(world) {
|
|
979
|
+
return this.maxBurning - (world.states.has(fireState) ? this.burningIn(world.state(fireState)) : 0);
|
|
980
|
+
}
|
|
981
|
+
/** Whether any cell of the pack's layers burns now */
|
|
982
|
+
anyBurning(world) {
|
|
983
|
+
if (!world.states.has(fireState)) return false;
|
|
984
|
+
const { burning } = world.state(fireState);
|
|
985
|
+
for (const layer of this.layers) if (burning[layer]?.cells.length) return true;
|
|
986
|
+
return false;
|
|
987
|
+
}
|
|
988
|
+
/**
|
|
989
|
+
* The burning cells whose turn to try about them it is this tick (once in `every` a cell, as the fire's own tries:
|
|
990
|
+
* `turnOf`), still burning and not out this tick, in order of the layers and their cells: each told with who lit its
|
|
991
|
+
* fire and its heat (its style's `fuel`, less what is wet and falls on it), those with any
|
|
992
|
+
*/
|
|
993
|
+
eachTrying(world, visit) {
|
|
994
|
+
if (!world.states.has(fireState)) return;
|
|
995
|
+
const state = world.state(fireState);
|
|
996
|
+
const { tick, terrain } = world;
|
|
997
|
+
const { width } = terrain;
|
|
998
|
+
const stride = this.stride(world);
|
|
999
|
+
const turn = tick % stride;
|
|
1000
|
+
const styles = this.stylesOf(world);
|
|
1001
|
+
const air = this.airOf(world);
|
|
1002
|
+
const lasts = this.lasts === void 0 ? Infinity : Math.max(1, Math.round(this.lasts / world.dt));
|
|
1003
|
+
for (let l = 0; l < this.layers.length; l++) {
|
|
1004
|
+
const fire = state.burning[this.layers[l]];
|
|
1005
|
+
if (!fire) continue;
|
|
1006
|
+
const values = terrain.cells[this.layers[l]];
|
|
1007
|
+
const states = terrain.cells[this.states[l]];
|
|
1008
|
+
const fuel = styles.fuel[l];
|
|
1009
|
+
const { cells, ends, lit, by } = fire;
|
|
1010
|
+
for (let i = 0; i < cells.length; i++) {
|
|
1011
|
+
const cell = cells[i];
|
|
1012
|
+
if (turnOf(cell, stride) !== turn || states?.[cell] !== FOLIAGE_STATE.burning || !values?.[cell]) continue;
|
|
1013
|
+
if (ends[i] <= tick || lit[i] + lasts <= tick) continue;
|
|
1014
|
+
const x = cell % width;
|
|
1015
|
+
const heat = (1 - Math.min(1, this.wet + this.fallsOn(air, x, (cell - x) / width))) * fuel[values[cell]];
|
|
1016
|
+
if (heat > 0) visit(l, cell, by[i], heat);
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
/**
|
|
1021
|
+
* How likely a cell of a layer is to catch at a try of a burning thing standing at `x`, `z` beside it
|
|
1022
|
+
* (`BurningOptions.lightsFoliage`): `FROM_THING` by its style's `flammable`, less what is wet and falls on it, weighed
|
|
1023
|
+
* by the wind (by `weight`: the burning pack's), 1 at the most. 0 where it may not catch now
|
|
1024
|
+
*/
|
|
1025
|
+
chanceFrom(world, l, cell, x, z, weight) {
|
|
1026
|
+
const styles = this.stylesOf(world);
|
|
1027
|
+
if (!this.mayCatch(world, styles, this.roadOf(world), l, cell)) return 0;
|
|
1028
|
+
const { width } = world.terrain;
|
|
1029
|
+
const cx = cell % width;
|
|
1030
|
+
const cz = (cell - cx) / width;
|
|
1031
|
+
const air = this.airOf(world);
|
|
1032
|
+
let chance = FROM_THING * styles.flammable[l][world.terrain.cells[this.layers[l]][cell]] * (1 - Math.min(1, this.wet + this.fallsOn(air, cx, cz)));
|
|
1033
|
+
if (chance > 0 && air.strength && weight) {
|
|
1034
|
+
const dx = cx + .5 - x;
|
|
1035
|
+
const dz = cz + .5 - z;
|
|
1036
|
+
const far = Math.sqrt(dx * dx + dz * dz);
|
|
1037
|
+
if (far > 0) chance *= exp(WIND * weight * air.strength * (dx * air.x + dz * air.z) / far);
|
|
1038
|
+
}
|
|
1039
|
+
return Math.min(1, chance);
|
|
1040
|
+
}
|
|
1041
|
+
/**
|
|
1042
|
+
* Cells found caught from burning things at the burning pack's turn (`BurningOptions.lightsFoliage`; by layer, cell
|
|
1043
|
+
* and who lit the thing, in any order): lit (`burning`), in order of the layers and the cells, each once, those that
|
|
1044
|
+
* may still catch, as many as there is room for (`maxBurning`: the rest do not catch, as a spread's past it). How
|
|
1045
|
+
* many caught
|
|
1046
|
+
*/
|
|
1047
|
+
lightCaught(world, layers, cells, by) {
|
|
1048
|
+
if (!cells.length) return 0;
|
|
1049
|
+
const order = cells.map((_, k) => k).sort((a, b) => layers[a] - layers[b] || cells[a] - cells[b] || a - b);
|
|
1050
|
+
const state = world.state(fireState);
|
|
1051
|
+
const styles = this.stylesOf(world);
|
|
1052
|
+
const road = this.roadOf(world);
|
|
1053
|
+
let room = this.maxBurning - this.burningIn(state);
|
|
1054
|
+
let caught = 0;
|
|
1055
|
+
for (let l = 0; l < this.layers.length && room > 0; l++) {
|
|
1056
|
+
const lit = [];
|
|
1057
|
+
const whose = [];
|
|
1058
|
+
for (const k of order) {
|
|
1059
|
+
if (layers[k] !== l || room <= 0) continue;
|
|
1060
|
+
const cell = cells[k];
|
|
1061
|
+
if (lit.length && lit[lit.length - 1] === cell) continue;
|
|
1062
|
+
if (!this.mayCatch(world, styles, road, l, cell)) continue;
|
|
1063
|
+
lit.push(cell);
|
|
1064
|
+
whose.push(by[k]);
|
|
1065
|
+
room--;
|
|
1066
|
+
}
|
|
1067
|
+
this.light(world, state, l, lit, (k) => whose[k], () => world.tick, "burning");
|
|
1068
|
+
caught += lit.length;
|
|
1069
|
+
}
|
|
1070
|
+
return caught;
|
|
1071
|
+
}
|
|
1072
|
+
/** Who stands in a burning cell is hurt, by whoever lit its fire: units on the ground, once whatever burns there */
|
|
1073
|
+
scorch(world, state) {
|
|
1074
|
+
const { terrain } = world;
|
|
1075
|
+
const { width, depth } = terrain;
|
|
1076
|
+
const amount = this.damage * Math.max(1, Math.round(SCORCH_EVERY / world.dt)) * world.dt;
|
|
1077
|
+
const hurt = [];
|
|
1078
|
+
for (const unit of world.units.values()) {
|
|
1079
|
+
if (!unit.alive || unit.hidden || unit.flying || unit.def.footprint || unit.def.kind !== "unit") continue;
|
|
1080
|
+
const { x, z } = unit.pos;
|
|
1081
|
+
if (x < 0 || z < 0 || x >= width || z >= depth) continue;
|
|
1082
|
+
const cell = Math.floor(z) * width + Math.floor(x);
|
|
1083
|
+
for (let l = 0; l < this.layers.length; l++) {
|
|
1084
|
+
if (terrain.cells[this.states[l]]?.[cell] !== FOLIAGE_STATE.burning) continue;
|
|
1085
|
+
const fire = state.burning[this.layers[l]];
|
|
1086
|
+
const at = fire ? indexIn(fire.cells, cell) : -1;
|
|
1087
|
+
if (at < 0) continue;
|
|
1088
|
+
hurt.push({
|
|
1089
|
+
unit,
|
|
1090
|
+
by: fire.by[at]
|
|
1091
|
+
});
|
|
1092
|
+
break;
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
for (const { unit, by } of hurt) {
|
|
1096
|
+
if (!unit.alive) continue;
|
|
1097
|
+
world.damage(unit, amount, by ? world.entities.get(by) : void 0, {
|
|
1098
|
+
damageType: this.damageType,
|
|
1099
|
+
tags: ["fire"],
|
|
1100
|
+
how: "burnt"
|
|
1101
|
+
});
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
};
|
|
1105
|
+
/**
|
|
1106
|
+
* Which tick of every `stride` a burning cell tries the cells about it on: of a hash of its index, so that a front's
|
|
1107
|
+
* cells take their turns spread over the ticks, and the wait from catching to trying is no shorter one way than another
|
|
1108
|
+
*/
|
|
1109
|
+
var turnOf = (cell, stride) => (Math.imul(cell, 2654435761) >>> 16) % stride;
|
|
1110
|
+
/** The height of a cell's middle: its corners' */
|
|
1111
|
+
var cellHeight = (heights, vertsX, x, z) => {
|
|
1112
|
+
const i = z * vertsX + x;
|
|
1113
|
+
return (heights[i] + heights[i + 1] + heights[i + vertsX] + heights[i + vertsX + 1]) / 4;
|
|
1114
|
+
};
|
|
1115
|
+
/** Where a cell is in a list of cells in order: -1 where it is not */
|
|
1116
|
+
function indexIn(cells, cell) {
|
|
1117
|
+
let low = 0;
|
|
1118
|
+
let high = cells.length - 1;
|
|
1119
|
+
while (low <= high) {
|
|
1120
|
+
const middle = low + high >> 1;
|
|
1121
|
+
const at = cells[middle];
|
|
1122
|
+
if (at === cell) return middle;
|
|
1123
|
+
if (at < cell) low = middle + 1;
|
|
1124
|
+
else high = middle - 1;
|
|
1125
|
+
}
|
|
1126
|
+
return -1;
|
|
1127
|
+
}
|
|
1128
|
+
/** The fire's rules of a world's game: none where it has no foliage pack. `what` names the call that asks, which throws then */
|
|
1129
|
+
function fireOf(world, what) {
|
|
1130
|
+
const pack = world.registry.assembly?.rules.packs?.find((each) => each.id === FOLIAGE);
|
|
1131
|
+
if (!pack) throw new Error(`${what}: the game has no foliage pack (foliagePack)`);
|
|
1132
|
+
return pack[FIRE] ??= new FoliageFireRules(pack.options);
|
|
1133
|
+
}
|
|
1134
|
+
/**
|
|
1135
|
+
* The grass's fire of a world's game, for the burning pack's link to it (`BurningOptions.lightsFoliage`,
|
|
1136
|
+
* `FoliageFire.lights`): none where it has no foliage pack, or one whose grass never burns
|
|
1137
|
+
*
|
|
1138
|
+
* @internal
|
|
1139
|
+
*/
|
|
1140
|
+
function foliageFireOf(world) {
|
|
1141
|
+
const pack = world.registry.assembly?.rules.packs?.find((each) => each.id === FOLIAGE);
|
|
1142
|
+
if (!pack) return void 0;
|
|
1143
|
+
const fire = pack[FIRE] ??= new FoliageFireRules(pack.options);
|
|
1144
|
+
return fire.on ? fire : void 0;
|
|
1145
|
+
}
|
|
1146
|
+
/** The cells a call is given, as indices: of a shape, the cells whose middle is in it; indices as they are */
|
|
1147
|
+
function cellsOf(world, where) {
|
|
1148
|
+
if (Array.isArray(where)) return where;
|
|
1149
|
+
const { width, depth } = world.terrain;
|
|
1150
|
+
const shape = where;
|
|
1151
|
+
const { x0, z0, x1, z1 } = shapeBounds(shape);
|
|
1152
|
+
const cells = [];
|
|
1153
|
+
for (let cz = Math.max(Math.floor(z0), 0); cz < Math.min(Math.ceil(z1), depth); cz++) for (let cx = Math.max(Math.floor(x0), 0); cx < Math.min(Math.ceil(x1), width); cx++) if (inShape(shape, {
|
|
1154
|
+
x: cx + .5,
|
|
1155
|
+
z: cz + .5
|
|
1156
|
+
})) cells.push(cz * width + cx);
|
|
1157
|
+
return cells;
|
|
1158
|
+
}
|
|
1159
|
+
/**
|
|
1160
|
+
* Sets grass alight: the cells there that can burn start burning (`foliageIgnite` is asked of each), and the fire
|
|
1161
|
+
* goes on from them. `by`: who lit it, whom its damage is dealt by. A cell catches where its style burns
|
|
1162
|
+
* (`flammable` over 0), it stands whole or grows back, and it is not on water, a road (the game's `road` tile), what
|
|
1163
|
+
* blocks the way or under a building. Past the most that may burn at once (`FoliageFire.maxBurning`), the rest wait
|
|
1164
|
+
* their turn. Returns the cells that caught, in order; none in a game whose grass does not burn (`fire: false`)
|
|
1165
|
+
*
|
|
1166
|
+
* @beta
|
|
1167
|
+
*/
|
|
1168
|
+
function ignite(world, layer, where, options = {}) {
|
|
1169
|
+
return fireOf(world, "ignite").ignite(world, layer, cellsOf(world, where), options.by);
|
|
1170
|
+
}
|
|
1171
|
+
/**
|
|
1172
|
+
* Puts out what burns there: the cells stop burning as they are, burnt. Returns the cells put out, in order
|
|
1173
|
+
*
|
|
1174
|
+
* @beta
|
|
1175
|
+
*/
|
|
1176
|
+
function extinguish(world, layer, where) {
|
|
1177
|
+
const fire = fireOf(world, "extinguish");
|
|
1178
|
+
const l = fire.indexOf("extinguish", layer);
|
|
1179
|
+
if (!world.states.has(fireState)) return [];
|
|
1180
|
+
const out = fire.quench(world, world.state(fireState), l, new Set(cellsOf(world, where)), FOLIAGE_STATE.burnt);
|
|
1181
|
+
fire.regrowth.ruined(world, l, out);
|
|
1182
|
+
return out;
|
|
1183
|
+
}
|
|
1184
|
+
/**
|
|
1185
|
+
* Cuts grass down to stubble, which fire does not cross: `ruin` with `cut`. What burns there stops burning, cut. A
|
|
1186
|
+
* cell burnt already, or cut, is left as it is. Returns the cells cut, in order
|
|
1187
|
+
*
|
|
1188
|
+
* @beta
|
|
1189
|
+
*/
|
|
1190
|
+
function firebreak(world, layer, where, options = {}) {
|
|
1191
|
+
return ruinAs(world, "firebreak", layer, where, "cut", options.by);
|
|
1192
|
+
}
|
|
1193
|
+
/**
|
|
1194
|
+
* Puts out every fire of a layer, or of all the pack's layers when none is named: what burns is burnt, what waits its
|
|
1195
|
+
* turn is not lit. Returns how many cells were burning
|
|
1196
|
+
*
|
|
1197
|
+
* @beta
|
|
1198
|
+
*/
|
|
1199
|
+
function stopFire(world, layer) {
|
|
1200
|
+
const fire = fireOf(world, "stopFire");
|
|
1201
|
+
const which = layer === void 0 ? fire.layers.map((_, l) => l) : [fire.indexOf("stopFire", layer)];
|
|
1202
|
+
if (!world.states.has(fireState)) return 0;
|
|
1203
|
+
const state = world.state(fireState);
|
|
1204
|
+
let count = 0;
|
|
1205
|
+
for (const l of which) {
|
|
1206
|
+
const out = fire.quench(world, state, l, void 0, FOLIAGE_STATE.burnt);
|
|
1207
|
+
fire.regrowth.ruined(world, l, out);
|
|
1208
|
+
count += out.length;
|
|
1209
|
+
}
|
|
1210
|
+
return count;
|
|
1211
|
+
}
|
|
1212
|
+
/**
|
|
1213
|
+
* Ruins grass: cut to stubble (`cut`, state `cut`: a firebreak), crushed flat (`crush`, state `flattened`, as what
|
|
1214
|
+
* tramples it does) or scorched black (`scorch`, state `burnt`: nothing left to burn) (`FoliageRuin`). What burns there
|
|
1215
|
+
* goes out as it is ruined. It hides nobody and does not burn until it has grown back (`regrow`, or by itself after
|
|
1216
|
+
* its style's `regrows` seconds, over its `grows`). A cell is left as it is where it is that already, or burnt (nothing
|
|
1217
|
+
* to cut or crush), or cut (nothing to crush). Told (`foliageRuined`), by `by` where it says. Changes the state layer
|
|
1218
|
+
* alone: the ways are not weighed again. Returns the cells ruined, in order
|
|
1219
|
+
*
|
|
1220
|
+
* @beta
|
|
1221
|
+
*/
|
|
1222
|
+
function ruin(world, layer, where, options) {
|
|
1223
|
+
return ruinAs(world, "ruin", layer, where, options.how, options.by);
|
|
1224
|
+
}
|
|
1225
|
+
/** What each way of ruining makes a cell (`FOLIAGE_STATE`) */
|
|
1226
|
+
var RUINED = {
|
|
1227
|
+
cut: FOLIAGE_STATE.cut,
|
|
1228
|
+
crush: FOLIAGE_STATE.flattened,
|
|
1229
|
+
scorch: FOLIAGE_STATE.burnt
|
|
1230
|
+
};
|
|
1231
|
+
/** Whether a cell in a state can be ruined so (`ruin`): not where it is that already, nor where nothing is left to cut or crush */
|
|
1232
|
+
function ruinable(how, state) {
|
|
1233
|
+
if (state === FOLIAGE_STATE.burnt) return false;
|
|
1234
|
+
if (how === "cut") return state !== FOLIAGE_STATE.cut;
|
|
1235
|
+
if (how === "crush") return state !== FOLIAGE_STATE.flattened && state !== FOLIAGE_STATE.cut;
|
|
1236
|
+
return true;
|
|
1237
|
+
}
|
|
1238
|
+
/** `ruin`, said as `what` (a call of its own, `firebreak`): the cells ruined, in order */
|
|
1239
|
+
function ruinAs(world, what, layer, where, how, by) {
|
|
1240
|
+
const fire = fireOf(world, what);
|
|
1241
|
+
const l = fire.indexOf(what, layer);
|
|
1242
|
+
const to = RUINED[how];
|
|
1243
|
+
if (to === void 0) throw new Error(`${what}: "${how}" is no way to ruin grass (cut, crush, scorch)`);
|
|
1244
|
+
const { cells } = world.terrain;
|
|
1245
|
+
const values = cells[layer];
|
|
1246
|
+
const states = cells[foliageStateLayer(layer)];
|
|
1247
|
+
const ruined = [...new Set(cellsOf(world, where))].filter((cell) => values?.[cell] && ruinable(how, states?.[cell] ?? FOLIAGE_STATE.whole)).sort((a, b) => a - b);
|
|
1248
|
+
if (!ruined.length) return ruined;
|
|
1249
|
+
if (world.states.has(fireState)) fire.quench(world, world.state(fireState), l, new Set(ruined), to);
|
|
1250
|
+
world.setCells(foliageStateLayer(layer), ruined, to);
|
|
1251
|
+
world.events.emit(foliageRuined, {
|
|
1252
|
+
layer,
|
|
1253
|
+
cells: [...ruined],
|
|
1254
|
+
how,
|
|
1255
|
+
...by ? { by: by.id } : {}
|
|
1256
|
+
});
|
|
1257
|
+
fire.regrowth.ruined(world, l, ruined);
|
|
1258
|
+
return ruined;
|
|
1259
|
+
}
|
|
1260
|
+
/**
|
|
1261
|
+
* Has ruined or burnt grass (cut, flattened, burnt) grow back to what it was: over `over` seconds (growing, which
|
|
1262
|
+
* hides and burns as whole grass does, and whole at its end), or at once when left out or 0, when grass growing back
|
|
1263
|
+
* already stands whole at once too. What it waited for by itself (`regrows`) it waits for no more. Told as it is whole
|
|
1264
|
+
* (`foliageRegrown`), by `by` where it says. Returns the cells that started to, in order
|
|
1265
|
+
*
|
|
1266
|
+
* @beta
|
|
1267
|
+
*/
|
|
1268
|
+
function regrow(world, layer, where, options = {}) {
|
|
1269
|
+
const fire = fireOf(world, "regrow");
|
|
1270
|
+
const l = fire.indexOf("regrow", layer);
|
|
1271
|
+
const { over = 0, by } = options;
|
|
1272
|
+
if (!(over >= 0) || !Number.isFinite(over)) throw new Error(`regrow: over is seconds, 0 or more (not ${over})`);
|
|
1273
|
+
const cells = [...new Set(cellsOf(world, where))].sort((a, b) => a - b);
|
|
1274
|
+
return fire.regrowth.regrow(world, l, cells, over > 0 ? Math.max(1, Math.round(over / world.dt)) : 0, by?.id ?? 0);
|
|
1275
|
+
}
|
|
1276
|
+
/**
|
|
1277
|
+
* Takes grass away for good: the cells are no style any more (0), and nothing grows back. Returns the cells cleared
|
|
1278
|
+
*
|
|
1279
|
+
* @beta
|
|
1280
|
+
*/
|
|
1281
|
+
function clearFoliage(world, layer, where) {
|
|
1282
|
+
return paint(world, "clearFoliage", layer, where, 0);
|
|
1283
|
+
}
|
|
1284
|
+
/** The game a world is of, as `foliageStyle` reads it: its layers of cells as laid (its data and the map's over the code), its packs */
|
|
1285
|
+
var gameOf = (world) => ({
|
|
1286
|
+
cellLayers: world.registry.cellLayers,
|
|
1287
|
+
packs: world.registry.assembly?.rules.packs
|
|
1288
|
+
});
|
|
1289
|
+
/** Paints a layer's cells with a value, checked, and its state whole there again: the cells that changed, in order */
|
|
1290
|
+
function paint(world, what, layer, where, value) {
|
|
1291
|
+
const def = world.registry.cellLayers.find((each) => each.id === layer);
|
|
1292
|
+
if (!def) throw new Error(`${what}: the game has no layer of cells "${layer}" (Rules.cellLayers)`);
|
|
1293
|
+
const values = def.values?.map((each) => each.value) ?? [1];
|
|
1294
|
+
if (value !== 0 && !values.includes(value)) throw new Error(`${what}: ${value} is no style of the layer "${layer}" (${values.join(", ")}, or 0 for none)`);
|
|
1295
|
+
const fire = world.states.has(fireState) ? foliageFireOf(world) : void 0;
|
|
1296
|
+
const l = fire ? fire.layers.indexOf(layer) : -1;
|
|
1297
|
+
if (fire && l >= 0) fire.quench(world, world.state(fireState), l, new Set(cellsOf(world, where)), void 0);
|
|
1298
|
+
const changed = world.setCells(layer, where, value);
|
|
1299
|
+
const state = foliageStateLayer(layer);
|
|
1300
|
+
const whole = world.terrain.cells[state] ? world.setCells(state, where, FOLIAGE_STATE.whole) : [];
|
|
1301
|
+
if (!whole.length) return changed.sort((a, b) => a - b);
|
|
1302
|
+
return [.../* @__PURE__ */ new Set([...changed, ...whole])].sort((a, b) => a - b);
|
|
1303
|
+
}
|
|
1304
|
+
/**
|
|
1305
|
+
* Paints grass of a style: `world.setCells` on the layer, checked (a value the layer has a style for, or 0), the
|
|
1306
|
+
* cells whole again. Returns the cells that changed
|
|
1307
|
+
*
|
|
1308
|
+
* @beta
|
|
1309
|
+
*/
|
|
1310
|
+
function setFoliage(world, layer, where, value) {
|
|
1311
|
+
return paint(world, "setFoliage", layer, where, value);
|
|
1312
|
+
}
|
|
1313
|
+
/**
|
|
1314
|
+
* The grass at a point as the rules know it (`FoliageCell`): its style, what happened to it, whether it burns. None
|
|
1315
|
+
* where no grass is, or off the map
|
|
1316
|
+
*
|
|
1317
|
+
* @beta
|
|
1318
|
+
*/
|
|
1319
|
+
function foliageAt(world, layer, x, z) {
|
|
1320
|
+
const { terrain } = world;
|
|
1321
|
+
if (!(x >= 0 && z >= 0 && x < terrain.width && z < terrain.depth)) return void 0;
|
|
1322
|
+
const cell = Math.floor(z) * terrain.width + Math.floor(x);
|
|
1323
|
+
const value = terrain.cells[layer]?.[cell] ?? 0;
|
|
1324
|
+
if (!value) return void 0;
|
|
1325
|
+
const state = foliageStateOf(terrain.cells[foliageStateLayer(layer)]?.[cell] ?? FOLIAGE_STATE.whole);
|
|
1326
|
+
const found = {
|
|
1327
|
+
cell,
|
|
1328
|
+
value,
|
|
1329
|
+
style: foliageStyle(gameOf(world), layer, value),
|
|
1330
|
+
state,
|
|
1331
|
+
burning: state === "burning",
|
|
1332
|
+
left: 0
|
|
1333
|
+
};
|
|
1334
|
+
const fire = state === "burning" && world.states.has(fireState) ? world.state(fireState).burning[layer] : void 0;
|
|
1335
|
+
const at = fire ? indexIn(fire.cells, cell) : -1;
|
|
1336
|
+
if (at < 0) return found;
|
|
1337
|
+
const rules = fireOf(world, "foliageAt");
|
|
1338
|
+
const lasts = rules.lasts === void 0 ? Infinity : fire.lit[at] + Math.max(1, Math.round(rules.lasts / world.dt));
|
|
1339
|
+
found.left = Math.max(0, Math.min(fire.ends[at], lasts) - world.tick) * world.dt;
|
|
1340
|
+
if (fire.by[at]) found.by = fire.by[at];
|
|
1341
|
+
return found;
|
|
1342
|
+
}
|
|
1343
|
+
/** What `burningCells` gives where nothing burns */
|
|
1344
|
+
var NONE = Object.freeze([]);
|
|
1345
|
+
/**
|
|
1346
|
+
* The cells of a layer that burn now, in order of their indices: for a game's rules and its computer players. Not to
|
|
1347
|
+
* be kept or changed: the pack's own list. None in a game whose grass does not burn
|
|
1348
|
+
*
|
|
1349
|
+
* @beta
|
|
1350
|
+
*/
|
|
1351
|
+
function burningCells(world, layer) {
|
|
1352
|
+
fireOf(world, "burningCells").indexOf("burningCells", layer);
|
|
1353
|
+
return world.states.has(fireState) && world.state(fireState).burning[layer]?.cells || NONE;
|
|
1354
|
+
}
|
|
1355
|
+
/** The cells an effect's area takes in (`effectArea`): those whose middle is in it */
|
|
1356
|
+
function cellsInArea(world, area) {
|
|
1357
|
+
const { width, depth } = world.terrain;
|
|
1358
|
+
const reach = areaReach(area);
|
|
1359
|
+
const cells = [];
|
|
1360
|
+
for (let cz = Math.max(Math.floor(area.z - reach), 0); cz < Math.min(Math.ceil(area.z + reach), depth); cz++) for (let cx = Math.max(Math.floor(area.x - reach), 0); cx < Math.min(Math.ceil(area.x + reach), width); cx++) if (inArea(area, {
|
|
1361
|
+
x: cx + .5,
|
|
1362
|
+
z: cz + .5
|
|
1363
|
+
})) cells.push(cz * width + cx);
|
|
1364
|
+
return cells;
|
|
1365
|
+
}
|
|
1366
|
+
/**
|
|
1367
|
+
* The `foliage` effect (`EffectTypes.foliage`): does to the grass where it lands what its `act` says, by the caster.
|
|
1368
|
+
* Over its area (`radius`, `shape`), or the cell it landed on; on its `layer`, or every layer of the pack
|
|
1369
|
+
*/
|
|
1370
|
+
var foliageEffect = /* @__PURE__ */ defineEffect({
|
|
1371
|
+
type: "foliage",
|
|
1372
|
+
run(context, effect) {
|
|
1373
|
+
const { world, caster, point } = context;
|
|
1374
|
+
const area = effectArea(context, effect);
|
|
1375
|
+
const { width, depth } = world.terrain;
|
|
1376
|
+
const cells = area ? cellsInArea(world, area) : point.x >= 0 && point.z >= 0 && point.x < width && point.z < depth ? [Math.floor(point.z) * width + Math.floor(point.x)] : [];
|
|
1377
|
+
if (!cells.length) return;
|
|
1378
|
+
for (const layer of effect.layer !== void 0 ? [effect.layer] : fireOf(world, "foliage effect").layers) if (effect.act === "ignite") ignite(world, layer, cells, { by: caster });
|
|
1379
|
+
else if (effect.act === "extinguish") extinguish(world, layer, cells);
|
|
1380
|
+
else if (effect.act === "ruin") ruin(world, layer, cells, {
|
|
1381
|
+
how: effect.how ?? "cut",
|
|
1382
|
+
by: caster
|
|
1383
|
+
});
|
|
1384
|
+
else if (effect.act === "regrow") regrow(world, layer, cells, {
|
|
1385
|
+
...effect.over !== void 0 ? { over: effect.over } : {},
|
|
1386
|
+
by: caster
|
|
1387
|
+
});
|
|
1388
|
+
else if (effect.act === "clear") clearFoliage(world, layer, cells);
|
|
1389
|
+
},
|
|
1390
|
+
fields: [
|
|
1391
|
+
{
|
|
1392
|
+
path: "act",
|
|
1393
|
+
kind: "choice",
|
|
1394
|
+
options: [
|
|
1395
|
+
"ignite",
|
|
1396
|
+
"extinguish",
|
|
1397
|
+
"ruin",
|
|
1398
|
+
"regrow",
|
|
1399
|
+
"clear"
|
|
1400
|
+
],
|
|
1401
|
+
hint: "What it does to the grass where it lands: sets it alight, puts it out, ruins it, has it grow back, or takes it away"
|
|
1402
|
+
},
|
|
1403
|
+
{
|
|
1404
|
+
path: "layer",
|
|
1405
|
+
kind: "text",
|
|
1406
|
+
hint: "The layer of grass it does it to: every layer of the foliage pack when left out"
|
|
1407
|
+
},
|
|
1408
|
+
{
|
|
1409
|
+
path: "how",
|
|
1410
|
+
kind: "choice",
|
|
1411
|
+
options: [
|
|
1412
|
+
"cut",
|
|
1413
|
+
"crush",
|
|
1414
|
+
"scorch"
|
|
1415
|
+
],
|
|
1416
|
+
hint: "How it ruins: cut when left out"
|
|
1417
|
+
},
|
|
1418
|
+
{
|
|
1419
|
+
path: "over",
|
|
1420
|
+
kind: "number",
|
|
1421
|
+
min: 0,
|
|
1422
|
+
hint: "Seconds what it has grow back takes to: at once when left out"
|
|
1423
|
+
}
|
|
1424
|
+
]
|
|
1425
|
+
});
|
|
1426
|
+
/**
|
|
1427
|
+
* A gust of wind at a place, on the screen of every player who sees it (`WindGust`): the grass bends to it there (a
|
|
1428
|
+
* ring outwards as it spreads, or a push one way where it says `around`), as `client.gust` bends it on one screen. A
|
|
1429
|
+
* player is told where their team sees its middle or any of its edge; an observer always. Nothing it does decides
|
|
1430
|
+
* anything: it is not in the world's state or a save, and it changes nothing of the world
|
|
1431
|
+
*
|
|
1432
|
+
* @beta
|
|
1433
|
+
*/
|
|
1434
|
+
function gust(world, at, gust) {
|
|
1435
|
+
const { radius, strength, around, lasts } = gust;
|
|
1436
|
+
if (!(radius > 0) || !Number.isFinite(radius)) throw new Error(`gust: a radius over 0 (not ${radius})`);
|
|
1437
|
+
if (!(strength >= 0) || !Number.isFinite(strength)) throw new Error(`gust: a strength of 0 or more (not ${strength})`);
|
|
1438
|
+
if (around !== void 0 && !Number.isFinite(around)) throw new Error(`gust: around in degrees (not ${around})`);
|
|
1439
|
+
if (lasts !== void 0 && !(lasts > 0 && Number.isFinite(lasts))) throw new Error(`gust: lasts over 0 seconds (not ${lasts})`);
|
|
1440
|
+
if (!Number.isFinite(at.x) || !Number.isFinite(at.z)) throw new Error(`gust: a place on the map (not ${at.x}, ${at.z})`);
|
|
1441
|
+
world.events.emit(gusted, {
|
|
1442
|
+
x: at.x,
|
|
1443
|
+
z: at.z,
|
|
1444
|
+
gust: {
|
|
1445
|
+
radius,
|
|
1446
|
+
strength,
|
|
1447
|
+
...around !== void 0 && { around },
|
|
1448
|
+
...lasts !== void 0 && { lasts }
|
|
1449
|
+
}
|
|
1450
|
+
});
|
|
1451
|
+
}
|
|
1452
|
+
/** The places of a gust a team must see one of to be told of it: its middle and four points of its edge */
|
|
1453
|
+
var GUST_EDGE = [
|
|
1454
|
+
[0, 0],
|
|
1455
|
+
[1, 0],
|
|
1456
|
+
[-1, 0],
|
|
1457
|
+
[0, 1],
|
|
1458
|
+
[0, -1]
|
|
1459
|
+
];
|
|
1460
|
+
/** A gust of wind (`gust`): to each player whose team sees its middle or its edge, as a `gust` message */
|
|
1461
|
+
var toldGust = replicateEvent(gusted, "gust", ({ x, z, gust }, view) => {
|
|
1462
|
+
const { radius } = gust;
|
|
1463
|
+
if (!GUST_EDGE.some(([dx, dz]) => view.sees(x + dx * radius, z + dz * radius))) return void 0;
|
|
1464
|
+
const round = (value) => Math.round(value * 100) / 100;
|
|
1465
|
+
return {
|
|
1466
|
+
type: "gust",
|
|
1467
|
+
x: Math.round(x * 10) / 10,
|
|
1468
|
+
z: Math.round(z * 10) / 10,
|
|
1469
|
+
radius: round(radius),
|
|
1470
|
+
strength: round(gust.strength),
|
|
1471
|
+
...gust.around !== void 0 && { around: round(gust.around) },
|
|
1472
|
+
...gust.lasts !== void 0 && { lasts: round(gust.lasts) }
|
|
1473
|
+
};
|
|
1474
|
+
});
|
|
1475
|
+
//#endregion
|
|
1476
|
+
export { FOLIAGE, FOLIAGE_STATE, FoliageFireRules, burningCells, clearFoliage, extinguish, firebreak, foliageAt, foliageBurnt, foliageFireOf, foliageFireOut, foliageIgnite, foliageIgnited, foliageLayerOfState, foliageLayers, foliagePack, foliageRegrown, foliageRuined, foliageStateLayer, foliageStateOf, foliageStyle, foliageStyleProblem, gust, ignite, regrow, ruin, setFoliage, stopFire, toldGust };
|
|
1477
|
+
|
|
1478
|
+
//# sourceMappingURL=foliage.js.map
|