@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
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export declare function assertDefined<T>(value: T | undefined | null, name: string): asserts value is T;
|
|
2
|
+
export declare function assertString(value: unknown, name: string): asserts value is string;
|
|
3
|
+
export declare function assertNumber(value: unknown, name: string): asserts value is number;
|
|
4
|
+
export declare function assertNumberInRange(value: unknown, name: string, min: number, max: number): asserts value is number;
|
|
5
|
+
export declare function assertBoolean(value: unknown, name: string): asserts value is boolean;
|
|
6
|
+
export declare function assertArray(value: unknown, name: string): asserts value is unknown[];
|
|
7
|
+
export declare function assertObject(value: unknown, name: string): asserts value is Record<string, unknown>;
|
|
8
|
+
export type ValidationResult = {
|
|
9
|
+
valid: true;
|
|
10
|
+
} | {
|
|
11
|
+
valid: false;
|
|
12
|
+
errors: string[];
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Creates a reusable validator function from an array of rule functions.
|
|
16
|
+
*
|
|
17
|
+
* Each rule receives the raw input and returns `null` if valid or an error
|
|
18
|
+
* string if invalid. The validator runs ALL rules and collects ALL errors
|
|
19
|
+
* (not fail-fast) so the caller gets a complete diagnostic on first attempt.
|
|
20
|
+
*/
|
|
21
|
+
export declare function createValidator<_T>(name: string, rules: Array<(input: unknown) => string | null>): (input: unknown) => ValidationResult;
|
|
22
|
+
/**
|
|
23
|
+
* Validates raw JSON input against the IMonsterDefinition shape.
|
|
24
|
+
* Runs all rules and returns a complete list of errors.
|
|
25
|
+
*/
|
|
26
|
+
export declare const validateMonsterDefinition: (input: unknown) => ValidationResult;
|
|
27
|
+
/**
|
|
28
|
+
* Validates raw JSON input against the IFactionDefinition shape.
|
|
29
|
+
* Runs all rules and returns a complete list of errors.
|
|
30
|
+
*/
|
|
31
|
+
export declare const validateFactionDefinition: (input: unknown) => ValidationResult;
|
|
32
|
+
//# sourceMappingURL=validators.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validators.d.ts","sourceRoot":"","sources":["../../src/schema/validators.ts"],"names":[],"mappings":"AAOA,wBAAgB,aAAa,CAAC,CAAC,EAC7B,KAAK,EAAE,CAAC,GAAG,SAAS,GAAG,IAAI,EAC3B,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,KAAK,IAAI,CAAC,CAIpB;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,IAAI,MAAM,CAIlF;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,IAAI,MAAM,CAMlF;AAED,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,OAAO,EACd,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,KAAK,IAAI,MAAM,CAKzB;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,IAAI,OAAO,CAIpF;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,IAAI,OAAO,EAAE,CAIpF;AAED,wBAAgB,YAAY,CAC1B,KAAK,EAAE,OAAO,EACd,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAM1C;AAMD,MAAM,MAAM,gBAAgB,GAAG;IAAE,KAAK,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AAMpF;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAChC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,KAAK,CAAC,CAAC,KAAK,EAAE,OAAO,KAAK,MAAM,GAAG,IAAI,CAAC,GAC9C,CAAC,KAAK,EAAE,OAAO,KAAK,gBAAgB,CAatC;AAkHD;;;GAGG;AACH,eAAO,MAAM,yBAAyB,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,gBACY,CAAC;AAkDzE;;;GAGG;AACH,eAAO,MAAM,yBAAyB,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,gBACY,CAAC"}
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Assertion helpers — throw descriptive errors on invalid input
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
export function assertDefined(value, name) {
|
|
5
|
+
if (value === undefined || value === null) {
|
|
6
|
+
throw new Error(`${name} must be defined, got ${value === null ? 'null' : 'undefined'}`);
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
export function assertString(value, name) {
|
|
10
|
+
if (typeof value !== 'string') {
|
|
11
|
+
throw new Error(`${name} must be a string, got ${typeof value}`);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export function assertNumber(value, name) {
|
|
15
|
+
if (typeof value !== 'number' || Number.isNaN(value)) {
|
|
16
|
+
throw new Error(`${name} must be a number, got ${Number.isNaN(value) ? 'NaN' : typeof value}`);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export function assertNumberInRange(value, name, min, max) {
|
|
20
|
+
assertNumber(value, name);
|
|
21
|
+
if (value < min || value > max) {
|
|
22
|
+
throw new Error(`${name} must be in [${min}, ${max}], got ${value}`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export function assertBoolean(value, name) {
|
|
26
|
+
if (typeof value !== 'boolean') {
|
|
27
|
+
throw new Error(`${name} must be a boolean, got ${typeof value}`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export function assertArray(value, name) {
|
|
31
|
+
if (!Array.isArray(value)) {
|
|
32
|
+
throw new Error(`${name} must be an array, got ${typeof value}`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
export function assertObject(value, name) {
|
|
36
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value)) {
|
|
37
|
+
throw new Error(`${name} must be a plain object, got ${value === null ? 'null' : Array.isArray(value) ? 'array' : typeof value}`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
// ---------------------------------------------------------------------------
|
|
41
|
+
// Generic validator factory
|
|
42
|
+
// ---------------------------------------------------------------------------
|
|
43
|
+
/**
|
|
44
|
+
* Creates a reusable validator function from an array of rule functions.
|
|
45
|
+
*
|
|
46
|
+
* Each rule receives the raw input and returns `null` if valid or an error
|
|
47
|
+
* string if invalid. The validator runs ALL rules and collects ALL errors
|
|
48
|
+
* (not fail-fast) so the caller gets a complete diagnostic on first attempt.
|
|
49
|
+
*/
|
|
50
|
+
export function createValidator(name, rules) {
|
|
51
|
+
return (input) => {
|
|
52
|
+
const errors = [];
|
|
53
|
+
for (const rule of rules) {
|
|
54
|
+
const error = rule(input);
|
|
55
|
+
if (error !== null) {
|
|
56
|
+
errors.push(`[${name}] ${error}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return errors.length === 0 ? { valid: true } : { valid: false, errors };
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
// ---------------------------------------------------------------------------
|
|
63
|
+
// Private helpers
|
|
64
|
+
// ---------------------------------------------------------------------------
|
|
65
|
+
function isObject(v) {
|
|
66
|
+
return v !== null && typeof v === 'object' && !Array.isArray(v);
|
|
67
|
+
}
|
|
68
|
+
function checkString(obj, field) {
|
|
69
|
+
if (typeof obj[field] !== 'string' || obj[field].length === 0) {
|
|
70
|
+
return `"${field}" must be a non-empty string`;
|
|
71
|
+
}
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
function checkPositiveNumber(obj, field) {
|
|
75
|
+
const v = obj[field];
|
|
76
|
+
if (typeof v !== 'number' || Number.isNaN(v) || v <= 0) {
|
|
77
|
+
return `"${field}" must be a positive number`;
|
|
78
|
+
}
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
function checkNumberInRange(obj, field, min, max) {
|
|
82
|
+
const v = obj[field];
|
|
83
|
+
if (typeof v !== 'number' || Number.isNaN(v) || v < min || v > max) {
|
|
84
|
+
return `"${field}" must be a number in [${min}, ${max}]`;
|
|
85
|
+
}
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
// ---------------------------------------------------------------------------
|
|
89
|
+
// Monster definition validator
|
|
90
|
+
// ---------------------------------------------------------------------------
|
|
91
|
+
const monsterRules = [
|
|
92
|
+
(input) => (isObject(input) ? null : 'input must be an object'),
|
|
93
|
+
(input) => {
|
|
94
|
+
if (!isObject(input))
|
|
95
|
+
return null; // guarded by rule above
|
|
96
|
+
return checkString(input, 'name');
|
|
97
|
+
},
|
|
98
|
+
(input) => {
|
|
99
|
+
if (!isObject(input))
|
|
100
|
+
return null;
|
|
101
|
+
return checkPositiveNumber(input, 'hp');
|
|
102
|
+
},
|
|
103
|
+
(input) => {
|
|
104
|
+
if (!isObject(input))
|
|
105
|
+
return null;
|
|
106
|
+
return checkPositiveNumber(input, 'speed');
|
|
107
|
+
},
|
|
108
|
+
(input) => {
|
|
109
|
+
if (!isObject(input))
|
|
110
|
+
return null;
|
|
111
|
+
return checkPositiveNumber(input, 'damage');
|
|
112
|
+
},
|
|
113
|
+
(input) => {
|
|
114
|
+
if (!isObject(input))
|
|
115
|
+
return null;
|
|
116
|
+
return checkPositiveNumber(input, 'attackRange');
|
|
117
|
+
},
|
|
118
|
+
(input) => {
|
|
119
|
+
if (!isObject(input))
|
|
120
|
+
return null;
|
|
121
|
+
return checkPositiveNumber(input, 'detectionRange');
|
|
122
|
+
},
|
|
123
|
+
(input) => {
|
|
124
|
+
if (!isObject(input))
|
|
125
|
+
return null;
|
|
126
|
+
return checkNumberInRange(input, 'fov', 0.01, 360);
|
|
127
|
+
},
|
|
128
|
+
(input) => {
|
|
129
|
+
if (!isObject(input))
|
|
130
|
+
return null;
|
|
131
|
+
const ps = input['packSize'];
|
|
132
|
+
if (!Array.isArray(ps) || ps.length !== 2)
|
|
133
|
+
return '"packSize" must be a [min, max] tuple';
|
|
134
|
+
if (typeof ps[0] !== 'number' || ps[0] < 1)
|
|
135
|
+
return '"packSize[0]" must be >= 1';
|
|
136
|
+
if (typeof ps[1] !== 'number')
|
|
137
|
+
return '"packSize[1]" must be a number';
|
|
138
|
+
if (ps[0] > ps[1])
|
|
139
|
+
return '"packSize" min must be <= max';
|
|
140
|
+
return null;
|
|
141
|
+
},
|
|
142
|
+
(input) => {
|
|
143
|
+
if (!isObject(input))
|
|
144
|
+
return null;
|
|
145
|
+
if (!Array.isArray(input['abilities']))
|
|
146
|
+
return '"abilities" must be an array';
|
|
147
|
+
return null;
|
|
148
|
+
},
|
|
149
|
+
(input) => {
|
|
150
|
+
if (!isObject(input))
|
|
151
|
+
return null;
|
|
152
|
+
const lair = input['lair'];
|
|
153
|
+
if (!isObject(lair))
|
|
154
|
+
return '"lair" must be an object with inner, patrol, outer';
|
|
155
|
+
const inner = lair['inner'];
|
|
156
|
+
const patrol = lair['patrol'];
|
|
157
|
+
const outer = lair['outer'];
|
|
158
|
+
if (typeof inner !== 'number' || typeof patrol !== 'number' || typeof outer !== 'number') {
|
|
159
|
+
return '"lair" fields must be numbers';
|
|
160
|
+
}
|
|
161
|
+
if (inner >= patrol)
|
|
162
|
+
return '"lair.inner" must be < "lair.patrol"';
|
|
163
|
+
if (patrol >= outer)
|
|
164
|
+
return '"lair.patrol" must be < "lair.outer"';
|
|
165
|
+
return null;
|
|
166
|
+
},
|
|
167
|
+
(input) => {
|
|
168
|
+
if (!isObject(input))
|
|
169
|
+
return null;
|
|
170
|
+
return checkNumberInRange(input, 'rank', 1, 5);
|
|
171
|
+
},
|
|
172
|
+
(input) => {
|
|
173
|
+
if (!isObject(input))
|
|
174
|
+
return null;
|
|
175
|
+
const faction = input['faction'];
|
|
176
|
+
if (faction !== undefined && typeof faction !== 'string') {
|
|
177
|
+
return '"faction" must be a string if provided';
|
|
178
|
+
}
|
|
179
|
+
return null;
|
|
180
|
+
},
|
|
181
|
+
];
|
|
182
|
+
/**
|
|
183
|
+
* Validates raw JSON input against the IMonsterDefinition shape.
|
|
184
|
+
* Runs all rules and returns a complete list of errors.
|
|
185
|
+
*/
|
|
186
|
+
export const validateMonsterDefinition = createValidator('MonsterDefinition', monsterRules);
|
|
187
|
+
// ---------------------------------------------------------------------------
|
|
188
|
+
// Faction definition validator
|
|
189
|
+
// ---------------------------------------------------------------------------
|
|
190
|
+
const factionRules = [
|
|
191
|
+
(input) => (isObject(input) ? null : 'input must be an object'),
|
|
192
|
+
(input) => {
|
|
193
|
+
if (!isObject(input))
|
|
194
|
+
return null;
|
|
195
|
+
return checkString(input, 'name');
|
|
196
|
+
},
|
|
197
|
+
(input) => {
|
|
198
|
+
if (!isObject(input))
|
|
199
|
+
return null;
|
|
200
|
+
const br = input['baseRelations'];
|
|
201
|
+
if (!isObject(br))
|
|
202
|
+
return '"baseRelations" must be an object';
|
|
203
|
+
for (const [id, v] of Object.entries(br)) {
|
|
204
|
+
if (typeof v !== 'number' || v < -100 || v > 100) {
|
|
205
|
+
return `"baseRelations.${id}" must be a number in [-100, 100]`;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return null;
|
|
209
|
+
},
|
|
210
|
+
(input) => {
|
|
211
|
+
if (!isObject(input))
|
|
212
|
+
return null;
|
|
213
|
+
const imm = input['immunities'];
|
|
214
|
+
if (!isObject(imm))
|
|
215
|
+
return '"immunities" must be an object';
|
|
216
|
+
for (const [id, v] of Object.entries(imm)) {
|
|
217
|
+
if (typeof v !== 'number' || v < 0 || v > 1) {
|
|
218
|
+
return `"immunities.${id}" must be a number in [0, 1]`;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
return null;
|
|
222
|
+
},
|
|
223
|
+
(input) => {
|
|
224
|
+
if (!isObject(input))
|
|
225
|
+
return null;
|
|
226
|
+
const de = input['defaultEquipment'];
|
|
227
|
+
if (de !== undefined && !isObject(de))
|
|
228
|
+
return '"defaultEquipment" must be an object if provided';
|
|
229
|
+
return null;
|
|
230
|
+
},
|
|
231
|
+
(input) => {
|
|
232
|
+
if (!isObject(input))
|
|
233
|
+
return null;
|
|
234
|
+
const sr = input['spawnRules'];
|
|
235
|
+
if (!isObject(sr))
|
|
236
|
+
return '"spawnRules" must be an object';
|
|
237
|
+
if (typeof sr['targetRatio'] !== 'number')
|
|
238
|
+
return '"spawnRules.targetRatio" must be a number';
|
|
239
|
+
if (typeof sr['balanceTolerance'] !== 'number')
|
|
240
|
+
return '"spawnRules.balanceTolerance" must be a number';
|
|
241
|
+
return null;
|
|
242
|
+
},
|
|
243
|
+
];
|
|
244
|
+
/**
|
|
245
|
+
* Validates raw JSON input against the IFactionDefinition shape.
|
|
246
|
+
* Runs all rules and returns a complete list of errors.
|
|
247
|
+
*/
|
|
248
|
+
export const validateFactionDefinition = createValidator('FactionDefinition', factionRules);
|
|
249
|
+
//# sourceMappingURL=validators.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validators.js","sourceRoot":"","sources":["../../src/schema/validators.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Data-driven spawn management with cooldowns and faction balance.
|
|
3
|
+
*
|
|
4
|
+
* SpawnRegistry is a pure simulation object -- it never creates game objects.
|
|
5
|
+
* It tracks per-point cooldowns, live-count caps, and faction filters.
|
|
6
|
+
* External systems query eligible points and handle actual entity creation.
|
|
7
|
+
*
|
|
8
|
+
* Eligibility: cooldown expired AND activeCounts < maxNPCs.
|
|
9
|
+
*/
|
|
10
|
+
import type { Vec2 } from '../core/Vec2';
|
|
11
|
+
export interface ISpawnPointConfig {
|
|
12
|
+
readonly id: string;
|
|
13
|
+
readonly terrainId: string;
|
|
14
|
+
readonly position: Vec2;
|
|
15
|
+
readonly factionId: string;
|
|
16
|
+
readonly maxNPCs: number;
|
|
17
|
+
}
|
|
18
|
+
export interface ISpawnRegistryState {
|
|
19
|
+
readonly cooldowns: Readonly<Record<string, number>>;
|
|
20
|
+
readonly activeCounts: Readonly<Record<string, number>>;
|
|
21
|
+
}
|
|
22
|
+
export declare class SpawnRegistry {
|
|
23
|
+
private readonly points;
|
|
24
|
+
private readonly cooldowns;
|
|
25
|
+
private readonly activeCounts;
|
|
26
|
+
private readonly defaultCooldownMs;
|
|
27
|
+
constructor(defaultCooldownMs?: number);
|
|
28
|
+
addPoint(config: ISpawnPointConfig): void;
|
|
29
|
+
removePoint(id: string): void;
|
|
30
|
+
getPoint(id: string): ISpawnPointConfig | undefined;
|
|
31
|
+
/** Get all spawn points eligible for spawning now. */
|
|
32
|
+
getEligiblePoints(): ISpawnPointConfig[];
|
|
33
|
+
/** Mark a spawn point as used (starts cooldown, increments active count). */
|
|
34
|
+
markSpawned(spawnPointId: string): void;
|
|
35
|
+
/** Record NPC death -- decrement active count for the spawn point. */
|
|
36
|
+
markDespawned(spawnPointId: string): void;
|
|
37
|
+
/** Tick cooldowns by the given delta. */
|
|
38
|
+
update(deltaMs: number): void;
|
|
39
|
+
/** Reset all cooldowns to zero (e.g., after a surge for mass respawn). */
|
|
40
|
+
resetAllCooldowns(): void;
|
|
41
|
+
/** Get all spawn points that belong to the given faction. */
|
|
42
|
+
getPointsByFaction(factionId: string): ISpawnPointConfig[];
|
|
43
|
+
get totalPoints(): number;
|
|
44
|
+
serialize(): ISpawnRegistryState;
|
|
45
|
+
restore(state: ISpawnRegistryState): void;
|
|
46
|
+
private isEligible;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=SpawnRegistry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SpawnRegistry.d.ts","sourceRoot":"","sources":["../../src/spawn/SpawnRegistry.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAMzC,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAMD,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACrD,QAAQ,CAAC,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CACzD;AAYD,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAwC;IAC/D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA6B;IACvD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA6B;IAE1D,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAS;gBAE/B,iBAAiB,GAAE,MAA4B;IAQ3D,QAAQ,CAAC,MAAM,EAAE,iBAAiB,GAAG,IAAI;IAMzC,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAM7B,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS;IAQnD,sDAAsD;IACtD,iBAAiB,IAAI,iBAAiB,EAAE;IAgBxC,6EAA6E;IAC7E,WAAW,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI;IAQvC,sEAAsE;IACtE,aAAa,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI;IAWzC,yCAAyC;IACzC,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAY7B,0EAA0E;IAC1E,iBAAiB,IAAI,IAAI;IAUzB,6DAA6D;IAC7D,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,iBAAiB,EAAE;IAU1D,IAAI,WAAW,IAAI,MAAM,CAExB;IAMD,SAAS,IAAI,mBAAmB;IAOhC,OAAO,CAAC,KAAK,EAAE,mBAAmB,GAAG,IAAI;IAiBzC,OAAO,CAAC,UAAU;CASnB"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Data-driven spawn management with cooldowns and faction balance.
|
|
3
|
+
*
|
|
4
|
+
* SpawnRegistry is a pure simulation object -- it never creates game objects.
|
|
5
|
+
* It tracks per-point cooldowns, live-count caps, and faction filters.
|
|
6
|
+
* External systems query eligible points and handle actual entity creation.
|
|
7
|
+
*
|
|
8
|
+
* Eligibility: cooldown expired AND activeCounts < maxNPCs.
|
|
9
|
+
*/
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
// Constants
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
const DEFAULT_COOLDOWN_MS = 30000;
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
// SpawnRegistry
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
export class SpawnRegistry {
|
|
18
|
+
constructor(defaultCooldownMs = DEFAULT_COOLDOWN_MS) {
|
|
19
|
+
this.points = new Map();
|
|
20
|
+
this.cooldowns = new Map();
|
|
21
|
+
this.activeCounts = new Map();
|
|
22
|
+
this.defaultCooldownMs = defaultCooldownMs;
|
|
23
|
+
}
|
|
24
|
+
// -----------------------------------------------------------------------
|
|
25
|
+
// Point management
|
|
26
|
+
// -----------------------------------------------------------------------
|
|
27
|
+
addPoint(config) {
|
|
28
|
+
this.points.set(config.id, config);
|
|
29
|
+
this.cooldowns.set(config.id, 0);
|
|
30
|
+
this.activeCounts.set(config.id, 0);
|
|
31
|
+
}
|
|
32
|
+
removePoint(id) {
|
|
33
|
+
this.points.delete(id);
|
|
34
|
+
this.cooldowns.delete(id);
|
|
35
|
+
this.activeCounts.delete(id);
|
|
36
|
+
}
|
|
37
|
+
getPoint(id) {
|
|
38
|
+
return this.points.get(id);
|
|
39
|
+
}
|
|
40
|
+
// -----------------------------------------------------------------------
|
|
41
|
+
// Eligibility
|
|
42
|
+
// -----------------------------------------------------------------------
|
|
43
|
+
/** Get all spawn points eligible for spawning now. */
|
|
44
|
+
getEligiblePoints() {
|
|
45
|
+
const eligible = [];
|
|
46
|
+
for (const [id, config] of this.points) {
|
|
47
|
+
if (this.isEligible(id, config)) {
|
|
48
|
+
eligible.push(config);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return eligible;
|
|
52
|
+
}
|
|
53
|
+
// -----------------------------------------------------------------------
|
|
54
|
+
// Spawn lifecycle
|
|
55
|
+
// -----------------------------------------------------------------------
|
|
56
|
+
/** Mark a spawn point as used (starts cooldown, increments active count). */
|
|
57
|
+
markSpawned(spawnPointId) {
|
|
58
|
+
if (!this.points.has(spawnPointId))
|
|
59
|
+
return;
|
|
60
|
+
this.cooldowns.set(spawnPointId, this.defaultCooldownMs);
|
|
61
|
+
const current = this.activeCounts.get(spawnPointId) ?? 0;
|
|
62
|
+
this.activeCounts.set(spawnPointId, current + 1);
|
|
63
|
+
}
|
|
64
|
+
/** Record NPC death -- decrement active count for the spawn point. */
|
|
65
|
+
markDespawned(spawnPointId) {
|
|
66
|
+
const current = this.activeCounts.get(spawnPointId);
|
|
67
|
+
if (current === undefined)
|
|
68
|
+
return;
|
|
69
|
+
this.activeCounts.set(spawnPointId, Math.max(0, current - 1));
|
|
70
|
+
}
|
|
71
|
+
// -----------------------------------------------------------------------
|
|
72
|
+
// Update
|
|
73
|
+
// -----------------------------------------------------------------------
|
|
74
|
+
/** Tick cooldowns by the given delta. */
|
|
75
|
+
update(deltaMs) {
|
|
76
|
+
for (const [id, remaining] of this.cooldowns) {
|
|
77
|
+
if (remaining > 0) {
|
|
78
|
+
this.cooldowns.set(id, Math.max(0, remaining - deltaMs));
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
// -----------------------------------------------------------------------
|
|
83
|
+
// Batch operations
|
|
84
|
+
// -----------------------------------------------------------------------
|
|
85
|
+
/** Reset all cooldowns to zero (e.g., after a surge for mass respawn). */
|
|
86
|
+
resetAllCooldowns() {
|
|
87
|
+
for (const id of this.cooldowns.keys()) {
|
|
88
|
+
this.cooldowns.set(id, 0);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// -----------------------------------------------------------------------
|
|
92
|
+
// Queries
|
|
93
|
+
// -----------------------------------------------------------------------
|
|
94
|
+
/** Get all spawn points that belong to the given faction. */
|
|
95
|
+
getPointsByFaction(factionId) {
|
|
96
|
+
const result = [];
|
|
97
|
+
for (const config of this.points.values()) {
|
|
98
|
+
if (config.factionId === factionId) {
|
|
99
|
+
result.push(config);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return result;
|
|
103
|
+
}
|
|
104
|
+
get totalPoints() {
|
|
105
|
+
return this.points.size;
|
|
106
|
+
}
|
|
107
|
+
// -----------------------------------------------------------------------
|
|
108
|
+
// Serialisation
|
|
109
|
+
// -----------------------------------------------------------------------
|
|
110
|
+
serialize() {
|
|
111
|
+
return {
|
|
112
|
+
cooldowns: Object.fromEntries(this.cooldowns),
|
|
113
|
+
activeCounts: Object.fromEntries(this.activeCounts),
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
restore(state) {
|
|
117
|
+
for (const [id, value] of Object.entries(state.cooldowns)) {
|
|
118
|
+
if (this.cooldowns.has(id)) {
|
|
119
|
+
this.cooldowns.set(id, value);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
for (const [id, value] of Object.entries(state.activeCounts)) {
|
|
123
|
+
if (this.activeCounts.has(id)) {
|
|
124
|
+
this.activeCounts.set(id, value);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
// -----------------------------------------------------------------------
|
|
129
|
+
// Private
|
|
130
|
+
// -----------------------------------------------------------------------
|
|
131
|
+
isEligible(id, config) {
|
|
132
|
+
const cooldown = this.cooldowns.get(id) ?? 0;
|
|
133
|
+
if (cooldown > 0)
|
|
134
|
+
return false;
|
|
135
|
+
const active = this.activeCounts.get(id) ?? 0;
|
|
136
|
+
if (active >= config.maxNPCs)
|
|
137
|
+
return false;
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=SpawnRegistry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SpawnRegistry.js","sourceRoot":"","sources":["../../src/spawn/SpawnRegistry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/spawn/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,YAAY,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/spawn/index.ts"],"names":[],"mappings":"AAAA,wBAAwB;AACxB,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SmartTerrain -- a Zone with job slots, capacity, and NPC fitness scoring.
|
|
3
|
+
*
|
|
4
|
+
* NPCs evaluate available terrains and select the one with the highest
|
|
5
|
+
* fitness score. The terrain tracks its occupants and enforces capacity.
|
|
6
|
+
*/
|
|
7
|
+
import type { Vec2 } from '../core/Vec2';
|
|
8
|
+
import type { IRandom } from '../ports/IRandom';
|
|
9
|
+
import { Zone, type IZoneBounds } from './Zone';
|
|
10
|
+
export interface IJobPreconditions {
|
|
11
|
+
readonly minRank?: number;
|
|
12
|
+
readonly dayOnly?: boolean;
|
|
13
|
+
readonly nightOnly?: boolean;
|
|
14
|
+
readonly factions?: readonly string[];
|
|
15
|
+
}
|
|
16
|
+
export interface IJobSlot {
|
|
17
|
+
readonly type: string;
|
|
18
|
+
readonly slots: number;
|
|
19
|
+
readonly position?: Vec2;
|
|
20
|
+
readonly routeId?: string;
|
|
21
|
+
readonly preconditions?: IJobPreconditions;
|
|
22
|
+
}
|
|
23
|
+
export interface ISpawnPoint {
|
|
24
|
+
readonly x: number;
|
|
25
|
+
readonly y: number;
|
|
26
|
+
readonly factionId: string;
|
|
27
|
+
}
|
|
28
|
+
export interface IPatrolRouteConfig {
|
|
29
|
+
readonly id: string;
|
|
30
|
+
readonly routeType: 'loop' | 'ping_pong' | 'one_way';
|
|
31
|
+
readonly waypoints: readonly Vec2[];
|
|
32
|
+
}
|
|
33
|
+
/** Tunable scoring weights for SmartTerrain fitness evaluation. */
|
|
34
|
+
export interface IScoringConfig {
|
|
35
|
+
/** Distance penalty = dist / divisor. Default: 100. */
|
|
36
|
+
readonly distancePenaltyDivisor?: number;
|
|
37
|
+
/** Bonus applied when terrain is a shelter. Default: 50. */
|
|
38
|
+
readonly shelterBonus?: number;
|
|
39
|
+
/** Bonus when NPC rank >= terrain danger level. Default: 10. */
|
|
40
|
+
readonly rankMatchBonus?: number;
|
|
41
|
+
/** Random ± noise applied to fitness score. Default: 0 (deterministic). */
|
|
42
|
+
readonly scoringJitter?: number;
|
|
43
|
+
/**
|
|
44
|
+
* Use squared distance instead of sqrt for the distance penalty.
|
|
45
|
+
* Eliminates Math.sqrt per terrain per NPC but changes the penalty curve
|
|
46
|
+
* from linear to quadratic (nearby terrains are even more preferred).
|
|
47
|
+
* When true, uses distancePenaltySqDivisor (default: distancePenaltyDivisor²).
|
|
48
|
+
*/
|
|
49
|
+
readonly useSquaredDistance?: boolean;
|
|
50
|
+
/** Squared-distance penalty divisor. Default: distancePenaltyDivisor². */
|
|
51
|
+
readonly distancePenaltySqDivisor?: number;
|
|
52
|
+
}
|
|
53
|
+
export interface ISmartTerrainConfig {
|
|
54
|
+
readonly id: string;
|
|
55
|
+
readonly name: string;
|
|
56
|
+
readonly bounds: IZoneBounds;
|
|
57
|
+
readonly dangerLevel?: number;
|
|
58
|
+
readonly capacity: number;
|
|
59
|
+
readonly allowedFactions?: readonly string[];
|
|
60
|
+
readonly isShelter?: boolean;
|
|
61
|
+
readonly tags?: readonly string[];
|
|
62
|
+
readonly jobs?: readonly IJobSlot[];
|
|
63
|
+
readonly spawnPoints?: readonly ISpawnPoint[];
|
|
64
|
+
readonly patrolRoutes?: readonly IPatrolRouteConfig[];
|
|
65
|
+
readonly scoring?: IScoringConfig;
|
|
66
|
+
/** Injectable RNG for deterministic scoring jitter. Falls back to Math.random(). */
|
|
67
|
+
readonly random?: IRandom;
|
|
68
|
+
}
|
|
69
|
+
export declare class SmartTerrain extends Zone {
|
|
70
|
+
readonly capacity: number;
|
|
71
|
+
readonly allowedFactions: ReadonlySet<string>;
|
|
72
|
+
readonly isShelter: boolean;
|
|
73
|
+
readonly tags: ReadonlySet<string>;
|
|
74
|
+
readonly jobs: readonly IJobSlot[];
|
|
75
|
+
readonly spawnPoints: readonly ISpawnPoint[];
|
|
76
|
+
readonly patrolRoutes: ReadonlyMap<string, IPatrolRouteConfig>;
|
|
77
|
+
private readonly distancePenaltyDivisor;
|
|
78
|
+
private readonly useSquaredDistance;
|
|
79
|
+
private readonly distancePenaltySqDivisor;
|
|
80
|
+
private readonly shelterBonus;
|
|
81
|
+
private readonly rankMatchBonus;
|
|
82
|
+
private readonly scoringJitter;
|
|
83
|
+
private readonly random;
|
|
84
|
+
private readonly occupants;
|
|
85
|
+
constructor(config: ISmartTerrainConfig);
|
|
86
|
+
/** Number of NPCs currently assigned to this terrain. */
|
|
87
|
+
get occupantCount(): number;
|
|
88
|
+
/** Whether the terrain can accept another NPC. */
|
|
89
|
+
get hasCapacity(): boolean;
|
|
90
|
+
/**
|
|
91
|
+
* Register an NPC as an occupant.
|
|
92
|
+
* Returns false if the terrain is already at capacity.
|
|
93
|
+
*/
|
|
94
|
+
addOccupant(npcId: string): boolean;
|
|
95
|
+
/** Remove an NPC from the occupant set. */
|
|
96
|
+
removeOccupant(npcId: string): void;
|
|
97
|
+
/** Check whether a given NPC is an occupant. */
|
|
98
|
+
hasOccupant(npcId: string): boolean;
|
|
99
|
+
/** Read-only view of the current occupant set. */
|
|
100
|
+
getOccupants(): ReadonlySet<string>;
|
|
101
|
+
/**
|
|
102
|
+
* Compute a fitness score for an NPC considering faction, distance,
|
|
103
|
+
* capacity, shelter status, and danger-to-rank matching.
|
|
104
|
+
*
|
|
105
|
+
* Scoring breakdown:
|
|
106
|
+
* - Base = remaining capacity (capacity - occupantCount)
|
|
107
|
+
* - Faction not allowed: -Infinity
|
|
108
|
+
* - Distance penalty: -distance / 100
|
|
109
|
+
* - Shelter bonus: +50 if isShelter
|
|
110
|
+
* - Rank >= dangerLevel: +10
|
|
111
|
+
*/
|
|
112
|
+
scoreFitness(npcFaction: string, npcPosition: Vec2, npcRank: number): number;
|
|
113
|
+
/**
|
|
114
|
+
* Check whether a faction is allowed in this terrain.
|
|
115
|
+
* An empty allowedFactions set means all factions are accepted.
|
|
116
|
+
*/
|
|
117
|
+
acceptsFaction(factionId: string): boolean;
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=SmartTerrain.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SmartTerrain.d.ts","sourceRoot":"","sources":["../../src/terrain/SmartTerrain.ts"],"names":[],"mappings":"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"}
|