@jgengine/core 0.10.0 → 0.12.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/CHANGELOG.md +39 -2
- package/LICENSE +203 -661
- package/README.md +1 -1
- package/dist/ai/crowd.d.ts +55 -0
- package/dist/ai/crowd.js +114 -0
- package/dist/ai/flock.d.ts +5 -2
- package/dist/ai/flock.js +5 -2
- package/dist/ai/groupAssist.d.ts +1 -0
- package/dist/ai/groupAssist.js +1 -0
- package/dist/ai/heatSystem.d.ts +76 -0
- package/dist/ai/heatSystem.js +97 -0
- package/dist/ai/interestScheduler.d.ts +107 -0
- package/dist/ai/interestScheduler.js +118 -0
- package/dist/ai/jobBoard.d.ts +1 -0
- package/dist/ai/jobBoard.js +1 -0
- package/dist/ai/laneSelect.d.ts +5 -2
- package/dist/ai/laneSelect.js +5 -2
- package/dist/ai/mobBrain.d.ts +1 -0
- package/dist/ai/mobBrain.js +1 -0
- package/dist/ai/populationDirector.d.ts +103 -0
- package/dist/ai/populationDirector.js +190 -0
- package/dist/ai/pursuit.d.ts +56 -0
- package/dist/ai/pursuit.js +53 -0
- package/dist/ai/spawnDirector.d.ts +7 -2
- package/dist/ai/spawnDirector.js +18 -15
- package/dist/ai/spawnPoint.d.ts +3 -1
- package/dist/ai/spawnPoint.js +3 -1
- package/dist/ai/targetAcquisition.d.ts +84 -0
- package/dist/ai/targetAcquisition.js +92 -0
- package/dist/anim/easing.d.ts +19 -0
- package/dist/anim/easing.js +19 -0
- package/dist/anim/oscillator.d.ts +12 -0
- package/dist/anim/oscillator.js +25 -0
- package/dist/area/areaEffectField.d.ts +127 -0
- package/dist/area/areaEffectField.js +175 -0
- package/dist/area/stackPolicy.d.ts +47 -0
- package/dist/area/stackPolicy.js +99 -0
- package/dist/authoring.d.ts +2 -1
- package/dist/authoring.js +2 -1
- package/dist/board/laneBoard.d.ts +13 -0
- package/dist/board/laneBoard.js +13 -0
- package/dist/board/timelineBoard.d.ts +10 -0
- package/dist/board/timelineBoard.js +10 -0
- package/dist/combat/abilityKit.d.ts +18 -0
- package/dist/combat/abilityKit.js +24 -9
- package/dist/combat/animationState.d.ts +5 -0
- package/dist/combat/animationState.js +5 -0
- package/dist/combat/breakMeters.d.ts +10 -0
- package/dist/combat/breakMeters.js +10 -0
- package/dist/combat/castRunner.d.ts +5 -0
- package/dist/combat/castRunner.js +5 -0
- package/dist/combat/comboPoints.d.ts +5 -0
- package/dist/combat/comboPoints.js +5 -0
- package/dist/combat/comboString.d.ts +5 -0
- package/dist/combat/comboString.js +5 -0
- package/dist/combat/damageInterceptors.d.ts +192 -0
- package/dist/combat/damageInterceptors.js +251 -0
- package/dist/combat/damageMatchup.d.ts +68 -0
- package/dist/combat/damageMatchup.js +42 -0
- package/dist/combat/damageResolution.d.ts +63 -0
- package/dist/combat/damageResolution.js +50 -0
- package/dist/combat/death.d.ts +7 -1
- package/dist/combat/death.js +5 -0
- package/dist/combat/deathReason.d.ts +14 -0
- package/dist/combat/deathReason.js +1 -0
- package/dist/combat/defensiveWindow.d.ts +5 -0
- package/dist/combat/defensiveWindow.js +5 -0
- package/dist/combat/dotField.d.ts +5 -1
- package/dist/combat/dotField.js +5 -1
- package/dist/combat/downed.d.ts +5 -0
- package/dist/combat/downed.js +5 -0
- package/dist/combat/effects.d.ts +5 -0
- package/dist/combat/effects.js +5 -0
- package/dist/combat/encounterSequence.d.ts +258 -0
- package/dist/combat/encounterSequence.js +426 -0
- package/dist/combat/hitReaction.d.ts +57 -1
- package/dist/combat/hitReaction.js +45 -5
- package/dist/combat/magazine.d.ts +54 -0
- package/dist/combat/magazine.js +96 -0
- package/dist/combat/projectiles.d.ts +5 -0
- package/dist/combat/projectiles.js +32 -14
- package/dist/combat/receivedDamage.d.ts +117 -0
- package/dist/combat/receivedDamage.js +92 -0
- package/dist/combat/regenShield.d.ts +5 -1
- package/dist/combat/regenShield.js +5 -1
- package/dist/combat/renderCues.d.ts +51 -0
- package/dist/combat/renderCues.js +44 -0
- package/dist/combat/resourcePool.d.ts +5 -0
- package/dist/combat/resourcePool.js +5 -0
- package/dist/combat/rewardAllocation.d.ts +121 -0
- package/dist/combat/rewardAllocation.js +251 -0
- package/dist/combat/shotOrigin.d.ts +18 -1
- package/dist/combat/shotOrigin.js +39 -0
- package/dist/combat/statusApplication.d.ts +96 -0
- package/dist/combat/statusApplication.js +81 -0
- package/dist/combat/telegraph.d.ts +11 -2
- package/dist/combat/telegraph.js +11 -2
- package/dist/combat/thresholdCrossings.d.ts +85 -0
- package/dist/combat/thresholdCrossings.js +116 -0
- package/dist/combat.d.ts +35 -0
- package/dist/combat.js +35 -0
- package/dist/commands/commandRegistry.d.ts +11 -0
- package/dist/commands/commandRegistry.js +9 -2
- package/dist/crafting/crop.d.ts +18 -0
- package/dist/crafting/crop.js +18 -0
- package/dist/crafting/production.d.ts +5 -0
- package/dist/crafting/production.js +5 -0
- package/dist/devtools/controls.d.ts +38 -0
- package/dist/devtools/controls.js +181 -0
- package/dist/devtools/devtools.d.ts +5 -197
- package/dist/devtools/devtools.js +38 -774
- package/dist/devtools/discover.d.ts +32 -0
- package/dist/devtools/discover.js +240 -0
- package/dist/devtools/fallbackSeams.d.ts +50 -0
- package/dist/devtools/fallbackSeams.js +111 -0
- package/dist/devtools/frame.d.ts +15 -0
- package/dist/devtools/frame.js +247 -0
- package/dist/devtools/logs.d.ts +15 -0
- package/dist/devtools/logs.js +86 -0
- package/dist/devtools/overrides.d.ts +16 -0
- package/dist/devtools/overrides.js +66 -0
- package/dist/devtools/rewriteTunables.d.ts +17 -0
- package/dist/devtools/rewriteTunables.js +276 -0
- package/dist/devtools/saveEndpoint.d.ts +46 -0
- package/dist/devtools/saveEndpoint.js +48 -0
- package/dist/devtools/transformTunables.d.ts +3 -0
- package/dist/devtools/transformTunables.js +3 -0
- package/dist/devtools/tunableSchema.d.ts +31 -0
- package/dist/devtools/tunableSchema.js +31 -0
- package/dist/devtools/types.d.ts +212 -0
- package/dist/devtools/types.js +1 -0
- package/dist/economy/auctionBook.d.ts +122 -0
- package/dist/economy/auctionBook.js +213 -0
- package/dist/economy/currency.d.ts +12 -1
- package/dist/economy/currency.js +12 -1
- package/dist/economy/listingBook.d.ts +91 -0
- package/dist/economy/listingBook.js +144 -0
- package/dist/economy/priceHistory.d.ts +44 -0
- package/dist/economy/priceHistory.js +89 -0
- package/dist/economy/resourceLedger.d.ts +222 -0
- package/dist/economy/resourceLedger.js +353 -0
- package/dist/economy/sharedWallet.d.ts +14 -0
- package/dist/economy/sharedWallet.js +14 -0
- package/dist/economy/techTree.d.ts +12 -0
- package/dist/economy/techTree.js +12 -0
- package/dist/economy/unlockPoints.d.ts +92 -0
- package/dist/economy/unlockPoints.js +103 -0
- package/dist/economy/wallet.d.ts +26 -2
- package/dist/economy/wallet.js +35 -6
- package/dist/editor/commandApply.d.ts +5 -0
- package/dist/editor/commandApply.js +755 -0
- package/dist/editor/commands.d.ts +235 -7
- package/dist/editor/commands.js +82 -124
- package/dist/editor/directives.d.ts +94 -0
- package/dist/editor/directives.js +206 -0
- package/dist/editor/document.d.ts +194 -13
- package/dist/editor/document.js +1166 -19
- package/dist/editor/entityCatalog.d.ts +42 -0
- package/dist/editor/entityCatalog.js +101 -0
- package/dist/editor/environment.d.ts +74 -0
- package/dist/editor/environment.js +169 -0
- package/dist/editor/grid.d.ts +229 -0
- package/dist/editor/grid.js +366 -0
- package/dist/editor/gridAdapters.d.ts +80 -0
- package/dist/editor/gridAdapters.js +134 -0
- package/dist/editor/index.d.ts +98 -6
- package/dist/editor/index.js +13 -2
- package/dist/editor/liveSync.d.ts +127 -0
- package/dist/editor/liveSync.js +249 -0
- package/dist/editor/minimap.d.ts +31 -0
- package/dist/editor/minimap.js +73 -0
- package/dist/editor/runtimeInspector.d.ts +88 -0
- package/dist/editor/runtimeInspector.js +239 -0
- package/dist/editor/streamer.d.ts +66 -0
- package/dist/editor/streamer.js +68 -0
- package/dist/editor/types.d.ts +250 -1
- package/dist/editor/world.d.ts +136 -0
- package/dist/editor/world.js +303 -0
- package/dist/faction/reputation.d.ts +5 -0
- package/dist/faction/reputation.js +5 -0
- package/dist/format/distance.d.ts +17 -0
- package/dist/format/distance.js +18 -0
- package/dist/format/duration.d.ts +27 -0
- package/dist/format/duration.js +45 -0
- package/dist/format/speed.d.ts +17 -0
- package/dist/format/speed.js +25 -0
- package/dist/game/breeding.d.ts +161 -0
- package/dist/game/breeding.js +181 -0
- package/dist/game/cameraConfig.d.ts +451 -0
- package/dist/game/cameraConfig.js +1 -0
- package/dist/game/connectedPlayers.d.ts +6 -4
- package/dist/game/connectedPlayers.js +2 -2
- package/dist/game/cosmetics.d.ts +9 -0
- package/dist/game/cosmetics.js +16 -0
- package/dist/game/defineGame.d.ts +110 -5
- package/dist/game/defineGame.js +49 -4
- package/dist/game/defineSystem.d.ts +90 -0
- package/dist/game/defineSystem.js +47 -0
- package/dist/game/dialogue.d.ts +33 -0
- package/dist/game/dialogue.js +21 -0
- package/dist/game/events.d.ts +63 -13
- package/dist/game/events.js +5 -0
- package/dist/game/feed.d.ts +33 -0
- package/dist/game/feed.js +35 -2
- package/dist/game/gamePhase.d.ts +11 -0
- package/dist/game/gamePhase.js +16 -0
- package/dist/game/leaderboard.d.ts +5 -0
- package/dist/game/leaderboard.js +5 -0
- package/dist/game/loadout.d.ts +5 -0
- package/dist/game/loadout.js +5 -0
- package/dist/game/lootFilter.d.ts +2 -0
- package/dist/game/lootFilter.js +2 -0
- package/dist/game/lootPipeline.d.ts +164 -0
- package/dist/game/lootPipeline.js +216 -0
- package/dist/game/lootTable.d.ts +19 -2
- package/dist/game/lootTable.js +15 -5
- package/dist/game/objectives.d.ts +43 -0
- package/dist/game/objectives.js +36 -0
- package/dist/game/paramLayers.d.ts +148 -0
- package/dist/game/paramLayers.js +185 -0
- package/dist/game/ping.d.ts +5 -0
- package/dist/game/ping.js +5 -0
- package/dist/game/playableGame.d.ts +116 -432
- package/dist/game/playableGame.js +1 -1
- package/dist/game/progression.d.ts +35 -0
- package/dist/game/progression.js +19 -0
- package/dist/game/quest.d.ts +8 -0
- package/dist/game/quest.js +30 -3
- package/dist/game/race.d.ts +141 -0
- package/dist/game/race.js +169 -0
- package/dist/game/recordBook.d.ts +3 -1
- package/dist/game/recordBook.js +4 -1
- package/dist/game/ruleSelection.d.ts +75 -0
- package/dist/game/ruleSelection.js +127 -0
- package/dist/game/runDraft.d.ts +5 -0
- package/dist/game/runDraft.js +5 -0
- package/dist/game/saveStore.d.ts +111 -0
- package/dist/game/saveStore.js +312 -0
- package/dist/game/snapshotHistory.d.ts +67 -0
- package/dist/game/snapshotHistory.js +95 -0
- package/dist/game/social.d.ts +38 -1
- package/dist/game/social.js +71 -0
- package/dist/game/spawnPoints.d.ts +5 -0
- package/dist/game/spawnPoints.js +5 -0
- package/dist/game/systemRuntime.d.ts +50 -0
- package/dist/game/systemRuntime.js +157 -0
- package/dist/game/systemSchedule.d.ts +72 -0
- package/dist/game/systemSchedule.js +242 -0
- package/dist/game/toasts.d.ts +43 -0
- package/dist/game/toasts.js +44 -0
- package/dist/game/trade.d.ts +10 -0
- package/dist/game/trade.js +10 -0
- package/dist/game/tribe.d.ts +184 -0
- package/dist/game/tribe.js +432 -0
- package/dist/game/unlocks.d.ts +8 -0
- package/dist/game/unlocks.js +16 -0
- package/dist/game/vfxInstance.d.ts +138 -0
- package/dist/game/vfxInstance.js +96 -0
- package/dist/game/worldItem.d.ts +17 -4
- package/dist/game/worldItem.js +17 -4
- package/dist/gameplay.d.ts +93 -0
- package/dist/gameplay.js +93 -0
- package/dist/index.d.ts +5 -14
- package/dist/index.js +5 -14
- package/dist/input/actionBindings.d.ts +23 -6
- package/dist/input/actionBindings.js +23 -6
- package/dist/input/axisInput.d.ts +7 -2
- package/dist/input/axisInput.js +7 -2
- package/dist/input/controlGroups.d.ts +67 -0
- package/dist/input/controlGroups.js +41 -0
- package/dist/input/touchScheme.d.ts +82 -6
- package/dist/input/touchScheme.js +123 -10
- package/dist/interaction/lockpick.d.ts +61 -0
- package/dist/interaction/lockpick.js +168 -0
- package/dist/interaction/proximityPrompt.d.ts +2 -0
- package/dist/interaction/proximityPrompt.js +2 -0
- package/dist/interaction/qte.d.ts +5 -0
- package/dist/interaction/qte.js +5 -0
- package/dist/interaction/skillCheck.d.ts +5 -0
- package/dist/interaction/skillCheck.js +5 -0
- package/dist/inventory/encumbrance.d.ts +69 -0
- package/dist/inventory/encumbrance.js +68 -0
- package/dist/inventory/inventoryModel.d.ts +12 -0
- package/dist/inventory/inventoryModel.js +12 -0
- package/dist/inventory/shapedGrid.d.ts +16 -0
- package/dist/inventory/shapedGrid.js +16 -0
- package/dist/inventory/slotModel.d.ts +10 -0
- package/dist/inventory/slotModel.js +10 -0
- package/dist/item/durability.d.ts +5 -0
- package/dist/item/durability.js +6 -3
- package/dist/item/itemIdentity.d.ts +171 -0
- package/dist/item/itemIdentity.js +138 -0
- package/dist/item/itemInstanceRegistry.d.ts +32 -0
- package/dist/item/itemInstanceRegistry.js +34 -0
- package/dist/item/itemgen.d.ts +163 -0
- package/dist/item/itemgen.js +151 -0
- package/dist/item/modularItem.d.ts +5 -0
- package/dist/item/modularItem.js +5 -0
- package/dist/item/use.d.ts +5 -0
- package/dist/item/use.js +5 -0
- package/dist/item/useBehavior.d.ts +142 -0
- package/dist/item/useBehavior.js +105 -0
- package/dist/item/weapon.d.ts +5 -0
- package/dist/item/weapon.js +5 -0
- package/dist/math/scalar.d.ts +25 -0
- package/dist/math/scalar.js +47 -0
- package/dist/meta/changelog.d.ts +4 -1
- package/dist/meta/changelog.js +39 -2
- package/dist/movement/avoidance.d.ts +45 -0
- package/dist/movement/avoidance.js +123 -0
- package/dist/movement/cameraRig.d.ts +8 -0
- package/dist/movement/cameraRig.js +8 -0
- package/dist/movement/dash.d.ts +11 -0
- package/dist/movement/dash.js +11 -0
- package/dist/movement/formation.d.ts +135 -0
- package/dist/movement/formation.js +194 -0
- package/dist/movement/glideModel.d.ts +5 -0
- package/dist/movement/glideModel.js +5 -0
- package/dist/movement/grappleSwing.d.ts +5 -0
- package/dist/movement/grappleSwing.js +5 -0
- package/dist/movement/leaderTrail.d.ts +5 -0
- package/dist/movement/leaderTrail.js +5 -0
- package/dist/movement/movementModel.d.ts +50 -9
- package/dist/movement/movementModel.js +75 -29
- package/dist/movement/playerMovement.js +167 -12
- package/dist/movement/poseState.d.ts +13 -0
- package/dist/movement/poseState.js +16 -0
- package/dist/movement/steering.d.ts +8 -0
- package/dist/movement/steering.js +18 -0
- package/dist/multiplayer/combatSnapshot.d.ts +3 -0
- package/dist/multiplayer/combatSnapshot.js +16 -8
- package/dist/multiplayer/lagCompensation.d.ts +5 -0
- package/dist/multiplayer/lagCompensation.js +5 -0
- package/dist/multiplayer/presenceModel.d.ts +11 -1
- package/dist/multiplayer/presenceModel.js +17 -1
- package/dist/multiplayer/simultaneousCommit.d.ts +3 -0
- package/dist/multiplayer/simultaneousCommit.js +3 -0
- package/dist/multiplayer.d.ts +11 -0
- package/dist/multiplayer.js +11 -0
- package/dist/nav/pathFollow.d.ts +57 -0
- package/dist/nav/pathFollow.js +109 -0
- package/dist/orders/orderKinds.d.ts +156 -0
- package/dist/orders/orderKinds.js +197 -0
- package/dist/orders/orderQueue.d.ts +208 -0
- package/dist/orders/orderQueue.js +211 -0
- package/dist/physics/drivableVehicle.d.ts +31 -0
- package/dist/physics/drivableVehicle.js +16 -0
- package/dist/physics/flightDynamics.d.ts +82 -0
- package/dist/physics/flightDynamics.js +165 -0
- package/dist/physics/gravityField.d.ts +25 -0
- package/dist/physics/gravityField.js +41 -0
- package/dist/physics/kinematicVehicle.d.ts +108 -1
- package/dist/physics/kinematicVehicle.js +212 -15
- package/dist/physics/physicsWorld.d.ts +50 -12
- package/dist/physics/physicsWorld.js +120 -122
- package/dist/physics/radialImpulse.d.ts +25 -0
- package/dist/physics/radialImpulse.js +27 -0
- package/dist/physics/vehicleObstacles.d.ts +44 -0
- package/dist/physics/vehicleObstacles.js +115 -0
- package/dist/procedural.d.ts +3 -0
- package/dist/procedural.js +3 -0
- package/dist/progression/statGraph.d.ts +116 -0
- package/dist/progression/statGraph.js +318 -0
- package/dist/puzzle/cellGrid.d.ts +9 -0
- package/dist/puzzle/cellGrid.js +9 -0
- package/dist/puzzle/fallingPiece.d.ts +9 -0
- package/dist/puzzle/fallingPiece.js +9 -0
- package/dist/puzzle/nonogram.d.ts +39 -0
- package/dist/puzzle/nonogram.js +136 -0
- package/dist/random/nameGen.d.ts +5 -0
- package/dist/random/nameGen.js +5 -0
- package/dist/random/pick.d.ts +8 -0
- package/dist/random/pick.js +31 -0
- package/dist/random/rng.d.ts +26 -1
- package/dist/random/rng.js +32 -9
- package/dist/random/seedLink.d.ts +4 -0
- package/dist/random/seedLink.js +4 -0
- package/dist/relation/keyedValues.d.ts +54 -0
- package/dist/relation/keyedValues.js +115 -0
- package/dist/relation/thresholds.d.ts +62 -0
- package/dist/relation/thresholds.js +62 -0
- package/dist/render/color.d.ts +12 -0
- package/dist/render/color.js +26 -0
- package/dist/render/lookPreset.d.ts +41 -0
- package/dist/render/lookPreset.js +29 -0
- package/dist/render/postProcessing.d.ts +20 -0
- package/dist/render/postProcessing.js +21 -1
- package/dist/rules/predicate.d.ts +53 -0
- package/dist/rules/predicate.js +64 -0
- package/dist/rules/ruleEffects.d.ts +38 -0
- package/dist/rules/ruleEffects.js +37 -0
- package/dist/rules/triggeredRules.d.ts +160 -0
- package/dist/rules/triggeredRules.js +241 -0
- package/dist/runtime/adapter.d.ts +55 -3
- package/dist/runtime/adapter.js +57 -1
- package/dist/runtime/cameraDirector.d.ts +1 -0
- package/dist/runtime/cameraDirector.js +1 -0
- package/dist/runtime/commandRunner.d.ts +1 -0
- package/dist/runtime/commandRunner.js +1 -0
- package/dist/runtime/context/combat.d.ts +51 -0
- package/dist/runtime/context/combat.js +130 -0
- package/dist/runtime/context/combatFx.d.ts +23 -0
- package/dist/runtime/context/combatFx.js +161 -0
- package/dist/runtime/context/deathLoot.d.ts +30 -0
- package/dist/runtime/context/deathLoot.js +39 -0
- package/dist/runtime/context/player.d.ts +48 -0
- package/dist/runtime/context/player.js +125 -0
- package/dist/runtime/context/registries.d.ts +13 -0
- package/dist/runtime/context/registries.js +84 -0
- package/dist/runtime/context/scene.d.ts +59 -0
- package/dist/runtime/context/scene.js +291 -0
- package/dist/runtime/context/snapshotCodecs.d.ts +12 -0
- package/dist/runtime/context/snapshotCodecs.js +26 -0
- package/dist/runtime/context/worldItems.d.ts +21 -0
- package/dist/runtime/context/worldItems.js +37 -0
- package/dist/runtime/descriptors/baseline.d.ts +48 -0
- package/dist/runtime/descriptors/baseline.js +157 -0
- package/dist/runtime/descriptors/features.d.ts +79 -0
- package/dist/runtime/descriptors/features.js +299 -0
- package/dist/runtime/gameContext.d.ts +2 -327
- package/dist/runtime/gameContext.js +273 -778
- package/dist/runtime/gameContextTypes.d.ts +467 -0
- package/dist/runtime/gameContextTypes.js +1 -0
- package/dist/runtime/gameRuntime.d.ts +1 -0
- package/dist/runtime/gameRuntime.js +1 -0
- package/dist/runtime/headlessRunner.d.ts +62 -0
- package/dist/runtime/headlessRunner.js +45 -0
- package/dist/runtime/hostPersistence.d.ts +12 -0
- package/dist/runtime/hostPersistence.js +12 -0
- package/dist/runtime/hostPolicy.d.ts +51 -0
- package/dist/runtime/hostPolicy.js +68 -0
- package/dist/runtime/hostedGameRunner.d.ts +11 -4
- package/dist/runtime/hostedGameRunner.js +27 -3
- package/dist/runtime/hostedWorldSession.d.ts +15 -5
- package/dist/runtime/hostedWorldSession.js +12 -4
- package/dist/runtime/inputSnapshot.d.ts +8 -3
- package/dist/runtime/inputSnapshot.js +6 -2
- package/dist/runtime/motionIntents.d.ts +11 -2
- package/dist/runtime/motionIntents.js +16 -2
- package/dist/runtime/perContext.d.ts +15 -0
- package/dist/runtime/perContext.js +21 -0
- package/dist/runtime/runtimeSave.d.ts +79 -0
- package/dist/runtime/runtimeSave.js +105 -0
- package/dist/runtime/save.d.ts +4 -0
- package/dist/runtime/save.js +4 -0
- package/dist/runtime/snapshot.d.ts +7 -0
- package/dist/runtime/snapshot.js +7 -0
- package/dist/runtime/visibility.d.ts +2 -1
- package/dist/runtime/visibility.js +2 -1
- package/dist/runtime/worldChannel.d.ts +7 -3
- package/dist/runtime/worldChannel.js +51 -6
- package/dist/runtime/worldMirror.d.ts +14 -2
- package/dist/runtime/worldMirror.js +15 -2
- package/dist/runtime/worldProjection.d.ts +47 -0
- package/dist/runtime/worldProjection.js +52 -0
- package/dist/runtime/worldReplication.d.ts +30 -7
- package/dist/runtime/worldReplication.js +41 -9
- package/dist/runtime/worldSnapshot.d.ts +42 -3
- package/dist/runtime/worldSnapshot.js +34 -7
- package/dist/scene/assetCatalog.d.ts +26 -0
- package/dist/scene/assetCatalog.js +4 -0
- package/dist/scene/assetDiagnostics.d.ts +69 -0
- package/dist/scene/assetDiagnostics.js +110 -0
- package/dist/scene/assetGenerator.d.ts +65 -0
- package/dist/scene/assetGenerator.js +64 -0
- package/dist/scene/assetSpace.d.ts +137 -0
- package/dist/scene/assetSpace.js +257 -0
- package/dist/scene/authoredTriggers.d.ts +219 -0
- package/dist/scene/authoredTriggers.js +454 -0
- package/dist/scene/behaviorRuntime.d.ts +75 -0
- package/dist/scene/behaviorRuntime.js +217 -0
- package/dist/scene/behaviors.d.ts +14 -2
- package/dist/scene/behaviors.js +7 -2
- package/dist/scene/bodyBind.d.ts +60 -0
- package/dist/scene/bodyBind.js +51 -0
- package/dist/scene/builtinSceneKinds.d.ts +5 -0
- package/dist/scene/builtinSceneKinds.js +67 -0
- package/dist/scene/colliders.d.ts +71 -1
- package/dist/scene/colliders.js +145 -1
- package/dist/scene/collisionMesh.d.ts +94 -0
- package/dist/scene/collisionMesh.js +699 -0
- package/dist/scene/companion.d.ts +147 -0
- package/dist/scene/companion.js +193 -0
- package/dist/scene/entityStats.d.ts +18 -11
- package/dist/scene/entityStats.js +21 -16
- package/dist/scene/entityStore.d.ts +12 -1
- package/dist/scene/entityStore.js +15 -0
- package/dist/scene/facing.d.ts +18 -0
- package/dist/scene/facing.js +26 -0
- package/dist/scene/modelSockets.d.ts +33 -0
- package/dist/scene/modelSockets.js +29 -0
- package/dist/scene/objectQuery.d.ts +2 -0
- package/dist/scene/objectQuery.js +2 -0
- package/dist/scene/objectStore.d.ts +4 -0
- package/dist/scene/objectStore.js +6 -0
- package/dist/scene/possession.d.ts +8 -0
- package/dist/scene/possession.js +14 -0
- package/dist/scene/roster.d.ts +3 -0
- package/dist/scene/roster.js +12 -0
- package/dist/scene/sceneKinds.d.ts +256 -0
- package/dist/scene/sceneKinds.js +218 -0
- package/dist/scene/sceneOwnership.d.ts +169 -0
- package/dist/scene/sceneOwnership.js +179 -0
- package/dist/scene/sceneRaycast.js +15 -0
- package/dist/scene/selectionBookmarks.d.ts +93 -0
- package/dist/scene/selectionBookmarks.js +122 -0
- package/dist/scene/vehicleSeat.d.ts +68 -0
- package/dist/scene/vehicleSeat.js +59 -0
- package/dist/sensor/concealment.d.ts +3 -0
- package/dist/sensor/concealment.js +3 -0
- package/dist/sensor/freezeMonitor.d.ts +1 -0
- package/dist/sensor/freezeMonitor.js +1 -0
- package/dist/sensor/frustumSensor.d.ts +7 -3
- package/dist/sensor/frustumSensor.js +7 -3
- package/dist/sensor/hiddenStateProbe.d.ts +5 -2
- package/dist/sensor/hiddenStateProbe.js +5 -2
- package/dist/sensor/recordingBuffer.d.ts +2 -1
- package/dist/sensor/recordingBuffer.js +2 -1
- package/dist/sensor/replayLoop.d.ts +6 -2
- package/dist/sensor/replayLoop.js +6 -2
- package/dist/sensor/revealQuery.d.ts +2 -1
- package/dist/sensor/revealQuery.js +2 -1
- package/dist/sensor/visionCone.d.ts +10 -3
- package/dist/sensor/visionCone.js +10 -3
- package/dist/session/contestedChannel.d.ts +1 -0
- package/dist/session/contestedChannel.js +1 -0
- package/dist/session/extraction.d.ts +1 -0
- package/dist/session/extraction.js +1 -0
- package/dist/session/roles.d.ts +6 -0
- package/dist/session/roles.js +6 -0
- package/dist/session/roundState.d.ts +8 -0
- package/dist/session/roundState.js +2 -0
- package/dist/settings/settingsModel.d.ts +1 -0
- package/dist/settings/settingsModel.js +1 -0
- package/dist/stats/accumulatorMeter.d.ts +6 -0
- package/dist/stats/accumulatorMeter.js +6 -0
- package/dist/stats/eventMeter.d.ts +5 -0
- package/dist/stats/eventMeter.js +5 -0
- package/dist/stats/rollCheck.d.ts +5 -0
- package/dist/stats/rollCheck.js +5 -0
- package/dist/stats/spawnLevelStats.d.ts +110 -0
- package/dist/stats/spawnLevelStats.js +140 -0
- package/dist/stats/statModifiers.d.ts +5 -0
- package/dist/stats/statModifiers.js +5 -0
- package/dist/stats/statPool.d.ts +70 -0
- package/dist/stats/statPool.js +59 -0
- package/dist/store/changeSignal.d.ts +3 -0
- package/dist/store/changeSignal.js +2 -0
- package/dist/store/defineKeyedStore.d.ts +38 -0
- package/dist/store/defineKeyedStore.js +42 -0
- package/dist/store/defineStore.d.ts +33 -0
- package/dist/store/defineStore.js +35 -0
- package/dist/store/observableKeyedStore.d.ts +7 -0
- package/dist/store/observableKeyedStore.js +35 -2
- package/dist/survival/decayMeter.d.ts +55 -0
- package/dist/survival/decayMeter.js +130 -57
- package/dist/survival/moodle.d.ts +2 -0
- package/dist/survival/regionHealth.d.ts +6 -0
- package/dist/survival/regionHealth.js +6 -3
- package/dist/tactics/fallingGrid.d.ts +4 -2
- package/dist/tactics/fallingGrid.js +4 -2
- package/dist/tactics/predictiveQuery.d.ts +3 -0
- package/dist/tactics/predictiveQuery.js +3 -0
- package/dist/tactics/snapshot.d.ts +2 -0
- package/dist/tactics/snapshot.js +2 -0
- package/dist/tactics/surface.d.ts +1 -0
- package/dist/tactics/surface.js +1 -0
- package/dist/tactics/tacticalGrid.d.ts +1 -0
- package/dist/tactics/tacticalGrid.js +1 -0
- package/dist/time/beatClock.d.ts +14 -4
- package/dist/time/beatClock.js +14 -4
- package/dist/time/calendarClock.d.ts +3 -0
- package/dist/time/calendarClock.js +3 -0
- package/dist/time/idleProgress.d.ts +4 -0
- package/dist/time/idleProgress.js +4 -0
- package/dist/time/simClock.d.ts +2 -0
- package/dist/time/simClock.js +20 -5
- package/dist/ui/actionModel.d.ts +110 -0
- package/dist/ui/actionModel.js +159 -0
- package/dist/ui/gameLayout.d.ts +30 -11
- package/dist/ui/gameLayout.js +30 -11
- package/dist/ui/hudDocument.d.ts +114 -0
- package/dist/ui/hudDocument.js +220 -0
- package/dist/ui/hudLayout.d.ts +38 -1
- package/dist/ui/hudLayout.js +220 -17
- package/dist/ui/selectionModel.d.ts +92 -0
- package/dist/ui/selectionModel.js +88 -0
- package/dist/ui/tooltipModel.d.ts +63 -0
- package/dist/ui/tooltipModel.js +82 -0
- package/dist/ui.d.ts +15 -0
- package/dist/ui.js +15 -0
- package/dist/visibility/bounds.d.ts +8 -1
- package/dist/visibility/bounds.js +8 -1
- package/dist/visibility/frustum.d.ts +12 -3
- package/dist/visibility/frustum.js +12 -3
- package/dist/work/jobQueue.d.ts +201 -0
- package/dist/work/jobQueue.js +253 -0
- package/dist/work/unitTraining.d.ts +58 -0
- package/dist/work/unitTraining.js +52 -0
- package/dist/world/authoredEntities.d.ts +29 -0
- package/dist/world/authoredEntities.js +29 -0
- package/dist/world/authoredObjects.d.ts +72 -0
- package/dist/world/authoredObjects.js +81 -0
- package/dist/world/authoredSpawn.d.ts +39 -0
- package/dist/world/authoredSpawn.js +37 -0
- package/dist/world/buildSockets.d.ts +152 -0
- package/dist/world/buildSockets.js +188 -0
- package/dist/world/buildingGenerator.d.ts +18 -0
- package/dist/world/buildingGenerator.js +62 -0
- package/dist/world/buildings.d.ts +5 -0
- package/dist/world/buildings.js +5 -0
- package/dist/world/catenary.d.ts +22 -0
- package/dist/world/catenary.js +69 -0
- package/dist/world/cityBlocks.d.ts +152 -0
- package/dist/world/cityBlocks.js +670 -0
- package/dist/world/cityContent.d.ts +77 -0
- package/dist/world/cityContent.js +261 -0
- package/dist/world/cityGeometry.d.ts +114 -0
- package/dist/world/cityGeometry.js +573 -0
- package/dist/world/cityKind.d.ts +314 -0
- package/dist/world/cityKind.js +1578 -0
- package/dist/world/features.d.ts +133 -10
- package/dist/world/features.js +66 -6
- package/dist/world/footprintGrid.d.ts +59 -0
- package/dist/world/footprintGrid.js +141 -0
- package/dist/world/geometry.d.ts +64 -0
- package/dist/world/geometry.js +94 -0
- package/dist/world/grassKind.d.ts +51 -0
- package/dist/world/grassKind.js +101 -0
- package/dist/world/markers.d.ts +50 -4
- package/dist/world/markers.js +49 -0
- package/dist/world/massing.js +1 -1
- package/dist/world/minimapBake.d.ts +78 -0
- package/dist/world/minimapBake.js +208 -0
- package/dist/world/minimapTrack.d.ts +17 -0
- package/dist/world/minimapTrack.js +22 -0
- package/dist/world/pathInstances.d.ts +27 -0
- package/dist/world/pathInstances.js +27 -0
- package/dist/world/pathNetwork.d.ts +159 -0
- package/dist/world/pathNetwork.js +684 -0
- package/dist/world/pathTerrain.d.ts +80 -0
- package/dist/world/pathTerrain.js +142 -0
- package/dist/world/place.d.ts +166 -0
- package/dist/world/place.js +96 -0
- package/dist/world/placeAsset.d.ts +81 -0
- package/dist/world/placeAsset.js +79 -0
- package/dist/world/placement.d.ts +4 -0
- package/dist/world/placement.js +4 -0
- package/dist/world/placementController.d.ts +6 -0
- package/dist/world/placementController.js +6 -0
- package/dist/world/poleLineKind.d.ts +40 -0
- package/dist/world/poleLineKind.js +97 -0
- package/dist/world/polyline.d.ts +34 -0
- package/dist/world/polyline.js +88 -0
- package/dist/world/resourceNode.d.ts +109 -0
- package/dist/world/resourceNode.js +140 -0
- package/dist/world/roads.d.ts +8 -0
- package/dist/world/roads.js +38 -0
- package/dist/world/scatter.js +2 -20
- package/dist/world/scatterRegion.d.ts +164 -0
- package/dist/world/scatterRegion.js +409 -0
- package/dist/world/sceneShapes.d.ts +43 -0
- package/dist/world/sceneShapes.js +1 -0
- package/dist/world/segment.d.ts +27 -0
- package/dist/world/segment.js +43 -0
- package/dist/world/soilKind.d.ts +48 -0
- package/dist/world/soilKind.js +92 -0
- package/dist/world/spatialSample.d.ts +241 -0
- package/dist/world/spatialSample.js +465 -0
- package/dist/world/streets.d.ts +29 -0
- package/dist/world/streets.js +55 -0
- package/dist/world/terraform.d.ts +213 -1
- package/dist/world/terraform.js +627 -22
- package/dist/world/terrain.d.ts +164 -20
- package/dist/world/terrain.js +325 -41
- package/dist/world/terrainGuides.d.ts +182 -0
- package/dist/world/terrainGuides.js +343 -0
- package/dist/world/vec2.d.ts +81 -0
- package/dist/world/vec2.js +128 -0
- package/dist/world/vec3.d.ts +49 -0
- package/dist/world/vec3.js +76 -0
- package/dist/world/vegetation.d.ts +71 -0
- package/dist/world/vegetation.js +151 -0
- package/dist/world/visibilityField.d.ts +154 -0
- package/dist/world/visibilityField.js +271 -0
- package/dist/world/volumetricClouds.d.ts +52 -0
- package/dist/world/volumetricClouds.js +43 -0
- package/dist/world/walls.d.ts +9 -0
- package/dist/world/walls.js +9 -0
- package/dist/world/waterKind.d.ts +55 -0
- package/dist/world/waterKind.js +99 -0
- package/dist/world.d.ts +141 -0
- package/dist/world.js +141 -0
- package/package.json +32 -8
- package/skills/game-design/SKILL.md +28 -0
- package/skills/game-design/agents/openai.yaml +4 -0
- package/skills/game-design/references/application-playbook.md +170 -0
- package/skills/game-design/references/field-guide.md +288 -0
- package/skills/jgengine/SKILL.md +54 -0
- package/skills/jgengine/api.md +527 -0
- package/skills/jgengine/capabilities.md +131 -0
- package/skills/jgengine/recipes/minimal-game.md +88 -0
- package/skills/jgengine-combat/SKILL.md +38 -0
- package/skills/jgengine-combat/api.md +585 -0
- package/skills/jgengine-combat/capabilities.md +213 -0
- package/skills/jgengine-combat/recipes/portable-stat-pools.md +122 -0
- package/skills/jgengine-combat/reference.md +108 -0
- package/skills/jgengine-gameplay/SKILL.md +39 -0
- package/skills/jgengine-gameplay/api.md +1920 -0
- package/skills/jgengine-gameplay/capabilities.md +454 -0
- package/skills/jgengine-gameplay/reference-systems.md +56 -0
- package/skills/jgengine-world/SKILL.md +51 -0
- package/skills/jgengine-world/api.md +3056 -0
- package/skills/jgengine-world/capabilities.md +476 -0
- package/skills/jgengine-world/recipes/commanding-entities.md +128 -0
- package/skills/jgengine-world/reference.md +261 -0
- package/dist/cartridge/runtime.d.ts +0 -15
- package/dist/cartridge/runtime.js +0 -556
- package/dist/cartridge/spec.d.ts +0 -188
- package/dist/cartridge/spec.js +0 -19
- package/dist/cartridge/validate.d.ts +0 -2
- package/dist/cartridge/validate.js +0 -78
- package/dist/store/engineStore.d.ts +0 -22
- package/dist/store/engineStore.js +0 -50
- package/dist/store/features.d.ts +0 -10
- package/dist/store/features.js +0 -23
- package/llms.txt +0 -5389
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { hashString } from "../random/rng.js";
|
|
2
|
+
/**
|
|
3
|
+
* A deterministic `[0,1)` cadence phase derived from a stable id, for staggering sibling gates so a
|
|
4
|
+
* batch of agents spawned together does not fire their first active tick on the same frame. Pass the
|
|
5
|
+
* result as the `phase` argument to {@link createInterestGateState}.
|
|
6
|
+
*
|
|
7
|
+
* @capability interest-stagger deterministic per-id cadence phase that spreads sibling gate ticks across frames
|
|
8
|
+
*/
|
|
9
|
+
export function interestPhase(seed) {
|
|
10
|
+
const hashed = typeof seed === "number" ? hashString(String(seed)) : hashString(seed);
|
|
11
|
+
return (hashed % 100000) / 100000;
|
|
12
|
+
}
|
|
13
|
+
function nominalInterval(config) {
|
|
14
|
+
return config.activeInterval ?? config.tiers?.[0]?.interval ?? 0;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Create a dormant gate state, staggered by `phase` (`[0,1)`, typically {@link interestPhase} of the
|
|
18
|
+
* agent id) so siblings created together do not all fire their first active tick on the same frame.
|
|
19
|
+
*
|
|
20
|
+
* @capability interest-gate per-agent sleep/wake + cadence gate state so far agents skip expensive ticks
|
|
21
|
+
*/
|
|
22
|
+
export function createInterestGateState(config, phase = 0) {
|
|
23
|
+
const clamped = phase - Math.floor(phase);
|
|
24
|
+
return {
|
|
25
|
+
state: "dormant",
|
|
26
|
+
clock: clamped * nominalInterval(config),
|
|
27
|
+
awakeHold: 0,
|
|
28
|
+
phase: clamped,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
function intervalFor(config, proximity) {
|
|
32
|
+
if (config.tiers !== undefined && proximity !== null) {
|
|
33
|
+
for (const tier of config.tiers) {
|
|
34
|
+
if (proximity <= tier.within)
|
|
35
|
+
return Math.max(0, tier.interval);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return Math.max(0, config.activeInterval ?? 0);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Advance one gate by `dt` seconds against this tick's `input`, mutating `state` in place and
|
|
42
|
+
* returning what the caller should do. Sleeping skips the expensive work (`active: false`) while the
|
|
43
|
+
* gate's timers keep advancing, so state is preserved; a `wake` signal or crossing `wakeRadius`
|
|
44
|
+
* flips it back to active and fires an immediate tick.
|
|
45
|
+
*
|
|
46
|
+
* @capability interest-scheduler advance a sleep/wake gate with hysteresis, cadence tiers, and stagger
|
|
47
|
+
*/
|
|
48
|
+
export function advanceInterestGate(state, config, dt, input = {}) {
|
|
49
|
+
const wakeRadius = config.wakeRadius;
|
|
50
|
+
const sleepRadius = Math.max(config.sleepRadius ?? wakeRadius, wakeRadius);
|
|
51
|
+
const proximity = input.proximity ?? null;
|
|
52
|
+
const prev = state.state;
|
|
53
|
+
if (input.wake === true) {
|
|
54
|
+
state.awakeHold = Math.max(state.awakeHold, config.stayAwakeSeconds ?? 0);
|
|
55
|
+
}
|
|
56
|
+
let want;
|
|
57
|
+
if (input.wake === true || state.awakeHold > 0) {
|
|
58
|
+
want = "active";
|
|
59
|
+
}
|
|
60
|
+
else if (proximity === null) {
|
|
61
|
+
want = prev;
|
|
62
|
+
}
|
|
63
|
+
else if (prev === "dormant") {
|
|
64
|
+
want = proximity <= wakeRadius ? "active" : "dormant";
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
want = proximity > sleepRadius ? "dormant" : "active";
|
|
68
|
+
}
|
|
69
|
+
state.state = want;
|
|
70
|
+
const woke = prev === "dormant" && want === "active";
|
|
71
|
+
const slept = prev === "active" && want === "dormant";
|
|
72
|
+
let active = false;
|
|
73
|
+
if (want === "active") {
|
|
74
|
+
const interval = intervalFor(config, proximity);
|
|
75
|
+
if (interval <= 0 || woke || input.wake === true) {
|
|
76
|
+
active = true;
|
|
77
|
+
state.clock = 0;
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
state.clock += dt;
|
|
81
|
+
if (state.clock >= interval) {
|
|
82
|
+
active = true;
|
|
83
|
+
state.clock -= interval;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
// Dormant: expensive work is skipped, but the gate keeps its timers so a later wake resumes cleanly.
|
|
89
|
+
state.clock = 0;
|
|
90
|
+
}
|
|
91
|
+
if (state.awakeHold > 0)
|
|
92
|
+
state.awakeHold = Math.max(0, state.awakeHold - dt);
|
|
93
|
+
return { state: want, active, woke, slept };
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Create a census accumulator so the caller can tally active/dormant gates during the loop it already
|
|
97
|
+
* runs, avoiding any separate full-world scan just to report scheduler metrics.
|
|
98
|
+
*
|
|
99
|
+
* @capability interest-census running active/dormant gate tally folded into the caller's tick loop
|
|
100
|
+
*/
|
|
101
|
+
export function createInterestCensus() {
|
|
102
|
+
let active = 0;
|
|
103
|
+
let dormant = 0;
|
|
104
|
+
return {
|
|
105
|
+
record(state) {
|
|
106
|
+
const value = typeof state === "string" ? state : state.state;
|
|
107
|
+
if (value === "active")
|
|
108
|
+
active += 1;
|
|
109
|
+
else
|
|
110
|
+
dormant += 1;
|
|
111
|
+
},
|
|
112
|
+
snapshot: () => ({ active, dormant, total: active + dormant }),
|
|
113
|
+
reset() {
|
|
114
|
+
active = 0;
|
|
115
|
+
dormant = 0;
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
}
|
package/dist/ai/jobBoard.d.ts
CHANGED
package/dist/ai/jobBoard.js
CHANGED
package/dist/ai/laneSelect.d.ts
CHANGED
|
@@ -15,7 +15,10 @@ export interface PickLaneOptions<TId extends string = string> {
|
|
|
15
15
|
* Live cost-based selection over parallel corridors (#286.7) — the racing-line / lane-merge pick
|
|
16
16
|
* every AI driver hand-rolled. Evaluate each lane's cost this tick (crowding, hazards, distance)
|
|
17
17
|
* and let stickiness hysteresis stop the agent flip-flopping between near-equal lanes.
|
|
18
|
-
|
|
18
|
+
* @internal
|
|
19
|
+
*/
|
|
19
20
|
export declare function pickLane<TId extends string>(candidates: readonly LaneCandidate<TId>[], options?: PickLaneOptions<TId>): TId | null;
|
|
20
|
-
/** Sum a live cost function over a corridor's sample points — the standard way to build `LaneCandidate.cost`.
|
|
21
|
+
/** Sum a live cost function over a corridor's sample points — the standard way to build `LaneCandidate.cost`.
|
|
22
|
+
* @internal
|
|
23
|
+
*/
|
|
21
24
|
export declare function corridorCost(points: readonly (readonly [number, number])[], costAt: (x: number, z: number) => number): number;
|
package/dist/ai/laneSelect.js
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
* Live cost-based selection over parallel corridors (#286.7) — the racing-line / lane-merge pick
|
|
3
3
|
* every AI driver hand-rolled. Evaluate each lane's cost this tick (crowding, hazards, distance)
|
|
4
4
|
* and let stickiness hysteresis stop the agent flip-flopping between near-equal lanes.
|
|
5
|
-
|
|
5
|
+
* @internal
|
|
6
|
+
*/
|
|
6
7
|
export function pickLane(candidates, options = {}) {
|
|
7
8
|
if (candidates.length === 0)
|
|
8
9
|
return null;
|
|
@@ -28,7 +29,9 @@ export function pickLane(candidates, options = {}) {
|
|
|
28
29
|
}
|
|
29
30
|
return best.id;
|
|
30
31
|
}
|
|
31
|
-
/** Sum a live cost function over a corridor's sample points — the standard way to build `LaneCandidate.cost`.
|
|
32
|
+
/** Sum a live cost function over a corridor's sample points — the standard way to build `LaneCandidate.cost`.
|
|
33
|
+
* @internal
|
|
34
|
+
*/
|
|
32
35
|
export function corridorCost(points, costAt) {
|
|
33
36
|
let total = 0;
|
|
34
37
|
for (const [x, z] of points)
|
package/dist/ai/mobBrain.d.ts
CHANGED
package/dist/ai/mobBrain.js
CHANGED
|
@@ -9,6 +9,7 @@ const HOLD = {
|
|
|
9
9
|
function distance(a, b) {
|
|
10
10
|
return Math.hypot(a[0] - b[0], a[1] - b[1], a[2] - b[2]);
|
|
11
11
|
}
|
|
12
|
+
/** @internal */
|
|
12
13
|
export function createMobBrain(config, deps) {
|
|
13
14
|
const threat = createThreatTable(config.threat);
|
|
14
15
|
const stickiness = config.stickiness ?? 1.15;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import type { NavPoint } from "../nav/navGrid.js";
|
|
2
|
+
import { type RandomSeed } from "../random/rng.js";
|
|
3
|
+
/** One species that ambiently populates a region: how heavily it is favoured and its alive ceiling. */
|
|
4
|
+
export interface PopulationSpeciesEntry {
|
|
5
|
+
/** Opaque species/creature id the engine never interprets. */
|
|
6
|
+
species: string;
|
|
7
|
+
/** Relative pick weight among species below their cap (default 1). */
|
|
8
|
+
weight?: number;
|
|
9
|
+
/** Target/maximum number of this species alive in the region at once. */
|
|
10
|
+
cap: number;
|
|
11
|
+
}
|
|
12
|
+
/** Ambient population budget for a single region: its species ceilings, refill timing, and spawn geometry. */
|
|
13
|
+
export interface PopulationRegionConfig {
|
|
14
|
+
/** Opaque region id the engine never interprets. */
|
|
15
|
+
region: string;
|
|
16
|
+
species: readonly PopulationSpeciesEntry[];
|
|
17
|
+
/** Seconds a freed slot waits before it becomes a spawn candidate (overrides the director default). */
|
|
18
|
+
respawnDelay?: number;
|
|
19
|
+
/** Candidate spawn locations; when present each request is tagged with one. */
|
|
20
|
+
spawnPoints?: readonly NavPoint[];
|
|
21
|
+
}
|
|
22
|
+
/** Full ambient-population configuration: per-region species budgets plus global refill limits and PRNG seed. */
|
|
23
|
+
export interface PopulationDirectorConfig {
|
|
24
|
+
regions: readonly PopulationRegionConfig[];
|
|
25
|
+
/** Default respawn delay in game-seconds for regions without their own (default 0 — refill on the next tick). */
|
|
26
|
+
respawnDelay?: number;
|
|
27
|
+
/** Upper bound on spawn requests emitted per {@link PopulationDirector.tick} call (default 32). */
|
|
28
|
+
maxSpawnsPerTick?: number;
|
|
29
|
+
/** Seed for the persisted, serializable PRNG cursor (default 1). */
|
|
30
|
+
seed?: number;
|
|
31
|
+
}
|
|
32
|
+
/** A single ambient spawn the game should realise, refilling a region toward its species caps. */
|
|
33
|
+
export interface PopulationSpawnRequest {
|
|
34
|
+
region: string;
|
|
35
|
+
species: string;
|
|
36
|
+
/** Chosen spawn location when the region declares `spawnPoints`. */
|
|
37
|
+
point?: NavPoint;
|
|
38
|
+
}
|
|
39
|
+
/** Per-call spawn-point selection hook, letting a game apply bias (distance from players, etc.) at tick time. */
|
|
40
|
+
export interface PopulationTickContext {
|
|
41
|
+
/**
|
|
42
|
+
* Choose a spawn point for a request. Receives the region id, its configured candidates, and a
|
|
43
|
+
* deterministic roll in `[0, 1)` drawn from the persisted cursor. Return `null` to leave the
|
|
44
|
+
* request unplaced. When omitted, a candidate is picked uniformly from the roll.
|
|
45
|
+
*/
|
|
46
|
+
pickSpawnPoint?(region: string, candidates: readonly NavPoint[], roll: number): NavPoint | null;
|
|
47
|
+
}
|
|
48
|
+
/** Live census of alive counts keyed `region -> species -> count`, used to reconcile the director to reality. */
|
|
49
|
+
export type PopulationCensus = Record<string, Record<string, number>>;
|
|
50
|
+
/**
|
|
51
|
+
* A queued refill slot awaiting its {@link PopulationDirectorState.elapsed} deadline.
|
|
52
|
+
* @internal
|
|
53
|
+
*/
|
|
54
|
+
export interface PopulationRespawnSlot {
|
|
55
|
+
region: string;
|
|
56
|
+
readyAt: number;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Opaque, JSON-serializable persistence for a {@link PopulationDirector}. Round-trip it through
|
|
60
|
+
* `snapshot`/`hydrate`; never read or mutate the fields directly.
|
|
61
|
+
*/
|
|
62
|
+
export interface PopulationDirectorState {
|
|
63
|
+
/** Accumulated game-seconds. */
|
|
64
|
+
elapsed: number;
|
|
65
|
+
/** Believed alive counts, `region -> species -> count`. */
|
|
66
|
+
alive: Record<string, Record<string, number>>;
|
|
67
|
+
/** Pending refill slots, each ready at its `readyAt` game-second. */
|
|
68
|
+
queue: readonly PopulationRespawnSlot[];
|
|
69
|
+
/** Opaque PRNG cursor — round-trip as part of the state, never read or set it directly. */
|
|
70
|
+
rng: RandomSeed;
|
|
71
|
+
}
|
|
72
|
+
/** Stateful ambient population manager for one world; drive it with `tick` and lifecycle notifications. */
|
|
73
|
+
export interface PopulationDirector {
|
|
74
|
+
/**
|
|
75
|
+
* Advance by `dt` game-seconds and emit spawn requests for refill slots whose delay has elapsed,
|
|
76
|
+
* up to the per-tick cap. Only touches the bounded respawn queue — never scans the world.
|
|
77
|
+
*/
|
|
78
|
+
tick(dt: number, ctx?: PopulationTickContext): PopulationSpawnRequest[];
|
|
79
|
+
/** Register that a creature left the region (killed/despawned/tamed), freeing a slot to refill after the delay. */
|
|
80
|
+
notifyRemoved(region: string, species: string, id?: string): void;
|
|
81
|
+
/** Register a creature the game introduced itself (not via a request), so caps account for it. */
|
|
82
|
+
notifySpawned(region: string, species: string, id?: string): void;
|
|
83
|
+
/** Snap believed alive counts to a live census and re-queue any deficit toward the caps. */
|
|
84
|
+
reconcile(census: PopulationCensus): void;
|
|
85
|
+
/** Believed alive count for a `(region, species)` pair. */
|
|
86
|
+
alive(region: string, species: string): number;
|
|
87
|
+
/** Serializable copy of the full director state (deep, safe to persist). */
|
|
88
|
+
snapshot(): PopulationDirectorState;
|
|
89
|
+
/** Replace the director state from a previously taken (and possibly JSON round-tripped) snapshot. */
|
|
90
|
+
hydrate(state: PopulationDirectorState): void;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Ambient open-world population director. Holds a target creature population per region and refills
|
|
94
|
+
* it over time, distinct from wave/horde spawning: instead of a budget draining down a wave, each
|
|
95
|
+
* region has per-species caps and a timed respawn queue. Removing a creature frees a slot; after a
|
|
96
|
+
* respawn delay `tick` emits weighted spawn requests (bounded per tick) that refill toward the caps
|
|
97
|
+
* without ever exceeding them. Species are chosen through a persisted, serializable {@link RandomSeed}
|
|
98
|
+
* cursor, so the same seed and the same lifecycle events always yield the same requests. Regions are
|
|
99
|
+
* independent, spawn points are optional, and the whole state round-trips through `snapshot`/`hydrate`.
|
|
100
|
+
*
|
|
101
|
+
* @capability population-director ambient per-region creature population manager with timed weighted respawns and caps
|
|
102
|
+
*/
|
|
103
|
+
export declare function createPopulationDirector(config: PopulationDirectorConfig): PopulationDirector;
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import { randomSeedFrom, stepRandomSeed } from "../random/rng.js";
|
|
2
|
+
const DEFAULT_MAX_SPAWNS_PER_TICK = 32;
|
|
3
|
+
function clamp01(value) {
|
|
4
|
+
return value < 0 ? 0 : value > 1 ? 1 : value;
|
|
5
|
+
}
|
|
6
|
+
function cloneState(state) {
|
|
7
|
+
const alive = {};
|
|
8
|
+
for (const region of Object.keys(state.alive))
|
|
9
|
+
alive[region] = { ...state.alive[region] };
|
|
10
|
+
return {
|
|
11
|
+
elapsed: state.elapsed,
|
|
12
|
+
alive,
|
|
13
|
+
queue: state.queue.map((slot) => ({ region: slot.region, readyAt: slot.readyAt })),
|
|
14
|
+
rng: state.rng,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Ambient open-world population director. Holds a target creature population per region and refills
|
|
19
|
+
* it over time, distinct from wave/horde spawning: instead of a budget draining down a wave, each
|
|
20
|
+
* region has per-species caps and a timed respawn queue. Removing a creature frees a slot; after a
|
|
21
|
+
* respawn delay `tick` emits weighted spawn requests (bounded per tick) that refill toward the caps
|
|
22
|
+
* without ever exceeding them. Species are chosen through a persisted, serializable {@link RandomSeed}
|
|
23
|
+
* cursor, so the same seed and the same lifecycle events always yield the same requests. Regions are
|
|
24
|
+
* independent, spawn points are optional, and the whole state round-trips through `snapshot`/`hydrate`.
|
|
25
|
+
*
|
|
26
|
+
* @capability population-director ambient per-region creature population manager with timed weighted respawns and caps
|
|
27
|
+
*/
|
|
28
|
+
export function createPopulationDirector(config) {
|
|
29
|
+
const regions = new Map();
|
|
30
|
+
for (const region of config.regions)
|
|
31
|
+
regions.set(region.region, region);
|
|
32
|
+
const maxSpawnsPerTick = config.maxSpawnsPerTick ?? DEFAULT_MAX_SPAWNS_PER_TICK;
|
|
33
|
+
const defaultDelay = config.respawnDelay ?? 0;
|
|
34
|
+
let state = {
|
|
35
|
+
elapsed: 0,
|
|
36
|
+
alive: {},
|
|
37
|
+
queue: [],
|
|
38
|
+
rng: randomSeedFrom(config.seed ?? 1),
|
|
39
|
+
};
|
|
40
|
+
const totalCap = (region) => {
|
|
41
|
+
let sum = 0;
|
|
42
|
+
for (const entry of region.species)
|
|
43
|
+
sum += entry.cap;
|
|
44
|
+
return sum;
|
|
45
|
+
};
|
|
46
|
+
const totalAlive = (regionId) => {
|
|
47
|
+
const counts = state.alive[regionId];
|
|
48
|
+
if (counts === undefined)
|
|
49
|
+
return 0;
|
|
50
|
+
let sum = 0;
|
|
51
|
+
for (const key of Object.keys(counts))
|
|
52
|
+
sum += counts[key];
|
|
53
|
+
return sum;
|
|
54
|
+
};
|
|
55
|
+
const queuedCount = (regionId) => {
|
|
56
|
+
let sum = 0;
|
|
57
|
+
for (const slot of state.queue)
|
|
58
|
+
if (slot.region === regionId)
|
|
59
|
+
sum += 1;
|
|
60
|
+
return sum;
|
|
61
|
+
};
|
|
62
|
+
const delayFor = (region) => region.respawnDelay ?? defaultDelay;
|
|
63
|
+
const aliveFor = (regionId) => {
|
|
64
|
+
let counts = state.alive[regionId];
|
|
65
|
+
if (counts === undefined) {
|
|
66
|
+
counts = {};
|
|
67
|
+
state.alive[regionId] = counts;
|
|
68
|
+
}
|
|
69
|
+
return counts;
|
|
70
|
+
};
|
|
71
|
+
/** Top up the queue so `alive + queued` reaches the region cap, appending ready-at slots. */
|
|
72
|
+
const ensureDeficitQueued = (region, readyAt) => {
|
|
73
|
+
const deficit = totalCap(region) - totalAlive(region.region) - queuedCount(region.region);
|
|
74
|
+
if (deficit <= 0)
|
|
75
|
+
return;
|
|
76
|
+
const next = state.queue.slice();
|
|
77
|
+
for (let i = 0; i < deficit; i += 1)
|
|
78
|
+
next.push({ region: region.region, readyAt });
|
|
79
|
+
state.queue = next;
|
|
80
|
+
};
|
|
81
|
+
// Prime each region to fill toward its caps on the first ticks.
|
|
82
|
+
for (const region of config.regions) {
|
|
83
|
+
aliveFor(region.region);
|
|
84
|
+
ensureDeficitQueued(region, 0);
|
|
85
|
+
}
|
|
86
|
+
const pickSpecies = (region) => {
|
|
87
|
+
const counts = state.alive[region.region] ?? {};
|
|
88
|
+
let total = 0;
|
|
89
|
+
const eligible = [];
|
|
90
|
+
for (const entry of region.species) {
|
|
91
|
+
if ((counts[entry.species] ?? 0) >= entry.cap)
|
|
92
|
+
continue;
|
|
93
|
+
eligible.push(entry);
|
|
94
|
+
total += entry.weight ?? 1;
|
|
95
|
+
}
|
|
96
|
+
if (eligible.length === 0 || total <= 0)
|
|
97
|
+
return null;
|
|
98
|
+
const [roll, nextRng] = stepRandomSeed(state.rng);
|
|
99
|
+
state.rng = nextRng;
|
|
100
|
+
let cursor = roll * total;
|
|
101
|
+
for (const entry of eligible) {
|
|
102
|
+
cursor -= entry.weight ?? 1;
|
|
103
|
+
if (cursor <= 0)
|
|
104
|
+
return entry.species;
|
|
105
|
+
}
|
|
106
|
+
return eligible[eligible.length - 1].species;
|
|
107
|
+
};
|
|
108
|
+
const choosePoint = (region, ctx) => {
|
|
109
|
+
const points = region.spawnPoints;
|
|
110
|
+
if (points === undefined || points.length === 0)
|
|
111
|
+
return undefined;
|
|
112
|
+
const [roll, nextRng] = stepRandomSeed(state.rng);
|
|
113
|
+
state.rng = nextRng;
|
|
114
|
+
if (ctx?.pickSpawnPoint !== undefined) {
|
|
115
|
+
const chosen = ctx.pickSpawnPoint(region.region, points, roll);
|
|
116
|
+
return chosen ?? undefined;
|
|
117
|
+
}
|
|
118
|
+
return points[Math.min(points.length - 1, Math.floor(clamp01(roll) * points.length))];
|
|
119
|
+
};
|
|
120
|
+
return {
|
|
121
|
+
tick(dt, ctx) {
|
|
122
|
+
if (dt <= 0)
|
|
123
|
+
return [];
|
|
124
|
+
state.elapsed += dt;
|
|
125
|
+
const now = state.elapsed;
|
|
126
|
+
const requests = [];
|
|
127
|
+
const remaining = [];
|
|
128
|
+
for (const slot of state.queue) {
|
|
129
|
+
if (requests.length >= maxSpawnsPerTick || slot.readyAt > now) {
|
|
130
|
+
remaining.push(slot);
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
const region = regions.get(slot.region);
|
|
134
|
+
if (region === undefined)
|
|
135
|
+
continue; // region no longer configured — drop the slot
|
|
136
|
+
const species = pickSpecies(region);
|
|
137
|
+
if (species === null)
|
|
138
|
+
continue; // region already at cap (filled externally) — drop the slot
|
|
139
|
+
aliveFor(region.region)[species] = (state.alive[region.region][species] ?? 0) + 1;
|
|
140
|
+
const request = { region: region.region, species };
|
|
141
|
+
const point = choosePoint(region, ctx);
|
|
142
|
+
if (point !== undefined)
|
|
143
|
+
request.point = point;
|
|
144
|
+
requests.push(request);
|
|
145
|
+
}
|
|
146
|
+
state.queue = remaining;
|
|
147
|
+
return requests;
|
|
148
|
+
},
|
|
149
|
+
notifyRemoved(region, species, _id) {
|
|
150
|
+
const counts = state.alive[region];
|
|
151
|
+
if (counts !== undefined) {
|
|
152
|
+
const current = counts[species] ?? 0;
|
|
153
|
+
if (current > 0)
|
|
154
|
+
counts[species] = current - 1;
|
|
155
|
+
}
|
|
156
|
+
const regionConfig = regions.get(region);
|
|
157
|
+
if (regionConfig === undefined)
|
|
158
|
+
return;
|
|
159
|
+
const next = state.queue.slice();
|
|
160
|
+
next.push({ region, readyAt: state.elapsed + delayFor(regionConfig) });
|
|
161
|
+
state.queue = next;
|
|
162
|
+
},
|
|
163
|
+
notifySpawned(region, species, _id) {
|
|
164
|
+
if (!regions.has(region))
|
|
165
|
+
return;
|
|
166
|
+
const counts = aliveFor(region);
|
|
167
|
+
counts[species] = (counts[species] ?? 0) + 1;
|
|
168
|
+
},
|
|
169
|
+
reconcile(census) {
|
|
170
|
+
for (const region of config.regions) {
|
|
171
|
+
const observed = census[region.region] ?? {};
|
|
172
|
+
const counts = {};
|
|
173
|
+
for (const entry of region.species)
|
|
174
|
+
counts[entry.species] = observed[entry.species] ?? 0;
|
|
175
|
+
state.alive[region.region] = counts;
|
|
176
|
+
}
|
|
177
|
+
for (const region of config.regions)
|
|
178
|
+
ensureDeficitQueued(region, state.elapsed);
|
|
179
|
+
},
|
|
180
|
+
alive(region, species) {
|
|
181
|
+
return state.alive[region]?.[species] ?? 0;
|
|
182
|
+
},
|
|
183
|
+
snapshot() {
|
|
184
|
+
return cloneState(state);
|
|
185
|
+
},
|
|
186
|
+
hydrate(next) {
|
|
187
|
+
state = cloneState(next);
|
|
188
|
+
},
|
|
189
|
+
};
|
|
190
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Composable pursuit/aggro step: the "I have a target — now chase it, stop at reach, hit it on a
|
|
3
|
+
* cooldown, and break off if led too far from home" loop that melee mobs, RTS units, and stationary
|
|
4
|
+
* turrets all re-implement by hand. This owns exactly that state machine and the per-entity attack
|
|
5
|
+
* cooldown; target *selection* stays separate (see {@link ./targetAcquisition}), and every side
|
|
6
|
+
* effect — move, attack, break off — is performed by the caller in response to the returned action.
|
|
7
|
+
*
|
|
8
|
+
* Deterministic and allocation-free: distances are measured by the caller and passed in as scalars,
|
|
9
|
+
* the only state is one serializable number ({@link PursuitState.attackCooldown}) advanced in place,
|
|
10
|
+
* and the returned {@link PursuitAction} is a string literal. No object is built per entity per step,
|
|
11
|
+
* and nothing here scans the world — feed it a target you already resolved.
|
|
12
|
+
*/
|
|
13
|
+
/** The action a pursuit step resolves to; the caller performs the matching side effect. */
|
|
14
|
+
export type PursuitAction =
|
|
15
|
+
/** Home distance exceeded the leash — abandon the target and return home. */
|
|
16
|
+
"leash"
|
|
17
|
+
/** Out of range — advance toward the target. */
|
|
18
|
+
| "pursue"
|
|
19
|
+
/** In range and the cooldown is ready — perform the attack, then {@link armPursuit}. */
|
|
20
|
+
| "attack"
|
|
21
|
+
/** In range but the cooldown has not elapsed — hold (face the target, idle, etc.). */
|
|
22
|
+
| "wait"
|
|
23
|
+
/** No engageable target this step (distance was `null`). */
|
|
24
|
+
| "idle";
|
|
25
|
+
/**
|
|
26
|
+
* When the attack cooldown ticks down.
|
|
27
|
+
* - `"always"` (default): every step, like a wall-clock weapon timer that keeps counting during the
|
|
28
|
+
* chase, so the entity can swing the instant it reaches its target.
|
|
29
|
+
* - `"inRange"`: only while within `stopDistance`, so the timer freezes during the chase and the
|
|
30
|
+
* full interval is paid out after each contact.
|
|
31
|
+
*/
|
|
32
|
+
export type CooldownMode = "always" | "inRange";
|
|
33
|
+
/** Per-entity cooldown state owned by the primitive. One serializable number; no methods. */
|
|
34
|
+
export interface PursuitState {
|
|
35
|
+
/** Seconds remaining until the next attack may fire. Advanced toward `0` by {@link advancePursuit}. */
|
|
36
|
+
attackCooldown: number;
|
|
37
|
+
}
|
|
38
|
+
/** A fresh pursuit state, ready to attack immediately (`attackCooldown` at `0`). */
|
|
39
|
+
export declare function createPursuitState(attackCooldown?: number): PursuitState;
|
|
40
|
+
/** Set the cooldown after an attack fires (clamped at `0`). Call on the step that returned `"attack"`. */
|
|
41
|
+
export declare function armPursuit(state: PursuitState, intervalSeconds: number): void;
|
|
42
|
+
/**
|
|
43
|
+
* Advance one pursuit step for a single entity, mutating `state.attackCooldown`, and return the
|
|
44
|
+
* action the caller should perform. All spatial input is scalar and measured this frame:
|
|
45
|
+
*
|
|
46
|
+
* - `targetDistance` — self→target distance, or `null` when there is no engageable target (`"idle"`).
|
|
47
|
+
* - `stopDistance` — attack once within this distance; pursue while beyond it.
|
|
48
|
+
* - `homeDistance` / `leashRange` — optional leash checked first: when `homeDistance > leashRange`
|
|
49
|
+
* the step is `"leash"`. Leave at their defaults (`-Infinity` / `+Infinity`) to disable leashing.
|
|
50
|
+
* - `cooldownMode` — see {@link CooldownMode}.
|
|
51
|
+
*
|
|
52
|
+
* On `"attack"` the caller applies the hit and calls {@link armPursuit} with the next interval.
|
|
53
|
+
*
|
|
54
|
+
* @capability pursuit chase-to-reach cooldown-gated attack with optional leash-to-home; owns the attack cooldown
|
|
55
|
+
*/
|
|
56
|
+
export declare function advancePursuit(state: PursuitState, dt: number, targetDistance: number | null, stopDistance: number, cooldownMode?: CooldownMode, homeDistance?: number, leashRange?: number): PursuitAction;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Composable pursuit/aggro step: the "I have a target — now chase it, stop at reach, hit it on a
|
|
3
|
+
* cooldown, and break off if led too far from home" loop that melee mobs, RTS units, and stationary
|
|
4
|
+
* turrets all re-implement by hand. This owns exactly that state machine and the per-entity attack
|
|
5
|
+
* cooldown; target *selection* stays separate (see {@link ./targetAcquisition}), and every side
|
|
6
|
+
* effect — move, attack, break off — is performed by the caller in response to the returned action.
|
|
7
|
+
*
|
|
8
|
+
* Deterministic and allocation-free: distances are measured by the caller and passed in as scalars,
|
|
9
|
+
* the only state is one serializable number ({@link PursuitState.attackCooldown}) advanced in place,
|
|
10
|
+
* and the returned {@link PursuitAction} is a string literal. No object is built per entity per step,
|
|
11
|
+
* and nothing here scans the world — feed it a target you already resolved.
|
|
12
|
+
*/
|
|
13
|
+
/** A fresh pursuit state, ready to attack immediately (`attackCooldown` at `0`). */
|
|
14
|
+
export function createPursuitState(attackCooldown = 0) {
|
|
15
|
+
return { attackCooldown };
|
|
16
|
+
}
|
|
17
|
+
/** Set the cooldown after an attack fires (clamped at `0`). Call on the step that returned `"attack"`. */
|
|
18
|
+
export function armPursuit(state, intervalSeconds) {
|
|
19
|
+
state.attackCooldown = intervalSeconds > 0 ? intervalSeconds : 0;
|
|
20
|
+
}
|
|
21
|
+
function tickCooldown(state, dt) {
|
|
22
|
+
if (state.attackCooldown > 0) {
|
|
23
|
+
const next = state.attackCooldown - dt;
|
|
24
|
+
state.attackCooldown = next > 0 ? next : 0;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Advance one pursuit step for a single entity, mutating `state.attackCooldown`, and return the
|
|
29
|
+
* action the caller should perform. All spatial input is scalar and measured this frame:
|
|
30
|
+
*
|
|
31
|
+
* - `targetDistance` — self→target distance, or `null` when there is no engageable target (`"idle"`).
|
|
32
|
+
* - `stopDistance` — attack once within this distance; pursue while beyond it.
|
|
33
|
+
* - `homeDistance` / `leashRange` — optional leash checked first: when `homeDistance > leashRange`
|
|
34
|
+
* the step is `"leash"`. Leave at their defaults (`-Infinity` / `+Infinity`) to disable leashing.
|
|
35
|
+
* - `cooldownMode` — see {@link CooldownMode}.
|
|
36
|
+
*
|
|
37
|
+
* On `"attack"` the caller applies the hit and calls {@link armPursuit} with the next interval.
|
|
38
|
+
*
|
|
39
|
+
* @capability pursuit chase-to-reach cooldown-gated attack with optional leash-to-home; owns the attack cooldown
|
|
40
|
+
*/
|
|
41
|
+
export function advancePursuit(state, dt, targetDistance, stopDistance, cooldownMode = "always", homeDistance = Number.NEGATIVE_INFINITY, leashRange = Number.POSITIVE_INFINITY) {
|
|
42
|
+
if (cooldownMode === "always")
|
|
43
|
+
tickCooldown(state, dt);
|
|
44
|
+
if (homeDistance > leashRange)
|
|
45
|
+
return "leash";
|
|
46
|
+
if (targetDistance === null)
|
|
47
|
+
return "idle";
|
|
48
|
+
if (targetDistance > stopDistance)
|
|
49
|
+
return "pursue";
|
|
50
|
+
if (cooldownMode === "inRange")
|
|
51
|
+
tickCooldown(state, dt);
|
|
52
|
+
return state.attackCooldown <= 0 ? "attack" : "wait";
|
|
53
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { NavPoint } from "../nav/navGrid.js";
|
|
2
|
+
import { type RandomSeed } from "../random/rng.js";
|
|
2
3
|
export interface SpawnEntry {
|
|
3
4
|
id: string;
|
|
4
5
|
cost: number;
|
|
@@ -32,7 +33,8 @@ export interface SpawnDirectorState {
|
|
|
32
33
|
alert: number;
|
|
33
34
|
spawnedThisWave: number;
|
|
34
35
|
spawnedTotal: number;
|
|
35
|
-
|
|
36
|
+
/** Opaque PRNG cursor — round-trip it as part of the state, never read or set it directly. */
|
|
37
|
+
rng: RandomSeed;
|
|
36
38
|
done: boolean;
|
|
37
39
|
}
|
|
38
40
|
export interface DirectorContext {
|
|
@@ -49,13 +51,16 @@ export interface SpawnRequest {
|
|
|
49
51
|
}
|
|
50
52
|
/** Preference for picking a spawn point relative to `avoid` positions: closer, farther, or unweighted. */
|
|
51
53
|
export type SpawnPointDistanceBias = "near" | "far" | "none";
|
|
54
|
+
/** How strongly `distanceBias` weights candidates by distance from `avoid` — a named intent, not a weighting exponent. */
|
|
55
|
+
export type SpawnPointBiasStrength = "subtle" | "moderate" | "strong";
|
|
52
56
|
/** Semantic options for selecting a spawn point without exposing weighting internals. */
|
|
53
57
|
export interface SpawnPointSelectionOptions {
|
|
54
58
|
candidates: readonly NavPoint[];
|
|
55
59
|
avoid?: readonly NavPoint[];
|
|
56
60
|
random: () => number;
|
|
57
61
|
distanceBias?: SpawnPointDistanceBias;
|
|
58
|
-
|
|
62
|
+
/** Default `"moderate"`. */
|
|
63
|
+
biasStrength?: SpawnPointBiasStrength;
|
|
59
64
|
}
|
|
60
65
|
export interface DirectorStep {
|
|
61
66
|
state: SpawnDirectorState;
|