@alife-sdk/core 0.1.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/LICENSE +21 -0
- package/README.md +283 -0
- package/dist/ai/DangerManager.d.ts +71 -0
- package/dist/ai/DangerManager.d.ts.map +1 -0
- package/dist/ai/DangerManager.js +176 -0
- package/dist/ai/DangerManager.js.map +1 -0
- package/dist/ai/GOAPAction.d.ts +45 -0
- package/dist/ai/GOAPAction.d.ts.map +1 -0
- package/dist/ai/GOAPAction.js +32 -0
- package/dist/ai/GOAPAction.js.map +1 -0
- package/dist/ai/GOAPPlanner.d.ts +80 -0
- package/dist/ai/GOAPPlanner.d.ts.map +1 -0
- package/dist/ai/GOAPPlanner.js +259 -0
- package/dist/ai/GOAPPlanner.js.map +1 -0
- package/dist/ai/IStateHandler.d.ts +8 -0
- package/dist/ai/IStateHandler.d.ts.map +1 -0
- package/dist/ai/IStateHandler.js +8 -0
- package/dist/ai/IStateHandler.js.map +1 -0
- package/dist/ai/MemorySystem.d.ts +94 -0
- package/dist/ai/MemorySystem.d.ts.map +1 -0
- package/dist/ai/MemorySystem.js +207 -0
- package/dist/ai/MemorySystem.js.map +1 -0
- package/dist/ai/StateMachine.d.ts +49 -0
- package/dist/ai/StateMachine.d.ts.map +1 -0
- package/dist/ai/StateMachine.js +83 -0
- package/dist/ai/StateMachine.js.map +1 -0
- package/dist/ai/WorldState.d.ts +48 -0
- package/dist/ai/WorldState.d.ts.map +1 -0
- package/dist/ai/WorldState.js +93 -0
- package/dist/ai/WorldState.js.map +1 -0
- package/dist/ai/index.d.ts +10 -0
- package/dist/ai/index.d.ts.map +1 -0
- package/dist/ai/index.js +8 -0
- package/dist/ai/index.js.map +1 -0
- package/dist/combat/DamageInstance.d.ts +26 -0
- package/dist/combat/DamageInstance.d.ts.map +1 -0
- package/dist/combat/DamageInstance.js +25 -0
- package/dist/combat/DamageInstance.js.map +1 -0
- package/dist/combat/MoraleStateMachine.d.ts +53 -0
- package/dist/combat/MoraleStateMachine.d.ts.map +1 -0
- package/dist/combat/MoraleStateMachine.js +84 -0
- package/dist/combat/MoraleStateMachine.js.map +1 -0
- package/dist/combat/index.d.ts +5 -0
- package/dist/combat/index.d.ts.map +1 -0
- package/dist/combat/index.js +3 -0
- package/dist/combat/index.js.map +1 -0
- package/dist/config/ALifeConfig.d.ts +131 -0
- package/dist/config/ALifeConfig.d.ts.map +1 -0
- package/dist/config/ALifeConfig.js +82 -0
- package/dist/config/ALifeConfig.js.map +1 -0
- package/dist/config/index.d.ts +3 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +2 -0
- package/dist/config/index.js.map +1 -0
- package/dist/core/ALifeKernel.d.ts +163 -0
- package/dist/core/ALifeKernel.d.ts.map +1 -0
- package/dist/core/ALifeKernel.js +542 -0
- package/dist/core/ALifeKernel.js.map +1 -0
- package/dist/core/Clock.d.ts +123 -0
- package/dist/core/Clock.d.ts.map +1 -0
- package/dist/core/Clock.js +228 -0
- package/dist/core/Clock.js.map +1 -0
- package/dist/core/DevToolsInspector.d.ts +53 -0
- package/dist/core/DevToolsInspector.d.ts.map +1 -0
- package/dist/core/DevToolsInspector.js +8 -0
- package/dist/core/DevToolsInspector.js.map +1 -0
- package/dist/core/Diagnostics.d.ts +64 -0
- package/dist/core/Diagnostics.d.ts.map +1 -0
- package/dist/core/Diagnostics.js +107 -0
- package/dist/core/Diagnostics.js.map +1 -0
- package/dist/core/ISerializable.d.ts +12 -0
- package/dist/core/ISerializable.d.ts.map +1 -0
- package/dist/core/ISerializable.js +2 -0
- package/dist/core/ISerializable.js.map +1 -0
- package/dist/core/PortRegistry.d.ts +57 -0
- package/dist/core/PortRegistry.d.ts.map +1 -0
- package/dist/core/PortRegistry.js +72 -0
- package/dist/core/PortRegistry.js.map +1 -0
- package/dist/core/PortTokens.d.ts +39 -0
- package/dist/core/PortTokens.d.ts.map +1 -0
- package/dist/core/PortTokens.js +39 -0
- package/dist/core/PortTokens.js.map +1 -0
- package/dist/core/SpatialGrid.d.ts +114 -0
- package/dist/core/SpatialGrid.d.ts.map +1 -0
- package/dist/core/SpatialGrid.js +258 -0
- package/dist/core/SpatialGrid.js.map +1 -0
- package/dist/core/Vec2.d.ts +34 -0
- package/dist/core/Vec2.d.ts.map +1 -0
- package/dist/core/Vec2.js +52 -0
- package/dist/core/Vec2.js.map +1 -0
- package/dist/core/math/CatmullRom.d.ts +20 -0
- package/dist/core/math/CatmullRom.d.ts.map +1 -0
- package/dist/core/math/CatmullRom.js +37 -0
- package/dist/core/math/CatmullRom.js.map +1 -0
- package/dist/core/math/index.d.ts +6 -0
- package/dist/core/math/index.d.ts.map +1 -0
- package/dist/core/math/index.js +5 -0
- package/dist/core/math/index.js.map +1 -0
- package/dist/core/math/intersects.d.ts +32 -0
- package/dist/core/math/intersects.d.ts.map +1 -0
- package/dist/core/math/intersects.js +92 -0
- package/dist/core/math/intersects.js.map +1 -0
- package/dist/core/math/utils.d.ts +5 -0
- package/dist/core/math/utils.d.ts.map +1 -0
- package/dist/core/math/utils.js +13 -0
- package/dist/core/math/utils.js.map +1 -0
- package/dist/entity/IComponent.d.ts +17 -0
- package/dist/entity/IComponent.d.ts.map +1 -0
- package/dist/entity/IComponent.js +2 -0
- package/dist/entity/IComponent.js.map +1 -0
- package/dist/entity/IEntity.d.ts +33 -0
- package/dist/entity/IEntity.d.ts.map +1 -0
- package/dist/entity/IEntity.js +2 -0
- package/dist/entity/IEntity.js.map +1 -0
- package/dist/entity/index.d.ts +3 -0
- package/dist/entity/index.d.ts.map +1 -0
- package/dist/entity/index.js +2 -0
- package/dist/entity/index.js.map +1 -0
- package/dist/events/ALifeEvents.d.ts +241 -0
- package/dist/events/ALifeEvents.d.ts.map +1 -0
- package/dist/events/ALifeEvents.js +53 -0
- package/dist/events/ALifeEvents.js.map +1 -0
- package/dist/events/EventBus.d.ts +52 -0
- package/dist/events/EventBus.d.ts.map +1 -0
- package/dist/events/EventBus.js +129 -0
- package/dist/events/EventBus.js.map +1 -0
- package/dist/events/index.d.ts +4 -0
- package/dist/events/index.d.ts.map +1 -0
- package/dist/events/index.js +4 -0
- package/dist/events/index.js.map +1 -0
- package/dist/faction/Faction.d.ts +53 -0
- package/dist/faction/Faction.d.ts.map +1 -0
- package/dist/faction/Faction.js +101 -0
- package/dist/faction/Faction.js.map +1 -0
- package/dist/faction/FactionBuilder.d.ts +32 -0
- package/dist/faction/FactionBuilder.d.ts.map +1 -0
- package/dist/faction/FactionBuilder.js +80 -0
- package/dist/faction/FactionBuilder.js.map +1 -0
- package/dist/faction/ImmunityProfile.d.ts +24 -0
- package/dist/faction/ImmunityProfile.d.ts.map +1 -0
- package/dist/faction/ImmunityProfile.js +43 -0
- package/dist/faction/ImmunityProfile.js.map +1 -0
- package/dist/faction/index.d.ts +6 -0
- package/dist/faction/index.d.ts.map +1 -0
- package/dist/faction/index.js +5 -0
- package/dist/faction/index.js.map +1 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +34 -0
- package/dist/index.js.map +1 -0
- package/dist/logger/ILogEntry.d.ts +16 -0
- package/dist/logger/ILogEntry.d.ts.map +1 -0
- package/dist/logger/ILogEntry.js +2 -0
- package/dist/logger/ILogEntry.js.map +1 -0
- package/dist/logger/LogChannel.d.ts +27 -0
- package/dist/logger/LogChannel.d.ts.map +1 -0
- package/dist/logger/LogChannel.js +26 -0
- package/dist/logger/LogChannel.js.map +1 -0
- package/dist/logger/LogLevel.d.ts +10 -0
- package/dist/logger/LogLevel.d.ts.map +1 -0
- package/dist/logger/LogLevel.js +9 -0
- package/dist/logger/LogLevel.js.map +1 -0
- package/dist/logger/Logger.d.ts +56 -0
- package/dist/logger/Logger.d.ts.map +1 -0
- package/dist/logger/Logger.js +106 -0
- package/dist/logger/Logger.js.map +1 -0
- package/dist/logger/index.d.ts +8 -0
- package/dist/logger/index.d.ts.map +1 -0
- package/dist/logger/index.js +5 -0
- package/dist/logger/index.js.map +1 -0
- package/dist/movement/MonsterHome.d.ts +49 -0
- package/dist/movement/MonsterHome.d.ts.map +1 -0
- package/dist/movement/MonsterHome.js +75 -0
- package/dist/movement/MonsterHome.js.map +1 -0
- package/dist/movement/PatrolRoute.d.ts +99 -0
- package/dist/movement/PatrolRoute.d.ts.map +1 -0
- package/dist/movement/PatrolRoute.js +141 -0
- package/dist/movement/PatrolRoute.js.map +1 -0
- package/dist/movement/index.d.ts +5 -0
- package/dist/movement/index.d.ts.map +1 -0
- package/dist/movement/index.js +4 -0
- package/dist/movement/index.js.map +1 -0
- package/dist/navigation/LevelGraph.d.ts +78 -0
- package/dist/navigation/LevelGraph.d.ts.map +1 -0
- package/dist/navigation/LevelGraph.js +268 -0
- package/dist/navigation/LevelGraph.js.map +1 -0
- package/dist/navigation/NPCGraphMover.d.ts +87 -0
- package/dist/navigation/NPCGraphMover.d.ts.map +1 -0
- package/dist/navigation/NPCGraphMover.js +193 -0
- package/dist/navigation/NPCGraphMover.js.map +1 -0
- package/dist/navigation/index.d.ts +5 -0
- package/dist/navigation/index.d.ts.map +1 -0
- package/dist/navigation/index.js +4 -0
- package/dist/navigation/index.js.map +1 -0
- package/dist/plugins/AnomaliesPlugin.d.ts +26 -0
- package/dist/plugins/AnomaliesPlugin.d.ts.map +1 -0
- package/dist/plugins/AnomaliesPlugin.js +30 -0
- package/dist/plugins/AnomaliesPlugin.js.map +1 -0
- package/dist/plugins/CombatSchemaPlugin.d.ts +35 -0
- package/dist/plugins/CombatSchemaPlugin.d.ts.map +1 -0
- package/dist/plugins/CombatSchemaPlugin.js +44 -0
- package/dist/plugins/CombatSchemaPlugin.js.map +1 -0
- package/dist/plugins/FactionsPlugin.d.ts +26 -0
- package/dist/plugins/FactionsPlugin.d.ts.map +1 -0
- package/dist/plugins/FactionsPlugin.js +30 -0
- package/dist/plugins/FactionsPlugin.js.map +1 -0
- package/dist/plugins/IALifePlugin.d.ts +91 -0
- package/dist/plugins/IALifePlugin.d.ts.map +1 -0
- package/dist/plugins/IALifePlugin.js +2 -0
- package/dist/plugins/IALifePlugin.js.map +1 -0
- package/dist/plugins/MonstersPlugin.d.ts +26 -0
- package/dist/plugins/MonstersPlugin.d.ts.map +1 -0
- package/dist/plugins/MonstersPlugin.js +30 -0
- package/dist/plugins/MonstersPlugin.js.map +1 -0
- package/dist/plugins/NPCTypesPlugin.d.ts +26 -0
- package/dist/plugins/NPCTypesPlugin.d.ts.map +1 -0
- package/dist/plugins/NPCTypesPlugin.js +30 -0
- package/dist/plugins/NPCTypesPlugin.js.map +1 -0
- package/dist/plugins/PluginToken.d.ts +26 -0
- package/dist/plugins/PluginToken.d.ts.map +1 -0
- package/dist/plugins/PluginToken.js +22 -0
- package/dist/plugins/PluginToken.js.map +1 -0
- package/dist/plugins/SocialPlugin.d.ts +14 -0
- package/dist/plugins/SocialPlugin.d.ts.map +1 -0
- package/dist/plugins/SocialPlugin.js +16 -0
- package/dist/plugins/SocialPlugin.js.map +1 -0
- package/dist/plugins/SpawnPlugin.d.ts +15 -0
- package/dist/plugins/SpawnPlugin.d.ts.map +1 -0
- package/dist/plugins/SpawnPlugin.js +26 -0
- package/dist/plugins/SpawnPlugin.js.map +1 -0
- package/dist/plugins/SquadPlugin.d.ts +14 -0
- package/dist/plugins/SquadPlugin.d.ts.map +1 -0
- package/dist/plugins/SquadPlugin.js +16 -0
- package/dist/plugins/SquadPlugin.js.map +1 -0
- package/dist/plugins/SurgePlugin.d.ts +20 -0
- package/dist/plugins/SurgePlugin.d.ts.map +1 -0
- package/dist/plugins/SurgePlugin.js +22 -0
- package/dist/plugins/SurgePlugin.js.map +1 -0
- package/dist/plugins/TradePlugin.d.ts +16 -0
- package/dist/plugins/TradePlugin.d.ts.map +1 -0
- package/dist/plugins/TradePlugin.js +18 -0
- package/dist/plugins/TradePlugin.js.map +1 -0
- package/dist/plugins/index.d.ts +11 -0
- package/dist/plugins/index.d.ts.map +1 -0
- package/dist/plugins/index.js +10 -0
- package/dist/plugins/index.js.map +1 -0
- package/dist/plugins/pluginNames.d.ts +37 -0
- package/dist/plugins/pluginNames.d.ts.map +1 -0
- package/dist/plugins/pluginNames.js +28 -0
- package/dist/plugins/pluginNames.js.map +1 -0
- package/dist/plugins/presets.d.ts +31 -0
- package/dist/plugins/presets.d.ts.map +1 -0
- package/dist/plugins/presets.js +50 -0
- package/dist/plugins/presets.js.map +1 -0
- package/dist/ports/IDataLoader.d.ts +38 -0
- package/dist/ports/IDataLoader.d.ts.map +1 -0
- package/dist/ports/IDataLoader.js +12 -0
- package/dist/ports/IDataLoader.js.map +1 -0
- package/dist/ports/IEntityAdapter.d.ts +73 -0
- package/dist/ports/IEntityAdapter.d.ts.map +1 -0
- package/dist/ports/IEntityAdapter.js +36 -0
- package/dist/ports/IEntityAdapter.js.map +1 -0
- package/dist/ports/IEntityFactory.d.ts +66 -0
- package/dist/ports/IEntityFactory.d.ts.map +1 -0
- package/dist/ports/IEntityFactory.js +21 -0
- package/dist/ports/IEntityFactory.js.map +1 -0
- package/dist/ports/ILogger.d.ts +29 -0
- package/dist/ports/ILogger.d.ts.map +1 -0
- package/dist/ports/ILogger.js +2 -0
- package/dist/ports/ILogger.js.map +1 -0
- package/dist/ports/IPlayerPositionProvider.d.ts +20 -0
- package/dist/ports/IPlayerPositionProvider.d.ts.map +1 -0
- package/dist/ports/IPlayerPositionProvider.js +11 -0
- package/dist/ports/IPlayerPositionProvider.js.map +1 -0
- package/dist/ports/IRandom.d.ts +25 -0
- package/dist/ports/IRandom.d.ts.map +1 -0
- package/dist/ports/IRandom.js +39 -0
- package/dist/ports/IRandom.js.map +1 -0
- package/dist/ports/IRuntimeClock.d.ts +18 -0
- package/dist/ports/IRuntimeClock.d.ts.map +1 -0
- package/dist/ports/IRuntimeClock.js +2 -0
- package/dist/ports/IRuntimeClock.js.map +1 -0
- package/dist/ports/index.d.ts +12 -0
- package/dist/ports/index.d.ts.map +1 -0
- package/dist/ports/index.js +5 -0
- package/dist/ports/index.js.map +1 -0
- package/dist/registry/AIStateRegistry.d.ts +42 -0
- package/dist/registry/AIStateRegistry.d.ts.map +1 -0
- package/dist/registry/AIStateRegistry.js +27 -0
- package/dist/registry/AIStateRegistry.js.map +1 -0
- package/dist/registry/AnomalyTypeRegistry.d.ts +21 -0
- package/dist/registry/AnomalyTypeRegistry.d.ts.map +1 -0
- package/dist/registry/AnomalyTypeRegistry.js +20 -0
- package/dist/registry/AnomalyTypeRegistry.js.map +1 -0
- package/dist/registry/BehaviorSchemeRegistry.d.ts +21 -0
- package/dist/registry/BehaviorSchemeRegistry.d.ts.map +1 -0
- package/dist/registry/BehaviorSchemeRegistry.js +24 -0
- package/dist/registry/BehaviorSchemeRegistry.js.map +1 -0
- package/dist/registry/DamageTypeRegistry.d.ts +17 -0
- package/dist/registry/DamageTypeRegistry.d.ts.map +1 -0
- package/dist/registry/DamageTypeRegistry.js +24 -0
- package/dist/registry/DamageTypeRegistry.js.map +1 -0
- package/dist/registry/FactionRegistry.d.ts +41 -0
- package/dist/registry/FactionRegistry.d.ts.map +1 -0
- package/dist/registry/FactionRegistry.js +29 -0
- package/dist/registry/FactionRegistry.js.map +1 -0
- package/dist/registry/MonsterRegistry.d.ts +44 -0
- package/dist/registry/MonsterRegistry.d.ts.map +1 -0
- package/dist/registry/MonsterRegistry.js +43 -0
- package/dist/registry/MonsterRegistry.js.map +1 -0
- package/dist/registry/NPCTypeRegistry.d.ts +34 -0
- package/dist/registry/NPCTypeRegistry.d.ts.map +1 -0
- package/dist/registry/NPCTypeRegistry.js +20 -0
- package/dist/registry/NPCTypeRegistry.js.map +1 -0
- package/dist/registry/Registry.d.ts +44 -0
- package/dist/registry/Registry.d.ts.map +1 -0
- package/dist/registry/Registry.js +80 -0
- package/dist/registry/Registry.js.map +1 -0
- package/dist/registry/TaskTypeRegistry.d.ts +17 -0
- package/dist/registry/TaskTypeRegistry.d.ts.map +1 -0
- package/dist/registry/TaskTypeRegistry.js +16 -0
- package/dist/registry/TaskTypeRegistry.js.map +1 -0
- package/dist/registry/index.d.ts +19 -0
- package/dist/registry/index.d.ts.map +1 -0
- package/dist/registry/index.js +11 -0
- package/dist/registry/index.js.map +1 -0
- package/dist/schema/index.d.ts +3 -0
- package/dist/schema/index.d.ts.map +1 -0
- package/dist/schema/index.js +3 -0
- package/dist/schema/index.js.map +1 -0
- package/dist/schema/validators.d.ts +32 -0
- package/dist/schema/validators.d.ts.map +1 -0
- package/dist/schema/validators.js +249 -0
- package/dist/schema/validators.js.map +1 -0
- package/dist/spawn/SpawnRegistry.d.ts +48 -0
- package/dist/spawn/SpawnRegistry.d.ts.map +1 -0
- package/dist/spawn/SpawnRegistry.js +141 -0
- package/dist/spawn/SpawnRegistry.js.map +1 -0
- package/dist/spawn/index.d.ts +3 -0
- package/dist/spawn/index.d.ts.map +1 -0
- package/dist/spawn/index.js +3 -0
- package/dist/spawn/index.js.map +1 -0
- package/dist/terrain/SmartTerrain.d.ts +119 -0
- package/dist/terrain/SmartTerrain.d.ts.map +1 -0
- package/dist/terrain/SmartTerrain.js +124 -0
- package/dist/terrain/SmartTerrain.js.map +1 -0
- package/dist/terrain/TerrainBuilder.d.ts +44 -0
- package/dist/terrain/TerrainBuilder.d.ts.map +1 -0
- package/dist/terrain/TerrainBuilder.js +112 -0
- package/dist/terrain/TerrainBuilder.js.map +1 -0
- package/dist/terrain/Zone.d.ts +25 -0
- package/dist/terrain/Zone.d.ts.map +1 -0
- package/dist/terrain/Zone.js +29 -0
- package/dist/terrain/Zone.js.map +1 -0
- package/dist/terrain/index.d.ts +6 -0
- package/dist/terrain/index.d.ts.map +1 -0
- package/dist/terrain/index.js +5 -0
- package/dist/terrain/index.js.map +1 -0
- package/dist/time/TimeManager.d.ts +21 -0
- package/dist/time/TimeManager.d.ts.map +1 -0
- package/dist/time/TimeManager.js +41 -0
- package/dist/time/TimeManager.js.map +1 -0
- package/dist/time/index.d.ts +3 -0
- package/dist/time/index.d.ts.map +1 -0
- package/dist/time/index.js +2 -0
- package/dist/time/index.js.map +1 -0
- package/package.json +119 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Eugene Rusakov
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
# @alife-sdk/core
|
|
2
|
+
|
|
3
|
+
Framework-agnostic A-Life simulation and AI decision-making system.
|
|
4
|
+
|
|
5
|
+
Zero external dependencies. Works with Phaser, Unity, Node.js, or any other runtime.
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
npm install @alife-sdk/core
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## What this package does
|
|
14
|
+
|
|
15
|
+
`@alife-sdk/core` provides the complete foundation for a living game world:
|
|
16
|
+
|
|
17
|
+
- **NPC AI** — finite state machines, GOAP planners, memory and perception systems
|
|
18
|
+
- **A-Life simulation** — offline NPC brains, terrain selection, spawn cooldowns, faction diplomacy
|
|
19
|
+
- **Game clock** — accelerated in-game time, day/night cycle, hour events
|
|
20
|
+
- **World graph** — waypoint graph with A* pathfinding for offline NPC movement
|
|
21
|
+
- **Plugin system** — extend the kernel with your own domain features
|
|
22
|
+
|
|
23
|
+
The package is intentionally engine-agnostic. It never imports Phaser,
|
|
24
|
+
renders sprites, or touches the DOM. All engine interaction goes through
|
|
25
|
+
**ports** — narrow interfaces you implement once for your engine.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Quick start
|
|
30
|
+
|
|
31
|
+
> The SDK ships **interfaces only** for engine adapters — `IEntityAdapter`,
|
|
32
|
+
> `IEntityFactory`, `IDataLoader`, etc. You implement them once for your engine.
|
|
33
|
+
> The example below uses placeholder names; replace them with your own implementations.
|
|
34
|
+
> See [`ports/README.md`](src/ports/README.md) for full interface specs and a Phaser example.
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
import { ALifeKernel, Ports } from '@alife-sdk/core';
|
|
38
|
+
import { fullPreset, Plugins } from '@alife-sdk/core/plugins';
|
|
39
|
+
|
|
40
|
+
// 1. Create the kernel
|
|
41
|
+
const kernel = new ALifeKernel();
|
|
42
|
+
|
|
43
|
+
// 2. Register engine adapters (optional — kernel auto-provides no-ops if omitted)
|
|
44
|
+
// (MyEntityAdapter / MyEntityFactory — your implementations of
|
|
45
|
+
// IEntityAdapter / IEntityFactory from @alife-sdk/core/ports)
|
|
46
|
+
kernel.provide(Ports.EntityAdapter, new MyEntityAdapter(scene));
|
|
47
|
+
kernel.provide(Ports.EntityFactory, new MyEntityFactory(scene));
|
|
48
|
+
kernel.provide(Ports.PlayerPosition, { getPlayerPosition: () => ({ x: player.x, y: player.y }) });
|
|
49
|
+
// Ports.RuntimeClock and Ports.Random are also optional (SDK provides defaults)
|
|
50
|
+
|
|
51
|
+
// 3. Install built-in plugins
|
|
52
|
+
fullPreset(kernel);
|
|
53
|
+
|
|
54
|
+
// 4. Register game data (before init)
|
|
55
|
+
const factions = kernel.getPlugin(Plugins.FACTIONS).factions;
|
|
56
|
+
factions.register('stalker', { name: 'Stalker', baseRelations: { bandit: -80 } });
|
|
57
|
+
factions.register('bandit', { name: 'Bandit', baseRelations: { stalker: -80 } });
|
|
58
|
+
|
|
59
|
+
// 5. Init — validates ports, freezes registries, returns DiagnosticsCollector
|
|
60
|
+
const diag = kernel.init();
|
|
61
|
+
|
|
62
|
+
// 6. Start — enables frame-based update()
|
|
63
|
+
kernel.start();
|
|
64
|
+
|
|
65
|
+
// 7. Game loop
|
|
66
|
+
function update(deltaMs: number): void {
|
|
67
|
+
kernel.update(deltaMs);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// 8. Save / load
|
|
71
|
+
const save = kernel.serialize();
|
|
72
|
+
kernel.restoreState(save);
|
|
73
|
+
|
|
74
|
+
// 9. Cleanup
|
|
75
|
+
kernel.destroy();
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Sub-path imports
|
|
81
|
+
|
|
82
|
+
Each module has its own import path for optimal tree-shaking:
|
|
83
|
+
|
|
84
|
+
| Import path | What's inside | Module docs |
|
|
85
|
+
|-------------|--------------|-------------|
|
|
86
|
+
| `@alife-sdk/core` | `ALifeKernel`, `Clock`, `SpatialGrid`, `Ports` | [core/](src/core/) |
|
|
87
|
+
| `@alife-sdk/core/ai` | `StateMachine`, `MemoryBank`, `DangerManager`, `GOAPPlanner` | [ai/](src/ai/README.md) |
|
|
88
|
+
| `@alife-sdk/core/combat` | `DamageInstance`, `MoraleTracker`, `ImmunityProfile` | [combat/](src/combat/README.md) |
|
|
89
|
+
| `@alife-sdk/core/config` | `createDefaultConfig`, `IALifeConfig` | [config/](src/config/README.md) |
|
|
90
|
+
| `@alife-sdk/core/entity` | `IEntity`, `IComponent` | [entity/](src/entity/README.md) |
|
|
91
|
+
| `@alife-sdk/core/events` | `EventBus`, `ALifeEvents`, `ALifeEventPayloads` | [events/](src/events/README.md) |
|
|
92
|
+
| `@alife-sdk/core/faction` | `Faction`, `FactionBuilder` | [faction/](src/faction/README.md) |
|
|
93
|
+
| `@alife-sdk/core/logger` | `Logger`, `LogLevel`, `LogChannel` | [logger/](src/logger/README.md) |
|
|
94
|
+
| `@alife-sdk/core/movement` | `PatrolRouteTracker`, `MonsterHome` | [movement/](src/movement/README.md) |
|
|
95
|
+
| `@alife-sdk/core/navigation` | `LevelGraph`, `NPCGraphMover` | [navigation/](src/navigation/README.md) |
|
|
96
|
+
| `@alife-sdk/core/plugins` | `IALifePlugin`, built-in plugins, `Plugins` tokens | [plugins/](src/plugins/README.md) |
|
|
97
|
+
| `@alife-sdk/core/ports` | `IEntityAdapter`, `IDataLoader`, `IRandom`, … | [ports/](src/ports/README.md) |
|
|
98
|
+
| `@alife-sdk/core/registry` | `Registry`, `FactionRegistry`, `AIStateRegistry`, … | [registry/](src/registry/README.md) |
|
|
99
|
+
| `@alife-sdk/core/schema` | `validateMonsterDefinition`, assertion helpers | [schema/](src/schema/README.md) |
|
|
100
|
+
| `@alife-sdk/core/spawn` | `SpawnRegistry` | [spawn/](src/spawn/README.md) |
|
|
101
|
+
| `@alife-sdk/core/terrain` | `Zone`, `SmartTerrain`, `TerrainBuilder` | [terrain/](src/terrain/README.md) |
|
|
102
|
+
| `@alife-sdk/core/time` | `TimeManager` | [time/](src/time/README.md) |
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## Architecture
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
┌─────────────────────────────────┐
|
|
110
|
+
│ ALifeKernel │
|
|
111
|
+
│ clock · events · logger · ports │
|
|
112
|
+
└──────────────┬──────────────────┘
|
|
113
|
+
│ kernel.use(plugin)
|
|
114
|
+
┌────────────────────────┼────────────────────────┐
|
|
115
|
+
│ │ │
|
|
116
|
+
FactionsPlugin NPCTypesPlugin SpawnPlugin
|
|
117
|
+
FactionRegistry NPCTypeRegistry SpawnRegistry
|
|
118
|
+
│ │ │
|
|
119
|
+
└────────────────────────┼────────────────────────┘
|
|
120
|
+
│
|
|
121
|
+
┌────────────────────────┼────────────────────────┐
|
|
122
|
+
│ │ │
|
|
123
|
+
StateMachine MemoryBank GOAPPlanner
|
|
124
|
+
(18 AI states) (4 channels, decay) (A* on WorldState)
|
|
125
|
+
│ │ │
|
|
126
|
+
└────────────────────────┼────────────────────────┘
|
|
127
|
+
│
|
|
128
|
+
┌────────────────────────┼────────────────────────┐
|
|
129
|
+
│ │ │
|
|
130
|
+
LevelGraph SmartTerrain Faction
|
|
131
|
+
(A* pathfinding) (capacity + fitness) (two-layer relations)
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## Key concepts
|
|
137
|
+
|
|
138
|
+
### Ports — engine adapter pattern
|
|
139
|
+
|
|
140
|
+
The kernel never calls Phaser or any engine API directly. Instead, it calls
|
|
141
|
+
**ports** — interfaces you implement to bridge the SDK to your engine.
|
|
142
|
+
|
|
143
|
+
All ports are optional — the kernel auto-provides silent no-op defaults for
|
|
144
|
+
engine ports if you don't supply real implementations. This means
|
|
145
|
+
`new ALifeKernel().init()` works with zero configuration for offline
|
|
146
|
+
simulation, persistence, and unit tests.
|
|
147
|
+
|
|
148
|
+
| Port | Interface | Default | Purpose |
|
|
149
|
+
|------|-----------|---------|---------|
|
|
150
|
+
| Entity adapter | `IEntityAdapter` | no-op | Read/write entity position, visibility, components |
|
|
151
|
+
| Entity factory | `IEntityFactory` | no-op | Create and destroy game objects |
|
|
152
|
+
| Player position | `IPlayerPositionProvider` | `{x:0,y:0}` | Online/offline radius check each tick |
|
|
153
|
+
| Runtime clock | `IRuntimeClock` | `Date.now()` | Real-time ms for cooldown timers |
|
|
154
|
+
| Random | `IRandom` | `Math.random()` | PRNG for simulation randomness |
|
|
155
|
+
|
|
156
|
+
See [`ports/README.md`](src/ports/README.md) for implementation examples.
|
|
157
|
+
|
|
158
|
+
### Plugin system
|
|
159
|
+
|
|
160
|
+
The kernel is minimal by design. All domain features live in plugins that
|
|
161
|
+
you install with `kernel.use(plugin)`. Built-in plugins cover factions,
|
|
162
|
+
NPC types, combat schemas, spawning, monsters, and anomalies.
|
|
163
|
+
|
|
164
|
+
Write your own plugin by implementing `IALifePlugin`:
|
|
165
|
+
|
|
166
|
+
```ts
|
|
167
|
+
class WeatherPlugin implements IALifePlugin {
|
|
168
|
+
readonly name = 'weather';
|
|
169
|
+
install(kernel: ALifeKernel): void { ... }
|
|
170
|
+
update(deltaMs: number): void { ... }
|
|
171
|
+
destroy(): void { ... }
|
|
172
|
+
}
|
|
173
|
+
kernel.use(new WeatherPlugin());
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
See [`plugins/README.md`](src/plugins/README.md).
|
|
177
|
+
|
|
178
|
+
### Event bus
|
|
179
|
+
|
|
180
|
+
All simulation events are delivered via a deferred `EventBus`.
|
|
181
|
+
`emit()` queues an event; `flush()` delivers it — called automatically by
|
|
182
|
+
`kernel.update()` at the end of each frame.
|
|
183
|
+
|
|
184
|
+
```ts
|
|
185
|
+
kernel.events.on(ALifeEvents.NPC_DIED, ({ npcId, killedBy }) => {
|
|
186
|
+
questSystem.onNpcKilled(npcId);
|
|
187
|
+
});
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
38 typed events across 9 categories: A-Life, AI, Surge, Anomaly, Squad,
|
|
191
|
+
Faction, Time, Social, Monster. See [`events/README.md`](src/events/README.md).
|
|
192
|
+
|
|
193
|
+
### AI — StateMachine + GOAP
|
|
194
|
+
|
|
195
|
+
Every online NPC runs a `StateMachine` over states registered in `AIStateRegistry`.
|
|
196
|
+
Each state has `enter / update / exit` handlers and optional auto-transition rules.
|
|
197
|
+
|
|
198
|
+
Elite NPCs (rank ≥ 5) additionally run a `GOAPPlanner` — an A* planner over
|
|
199
|
+
a `WorldState` bitmask that picks the optimal action sequence to achieve a goal.
|
|
200
|
+
|
|
201
|
+
See [`ai/README.md`](src/ai/README.md).
|
|
202
|
+
|
|
203
|
+
### Offline simulation — LevelGraph + SmartTerrain
|
|
204
|
+
|
|
205
|
+
NPCs outside the player's view radius move through a `LevelGraph` (waypoint
|
|
206
|
+
graph with A*) without needing a full physics update. Each offline NPC gets
|
|
207
|
+
a `NPCGraphMover` cursor that interpolates world position along graph edges.
|
|
208
|
+
|
|
209
|
+
NPCs choose destinations by scoring all `SmartTerrain` instances via
|
|
210
|
+
`scoreFitness()` — a function of distance, capacity, shelter bonus, and
|
|
211
|
+
danger-vs-rank match.
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
## Lifecycle
|
|
216
|
+
|
|
217
|
+
```
|
|
218
|
+
kernel.provide(port) ← register port adapters
|
|
219
|
+
↓
|
|
220
|
+
kernel.use(plugin) ← register plugins
|
|
221
|
+
↓
|
|
222
|
+
kernel.init() ← validate ports, freeze registries, call plugin.init()
|
|
223
|
+
↓
|
|
224
|
+
kernel.start() ← enable frame-based update()
|
|
225
|
+
↓
|
|
226
|
+
kernel.update(delta) ← each frame: tick plugins → flush events
|
|
227
|
+
↓
|
|
228
|
+
kernel.serialize() ← capture state for save
|
|
229
|
+
kernel.restoreState() ← restore from save
|
|
230
|
+
↓
|
|
231
|
+
kernel.destroy() ← cleanup, call plugin.destroy() in reverse order
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
---
|
|
235
|
+
|
|
236
|
+
## Testing
|
|
237
|
+
|
|
238
|
+
```
|
|
239
|
+
pnpm test --filter @alife-sdk/core
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
The SDK is designed to be test-friendly:
|
|
243
|
+
- Engine ports (`EntityAdapter`, `PlayerPosition`, `EntityFactory`) auto-provide
|
|
244
|
+
no-ops — no boilerplate needed for offline/persistence tests
|
|
245
|
+
- `IRandom` port → inject `SeededRandom` for deterministic results
|
|
246
|
+
- `IRuntimeClock` port → inject a frozen clock
|
|
247
|
+
|
|
248
|
+
```ts
|
|
249
|
+
// Minimal test kernel — no provide() needed
|
|
250
|
+
const kernel = new ALifeKernel();
|
|
251
|
+
kernel.init();
|
|
252
|
+
kernel.step(10);
|
|
253
|
+
|
|
254
|
+
// Override only what your test actually needs
|
|
255
|
+
const kernel = new ALifeKernel();
|
|
256
|
+
kernel.provide(Ports.Random, new SeededRandom(42));
|
|
257
|
+
kernel.init();
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
---
|
|
261
|
+
|
|
262
|
+
## Module map
|
|
263
|
+
|
|
264
|
+
```
|
|
265
|
+
src/
|
|
266
|
+
├── core/ ALifeKernel, Clock, SpatialGrid, Vec2, PortRegistry, Diagnostics
|
|
267
|
+
├── ai/ StateMachine, MemorySystem, DangerManager, GOAPPlanner/Action/WorldState
|
|
268
|
+
├── combat/ DamageInstance, ImmunityProfile, MoraleTracker
|
|
269
|
+
├── config/ IALifeConfig, createDefaultConfig
|
|
270
|
+
├── entity/ IEntity, IComponent (interfaces only)
|
|
271
|
+
├── events/ EventBus, ALifeEvents, ALifeEventPayloads
|
|
272
|
+
├── faction/ Faction, FactionBuilder, IFactionState
|
|
273
|
+
├── logger/ Logger, LogLevel, LogChannel, ILogEntry
|
|
274
|
+
├── movement/ PatrolRouteTracker, RouteType, MonsterHome
|
|
275
|
+
├── navigation/ LevelGraph, NPCGraphMover
|
|
276
|
+
├── plugins/ IALifePlugin, built-in plugins, PluginToken, presets
|
|
277
|
+
├── ports/ IEntityAdapter, IEntityFactory, IRandom, IRuntimeClock, IDataLoader, ILogger
|
|
278
|
+
├── registry/ Registry, FactionRegistry, NPCTypeRegistry, MonsterRegistry, AIStateRegistry, …
|
|
279
|
+
├── schema/ validateMonsterDefinition, validateFactionDefinition, assertion helpers
|
|
280
|
+
├── spawn/ SpawnRegistry
|
|
281
|
+
├── terrain/ Zone, SmartTerrain, TerrainBuilder
|
|
282
|
+
└── time/ TimeManager
|
|
283
|
+
```
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed danger system with spatial awareness.
|
|
3
|
+
*
|
|
4
|
+
* DangerManager maintains a set of active danger zones in the world.
|
|
5
|
+
* Each danger has a type, position, radius, threat score, and time-to-live.
|
|
6
|
+
* NPCs query this manager to find nearby threats and compute safe
|
|
7
|
+
* movement directions.
|
|
8
|
+
*
|
|
9
|
+
* All spatial queries use squared-distance math for performance.
|
|
10
|
+
*/
|
|
11
|
+
import type { Vec2 } from '../core/Vec2';
|
|
12
|
+
export declare const DangerType: {
|
|
13
|
+
readonly GRENADE: "grenade";
|
|
14
|
+
readonly GUNFIRE: "gunfire";
|
|
15
|
+
readonly EXPLOSION: "explosion";
|
|
16
|
+
readonly CORPSE: "corpse";
|
|
17
|
+
readonly ANOMALY: "anomaly";
|
|
18
|
+
readonly ATTACK_SOUND: "attack_sound";
|
|
19
|
+
};
|
|
20
|
+
export type DangerType = (typeof DangerType)[keyof typeof DangerType] | (string & {});
|
|
21
|
+
export interface IDangerEntry {
|
|
22
|
+
readonly id: string;
|
|
23
|
+
readonly type: DangerType;
|
|
24
|
+
readonly position: Vec2;
|
|
25
|
+
readonly radius: number;
|
|
26
|
+
/** Urgency score in [0, 1]. Higher = more threatening. */
|
|
27
|
+
readonly threatScore: number;
|
|
28
|
+
/** Milliseconds remaining before this danger expires. */
|
|
29
|
+
readonly remainingMs: number;
|
|
30
|
+
}
|
|
31
|
+
export declare class DangerManager {
|
|
32
|
+
private readonly dangers;
|
|
33
|
+
private readonly defaultThreshold;
|
|
34
|
+
constructor(defaultThreshold?: number);
|
|
35
|
+
/** Register a danger zone. Replaces an existing danger with the same ID. */
|
|
36
|
+
addDanger(entry: IDangerEntry): void;
|
|
37
|
+
/** Remove a danger by ID. */
|
|
38
|
+
removeDanger(id: string): void;
|
|
39
|
+
/**
|
|
40
|
+
* Get total threat score at a position.
|
|
41
|
+
*
|
|
42
|
+
* Sums the threat scores of all dangers whose radius covers the position.
|
|
43
|
+
* Result is not clamped -- may exceed 1.0 when multiple dangers overlap.
|
|
44
|
+
*/
|
|
45
|
+
getThreatAt(position: Vec2): number;
|
|
46
|
+
/** Get all dangers within the given radius of a position. */
|
|
47
|
+
getDangersNear(position: Vec2, radius: number): IDangerEntry[];
|
|
48
|
+
/**
|
|
49
|
+
* Find the safest direction to move (away from threats).
|
|
50
|
+
*
|
|
51
|
+
* Computes a weighted repulsion vector from all nearby dangers.
|
|
52
|
+
* Each danger contributes a repulsion force inversely proportional to
|
|
53
|
+
* its distance and proportional to its threat score.
|
|
54
|
+
*
|
|
55
|
+
* Returns ZERO if no dangers are active.
|
|
56
|
+
*/
|
|
57
|
+
getSafeDirection(position: Vec2): Vec2;
|
|
58
|
+
/** Tick: decay danger durations, remove expired entries. */
|
|
59
|
+
update(deltaMs: number): void;
|
|
60
|
+
/**
|
|
61
|
+
* Check if a position is dangerous (total threat exceeds threshold).
|
|
62
|
+
*
|
|
63
|
+
* @param position - World-space position to test.
|
|
64
|
+
* @param threshold - Minimum threat level to consider dangerous.
|
|
65
|
+
*/
|
|
66
|
+
isDangerous(position: Vec2, threshold?: number): boolean;
|
|
67
|
+
get activeDangerCount(): number;
|
|
68
|
+
serialize(): IDangerEntry[];
|
|
69
|
+
restore(entries: IDangerEntry[]): void;
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=DangerManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DangerManager.d.ts","sourceRoot":"","sources":["../../src/ai/DangerManager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAOzC,eAAO,MAAM,UAAU;;;;;;;CAOb,CAAC;AAEX,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,OAAO,UAAU,CAAC,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;AAMtF,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,0DAA0D;IAC1D,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,yDAAyD;IACzD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AA0BD,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAyC;IACjE,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;gBAE9B,gBAAgB,GAAE,MAAiC;IAQ/D,4EAA4E;IAC5E,SAAS,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI;IAIpC,6BAA6B;IAC7B,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAQ9B;;;;;OAKG;IACH,WAAW,CAAC,QAAQ,EAAE,IAAI,GAAG,MAAM;IAcnC,6DAA6D;IAC7D,cAAc,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,GAAG,YAAY,EAAE;IAc9D;;;;;;;;OAQG;IACH,gBAAgB,CAAC,QAAQ,EAAE,IAAI,GAAG,IAAI;IA8CtC,4DAA4D;IAC5D,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAiB7B;;;;;OAKG;IACH,WAAW,CACT,QAAQ,EAAE,IAAI,EACd,SAAS,GAAE,MAA8B,GACxC,OAAO;IAeV,IAAI,iBAAiB,IAAI,MAAM,CAE9B;IAMD,SAAS,IAAI,YAAY,EAAE;IAI3B,OAAO,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,IAAI;CAMvC"}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed danger system with spatial awareness.
|
|
3
|
+
*
|
|
4
|
+
* DangerManager maintains a set of active danger zones in the world.
|
|
5
|
+
* Each danger has a type, position, radius, threat score, and time-to-live.
|
|
6
|
+
* NPCs query this manager to find nearby threats and compute safe
|
|
7
|
+
* movement directions.
|
|
8
|
+
*
|
|
9
|
+
* All spatial queries use squared-distance math for performance.
|
|
10
|
+
*/
|
|
11
|
+
import { distanceSq, ZERO } from '../core/Vec2';
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
// Danger type
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
export const DangerType = {
|
|
16
|
+
GRENADE: 'grenade',
|
|
17
|
+
GUNFIRE: 'gunfire',
|
|
18
|
+
EXPLOSION: 'explosion',
|
|
19
|
+
CORPSE: 'corpse',
|
|
20
|
+
ANOMALY: 'anomaly',
|
|
21
|
+
ATTACK_SOUND: 'attack_sound',
|
|
22
|
+
};
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
// Constants
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
const DEFAULT_THREAT_THRESHOLD = 0.1;
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
// DangerManager
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
export class DangerManager {
|
|
31
|
+
constructor(defaultThreshold = DEFAULT_THREAT_THRESHOLD) {
|
|
32
|
+
this.dangers = new Map();
|
|
33
|
+
this.defaultThreshold = defaultThreshold;
|
|
34
|
+
}
|
|
35
|
+
// -----------------------------------------------------------------------
|
|
36
|
+
// Mutation
|
|
37
|
+
// -----------------------------------------------------------------------
|
|
38
|
+
/** Register a danger zone. Replaces an existing danger with the same ID. */
|
|
39
|
+
addDanger(entry) {
|
|
40
|
+
this.dangers.set(entry.id, { ...entry });
|
|
41
|
+
}
|
|
42
|
+
/** Remove a danger by ID. */
|
|
43
|
+
removeDanger(id) {
|
|
44
|
+
this.dangers.delete(id);
|
|
45
|
+
}
|
|
46
|
+
// -----------------------------------------------------------------------
|
|
47
|
+
// Spatial queries
|
|
48
|
+
// -----------------------------------------------------------------------
|
|
49
|
+
/**
|
|
50
|
+
* Get total threat score at a position.
|
|
51
|
+
*
|
|
52
|
+
* Sums the threat scores of all dangers whose radius covers the position.
|
|
53
|
+
* Result is not clamped -- may exceed 1.0 when multiple dangers overlap.
|
|
54
|
+
*/
|
|
55
|
+
getThreatAt(position) {
|
|
56
|
+
let totalThreat = 0;
|
|
57
|
+
for (const danger of this.dangers.values()) {
|
|
58
|
+
const dsq = distanceSq(position, danger.position);
|
|
59
|
+
const rSq = danger.radius * danger.radius;
|
|
60
|
+
if (dsq <= rSq) {
|
|
61
|
+
totalThreat += danger.threatScore;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return totalThreat;
|
|
65
|
+
}
|
|
66
|
+
/** Get all dangers within the given radius of a position. */
|
|
67
|
+
getDangersNear(position, radius) {
|
|
68
|
+
const result = [];
|
|
69
|
+
const searchRadiusSq = radius * radius;
|
|
70
|
+
for (const danger of this.dangers.values()) {
|
|
71
|
+
const dsq = distanceSq(position, danger.position);
|
|
72
|
+
if (dsq <= searchRadiusSq) {
|
|
73
|
+
result.push(danger);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return result;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Find the safest direction to move (away from threats).
|
|
80
|
+
*
|
|
81
|
+
* Computes a weighted repulsion vector from all nearby dangers.
|
|
82
|
+
* Each danger contributes a repulsion force inversely proportional to
|
|
83
|
+
* its distance and proportional to its threat score.
|
|
84
|
+
*
|
|
85
|
+
* Returns ZERO if no dangers are active.
|
|
86
|
+
*/
|
|
87
|
+
getSafeDirection(position) {
|
|
88
|
+
let repulsionX = 0;
|
|
89
|
+
let repulsionY = 0;
|
|
90
|
+
let hasDangers = false;
|
|
91
|
+
for (const danger of this.dangers.values()) {
|
|
92
|
+
const dsq = distanceSq(position, danger.position);
|
|
93
|
+
const rSq = danger.radius * danger.radius;
|
|
94
|
+
if (dsq > rSq)
|
|
95
|
+
continue;
|
|
96
|
+
hasDangers = true;
|
|
97
|
+
const dist = Math.sqrt(dsq);
|
|
98
|
+
if (dist < 1) {
|
|
99
|
+
// Directly on top of danger -- derive a direction from danger position
|
|
100
|
+
// to avoid a constant northeast bias.
|
|
101
|
+
const angle = ((danger.position.x * 73 + danger.position.y * 37) % 360) * (Math.PI / 180);
|
|
102
|
+
repulsionX += Math.cos(angle) * danger.threatScore;
|
|
103
|
+
repulsionY += Math.sin(angle) * danger.threatScore;
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
// Direction from danger to position (away from danger), inlined.
|
|
107
|
+
const dx = position.x - danger.position.x;
|
|
108
|
+
const dy = position.y - danger.position.y;
|
|
109
|
+
// Weight by threat score and inverse distance.
|
|
110
|
+
const weight = danger.threatScore / dist;
|
|
111
|
+
repulsionX += dx * weight;
|
|
112
|
+
repulsionY += dy * weight;
|
|
113
|
+
}
|
|
114
|
+
if (!hasDangers)
|
|
115
|
+
return ZERO;
|
|
116
|
+
// Inline normalize — avoid allocating intermediate {x, y}.
|
|
117
|
+
const mag = Math.sqrt(repulsionX * repulsionX + repulsionY * repulsionY);
|
|
118
|
+
if (mag === 0)
|
|
119
|
+
return ZERO;
|
|
120
|
+
return { x: repulsionX / mag, y: repulsionY / mag };
|
|
121
|
+
}
|
|
122
|
+
// -----------------------------------------------------------------------
|
|
123
|
+
// Update
|
|
124
|
+
// -----------------------------------------------------------------------
|
|
125
|
+
/** Tick: decay danger durations, remove expired entries. */
|
|
126
|
+
update(deltaMs) {
|
|
127
|
+
const toDelete = [];
|
|
128
|
+
for (const [id, danger] of this.dangers) {
|
|
129
|
+
danger.remainingMs -= deltaMs;
|
|
130
|
+
if (danger.remainingMs <= 0) {
|
|
131
|
+
toDelete.push(id);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
for (const id of toDelete) {
|
|
135
|
+
this.dangers.delete(id);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
// -----------------------------------------------------------------------
|
|
139
|
+
// Convenience checks
|
|
140
|
+
// -----------------------------------------------------------------------
|
|
141
|
+
/**
|
|
142
|
+
* Check if a position is dangerous (total threat exceeds threshold).
|
|
143
|
+
*
|
|
144
|
+
* @param position - World-space position to test.
|
|
145
|
+
* @param threshold - Minimum threat level to consider dangerous.
|
|
146
|
+
*/
|
|
147
|
+
isDangerous(position, threshold = this.defaultThreshold) {
|
|
148
|
+
let totalThreat = 0;
|
|
149
|
+
for (const danger of this.dangers.values()) {
|
|
150
|
+
const dsq = distanceSq(position, danger.position);
|
|
151
|
+
const rSq = danger.radius * danger.radius;
|
|
152
|
+
if (dsq <= rSq) {
|
|
153
|
+
totalThreat += danger.threatScore;
|
|
154
|
+
if (totalThreat >= threshold)
|
|
155
|
+
return true;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
get activeDangerCount() {
|
|
161
|
+
return this.dangers.size;
|
|
162
|
+
}
|
|
163
|
+
// -----------------------------------------------------------------------
|
|
164
|
+
// Serialisation
|
|
165
|
+
// -----------------------------------------------------------------------
|
|
166
|
+
serialize() {
|
|
167
|
+
return [...this.dangers.values()];
|
|
168
|
+
}
|
|
169
|
+
restore(entries) {
|
|
170
|
+
this.dangers.clear();
|
|
171
|
+
for (const entry of entries) {
|
|
172
|
+
this.dangers.set(entry.id, { ...entry });
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
//# sourceMappingURL=DangerManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DangerManager.js","sourceRoot":"","sources":["../../src/ai/DangerManager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAEhD,8EAA8E;AAC9E,cAAc;AACd,8EAA8E;AAE9E,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,OAAO,EAAE,SAAS;IAClB,OAAO,EAAE,SAAS;IAClB,SAAS,EAAE,WAAW;IACtB,MAAM,EAAE,QAAQ;IAChB,OAAO,EAAE,SAAS;IAClB,YAAY,EAAE,cAAc;CACpB,CAAC;AAiCX,8EAA8E;AAC9E,YAAY;AACZ,8EAA8E;AAE9E,MAAM,wBAAwB,GAAG,GAAG,CAAC;AAErC,8EAA8E;AAC9E,gBAAgB;AAChB,8EAA8E;AAE9E,MAAM,OAAO,aAAa;IAIxB,YAAY,mBAA2B,wBAAwB;QAH9C,YAAO,GAAG,IAAI,GAAG,EAA8B,CAAC;QAI/D,IAAI,CAAC,gBAAgB,GAAG,gBAAgB,CAAC;IAC3C,CAAC;IAED,0EAA0E;IAC1E,WAAW;IACX,0EAA0E;IAE1E,4EAA4E;IAC5E,SAAS,CAAC,KAAmB;QAC3B,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC;IAC3C,CAAC;IAED,6BAA6B;IAC7B,YAAY,CAAC,EAAU;QACrB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAC1B,CAAC;IAED,0EAA0E;IAC1E,kBAAkB;IAClB,0EAA0E;IAE1E;;;;;OAKG;IACH,WAAW,CAAC,QAAc;QACxB,IAAI,WAAW,GAAG,CAAC,CAAC;QAEpB,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;YAC3C,MAAM,GAAG,GAAG,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;YAClD,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;YAC1C,IAAI,GAAG,IAAI,GAAG,EAAE,CAAC;gBACf,WAAW,IAAI,MAAM,CAAC,WAAW,CAAC;YACpC,CAAC;QACH,CAAC;QAED,OAAO,WAAW,CAAC;IACrB,CAAC;IAED,6DAA6D;IAC7D,cAAc,CAAC,QAAc,EAAE,MAAc;QAC3C,MAAM,MAAM,GAAmB,EAAE,CAAC;QAClC,MAAM,cAAc,GAAG,MAAM,GAAG,MAAM,CAAC;QAEvC,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;YAC3C,MAAM,GAAG,GAAG,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;YAClD,IAAI,GAAG,IAAI,cAAc,EAAE,CAAC;gBAC1B,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACtB,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;;;;;;;OAQG;IACH,gBAAgB,CAAC,QAAc;QAC7B,IAAI,UAAU,GAAG,CAAC,CAAC;QACnB,IAAI,UAAU,GAAG,CAAC,CAAC;QACnB,IAAI,UAAU,GAAG,KAAK,CAAC;QAEvB,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;YAC3C,MAAM,GAAG,GAAG,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;YAClD,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;YAE1C,IAAI,GAAG,GAAG,GAAG;gBAAE,SAAS;YAExB,UAAU,GAAG,IAAI,CAAC;YAElB,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAE5B,IAAI,IAAI,GAAG,CAAC,EAAE,CAAC;gBACb,uEAAuE;gBACvE,sCAAsC;gBACtC,MAAM,KAAK,GAAG,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC;gBAC1F,UAAU,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,WAAW,CAAC;gBACnD,UAAU,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,WAAW,CAAC;gBACnD,SAAS;YACX,CAAC;YAED,iEAAiE;YACjE,MAAM,EAAE,GAAG,QAAQ,CAAC,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;YAC1C,MAAM,EAAE,GAAG,QAAQ,CAAC,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;YAE1C,+CAA+C;YAC/C,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,GAAG,IAAI,CAAC;YACzC,UAAU,IAAI,EAAE,GAAG,MAAM,CAAC;YAC1B,UAAU,IAAI,EAAE,GAAG,MAAM,CAAC;QAC5B,CAAC;QAED,IAAI,CAAC,UAAU;YAAE,OAAO,IAAI,CAAC;QAE7B,2DAA2D;QAC3D,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,GAAG,UAAU,GAAG,UAAU,GAAG,UAAU,CAAC,CAAC;QACzE,IAAI,GAAG,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QAC3B,OAAO,EAAE,CAAC,EAAE,UAAU,GAAG,GAAG,EAAE,CAAC,EAAE,UAAU,GAAG,GAAG,EAAE,CAAC;IACtD,CAAC;IAED,0EAA0E;IAC1E,SAAS;IACT,0EAA0E;IAE1E,4DAA4D;IAC5D,MAAM,CAAC,OAAe;QACpB,MAAM,QAAQ,GAAa,EAAE,CAAC;QAC9B,KAAK,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACxC,MAAM,CAAC,WAAW,IAAI,OAAO,CAAC;YAC9B,IAAI,MAAM,CAAC,WAAW,IAAI,CAAC,EAAE,CAAC;gBAC5B,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACpB,CAAC;QACH,CAAC;QACD,KAAK,MAAM,EAAE,IAAI,QAAQ,EAAE,CAAC;YAC1B,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC;IAED,0EAA0E;IAC1E,qBAAqB;IACrB,0EAA0E;IAE1E;;;;;OAKG;IACH,WAAW,CACT,QAAc,EACd,YAAoB,IAAI,CAAC,gBAAgB;QAEzC,IAAI,WAAW,GAAG,CAAC,CAAC;QAEpB,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;YAC3C,MAAM,GAAG,GAAG,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;YAClD,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;YAC1C,IAAI,GAAG,IAAI,GAAG,EAAE,CAAC;gBACf,WAAW,IAAI,MAAM,CAAC,WAAW,CAAC;gBAClC,IAAI,WAAW,IAAI,SAAS;oBAAE,OAAO,IAAI,CAAC;YAC5C,CAAC;QACH,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,iBAAiB;QACnB,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;IAC3B,CAAC;IAED,0EAA0E;IAC1E,gBAAgB;IAChB,0EAA0E;IAE1E,SAAS;QACP,OAAO,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACpC,CAAC;IAED,OAAO,CAAC,OAAuB;QAC7B,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QACrB,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC;QAC3C,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Abstract GOAP action base.
|
|
3
|
+
*
|
|
4
|
+
* Each concrete action encodes:
|
|
5
|
+
* - id: Unique string identifier for logging and plan inspection.
|
|
6
|
+
* - cost: Planner cost. Lower = preferred path.
|
|
7
|
+
* - preconditions: WorldState properties that must be true before execution.
|
|
8
|
+
* - effects: WorldState properties this action produces on success.
|
|
9
|
+
*
|
|
10
|
+
* Execution lifecycle per action:
|
|
11
|
+
* 1. isValid() -- real-time guard (can bail on stale conditions)
|
|
12
|
+
* 2. execute() -- called every tick; returns RUNNING / SUCCESS / FAILURE
|
|
13
|
+
* 3. abort() -- called when the action is interrupted (default no-op)
|
|
14
|
+
*/
|
|
15
|
+
import type { WorldState } from './WorldState';
|
|
16
|
+
import type { IEntity } from '../entity/IEntity';
|
|
17
|
+
export declare const ActionStatus: {
|
|
18
|
+
readonly RUNNING: "running";
|
|
19
|
+
readonly SUCCESS: "success";
|
|
20
|
+
readonly FAILURE: "failure";
|
|
21
|
+
};
|
|
22
|
+
export type ActionStatus = (typeof ActionStatus)[keyof typeof ActionStatus];
|
|
23
|
+
export declare abstract class GOAPAction {
|
|
24
|
+
/** Unique action identifier for logging and plan inspection. */
|
|
25
|
+
abstract readonly id: string;
|
|
26
|
+
/** Planner cost. Lower cost = preferred path. */
|
|
27
|
+
abstract readonly cost: number;
|
|
28
|
+
/** Preconditions that must be true for this action to be valid. */
|
|
29
|
+
abstract getPreconditions(): WorldState;
|
|
30
|
+
/** Effects this action has on the world state when it completes. */
|
|
31
|
+
abstract getEffects(): WorldState;
|
|
32
|
+
/** Check if the action can currently execute (real-time guard). */
|
|
33
|
+
abstract isValid(entity: IEntity): boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Execute one tick of this action.
|
|
36
|
+
*
|
|
37
|
+
* @param entity - The entity executing this action.
|
|
38
|
+
* @param delta - Milliseconds elapsed since the last tick.
|
|
39
|
+
* @returns Status indicating whether to continue, succeed, or fail.
|
|
40
|
+
*/
|
|
41
|
+
abstract execute(entity: IEntity, delta: number): ActionStatus;
|
|
42
|
+
/** Called when the action is interrupted. Override for cleanup. */
|
|
43
|
+
abort(_entity: IEntity): void;
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=GOAPAction.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GOAPAction.d.ts","sourceRoot":"","sources":["../../src/ai/GOAPAction.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAMjD,eAAO,MAAM,YAAY;;;;CAIf,CAAC;AAEX,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,OAAO,YAAY,CAAC,CAAC;AAM5E,8BAAsB,UAAU;IAC9B,gEAAgE;IAChE,QAAQ,CAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAE7B,iDAAiD;IACjD,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAE/B,mEAAmE;IACnE,QAAQ,CAAC,gBAAgB,IAAI,UAAU;IAEvC,oEAAoE;IACpE,QAAQ,CAAC,UAAU,IAAI,UAAU;IAEjC,mEAAmE;IACnE,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO;IAE1C;;;;;;OAMG;IACH,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,YAAY;IAE9D,mEAAmE;IACnE,KAAK,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;CAG9B"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Abstract GOAP action base.
|
|
3
|
+
*
|
|
4
|
+
* Each concrete action encodes:
|
|
5
|
+
* - id: Unique string identifier for logging and plan inspection.
|
|
6
|
+
* - cost: Planner cost. Lower = preferred path.
|
|
7
|
+
* - preconditions: WorldState properties that must be true before execution.
|
|
8
|
+
* - effects: WorldState properties this action produces on success.
|
|
9
|
+
*
|
|
10
|
+
* Execution lifecycle per action:
|
|
11
|
+
* 1. isValid() -- real-time guard (can bail on stale conditions)
|
|
12
|
+
* 2. execute() -- called every tick; returns RUNNING / SUCCESS / FAILURE
|
|
13
|
+
* 3. abort() -- called when the action is interrupted (default no-op)
|
|
14
|
+
*/
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
// Action status
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
export const ActionStatus = {
|
|
19
|
+
RUNNING: 'running',
|
|
20
|
+
SUCCESS: 'success',
|
|
21
|
+
FAILURE: 'failure',
|
|
22
|
+
};
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
// Abstract base class
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
export class GOAPAction {
|
|
27
|
+
/** Called when the action is interrupted. Override for cleanup. */
|
|
28
|
+
abort(_entity) {
|
|
29
|
+
// Default no-op. Concrete actions override for cleanup.
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=GOAPAction.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GOAPAction.js","sourceRoot":"","sources":["../../src/ai/GOAPAction.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAKH,8EAA8E;AAC9E,gBAAgB;AAChB,8EAA8E;AAE9E,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,OAAO,EAAE,SAAS;IAClB,OAAO,EAAE,SAAS;IAClB,OAAO,EAAE,SAAS;CACV,CAAC;AAIX,8EAA8E;AAC9E,sBAAsB;AACtB,8EAA8E;AAE9E,MAAM,OAAgB,UAAU;IAyB9B,mEAAmE;IACnE,KAAK,CAAC,OAAgB;QACpB,wDAAwD;IAC1D,CAAC;CACF"}
|