@its-not-rocket-science/ananke 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/CHANGELOG.md +135 -0
- package/LICENSE +21 -0
- package/README.md +2199 -0
- package/STABLE_API.md +266 -0
- package/dist/src/anatomy/anatomy-compiler.d.ts +14 -0
- package/dist/src/anatomy/anatomy-compiler.js +277 -0
- package/dist/src/anatomy/anatomy-contracts.d.ts +94 -0
- package/dist/src/anatomy/anatomy-contracts.js +1 -0
- package/dist/src/anatomy/anatomy-helpers.d.ts +82 -0
- package/dist/src/anatomy/anatomy-helpers.js +233 -0
- package/dist/src/anatomy/anatomy-schema.d.ts +28 -0
- package/dist/src/anatomy/anatomy-schema.js +388 -0
- package/dist/src/anatomy/index.d.ts +4 -0
- package/dist/src/anatomy/index.js +4 -0
- package/dist/src/archetypes.d.ts +87 -0
- package/dist/src/archetypes.js +285 -0
- package/dist/src/arena.d.ts +173 -0
- package/dist/src/arena.js +695 -0
- package/dist/src/bridge/bridge-engine.d.ts +46 -0
- package/dist/src/bridge/bridge-engine.js +252 -0
- package/dist/src/bridge/index.d.ts +4 -0
- package/dist/src/bridge/index.js +5 -0
- package/dist/src/bridge/interpolation.d.ts +64 -0
- package/dist/src/bridge/interpolation.js +130 -0
- package/dist/src/bridge/mapping.d.ts +33 -0
- package/dist/src/bridge/mapping.js +54 -0
- package/dist/src/bridge/types.d.ts +94 -0
- package/dist/src/bridge/types.js +2 -0
- package/dist/src/campaign.d.ts +141 -0
- package/dist/src/campaign.js +235 -0
- package/dist/src/channels.d.ts +15 -0
- package/dist/src/channels.js +20 -0
- package/dist/src/chronicle.d.ts +124 -0
- package/dist/src/chronicle.js +232 -0
- package/dist/src/collective-activities.d.ts +154 -0
- package/dist/src/collective-activities.js +247 -0
- package/dist/src/competence/acoustic.d.ts +101 -0
- package/dist/src/competence/acoustic.js +242 -0
- package/dist/src/competence/catalogue.d.ts +30 -0
- package/dist/src/competence/catalogue.js +241 -0
- package/dist/src/competence/crafting.d.ts +35 -0
- package/dist/src/competence/crafting.js +88 -0
- package/dist/src/competence/engineering.d.ts +53 -0
- package/dist/src/competence/engineering.js +108 -0
- package/dist/src/competence/framework.d.ts +68 -0
- package/dist/src/competence/framework.js +694 -0
- package/dist/src/competence/index.d.ts +12 -0
- package/dist/src/competence/index.js +13 -0
- package/dist/src/competence/interspecies.d.ts +81 -0
- package/dist/src/competence/interspecies.js +108 -0
- package/dist/src/competence/language.d.ts +79 -0
- package/dist/src/competence/language.js +115 -0
- package/dist/src/competence/naturalist.d.ts +97 -0
- package/dist/src/competence/naturalist.js +187 -0
- package/dist/src/competence/navigation.d.ts +24 -0
- package/dist/src/competence/navigation.js +48 -0
- package/dist/src/competence/performance.d.ts +125 -0
- package/dist/src/competence/performance.js +210 -0
- package/dist/src/competence/teaching.d.ts +64 -0
- package/dist/src/competence/teaching.js +121 -0
- package/dist/src/competence/willpower.d.ts +74 -0
- package/dist/src/competence/willpower.js +114 -0
- package/dist/src/crafting/index.d.ts +55 -0
- package/dist/src/crafting/index.js +229 -0
- package/dist/src/crafting/manufacturing.d.ts +83 -0
- package/dist/src/crafting/manufacturing.js +165 -0
- package/dist/src/crafting/materials.d.ts +53 -0
- package/dist/src/crafting/materials.js +120 -0
- package/dist/src/crafting/recipes.d.ts +75 -0
- package/dist/src/crafting/recipes.js +233 -0
- package/dist/src/crafting/workshops.d.ts +61 -0
- package/dist/src/crafting/workshops.js +170 -0
- package/dist/src/debug.d.ts +86 -0
- package/dist/src/debug.js +76 -0
- package/dist/src/derive.d.ts +21 -0
- package/dist/src/derive.js +88 -0
- package/dist/src/describe.d.ts +29 -0
- package/dist/src/describe.js +276 -0
- package/dist/src/dialogue.d.ts +122 -0
- package/dist/src/dialogue.js +266 -0
- package/dist/src/dist.d.ts +20 -0
- package/dist/src/dist.js +39 -0
- package/dist/src/downtime.d.ts +89 -0
- package/dist/src/downtime.js +391 -0
- package/dist/src/economy.d.ts +116 -0
- package/dist/src/economy.js +182 -0
- package/dist/src/emotional-contagion.d.ts +142 -0
- package/dist/src/emotional-contagion.js +274 -0
- package/dist/src/equipment.d.ts +206 -0
- package/dist/src/equipment.js +598 -0
- package/dist/src/faction.d.ts +102 -0
- package/dist/src/faction.js +237 -0
- package/dist/src/generate.d.ts +35 -0
- package/dist/src/generate.js +166 -0
- package/dist/src/index.d.ts +42 -0
- package/dist/src/index.js +54 -0
- package/dist/src/inheritance.d.ts +69 -0
- package/dist/src/inheritance.js +136 -0
- package/dist/src/inventory.d.ts +194 -0
- package/dist/src/inventory.js +637 -0
- package/dist/src/item-durability.d.ts +69 -0
- package/dist/src/item-durability.js +308 -0
- package/dist/src/legend.d.ts +97 -0
- package/dist/src/legend.js +269 -0
- package/dist/src/lod.d.ts +9 -0
- package/dist/src/lod.js +84 -0
- package/dist/src/metrics.d.ts +51 -0
- package/dist/src/metrics.js +91 -0
- package/dist/src/model3d.d.ts +138 -0
- package/dist/src/model3d.js +214 -0
- package/dist/src/mythology.d.ts +101 -0
- package/dist/src/mythology.js +308 -0
- package/dist/src/narrative-render.d.ts +42 -0
- package/dist/src/narrative-render.js +194 -0
- package/dist/src/narrative-stress.d.ts +123 -0
- package/dist/src/narrative-stress.js +183 -0
- package/dist/src/narrative.d.ts +44 -0
- package/dist/src/narrative.js +257 -0
- package/dist/src/party.d.ts +70 -0
- package/dist/src/party.js +226 -0
- package/dist/src/polity.d.ts +262 -0
- package/dist/src/polity.js +398 -0
- package/dist/src/presets.d.ts +42 -0
- package/dist/src/presets.js +170 -0
- package/dist/src/progression.d.ts +170 -0
- package/dist/src/progression.js +256 -0
- package/dist/src/quest-generators.d.ts +76 -0
- package/dist/src/quest-generators.js +534 -0
- package/dist/src/quest.d.ts +239 -0
- package/dist/src/quest.js +520 -0
- package/dist/src/relationships-effects.d.ts +75 -0
- package/dist/src/relationships-effects.js +219 -0
- package/dist/src/relationships.d.ts +104 -0
- package/dist/src/relationships.js +347 -0
- package/dist/src/replay.d.ts +47 -0
- package/dist/src/replay.js +82 -0
- package/dist/src/rng.d.ts +9 -0
- package/dist/src/rng.js +37 -0
- package/dist/src/settlement-services.d.ts +67 -0
- package/dist/src/settlement-services.js +267 -0
- package/dist/src/settlement.d.ts +143 -0
- package/dist/src/settlement.js +419 -0
- package/dist/src/sim/action.d.ts +28 -0
- package/dist/src/sim/action.js +12 -0
- package/dist/src/sim/aging.d.ts +95 -0
- package/dist/src/sim/aging.js +243 -0
- package/dist/src/sim/ai/decide.d.ts +10 -0
- package/dist/src/sim/ai/decide.js +267 -0
- package/dist/src/sim/ai/perception.d.ts +12 -0
- package/dist/src/sim/ai/perception.js +54 -0
- package/dist/src/sim/ai/personality.d.ts +54 -0
- package/dist/src/sim/ai/personality.js +202 -0
- package/dist/src/sim/ai/presets.d.ts +2 -0
- package/dist/src/sim/ai/presets.js +28 -0
- package/dist/src/sim/ai/system.d.ts +6 -0
- package/dist/src/sim/ai/system.js +13 -0
- package/dist/src/sim/ai/targeting.d.ts +8 -0
- package/dist/src/sim/ai/targeting.js +42 -0
- package/dist/src/sim/ai/types.d.ts +14 -0
- package/dist/src/sim/ai/types.js +1 -0
- package/dist/src/sim/body.d.ts +9 -0
- package/dist/src/sim/body.js +32 -0
- package/dist/src/sim/bodyplan.d.ts +161 -0
- package/dist/src/sim/bodyplan.js +677 -0
- package/dist/src/sim/capability.d.ts +135 -0
- package/dist/src/sim/capability.js +8 -0
- package/dist/src/sim/combat.d.ts +21 -0
- package/dist/src/sim/combat.js +77 -0
- package/dist/src/sim/commandBuilders.d.ts +11 -0
- package/dist/src/sim/commandBuilders.js +39 -0
- package/dist/src/sim/commands.d.ts +71 -0
- package/dist/src/sim/commands.js +8 -0
- package/dist/src/sim/condition.d.ts +35 -0
- package/dist/src/sim/condition.js +21 -0
- package/dist/src/sim/cone.d.ts +40 -0
- package/dist/src/sim/cone.js +44 -0
- package/dist/src/sim/context.d.ts +68 -0
- package/dist/src/sim/context.js +1 -0
- package/dist/src/sim/density.d.ts +14 -0
- package/dist/src/sim/density.js +33 -0
- package/dist/src/sim/disease.d.ts +141 -0
- package/dist/src/sim/disease.js +353 -0
- package/dist/src/sim/entity.d.ts +251 -0
- package/dist/src/sim/entity.js +19 -0
- package/dist/src/sim/events.d.ts +25 -0
- package/dist/src/sim/events.js +5 -0
- package/dist/src/sim/explosion.d.ts +40 -0
- package/dist/src/sim/explosion.js +40 -0
- package/dist/src/sim/formation-unit.d.ts +138 -0
- package/dist/src/sim/formation-unit.js +197 -0
- package/dist/src/sim/formation.d.ts +12 -0
- package/dist/src/sim/formation.js +54 -0
- package/dist/src/sim/frontage.d.ts +30 -0
- package/dist/src/sim/frontage.js +84 -0
- package/dist/src/sim/grapple.d.ts +100 -0
- package/dist/src/sim/grapple.js +480 -0
- package/dist/src/sim/hazard.d.ts +104 -0
- package/dist/src/sim/hazard.js +201 -0
- package/dist/src/sim/hydrostatic.d.ts +58 -0
- package/dist/src/sim/hydrostatic.js +117 -0
- package/dist/src/sim/impairment.d.ts +20 -0
- package/dist/src/sim/impairment.js +162 -0
- package/dist/src/sim/indexing.d.ts +7 -0
- package/dist/src/sim/indexing.js +7 -0
- package/dist/src/sim/injury.d.ts +54 -0
- package/dist/src/sim/injury.js +66 -0
- package/dist/src/sim/intent.d.ts +26 -0
- package/dist/src/sim/intent.js +7 -0
- package/dist/src/sim/kernel.d.ts +45 -0
- package/dist/src/sim/kernel.js +1992 -0
- package/dist/src/sim/kinds.d.ts +64 -0
- package/dist/src/sim/kinds.js +56 -0
- package/dist/src/sim/knockback.d.ts +50 -0
- package/dist/src/sim/knockback.js +82 -0
- package/dist/src/sim/limb.d.ts +48 -0
- package/dist/src/sim/limb.js +78 -0
- package/dist/src/sim/medical.d.ts +32 -0
- package/dist/src/sim/medical.js +33 -0
- package/dist/src/sim/morale.d.ts +69 -0
- package/dist/src/sim/morale.js +92 -0
- package/dist/src/sim/mount.d.ts +150 -0
- package/dist/src/sim/mount.js +225 -0
- package/dist/src/sim/nutrition.d.ts +74 -0
- package/dist/src/sim/nutrition.js +168 -0
- package/dist/src/sim/occlusion.d.ts +8 -0
- package/dist/src/sim/occlusion.js +71 -0
- package/dist/src/sim/push.d.ts +11 -0
- package/dist/src/sim/push.js +79 -0
- package/dist/src/sim/ranged.d.ts +44 -0
- package/dist/src/sim/ranged.js +69 -0
- package/dist/src/sim/seeds.d.ts +3 -0
- package/dist/src/sim/seeds.js +16 -0
- package/dist/src/sim/sensory-extended.d.ts +103 -0
- package/dist/src/sim/sensory-extended.js +181 -0
- package/dist/src/sim/sensory.d.ts +38 -0
- package/dist/src/sim/sensory.js +109 -0
- package/dist/src/sim/skills.d.ts +70 -0
- package/dist/src/sim/skills.js +69 -0
- package/dist/src/sim/sleep.d.ts +107 -0
- package/dist/src/sim/sleep.js +215 -0
- package/dist/src/sim/spatial.d.ts +8 -0
- package/dist/src/sim/spatial.js +59 -0
- package/dist/src/sim/step/capability.d.ts +8 -0
- package/dist/src/sim/step/capability.js +77 -0
- package/dist/src/sim/step/concentration.d.ts +9 -0
- package/dist/src/sim/step/concentration.js +25 -0
- package/dist/src/sim/step/effects.d.ts +17 -0
- package/dist/src/sim/step/effects.js +96 -0
- package/dist/src/sim/step/energy.d.ts +3 -0
- package/dist/src/sim/step/energy.js +31 -0
- package/dist/src/sim/step/hazards.d.ts +4 -0
- package/dist/src/sim/step/hazards.js +19 -0
- package/dist/src/sim/step/injury.d.ts +10 -0
- package/dist/src/sim/step/injury.js +353 -0
- package/dist/src/sim/step/morale.d.ts +11 -0
- package/dist/src/sim/step/morale.js +130 -0
- package/dist/src/sim/step/movement.d.ts +5 -0
- package/dist/src/sim/step/movement.js +172 -0
- package/dist/src/sim/step/push.d.ts +11 -0
- package/dist/src/sim/step/push.js +79 -0
- package/dist/src/sim/step/substances.d.ts +3 -0
- package/dist/src/sim/step/substances.js +75 -0
- package/dist/src/sim/substance.d.ts +38 -0
- package/dist/src/sim/substance.js +57 -0
- package/dist/src/sim/systemic-toxicology.d.ts +109 -0
- package/dist/src/sim/systemic-toxicology.js +263 -0
- package/dist/src/sim/team.d.ts +9 -0
- package/dist/src/sim/team.js +37 -0
- package/dist/src/sim/tech.d.ts +36 -0
- package/dist/src/sim/tech.js +46 -0
- package/dist/src/sim/terrain.d.ts +121 -0
- package/dist/src/sim/terrain.js +141 -0
- package/dist/src/sim/testing.d.ts +13 -0
- package/dist/src/sim/testing.js +100 -0
- package/dist/src/sim/thermoregulation.d.ts +77 -0
- package/dist/src/sim/thermoregulation.js +161 -0
- package/dist/src/sim/tick.d.ts +3 -0
- package/dist/src/sim/tick.js +3 -0
- package/dist/src/sim/toxicology.d.ts +52 -0
- package/dist/src/sim/toxicology.js +104 -0
- package/dist/src/sim/trace.d.ts +141 -0
- package/dist/src/sim/trace.js +1 -0
- package/dist/src/sim/tuning.d.ts +16 -0
- package/dist/src/sim/tuning.js +42 -0
- package/dist/src/sim/vec3.d.ts +14 -0
- package/dist/src/sim/vec3.js +31 -0
- package/dist/src/sim/weapon_dynamics.d.ts +102 -0
- package/dist/src/sim/weapon_dynamics.js +142 -0
- package/dist/src/sim/weather.d.ts +95 -0
- package/dist/src/sim/weather.js +105 -0
- package/dist/src/sim/world.d.ts +52 -0
- package/dist/src/sim/world.js +1 -0
- package/dist/src/sim/wound-aging.d.ts +120 -0
- package/dist/src/sim/wound-aging.js +223 -0
- package/dist/src/species.d.ts +106 -0
- package/dist/src/species.js +664 -0
- package/dist/src/story-arcs.d.ts +17 -0
- package/dist/src/story-arcs.js +276 -0
- package/dist/src/tech-diffusion.d.ts +80 -0
- package/dist/src/tech-diffusion.js +185 -0
- package/dist/src/traits.d.ts +25 -0
- package/dist/src/traits.js +178 -0
- package/dist/src/types.d.ts +117 -0
- package/dist/src/types.js +1 -0
- package/dist/src/units.d.ts +41 -0
- package/dist/src/units.js +64 -0
- package/dist/src/weapons.d.ts +20 -0
- package/dist/src/weapons.js +824 -0
- package/dist/src/world-generation.d.ts +52 -0
- package/dist/src/world-generation.js +301 -0
- package/package.json +74 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import type { Q } from "../units.js";
|
|
2
|
+
import type { Entity } from "../sim/entity.js";
|
|
3
|
+
/** Acoustic signature of an entity — how much noise it produces. */
|
|
4
|
+
export interface AcousticSignature {
|
|
5
|
+
/** Base noise level in arbitrary units (0 = silent, 100 = very loud). */
|
|
6
|
+
baseNoise: number;
|
|
7
|
+
/** Noise from movement (scales with velocity). */
|
|
8
|
+
movementNoise: number;
|
|
9
|
+
/** Noise from equipment (armour clanking, weapon swinging). */
|
|
10
|
+
equipmentNoise: number;
|
|
11
|
+
/** Total noise level (computed). */
|
|
12
|
+
totalNoise: number;
|
|
13
|
+
}
|
|
14
|
+
/** Formation signal types for military/organized coordination. */
|
|
15
|
+
export type FormationSignal = "advance" | "retreat" | "hold" | "flank_left" | "flank_right" | "rally";
|
|
16
|
+
/** Outcome of a formation signal transmission attempt. */
|
|
17
|
+
export interface FormationSignalOutcome {
|
|
18
|
+
/** Clarity of the signal (0–1). */
|
|
19
|
+
clarity_Q: Q;
|
|
20
|
+
/** Whether the signal was successfully received. */
|
|
21
|
+
received: boolean;
|
|
22
|
+
/** Latency in milliseconds before signal is understood. */
|
|
23
|
+
latency_ms: number;
|
|
24
|
+
}
|
|
25
|
+
/** Detection outcome for acoustic sensing. */
|
|
26
|
+
export interface AcousticDetectionOutcome {
|
|
27
|
+
/** Detection confidence (0–1). */
|
|
28
|
+
confidence_Q: Q;
|
|
29
|
+
/** Estimated direction in degrees (0–360, -1 if unknown). */
|
|
30
|
+
estimatedDirection_deg: number;
|
|
31
|
+
/** Estimated distance in metres (-1 if unknown). */
|
|
32
|
+
estimatedDistance_m: number;
|
|
33
|
+
/** Whether detection is certain enough to act on. */
|
|
34
|
+
detected: boolean;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Derive the acoustic signature of an entity.
|
|
38
|
+
*
|
|
39
|
+
* Formula:
|
|
40
|
+
* baseNoise = 50 (normal human movement)
|
|
41
|
+
* stealth reduces baseNoise: base × (1 − stealth × 0.60)
|
|
42
|
+
* movementNoise = velocity_mps × 10
|
|
43
|
+
* equipmentNoise = based on armour material and weapon mass
|
|
44
|
+
*
|
|
45
|
+
* @param entity - The entity to analyze.
|
|
46
|
+
* @returns Acoustic signature with all noise components.
|
|
47
|
+
*/
|
|
48
|
+
export declare function deriveAcousticSignature(entity: Entity): AcousticSignature;
|
|
49
|
+
/**
|
|
50
|
+
* Detect an acoustic signature.
|
|
51
|
+
*
|
|
52
|
+
* Formula:
|
|
53
|
+
* detection_Q = clamp(sourceNoise / dist_m × listener.musical × SCALE_ACOUSTIC, 0, 1)
|
|
54
|
+
*
|
|
55
|
+
* Higher sourceNoise = easier to detect.
|
|
56
|
+
* Higher listener musical intelligence = better detection.
|
|
57
|
+
* Distance degrades detection linearly.
|
|
58
|
+
*
|
|
59
|
+
* @param listener - The entity attempting to detect.
|
|
60
|
+
* @param source - The entity producing sound.
|
|
61
|
+
* @param dist_m - Distance between entities in metres.
|
|
62
|
+
* @returns Detection confidence and metadata.
|
|
63
|
+
*/
|
|
64
|
+
export declare function detectAcousticSignature(listener: Entity, source: Entity, dist_m: number): AcousticDetectionOutcome;
|
|
65
|
+
/**
|
|
66
|
+
* Resolve a formation signal transmission.
|
|
67
|
+
*
|
|
68
|
+
* Used for military coordination: drums, horns, whistles, shouted commands.
|
|
69
|
+
*
|
|
70
|
+
* Formula:
|
|
71
|
+
* clarity_Q = musical(signaller) × musical(listener) × rangeFactor(dist_m)
|
|
72
|
+
* received = clarity_Q >= SIGNAL_RECEPTION_THRESHOLD
|
|
73
|
+
* latency_ms = BASE_LATENCY_MS × (1 − avgMusical × 0.50)
|
|
74
|
+
*
|
|
75
|
+
* Satyr signaller (0.95) → Elf listeners (0.85) → near-perfect reception at long range.
|
|
76
|
+
* Troll → Troll → commands degrade rapidly beyond a few metres.
|
|
77
|
+
*
|
|
78
|
+
* @param signaller - The entity sending the signal.
|
|
79
|
+
* @param signal - The formation signal type.
|
|
80
|
+
* @param listener - The entity receiving the signal.
|
|
81
|
+
* @param dist_m - Distance between entities in metres.
|
|
82
|
+
* @returns Signal outcome with clarity and reception status.
|
|
83
|
+
*/
|
|
84
|
+
export declare function resolveFormationSignal(signaller: Entity, signal: FormationSignal, listener: Entity, dist_m: number): FormationSignalOutcome;
|
|
85
|
+
/**
|
|
86
|
+
* Check if an entity can effectively use formation signals.
|
|
87
|
+
* Requires minimum musical intelligence to produce clear signals.
|
|
88
|
+
*
|
|
89
|
+
* @param entity - The potential signaller.
|
|
90
|
+
* @param minMusical - Minimum musical intelligence required (default q(0.40)).
|
|
91
|
+
* @returns True if entity can serve as a signaller.
|
|
92
|
+
*/
|
|
93
|
+
export declare function canUseFormationSignals(entity: Entity, minMusical?: Q): boolean;
|
|
94
|
+
/**
|
|
95
|
+
* Calculate maximum effective signal range for a signaller.
|
|
96
|
+
*
|
|
97
|
+
* @param signaller - The entity sending signals.
|
|
98
|
+
* @param minClarity - Minimum clarity required for reception (default q(0.40)).
|
|
99
|
+
* @returns Maximum range in metres.
|
|
100
|
+
*/
|
|
101
|
+
export declare function calculateSignalRange(signaller: Entity, minClarity?: Q): number;
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
// src/competence/acoustic.ts — Phase 39: Musical Intelligence & Acoustic Systems
|
|
2
|
+
//
|
|
3
|
+
// Musical intelligence governs cognition in the time-acoustic domain:
|
|
4
|
+
// - Recognition of rhythmic patterns and sound cues
|
|
5
|
+
// - Formation signal interpretation (drums, horns)
|
|
6
|
+
// - Acoustic detection and stealth counter-detection
|
|
7
|
+
//
|
|
8
|
+
// No kernel import — pure resolution module.
|
|
9
|
+
import { SCALE, q, clampQ, mulDiv } from "../units.js";
|
|
10
|
+
// ── Constants ─────────────────────────────────────────────────────────────────
|
|
11
|
+
/** Scale factor for acoustic detection formula. */
|
|
12
|
+
const SCALE_ACOUSTIC = 100; // multiplier to get useful detection ranges
|
|
13
|
+
/** Base detection range in metres at average musical intelligence. */
|
|
14
|
+
const BASE_DETECTION_RANGE_m = 50;
|
|
15
|
+
/** Maximum effective detection range. */
|
|
16
|
+
const MAX_DETECTION_RANGE_m = 500;
|
|
17
|
+
/** Range factor: clarity degrades with distance. */
|
|
18
|
+
const RANGE_DEGRADATION_PER_METER = 0.002; // 0.2% per metre
|
|
19
|
+
/** Threshold for successful signal reception. */
|
|
20
|
+
const SIGNAL_RECEPTION_THRESHOLD = q(0.40);
|
|
21
|
+
/** Base latency for signal interpretation in milliseconds. */
|
|
22
|
+
const BASE_SIGNAL_LATENCY_MS = 200;
|
|
23
|
+
/** Latency reduction from high musical intelligence. */
|
|
24
|
+
const MUSICAL_LATENCY_REDUCTION_FACTOR = 0.5; // up to 50% faster
|
|
25
|
+
// Noise level constants
|
|
26
|
+
const NOISE_SILENT = 0;
|
|
27
|
+
const NOISE_VERY_QUIET = 10;
|
|
28
|
+
const NOISE_QUIET = 25;
|
|
29
|
+
const NOISE_NORMAL = 50;
|
|
30
|
+
const NOISE_LOUD = 75;
|
|
31
|
+
const NOISE_VERY_LOUD = 100;
|
|
32
|
+
// ── Helpers ───────────────────────────────────────────────────────────────────
|
|
33
|
+
/**
|
|
34
|
+
* Get stealth skill value from entity (0 if not present).
|
|
35
|
+
* Higher stealth = lower noise.
|
|
36
|
+
*/
|
|
37
|
+
function getStealthValue(entity) {
|
|
38
|
+
// Check for stealth in skills map
|
|
39
|
+
const stealthSkill = entity.skills?.get("stealth");
|
|
40
|
+
if (stealthSkill !== undefined) {
|
|
41
|
+
// Convert SkillLevel to Q (SkillLevel is already a Q-encoded value)
|
|
42
|
+
return stealthSkill;
|
|
43
|
+
}
|
|
44
|
+
// Default: average stealth
|
|
45
|
+
return q(0.50);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Calculate equipment noise based on armour type.
|
|
49
|
+
*/
|
|
50
|
+
function calculateEquipmentNoise(entity) {
|
|
51
|
+
let noise = NOISE_NORMAL; // base walking noise
|
|
52
|
+
// Process all items in loadout
|
|
53
|
+
for (const item of entity.loadout.items) {
|
|
54
|
+
// Armour adds noise based on material
|
|
55
|
+
if (item.kind === "armour") {
|
|
56
|
+
const armour = item;
|
|
57
|
+
if (armour.material === "metal") {
|
|
58
|
+
noise += 15; // clanking
|
|
59
|
+
}
|
|
60
|
+
else if (armour.material === "leather") {
|
|
61
|
+
noise += 5; // creaking
|
|
62
|
+
}
|
|
63
|
+
// fabric/cloth is silent
|
|
64
|
+
}
|
|
65
|
+
// Weapons add noise when moved
|
|
66
|
+
if (item.kind === "weapon") {
|
|
67
|
+
const weapon = item;
|
|
68
|
+
if (weapon.mass_kg > 2000) { // heavy weapons
|
|
69
|
+
noise += 10;
|
|
70
|
+
}
|
|
71
|
+
else if (weapon.mass_kg > 1000) {
|
|
72
|
+
noise += 5;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return Math.min(NOISE_VERY_LOUD, noise);
|
|
77
|
+
}
|
|
78
|
+
// ── Public API ────────────────────────────────────────────────────────────────
|
|
79
|
+
/**
|
|
80
|
+
* Derive the acoustic signature of an entity.
|
|
81
|
+
*
|
|
82
|
+
* Formula:
|
|
83
|
+
* baseNoise = 50 (normal human movement)
|
|
84
|
+
* stealth reduces baseNoise: base × (1 − stealth × 0.60)
|
|
85
|
+
* movementNoise = velocity_mps × 10
|
|
86
|
+
* equipmentNoise = based on armour material and weapon mass
|
|
87
|
+
*
|
|
88
|
+
* @param entity - The entity to analyze.
|
|
89
|
+
* @returns Acoustic signature with all noise components.
|
|
90
|
+
*/
|
|
91
|
+
export function deriveAcousticSignature(entity) {
|
|
92
|
+
// Base noise level
|
|
93
|
+
let baseNoise = NOISE_NORMAL;
|
|
94
|
+
// Stealth reduces base noise
|
|
95
|
+
const stealth = getStealthValue(entity);
|
|
96
|
+
const stealthReduction = mulDiv(stealth, q(0.60), SCALE.Q) / SCALE.Q;
|
|
97
|
+
baseNoise = Math.round(baseNoise * (1 - stealthReduction));
|
|
98
|
+
// Movement noise from velocity
|
|
99
|
+
const velocity = Math.sqrt(entity.velocity_mps.x ** 2 +
|
|
100
|
+
entity.velocity_mps.y ** 2 +
|
|
101
|
+
entity.velocity_mps.z ** 2) / SCALE.mps; // convert to m/s
|
|
102
|
+
const movementNoise = Math.round(velocity * 10);
|
|
103
|
+
// Equipment noise
|
|
104
|
+
const equipmentNoise = calculateEquipmentNoise(entity);
|
|
105
|
+
// Total noise
|
|
106
|
+
const totalNoise = Math.min(NOISE_VERY_LOUD, baseNoise + movementNoise + equipmentNoise);
|
|
107
|
+
return {
|
|
108
|
+
baseNoise,
|
|
109
|
+
movementNoise,
|
|
110
|
+
equipmentNoise,
|
|
111
|
+
totalNoise,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Detect an acoustic signature.
|
|
116
|
+
*
|
|
117
|
+
* Formula:
|
|
118
|
+
* detection_Q = clamp(sourceNoise / dist_m × listener.musical × SCALE_ACOUSTIC, 0, 1)
|
|
119
|
+
*
|
|
120
|
+
* Higher sourceNoise = easier to detect.
|
|
121
|
+
* Higher listener musical intelligence = better detection.
|
|
122
|
+
* Distance degrades detection linearly.
|
|
123
|
+
*
|
|
124
|
+
* @param listener - The entity attempting to detect.
|
|
125
|
+
* @param source - The entity producing sound.
|
|
126
|
+
* @param dist_m - Distance between entities in metres.
|
|
127
|
+
* @returns Detection confidence and metadata.
|
|
128
|
+
*/
|
|
129
|
+
export function detectAcousticSignature(listener, source, dist_m) {
|
|
130
|
+
const musical = (listener.attributes.cognition?.musical ?? q(0.50));
|
|
131
|
+
// Get source noise
|
|
132
|
+
const signature = deriveAcousticSignature(source);
|
|
133
|
+
const sourceNoise = signature.totalNoise;
|
|
134
|
+
// Distance factor: detection degrades with distance
|
|
135
|
+
const distanceFactor = Math.max(0, 1 - dist_m * RANGE_DEGRADATION_PER_METER);
|
|
136
|
+
// Detection formula
|
|
137
|
+
const musicalNorm = musical / SCALE.Q; // 0-1
|
|
138
|
+
const rawDetection = (sourceNoise / 100) * distanceFactor * musicalNorm * SCALE_ACOUSTIC;
|
|
139
|
+
// Clamp to valid Q range
|
|
140
|
+
const confidence_Q = clampQ(Math.round(rawDetection * SCALE.Q), q(0), SCALE.Q);
|
|
141
|
+
// Detection threshold
|
|
142
|
+
const detected = confidence_Q >= q(0.30);
|
|
143
|
+
// Estimate direction (simplified: assume we can determine direction if confidence is high)
|
|
144
|
+
let estimatedDirection_deg = -1;
|
|
145
|
+
let estimatedDistance_m = -1;
|
|
146
|
+
if (confidence_Q >= q(0.50)) {
|
|
147
|
+
// Can estimate distance with moderate accuracy
|
|
148
|
+
estimatedDistance_m = Math.round(dist_m * (0.8 + Math.random() * 0.4));
|
|
149
|
+
}
|
|
150
|
+
if (confidence_Q >= q(0.70)) {
|
|
151
|
+
// Can determine direction (in a real implementation, would compute from positions)
|
|
152
|
+
estimatedDirection_deg = Math.floor(Math.random() * 360);
|
|
153
|
+
}
|
|
154
|
+
return {
|
|
155
|
+
confidence_Q,
|
|
156
|
+
estimatedDirection_deg,
|
|
157
|
+
estimatedDistance_m,
|
|
158
|
+
detected,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Resolve a formation signal transmission.
|
|
163
|
+
*
|
|
164
|
+
* Used for military coordination: drums, horns, whistles, shouted commands.
|
|
165
|
+
*
|
|
166
|
+
* Formula:
|
|
167
|
+
* clarity_Q = musical(signaller) × musical(listener) × rangeFactor(dist_m)
|
|
168
|
+
* received = clarity_Q >= SIGNAL_RECEPTION_THRESHOLD
|
|
169
|
+
* latency_ms = BASE_LATENCY_MS × (1 − avgMusical × 0.50)
|
|
170
|
+
*
|
|
171
|
+
* Satyr signaller (0.95) → Elf listeners (0.85) → near-perfect reception at long range.
|
|
172
|
+
* Troll → Troll → commands degrade rapidly beyond a few metres.
|
|
173
|
+
*
|
|
174
|
+
* @param signaller - The entity sending the signal.
|
|
175
|
+
* @param signal - The formation signal type.
|
|
176
|
+
* @param listener - The entity receiving the signal.
|
|
177
|
+
* @param dist_m - Distance between entities in metres.
|
|
178
|
+
* @returns Signal outcome with clarity and reception status.
|
|
179
|
+
*/
|
|
180
|
+
export function resolveFormationSignal(signaller, signal, listener, dist_m) {
|
|
181
|
+
const signallerMusical = (signaller.attributes.cognition?.musical ?? q(0.50));
|
|
182
|
+
const listenerMusical = (listener.attributes.cognition?.musical ?? q(0.50));
|
|
183
|
+
// Range factor degrades with distance
|
|
184
|
+
const rangeFactor = Math.max(0, 1 - dist_m * RANGE_DEGRADATION_PER_METER * 0.5); // slower degradation for intentional signals
|
|
185
|
+
// Musical product (both need musical intelligence for clear transmission)
|
|
186
|
+
const signallerNorm = signallerMusical / SCALE.Q;
|
|
187
|
+
const listenerNorm = listenerMusical / SCALE.Q;
|
|
188
|
+
const musicalProduct = signallerNorm * listenerNorm;
|
|
189
|
+
// Clarity calculation
|
|
190
|
+
const rawClarity = musicalProduct * rangeFactor * SCALE_ACOUSTIC / 100;
|
|
191
|
+
const clarity_Q = clampQ(Math.round(rawClarity * SCALE.Q), q(0), SCALE.Q);
|
|
192
|
+
// Reception check
|
|
193
|
+
const received = clarity_Q >= SIGNAL_RECEPTION_THRESHOLD;
|
|
194
|
+
// Latency: better musical intelligence = faster interpretation
|
|
195
|
+
const avgMusical = (signallerNorm + listenerNorm) / 2;
|
|
196
|
+
const latencyReduction = avgMusical * MUSICAL_LATENCY_REDUCTION_FACTOR;
|
|
197
|
+
const latency_ms = Math.round(BASE_SIGNAL_LATENCY_MS * (1 - latencyReduction));
|
|
198
|
+
return {
|
|
199
|
+
clarity_Q,
|
|
200
|
+
received,
|
|
201
|
+
latency_ms,
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Check if an entity can effectively use formation signals.
|
|
206
|
+
* Requires minimum musical intelligence to produce clear signals.
|
|
207
|
+
*
|
|
208
|
+
* @param entity - The potential signaller.
|
|
209
|
+
* @param minMusical - Minimum musical intelligence required (default q(0.40)).
|
|
210
|
+
* @returns True if entity can serve as a signaller.
|
|
211
|
+
*/
|
|
212
|
+
export function canUseFormationSignals(entity, minMusical = q(0.40)) {
|
|
213
|
+
const musical = (entity.attributes.cognition?.musical ?? q(0.50));
|
|
214
|
+
return musical >= minMusical;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Calculate maximum effective signal range for a signaller.
|
|
218
|
+
*
|
|
219
|
+
* @param signaller - The entity sending signals.
|
|
220
|
+
* @param minClarity - Minimum clarity required for reception (default q(0.40)).
|
|
221
|
+
* @returns Maximum range in metres.
|
|
222
|
+
*/
|
|
223
|
+
export function calculateSignalRange(signaller, minClarity = q(0.40)) {
|
|
224
|
+
const signallerMusical = (signaller.attributes.cognition?.musical ?? q(0.50));
|
|
225
|
+
const musicalNorm = signallerMusical / SCALE.Q;
|
|
226
|
+
// clarity = musicalProduct * rangeFactor * SCALE_ACOUSTIC / SCALE.Q
|
|
227
|
+
// At distance 0, rangeFactor = 1, so maxClarity = musicalProduct * SCALE_ACOUSTIC / SCALE.Q
|
|
228
|
+
// Assuming average listener (musical = 0.50)
|
|
229
|
+
const listenerNorm = 0.50;
|
|
230
|
+
const musicalProduct = musicalNorm * listenerNorm;
|
|
231
|
+
// Max possible clarity at point-blank
|
|
232
|
+
const maxClarity = musicalProduct * SCALE_ACOUSTIC; // This gives 0-100 range
|
|
233
|
+
const minClarityNorm = minClarity / SCALE.Q; // Convert Q to 0-1
|
|
234
|
+
if (maxClarity < minClarityNorm * 100) {
|
|
235
|
+
return 0; // Cannot reach minimum clarity even at point-blank
|
|
236
|
+
}
|
|
237
|
+
// minClarityNorm = musicalProduct * (1 - dist * degradation * 0.5) * SCALE_ACOUSTIC / SCALE.Q
|
|
238
|
+
// Solve for dist where clarity = minClarity
|
|
239
|
+
const requiredRatio = (minClarityNorm * 100) / (musicalProduct * SCALE_ACOUSTIC);
|
|
240
|
+
const maxDist = (1 - requiredRatio) / (RANGE_DEGRADATION_PER_METER * 0.5);
|
|
241
|
+
return Math.min(MAX_DETECTION_RANGE_m, Math.round(maxDist));
|
|
242
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Q } from "../units.js";
|
|
2
|
+
/** Domain of competence — maps to cognitive intelligence types. */
|
|
3
|
+
export type CompetenceDomain = "linguistic" | "logicalMathematical" | "spatial" | "bodilyKinesthetic" | "musical" | "interpersonal" | "intrapersonal" | "naturalist" | "interSpecies";
|
|
4
|
+
/** A single competence task definition. */
|
|
5
|
+
export interface CompetenceTask {
|
|
6
|
+
/** Unique task identifier. */
|
|
7
|
+
taskId: string;
|
|
8
|
+
/** Primary competence domain. */
|
|
9
|
+
domain: CompetenceDomain;
|
|
10
|
+
/** Secondary domain (optional, for compound tasks). */
|
|
11
|
+
secondaryDomain?: CompetenceDomain;
|
|
12
|
+
/** Difficulty rating (0–1). */
|
|
13
|
+
difficulty_Q: Q;
|
|
14
|
+
/** Base time required in seconds. */
|
|
15
|
+
timeBase_s: number;
|
|
16
|
+
/** Required tool/equipment (optional). */
|
|
17
|
+
requiredTool?: string;
|
|
18
|
+
/** Human-readable description. */
|
|
19
|
+
description: string;
|
|
20
|
+
}
|
|
21
|
+
/** Read-only catalogue of all competence tasks. */
|
|
22
|
+
export declare const COMPETENCE_CATALOGUE: readonly CompetenceTask[];
|
|
23
|
+
/** Lookup map for taskId → task. */
|
|
24
|
+
export declare const COMPETENCE_TASK_BY_ID: ReadonlyMap<string, CompetenceTask>;
|
|
25
|
+
/** Get a task by ID. Returns undefined if not found. */
|
|
26
|
+
export declare function getTaskById(taskId: string): CompetenceTask | undefined;
|
|
27
|
+
/** Check if a task exists in the catalogue. */
|
|
28
|
+
export declare function hasTask(taskId: string): boolean;
|
|
29
|
+
/** Get all tasks for a specific domain. */
|
|
30
|
+
export declare function getTasksByDomain(domain: CompetenceDomain): CompetenceTask[];
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
// src/competence/catalogue.ts — Phase 40: Competence Catalogue
|
|
2
|
+
//
|
|
3
|
+
// Predefined competence tasks with difficulty, time requirements, and domain.
|
|
4
|
+
// Parallel to weapons and food catalogues.
|
|
5
|
+
import { q } from "../units.js";
|
|
6
|
+
// ── Catalogue Entries ─────────────────────────────────────────────────────────
|
|
7
|
+
const entries = [
|
|
8
|
+
// ── Bodily-Kinesthetic (crafting, physical skill) ────────────────────────────
|
|
9
|
+
{
|
|
10
|
+
taskId: "craft_sword_basic",
|
|
11
|
+
domain: "bodilyKinesthetic",
|
|
12
|
+
difficulty_Q: q(0.40),
|
|
13
|
+
timeBase_s: 14400, // 4 hours
|
|
14
|
+
requiredTool: "forge",
|
|
15
|
+
description: "Forge a basic serviceable sword",
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
taskId: "craft_sword_master",
|
|
19
|
+
domain: "bodilyKinesthetic",
|
|
20
|
+
difficulty_Q: q(0.85),
|
|
21
|
+
timeBase_s: 28800, // 8 hours
|
|
22
|
+
requiredTool: "forge",
|
|
23
|
+
description: "Forge a masterwork sword",
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
taskId: "treat_wound_field",
|
|
27
|
+
domain: "bodilyKinesthetic",
|
|
28
|
+
difficulty_Q: q(0.50),
|
|
29
|
+
timeBase_s: 300, // 5 minutes
|
|
30
|
+
requiredTool: "medical_kit",
|
|
31
|
+
description: "Field treatment of bleeding wound",
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
taskId: "perform_surgery",
|
|
35
|
+
domain: "bodilyKinesthetic",
|
|
36
|
+
difficulty_Q: q(0.75),
|
|
37
|
+
timeBase_s: 3600, // 1 hour
|
|
38
|
+
requiredTool: "surgical_kit",
|
|
39
|
+
description: "Surgical repair of internal injuries",
|
|
40
|
+
},
|
|
41
|
+
// ── Spatial (navigation, wayfinding) ────────────────────────────────────────
|
|
42
|
+
{
|
|
43
|
+
taskId: "navigate_wilderness",
|
|
44
|
+
domain: "spatial",
|
|
45
|
+
difficulty_Q: q(0.50),
|
|
46
|
+
timeBase_s: 3600, // per hour of travel
|
|
47
|
+
description: "Navigate through untracked wilderness",
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
taskId: "navigate_urban",
|
|
51
|
+
domain: "spatial",
|
|
52
|
+
difficulty_Q: q(0.30),
|
|
53
|
+
timeBase_s: 600, // 10 minutes
|
|
54
|
+
description: "Find route through complex urban environment",
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
taskId: "read_map",
|
|
58
|
+
domain: "spatial",
|
|
59
|
+
difficulty_Q: q(0.25),
|
|
60
|
+
timeBase_s: 60, // 1 minute
|
|
61
|
+
requiredTool: "map",
|
|
62
|
+
description: "Interpret map and locate position",
|
|
63
|
+
},
|
|
64
|
+
// ── Naturalist (tracking, foraging, animal handling) ─────────────────────────
|
|
65
|
+
{
|
|
66
|
+
taskId: "track_quarry_fresh",
|
|
67
|
+
domain: "naturalist",
|
|
68
|
+
difficulty_Q: q(0.30),
|
|
69
|
+
timeBase_s: 1800, // 30 minutes
|
|
70
|
+
description: "Track quarry with fresh trail (< 1 hour)",
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
taskId: "track_quarry_aged",
|
|
74
|
+
domain: "naturalist",
|
|
75
|
+
difficulty_Q: q(0.60),
|
|
76
|
+
timeBase_s: 3600, // 1 hour
|
|
77
|
+
description: "Track quarry with aged trail (> 1 day)",
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
taskId: "forage_herbs",
|
|
81
|
+
domain: "naturalist",
|
|
82
|
+
difficulty_Q: q(0.35),
|
|
83
|
+
timeBase_s: 3600, // 1 hour
|
|
84
|
+
description: "Search for medicinal herbs",
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
taskId: "identify_herb",
|
|
88
|
+
domain: "naturalist",
|
|
89
|
+
difficulty_Q: q(0.25),
|
|
90
|
+
timeBase_s: 60, // 1 minute
|
|
91
|
+
description: "Identify unknown plant and properties",
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
taskId: "tame_horse",
|
|
95
|
+
domain: "naturalist",
|
|
96
|
+
secondaryDomain: "interSpecies",
|
|
97
|
+
difficulty_Q: q(0.40),
|
|
98
|
+
timeBase_s: 7200, // 2 hours per session
|
|
99
|
+
description: "Build trust with untrained horse",
|
|
100
|
+
},
|
|
101
|
+
// ── Inter-Species (communication across species boundaries) ───────────────────
|
|
102
|
+
{
|
|
103
|
+
taskId: "signal_alien_species",
|
|
104
|
+
domain: "interSpecies",
|
|
105
|
+
difficulty_Q: q(0.60),
|
|
106
|
+
timeBase_s: 300, // 5 minutes
|
|
107
|
+
description: "Attempt first-contact communication with unknown species",
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
taskId: "calm_agitated_beast",
|
|
111
|
+
domain: "interSpecies",
|
|
112
|
+
difficulty_Q: q(0.55),
|
|
113
|
+
timeBase_s: 600, // 10 minutes
|
|
114
|
+
description: "Calm frightened or aggressive animal",
|
|
115
|
+
},
|
|
116
|
+
// ── Linguistic (language, communication) ─────────────────────────────────────
|
|
117
|
+
{
|
|
118
|
+
taskId: "negotiate_treaty",
|
|
119
|
+
domain: "linguistic",
|
|
120
|
+
secondaryDomain: "interpersonal",
|
|
121
|
+
difficulty_Q: q(0.70),
|
|
122
|
+
timeBase_s: 1800, // 30 minutes
|
|
123
|
+
description: "Negotiate terms between conflicting parties",
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
taskId: "translate_foreign",
|
|
127
|
+
domain: "linguistic",
|
|
128
|
+
difficulty_Q: q(0.50),
|
|
129
|
+
timeBase_s: 3600, // 1 hour per page
|
|
130
|
+
requiredTool: "reference_texts",
|
|
131
|
+
description: "Translate unfamiliar language",
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
taskId: "command_formation",
|
|
135
|
+
domain: "linguistic",
|
|
136
|
+
difficulty_Q: q(0.40),
|
|
137
|
+
timeBase_s: 60, // 1 minute
|
|
138
|
+
description: "Issue clear commands to military formation",
|
|
139
|
+
},
|
|
140
|
+
// ── Interpersonal (teaching, leadership, empathy) ────────────────────────────
|
|
141
|
+
{
|
|
142
|
+
taskId: "teach_skill",
|
|
143
|
+
domain: "interpersonal",
|
|
144
|
+
difficulty_Q: q(0.45),
|
|
145
|
+
timeBase_s: 3600, // 1 hour lesson
|
|
146
|
+
description: "Teach specific skill to student",
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
taskId: "rally_troops",
|
|
150
|
+
domain: "interpersonal",
|
|
151
|
+
difficulty_Q: q(0.55),
|
|
152
|
+
timeBase_s: 300, // 5 minutes
|
|
153
|
+
description: "Rally frightened troops back to combat readiness",
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
taskId: "detect_deception",
|
|
157
|
+
domain: "interpersonal",
|
|
158
|
+
difficulty_Q: q(0.50),
|
|
159
|
+
timeBase_s: 60, // 1 minute during conversation
|
|
160
|
+
description: "Detect lies and falsehoods in conversation",
|
|
161
|
+
},
|
|
162
|
+
// ── Logical-Mathematical (engineering, planning, analysis) ────────────────────
|
|
163
|
+
{
|
|
164
|
+
taskId: "design_fortification",
|
|
165
|
+
domain: "logicalMathematical",
|
|
166
|
+
difficulty_Q: q(0.60),
|
|
167
|
+
timeBase_s: 86400, // 1 day
|
|
168
|
+
requiredTool: "drafting_tools",
|
|
169
|
+
description: "Engineer defensive fortification plans",
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
taskId: "design_siege_engine",
|
|
173
|
+
domain: "logicalMathematical",
|
|
174
|
+
difficulty_Q: q(0.75),
|
|
175
|
+
timeBase_s: 172800, // 2 days
|
|
176
|
+
requiredTool: "drafting_tools",
|
|
177
|
+
description: "Design complex siege machinery",
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
taskId: "solve_tactical_puzzle",
|
|
181
|
+
domain: "logicalMathematical",
|
|
182
|
+
difficulty_Q: q(0.55),
|
|
183
|
+
timeBase_s: 1800, // 30 minutes
|
|
184
|
+
description: "Analyze tactical situation and propose solution",
|
|
185
|
+
},
|
|
186
|
+
// ── Musical (performance, signaling) ─────────────────────────────────────────
|
|
187
|
+
{
|
|
188
|
+
taskId: "compose_march",
|
|
189
|
+
domain: "musical",
|
|
190
|
+
difficulty_Q: q(0.35),
|
|
191
|
+
timeBase_s: 1800, // 30 minutes
|
|
192
|
+
description: "Compose military marching cadence",
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
taskId: "perform_morale",
|
|
196
|
+
domain: "musical",
|
|
197
|
+
difficulty_Q: q(0.45),
|
|
198
|
+
timeBase_s: 1800, // 30 minutes performance
|
|
199
|
+
description: "Musical performance to boost morale",
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
taskId: "signal_formation",
|
|
203
|
+
domain: "musical",
|
|
204
|
+
difficulty_Q: q(0.30),
|
|
205
|
+
timeBase_s: 10, // 10 seconds
|
|
206
|
+
requiredTool: "signal_horn_or_drum",
|
|
207
|
+
description: "Signal formation maneuver via horn/drum",
|
|
208
|
+
},
|
|
209
|
+
// ── Intrapersonal (meditation, willpower) ────────────────────────────────────
|
|
210
|
+
{
|
|
211
|
+
taskId: "meditate_focus",
|
|
212
|
+
domain: "intrapersonal",
|
|
213
|
+
difficulty_Q: q(0.25),
|
|
214
|
+
timeBase_s: 1800, // 30 minutes
|
|
215
|
+
description: "Meditation to restore willpower",
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
taskId: "resist_temptation",
|
|
219
|
+
domain: "intrapersonal",
|
|
220
|
+
difficulty_Q: q(0.50),
|
|
221
|
+
timeBase_s: 60, // 1 minute decision point
|
|
222
|
+
description: "Resist immediate temptation for long-term gain",
|
|
223
|
+
},
|
|
224
|
+
];
|
|
225
|
+
// ── Exported Catalogue ───────────────────────────────────────────────────────
|
|
226
|
+
/** Read-only catalogue of all competence tasks. */
|
|
227
|
+
export const COMPETENCE_CATALOGUE = Object.freeze(entries);
|
|
228
|
+
/** Lookup map for taskId → task. */
|
|
229
|
+
export const COMPETENCE_TASK_BY_ID = new Map(entries.map((e) => [e.taskId, e]));
|
|
230
|
+
/** Get a task by ID. Returns undefined if not found. */
|
|
231
|
+
export function getTaskById(taskId) {
|
|
232
|
+
return COMPETENCE_TASK_BY_ID.get(taskId);
|
|
233
|
+
}
|
|
234
|
+
/** Check if a task exists in the catalogue. */
|
|
235
|
+
export function hasTask(taskId) {
|
|
236
|
+
return COMPETENCE_TASK_BY_ID.has(taskId);
|
|
237
|
+
}
|
|
238
|
+
/** Get all tasks for a specific domain. */
|
|
239
|
+
export function getTasksByDomain(domain) {
|
|
240
|
+
return entries.filter((t) => t.domain === domain || t.secondaryDomain === domain);
|
|
241
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { Q } from "../units.js";
|
|
2
|
+
import type { Entity } from "../sim/entity.js";
|
|
3
|
+
export interface CraftingSpec {
|
|
4
|
+
outputId: string;
|
|
5
|
+
toolCategory?: "bladed" | "blunt" | "needlework" | "forge" | "precision";
|
|
6
|
+
/** Base seconds for a bodilyKinesthetic q(0.50) entity. */
|
|
7
|
+
baseTime_s: number;
|
|
8
|
+
/** Raw material quality 0–1 (Q-encoded). */
|
|
9
|
+
materialQ: Q;
|
|
10
|
+
/** Minimum bodilyKinesthetic required to attempt; below → success=false. */
|
|
11
|
+
minBKQ: Q;
|
|
12
|
+
}
|
|
13
|
+
export interface CraftingOutcome {
|
|
14
|
+
quality_Q: Q;
|
|
15
|
+
timeTaken_s: number;
|
|
16
|
+
success: boolean;
|
|
17
|
+
descriptor: "masterwork" | "fine" | "adequate" | "poor" | "ruined";
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Resolve a crafting attempt.
|
|
21
|
+
*
|
|
22
|
+
* @param entity - The crafter; uses `cognition.bodilyKinesthetic` and `control.fineControl`.
|
|
23
|
+
* @param spec - Crafting specification.
|
|
24
|
+
* @param seed - Deterministic seed (e.g. from eventSeed()).
|
|
25
|
+
*/
|
|
26
|
+
export declare function resolveCrafting(entity: Entity, spec: CraftingSpec, seed: number): CraftingOutcome;
|
|
27
|
+
/**
|
|
28
|
+
* Phase 34: compute surgical precision multiplier from surgeon's bodilyKinesthetic.
|
|
29
|
+
* Result: lerp(q(0.70), q(1.30), bk)
|
|
30
|
+
* - Assign to `TreatmentSchedule.surgicalPrecisionMul` in downtime config.
|
|
31
|
+
* - BK q(0.00) → q(0.70) (clumsy; slower/worse surgery)
|
|
32
|
+
* - BK q(0.50) → q(1.00) (normal)
|
|
33
|
+
* - BK q(1.00) → q(1.30) (expert; faster/better surgery)
|
|
34
|
+
*/
|
|
35
|
+
export declare function computeSurgicalPrecision(entity: Entity): Q;
|