@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.
Files changed (311) hide show
  1. package/CHANGELOG.md +135 -0
  2. package/LICENSE +21 -0
  3. package/README.md +2199 -0
  4. package/STABLE_API.md +266 -0
  5. package/dist/src/anatomy/anatomy-compiler.d.ts +14 -0
  6. package/dist/src/anatomy/anatomy-compiler.js +277 -0
  7. package/dist/src/anatomy/anatomy-contracts.d.ts +94 -0
  8. package/dist/src/anatomy/anatomy-contracts.js +1 -0
  9. package/dist/src/anatomy/anatomy-helpers.d.ts +82 -0
  10. package/dist/src/anatomy/anatomy-helpers.js +233 -0
  11. package/dist/src/anatomy/anatomy-schema.d.ts +28 -0
  12. package/dist/src/anatomy/anatomy-schema.js +388 -0
  13. package/dist/src/anatomy/index.d.ts +4 -0
  14. package/dist/src/anatomy/index.js +4 -0
  15. package/dist/src/archetypes.d.ts +87 -0
  16. package/dist/src/archetypes.js +285 -0
  17. package/dist/src/arena.d.ts +173 -0
  18. package/dist/src/arena.js +695 -0
  19. package/dist/src/bridge/bridge-engine.d.ts +46 -0
  20. package/dist/src/bridge/bridge-engine.js +252 -0
  21. package/dist/src/bridge/index.d.ts +4 -0
  22. package/dist/src/bridge/index.js +5 -0
  23. package/dist/src/bridge/interpolation.d.ts +64 -0
  24. package/dist/src/bridge/interpolation.js +130 -0
  25. package/dist/src/bridge/mapping.d.ts +33 -0
  26. package/dist/src/bridge/mapping.js +54 -0
  27. package/dist/src/bridge/types.d.ts +94 -0
  28. package/dist/src/bridge/types.js +2 -0
  29. package/dist/src/campaign.d.ts +141 -0
  30. package/dist/src/campaign.js +235 -0
  31. package/dist/src/channels.d.ts +15 -0
  32. package/dist/src/channels.js +20 -0
  33. package/dist/src/chronicle.d.ts +124 -0
  34. package/dist/src/chronicle.js +232 -0
  35. package/dist/src/collective-activities.d.ts +154 -0
  36. package/dist/src/collective-activities.js +247 -0
  37. package/dist/src/competence/acoustic.d.ts +101 -0
  38. package/dist/src/competence/acoustic.js +242 -0
  39. package/dist/src/competence/catalogue.d.ts +30 -0
  40. package/dist/src/competence/catalogue.js +241 -0
  41. package/dist/src/competence/crafting.d.ts +35 -0
  42. package/dist/src/competence/crafting.js +88 -0
  43. package/dist/src/competence/engineering.d.ts +53 -0
  44. package/dist/src/competence/engineering.js +108 -0
  45. package/dist/src/competence/framework.d.ts +68 -0
  46. package/dist/src/competence/framework.js +694 -0
  47. package/dist/src/competence/index.d.ts +12 -0
  48. package/dist/src/competence/index.js +13 -0
  49. package/dist/src/competence/interspecies.d.ts +81 -0
  50. package/dist/src/competence/interspecies.js +108 -0
  51. package/dist/src/competence/language.d.ts +79 -0
  52. package/dist/src/competence/language.js +115 -0
  53. package/dist/src/competence/naturalist.d.ts +97 -0
  54. package/dist/src/competence/naturalist.js +187 -0
  55. package/dist/src/competence/navigation.d.ts +24 -0
  56. package/dist/src/competence/navigation.js +48 -0
  57. package/dist/src/competence/performance.d.ts +125 -0
  58. package/dist/src/competence/performance.js +210 -0
  59. package/dist/src/competence/teaching.d.ts +64 -0
  60. package/dist/src/competence/teaching.js +121 -0
  61. package/dist/src/competence/willpower.d.ts +74 -0
  62. package/dist/src/competence/willpower.js +114 -0
  63. package/dist/src/crafting/index.d.ts +55 -0
  64. package/dist/src/crafting/index.js +229 -0
  65. package/dist/src/crafting/manufacturing.d.ts +83 -0
  66. package/dist/src/crafting/manufacturing.js +165 -0
  67. package/dist/src/crafting/materials.d.ts +53 -0
  68. package/dist/src/crafting/materials.js +120 -0
  69. package/dist/src/crafting/recipes.d.ts +75 -0
  70. package/dist/src/crafting/recipes.js +233 -0
  71. package/dist/src/crafting/workshops.d.ts +61 -0
  72. package/dist/src/crafting/workshops.js +170 -0
  73. package/dist/src/debug.d.ts +86 -0
  74. package/dist/src/debug.js +76 -0
  75. package/dist/src/derive.d.ts +21 -0
  76. package/dist/src/derive.js +88 -0
  77. package/dist/src/describe.d.ts +29 -0
  78. package/dist/src/describe.js +276 -0
  79. package/dist/src/dialogue.d.ts +122 -0
  80. package/dist/src/dialogue.js +266 -0
  81. package/dist/src/dist.d.ts +20 -0
  82. package/dist/src/dist.js +39 -0
  83. package/dist/src/downtime.d.ts +89 -0
  84. package/dist/src/downtime.js +391 -0
  85. package/dist/src/economy.d.ts +116 -0
  86. package/dist/src/economy.js +182 -0
  87. package/dist/src/emotional-contagion.d.ts +142 -0
  88. package/dist/src/emotional-contagion.js +274 -0
  89. package/dist/src/equipment.d.ts +206 -0
  90. package/dist/src/equipment.js +598 -0
  91. package/dist/src/faction.d.ts +102 -0
  92. package/dist/src/faction.js +237 -0
  93. package/dist/src/generate.d.ts +35 -0
  94. package/dist/src/generate.js +166 -0
  95. package/dist/src/index.d.ts +42 -0
  96. package/dist/src/index.js +54 -0
  97. package/dist/src/inheritance.d.ts +69 -0
  98. package/dist/src/inheritance.js +136 -0
  99. package/dist/src/inventory.d.ts +194 -0
  100. package/dist/src/inventory.js +637 -0
  101. package/dist/src/item-durability.d.ts +69 -0
  102. package/dist/src/item-durability.js +308 -0
  103. package/dist/src/legend.d.ts +97 -0
  104. package/dist/src/legend.js +269 -0
  105. package/dist/src/lod.d.ts +9 -0
  106. package/dist/src/lod.js +84 -0
  107. package/dist/src/metrics.d.ts +51 -0
  108. package/dist/src/metrics.js +91 -0
  109. package/dist/src/model3d.d.ts +138 -0
  110. package/dist/src/model3d.js +214 -0
  111. package/dist/src/mythology.d.ts +101 -0
  112. package/dist/src/mythology.js +308 -0
  113. package/dist/src/narrative-render.d.ts +42 -0
  114. package/dist/src/narrative-render.js +194 -0
  115. package/dist/src/narrative-stress.d.ts +123 -0
  116. package/dist/src/narrative-stress.js +183 -0
  117. package/dist/src/narrative.d.ts +44 -0
  118. package/dist/src/narrative.js +257 -0
  119. package/dist/src/party.d.ts +70 -0
  120. package/dist/src/party.js +226 -0
  121. package/dist/src/polity.d.ts +262 -0
  122. package/dist/src/polity.js +398 -0
  123. package/dist/src/presets.d.ts +42 -0
  124. package/dist/src/presets.js +170 -0
  125. package/dist/src/progression.d.ts +170 -0
  126. package/dist/src/progression.js +256 -0
  127. package/dist/src/quest-generators.d.ts +76 -0
  128. package/dist/src/quest-generators.js +534 -0
  129. package/dist/src/quest.d.ts +239 -0
  130. package/dist/src/quest.js +520 -0
  131. package/dist/src/relationships-effects.d.ts +75 -0
  132. package/dist/src/relationships-effects.js +219 -0
  133. package/dist/src/relationships.d.ts +104 -0
  134. package/dist/src/relationships.js +347 -0
  135. package/dist/src/replay.d.ts +47 -0
  136. package/dist/src/replay.js +82 -0
  137. package/dist/src/rng.d.ts +9 -0
  138. package/dist/src/rng.js +37 -0
  139. package/dist/src/settlement-services.d.ts +67 -0
  140. package/dist/src/settlement-services.js +267 -0
  141. package/dist/src/settlement.d.ts +143 -0
  142. package/dist/src/settlement.js +419 -0
  143. package/dist/src/sim/action.d.ts +28 -0
  144. package/dist/src/sim/action.js +12 -0
  145. package/dist/src/sim/aging.d.ts +95 -0
  146. package/dist/src/sim/aging.js +243 -0
  147. package/dist/src/sim/ai/decide.d.ts +10 -0
  148. package/dist/src/sim/ai/decide.js +267 -0
  149. package/dist/src/sim/ai/perception.d.ts +12 -0
  150. package/dist/src/sim/ai/perception.js +54 -0
  151. package/dist/src/sim/ai/personality.d.ts +54 -0
  152. package/dist/src/sim/ai/personality.js +202 -0
  153. package/dist/src/sim/ai/presets.d.ts +2 -0
  154. package/dist/src/sim/ai/presets.js +28 -0
  155. package/dist/src/sim/ai/system.d.ts +6 -0
  156. package/dist/src/sim/ai/system.js +13 -0
  157. package/dist/src/sim/ai/targeting.d.ts +8 -0
  158. package/dist/src/sim/ai/targeting.js +42 -0
  159. package/dist/src/sim/ai/types.d.ts +14 -0
  160. package/dist/src/sim/ai/types.js +1 -0
  161. package/dist/src/sim/body.d.ts +9 -0
  162. package/dist/src/sim/body.js +32 -0
  163. package/dist/src/sim/bodyplan.d.ts +161 -0
  164. package/dist/src/sim/bodyplan.js +677 -0
  165. package/dist/src/sim/capability.d.ts +135 -0
  166. package/dist/src/sim/capability.js +8 -0
  167. package/dist/src/sim/combat.d.ts +21 -0
  168. package/dist/src/sim/combat.js +77 -0
  169. package/dist/src/sim/commandBuilders.d.ts +11 -0
  170. package/dist/src/sim/commandBuilders.js +39 -0
  171. package/dist/src/sim/commands.d.ts +71 -0
  172. package/dist/src/sim/commands.js +8 -0
  173. package/dist/src/sim/condition.d.ts +35 -0
  174. package/dist/src/sim/condition.js +21 -0
  175. package/dist/src/sim/cone.d.ts +40 -0
  176. package/dist/src/sim/cone.js +44 -0
  177. package/dist/src/sim/context.d.ts +68 -0
  178. package/dist/src/sim/context.js +1 -0
  179. package/dist/src/sim/density.d.ts +14 -0
  180. package/dist/src/sim/density.js +33 -0
  181. package/dist/src/sim/disease.d.ts +141 -0
  182. package/dist/src/sim/disease.js +353 -0
  183. package/dist/src/sim/entity.d.ts +251 -0
  184. package/dist/src/sim/entity.js +19 -0
  185. package/dist/src/sim/events.d.ts +25 -0
  186. package/dist/src/sim/events.js +5 -0
  187. package/dist/src/sim/explosion.d.ts +40 -0
  188. package/dist/src/sim/explosion.js +40 -0
  189. package/dist/src/sim/formation-unit.d.ts +138 -0
  190. package/dist/src/sim/formation-unit.js +197 -0
  191. package/dist/src/sim/formation.d.ts +12 -0
  192. package/dist/src/sim/formation.js +54 -0
  193. package/dist/src/sim/frontage.d.ts +30 -0
  194. package/dist/src/sim/frontage.js +84 -0
  195. package/dist/src/sim/grapple.d.ts +100 -0
  196. package/dist/src/sim/grapple.js +480 -0
  197. package/dist/src/sim/hazard.d.ts +104 -0
  198. package/dist/src/sim/hazard.js +201 -0
  199. package/dist/src/sim/hydrostatic.d.ts +58 -0
  200. package/dist/src/sim/hydrostatic.js +117 -0
  201. package/dist/src/sim/impairment.d.ts +20 -0
  202. package/dist/src/sim/impairment.js +162 -0
  203. package/dist/src/sim/indexing.d.ts +7 -0
  204. package/dist/src/sim/indexing.js +7 -0
  205. package/dist/src/sim/injury.d.ts +54 -0
  206. package/dist/src/sim/injury.js +66 -0
  207. package/dist/src/sim/intent.d.ts +26 -0
  208. package/dist/src/sim/intent.js +7 -0
  209. package/dist/src/sim/kernel.d.ts +45 -0
  210. package/dist/src/sim/kernel.js +1992 -0
  211. package/dist/src/sim/kinds.d.ts +64 -0
  212. package/dist/src/sim/kinds.js +56 -0
  213. package/dist/src/sim/knockback.d.ts +50 -0
  214. package/dist/src/sim/knockback.js +82 -0
  215. package/dist/src/sim/limb.d.ts +48 -0
  216. package/dist/src/sim/limb.js +78 -0
  217. package/dist/src/sim/medical.d.ts +32 -0
  218. package/dist/src/sim/medical.js +33 -0
  219. package/dist/src/sim/morale.d.ts +69 -0
  220. package/dist/src/sim/morale.js +92 -0
  221. package/dist/src/sim/mount.d.ts +150 -0
  222. package/dist/src/sim/mount.js +225 -0
  223. package/dist/src/sim/nutrition.d.ts +74 -0
  224. package/dist/src/sim/nutrition.js +168 -0
  225. package/dist/src/sim/occlusion.d.ts +8 -0
  226. package/dist/src/sim/occlusion.js +71 -0
  227. package/dist/src/sim/push.d.ts +11 -0
  228. package/dist/src/sim/push.js +79 -0
  229. package/dist/src/sim/ranged.d.ts +44 -0
  230. package/dist/src/sim/ranged.js +69 -0
  231. package/dist/src/sim/seeds.d.ts +3 -0
  232. package/dist/src/sim/seeds.js +16 -0
  233. package/dist/src/sim/sensory-extended.d.ts +103 -0
  234. package/dist/src/sim/sensory-extended.js +181 -0
  235. package/dist/src/sim/sensory.d.ts +38 -0
  236. package/dist/src/sim/sensory.js +109 -0
  237. package/dist/src/sim/skills.d.ts +70 -0
  238. package/dist/src/sim/skills.js +69 -0
  239. package/dist/src/sim/sleep.d.ts +107 -0
  240. package/dist/src/sim/sleep.js +215 -0
  241. package/dist/src/sim/spatial.d.ts +8 -0
  242. package/dist/src/sim/spatial.js +59 -0
  243. package/dist/src/sim/step/capability.d.ts +8 -0
  244. package/dist/src/sim/step/capability.js +77 -0
  245. package/dist/src/sim/step/concentration.d.ts +9 -0
  246. package/dist/src/sim/step/concentration.js +25 -0
  247. package/dist/src/sim/step/effects.d.ts +17 -0
  248. package/dist/src/sim/step/effects.js +96 -0
  249. package/dist/src/sim/step/energy.d.ts +3 -0
  250. package/dist/src/sim/step/energy.js +31 -0
  251. package/dist/src/sim/step/hazards.d.ts +4 -0
  252. package/dist/src/sim/step/hazards.js +19 -0
  253. package/dist/src/sim/step/injury.d.ts +10 -0
  254. package/dist/src/sim/step/injury.js +353 -0
  255. package/dist/src/sim/step/morale.d.ts +11 -0
  256. package/dist/src/sim/step/morale.js +130 -0
  257. package/dist/src/sim/step/movement.d.ts +5 -0
  258. package/dist/src/sim/step/movement.js +172 -0
  259. package/dist/src/sim/step/push.d.ts +11 -0
  260. package/dist/src/sim/step/push.js +79 -0
  261. package/dist/src/sim/step/substances.d.ts +3 -0
  262. package/dist/src/sim/step/substances.js +75 -0
  263. package/dist/src/sim/substance.d.ts +38 -0
  264. package/dist/src/sim/substance.js +57 -0
  265. package/dist/src/sim/systemic-toxicology.d.ts +109 -0
  266. package/dist/src/sim/systemic-toxicology.js +263 -0
  267. package/dist/src/sim/team.d.ts +9 -0
  268. package/dist/src/sim/team.js +37 -0
  269. package/dist/src/sim/tech.d.ts +36 -0
  270. package/dist/src/sim/tech.js +46 -0
  271. package/dist/src/sim/terrain.d.ts +121 -0
  272. package/dist/src/sim/terrain.js +141 -0
  273. package/dist/src/sim/testing.d.ts +13 -0
  274. package/dist/src/sim/testing.js +100 -0
  275. package/dist/src/sim/thermoregulation.d.ts +77 -0
  276. package/dist/src/sim/thermoregulation.js +161 -0
  277. package/dist/src/sim/tick.d.ts +3 -0
  278. package/dist/src/sim/tick.js +3 -0
  279. package/dist/src/sim/toxicology.d.ts +52 -0
  280. package/dist/src/sim/toxicology.js +104 -0
  281. package/dist/src/sim/trace.d.ts +141 -0
  282. package/dist/src/sim/trace.js +1 -0
  283. package/dist/src/sim/tuning.d.ts +16 -0
  284. package/dist/src/sim/tuning.js +42 -0
  285. package/dist/src/sim/vec3.d.ts +14 -0
  286. package/dist/src/sim/vec3.js +31 -0
  287. package/dist/src/sim/weapon_dynamics.d.ts +102 -0
  288. package/dist/src/sim/weapon_dynamics.js +142 -0
  289. package/dist/src/sim/weather.d.ts +95 -0
  290. package/dist/src/sim/weather.js +105 -0
  291. package/dist/src/sim/world.d.ts +52 -0
  292. package/dist/src/sim/world.js +1 -0
  293. package/dist/src/sim/wound-aging.d.ts +120 -0
  294. package/dist/src/sim/wound-aging.js +223 -0
  295. package/dist/src/species.d.ts +106 -0
  296. package/dist/src/species.js +664 -0
  297. package/dist/src/story-arcs.d.ts +17 -0
  298. package/dist/src/story-arcs.js +276 -0
  299. package/dist/src/tech-diffusion.d.ts +80 -0
  300. package/dist/src/tech-diffusion.js +185 -0
  301. package/dist/src/traits.d.ts +25 -0
  302. package/dist/src/traits.js +178 -0
  303. package/dist/src/types.d.ts +117 -0
  304. package/dist/src/types.js +1 -0
  305. package/dist/src/units.d.ts +41 -0
  306. package/dist/src/units.js +64 -0
  307. package/dist/src/weapons.d.ts +20 -0
  308. package/dist/src/weapons.js +824 -0
  309. package/dist/src/world-generation.d.ts +52 -0
  310. package/dist/src/world-generation.js +301 -0
  311. package/package.json +74 -0
@@ -0,0 +1,105 @@
1
+ // src/sim/weather.ts — Phase 51: Weather & Atmospheric Environment
2
+ //
3
+ // Pure computation module — no entity mutation. Defines weather state types
4
+ // and derives per-tick modifiers that the kernel applies to traction, sensory
5
+ // environment, ambient temperature, and ranged-combat aim error.
6
+ //
7
+ // Data flow:
8
+ // KernelContext.weather (WeatherState) → deriveWeatherModifiers → WeatherModifiers
9
+ // WeatherModifiers → kernel stepWorld → tractionCoeff, sensoryEnv, thermalAmbient_Q
10
+ // WeatherState.wind + resolveShoot → computeWindAimError → extra gRadius_m
11
+ import { SCALE, q, clampQ } from "../units.js";
12
+ // ── Constants ─────────────────────────────────────────────────────────────────
13
+ /**
14
+ * Approximate Q units per degree Celsius in the Phase-29 thermal encoding.
15
+ * (SCALE.Q / 54) where 54 = 64°C − 10°C temperature range).
16
+ */
17
+ export const WEATHER_Q_PER_DEG_C = 185;
18
+ /** Reference cone-weapon travel speed [SCALE.mps] for adjustConeRange. 20 m/s. */
19
+ const CONE_REF_SPEED_mps = 2_000;
20
+ // ── Precipitation lookup table ────────────────────────────────────────────────
21
+ /** Physical parameters indexed by PrecipitationType. */
22
+ const PRECIP_TABLE = {
23
+ none: { tractionMul: q(1.00), lightMul: q(1.00), precipVisionMul: q(1.00), thermalDegC: 0 },
24
+ rain: { tractionMul: q(0.85), lightMul: q(0.90), precipVisionMul: q(0.85), thermalDegC: 1 },
25
+ heavy_rain: { tractionMul: q(0.70), lightMul: q(0.70), precipVisionMul: q(0.60), thermalDegC: 2 },
26
+ snow: { tractionMul: q(0.60), lightMul: q(0.75), precipVisionMul: q(0.75), thermalDegC: 5 },
27
+ blizzard: { tractionMul: q(0.40), lightMul: q(0.30), precipVisionMul: q(0.30), thermalDegC: 12 },
28
+ hail: { tractionMul: q(0.75), lightMul: q(0.85), precipVisionMul: q(0.85), thermalDegC: 1 },
29
+ };
30
+ // ── deriveWeatherModifiers ─────────────────────────────────────────────────────
31
+ /**
32
+ * Compute all derived modifiers for a WeatherState.
33
+ * Pure function — no side effects.
34
+ */
35
+ export function deriveWeatherModifiers(weather) {
36
+ const pt = PRECIP_TABLE[weather.precipitation ?? "none"];
37
+ // Fog multiplier: q(0) fog = q(1.0) light; q(1.0) fog = q(0.10) minimum light.
38
+ const fogMul = weather.fogDensity_Q !== undefined
39
+ ? clampQ((SCALE.Q - weather.fogDensity_Q), q(0.10), SCALE.Q)
40
+ : SCALE.Q;
41
+ // Combined light reduction from precipitation and fog (multiplicative).
42
+ const lightMul_Q = clampQ(Math.trunc(pt.lightMul * fogMul / SCALE.Q), q(0.10), SCALE.Q);
43
+ return {
44
+ tractionMul_Q: pt.tractionMul,
45
+ lightMul_Q,
46
+ precipVisionMul_Q: pt.precipVisionMul,
47
+ thermalOffset_Q: pt.thermalDegC ? -(pt.thermalDegC * WEATHER_Q_PER_DEG_C) : 0,
48
+ };
49
+ }
50
+ // ── computeWindAimError ───────────────────────────────────────────────────────
51
+ /**
52
+ * Additional aim grouping radius from wind drift [SCALE.m].
53
+ *
54
+ * Physics: drift = v_wind_perp × (range / v_proj)
55
+ *
56
+ * The perpendicular wind component is the 2D cross product of shot direction
57
+ * and wind direction. Algebraic simplification yields:
58
+ *
59
+ * drift_scaled_m = wind.speed_mps × |shot × wind| / (SCALE.m × v_proj_mps)
60
+ *
61
+ * where |shot × wind| is the cross-product magnitude in SCALE.m² units with
62
+ * shot direction of magnitude `dist_m` and wind direction of magnitude SCALE.m.
63
+ * The `dist_m` factors cancel, leaving a formula independent of scale choice.
64
+ *
65
+ * @param wind Wind field (direction + speed).
66
+ * @param shotDx_m Shot direction x [SCALE.m] (raw, not normalised).
67
+ * @param shotDy_m Shot direction y [SCALE.m] (raw, not normalised).
68
+ * @param dist_m Range to target [SCALE.m].
69
+ * @param v_proj_mps Projectile speed [SCALE.mps].
70
+ * @returns Additional grouping radius [SCALE.m] (≥ 0).
71
+ */
72
+ export function computeWindAimError(wind, shotDx_m, shotDy_m, dist_m, v_proj_mps) {
73
+ if (wind.speed_mps <= 0 || v_proj_mps <= 0 || dist_m <= 0)
74
+ return 0;
75
+ // 2D cross product magnitude: |shot × wind| in SCALE.m² units.
76
+ const crossRaw = Math.abs(shotDx_m * wind.dy_m - shotDy_m * wind.dx_m);
77
+ // drift_scaled_m = wind.speed_mps × crossRaw / (SCALE.m × v_proj_mps)
78
+ return Math.trunc(wind.speed_mps * crossRaw / (SCALE.m * v_proj_mps));
79
+ }
80
+ // ── adjustConeRange ───────────────────────────────────────────────────────────
81
+ /**
82
+ * Adjust cone range for wind effects (breath weapons, gas clouds, flamethrowers).
83
+ *
84
+ * - Headwind (wind opposes cone direction) reduces range up to −20%.
85
+ * - Tailwind extends range up to +10%.
86
+ * - Crosswind (perpendicular) has no effect on range.
87
+ *
88
+ * @param wind Wind field.
89
+ * @param coneDx_m Cone facing direction x (SCALE.m unit vector).
90
+ * @param coneDy_m Cone facing direction y (SCALE.m unit vector).
91
+ * @param range_m Base cone range [SCALE.m].
92
+ * @returns Adjusted range [SCALE.m] (≥ 0).
93
+ */
94
+ export function adjustConeRange(wind, coneDx_m, coneDy_m, range_m) {
95
+ if (wind.speed_mps <= 0 || range_m <= 0)
96
+ return range_m;
97
+ // Dot product of cone dir (SCALE.m unit vector) and wind dir (SCALE.m unit vector).
98
+ // Result is in SCALE.m²; divide by SCALE.m to get aligned component in SCALE.m.
99
+ const dot_m = Math.trunc((coneDx_m * wind.dx_m + coneDy_m * wind.dy_m) / SCALE.m);
100
+ // Effect = aligned_speed / CONE_REF_SPEED as a Q fraction, clamped to ±20% / +10%.
101
+ // At CONE_REF_SPEED full-headwind (dot = −SCALE.m): effect_Q = −q(0.20).
102
+ const effect_Q = clampQ(Math.trunc(wind.speed_mps * dot_m * 2_000 / (SCALE.m * CONE_REF_SPEED_mps)), -2_000, // max −20% headwind reduction
103
+ 1_000);
104
+ return Math.max(0, range_m + Math.trunc(range_m * effect_Q / SCALE.Q));
105
+ }
@@ -0,0 +1,52 @@
1
+ import type { Entity } from "./entity.js";
2
+ import type { FieldEffect } from "./capability.js";
3
+ import { SensoryEnvironment } from "./sensory.js";
4
+ import { FactionRegistry } from "../faction.js";
5
+ import { PartyRegistry } from "../party.js";
6
+ import { RelationshipGraph } from "../relationships.js";
7
+ /**
8
+ * Top-level simulation container.
9
+ *
10
+ * Fields are annotated with stability tiers identical to `Entity`:
11
+ * - **`@core`** — required by `stepWorld` every tick.
12
+ * - **`@subsystem(name)`** — optional state consumed only by a specific sub-module.
13
+ */
14
+ export interface WorldState {
15
+ /** @core Current tick count; incremented by `stepWorld`. */
16
+ tick: number;
17
+ /** @core Deterministic RNG seed — same seed + same commands → identical output. */
18
+ seed: number;
19
+ /** @core All live and dead entities. Do not splice manually; use `stepWorld`. */
20
+ entities: Entity[];
21
+ /**
22
+ * @subsystem(capability) Active suppression zones and field-effect modifiers
23
+ * (e.g., mana-null zones, buff auras). Consumed by `src/sim/capability.ts`.
24
+ */
25
+ activeFieldEffects?: FieldEffect[];
26
+ /**
27
+ * @subsystem(sensory) Ambient lighting and visibility environment.
28
+ * Consumed by `src/sim/sensory.ts` when provided. Prefixed `__` to discourage
29
+ * direct access — use the sensory API instead.
30
+ */
31
+ __sensoryEnv?: SensoryEnvironment;
32
+ /**
33
+ * @subsystem(faction) Global faction-standing registry.
34
+ * Consumed by `src/faction.ts` and AI targeting.
35
+ */
36
+ __factionRegistry?: FactionRegistry;
37
+ /**
38
+ * @subsystem(party) Global party registry.
39
+ * Consumed by `src/party.ts` for morale and formation bonuses.
40
+ */
41
+ __partyRegistry?: PartyRegistry;
42
+ /**
43
+ * @subsystem(relationships) Inter-entity relationship graph.
44
+ * Consumed by `src/relationships.ts`.
45
+ */
46
+ __relationshipGraph?: RelationshipGraph;
47
+ /**
48
+ * @subsystem(nutrition) Cross-tick nutrition accumulator.
49
+ * Consumed by the nutrition sub-step in `src/sim/kernel.ts`.
50
+ */
51
+ __nutritionAccum?: number;
52
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,120 @@
1
+ import { type Q } from "../units.js";
2
+ import type { Entity } from "./entity.js";
3
+ /**
4
+ * PTSD-like trauma state accumulating from severe shock events.
5
+ * Stored on `entity.traumaState`.
6
+ * Reduces effective fear threshold via `deriveFearThresholdMul`.
7
+ */
8
+ export interface TraumaState {
9
+ /** Cumulative severity (Q 0..SCALE.Q). Grows with shock events; decays over time. */
10
+ severity_Q: Q;
11
+ }
12
+ /** Outcome summary returned by `stepWoundAging`. */
13
+ export interface WoundAgingResult {
14
+ /** Region ids whose surface or internal damage improved (healed). */
15
+ healedRegions: string[];
16
+ /** Region ids whose damage worsened (infection progression). */
17
+ worsenedRegions: string[];
18
+ /** True if any region crossed the sepsis damage threshold this step. */
19
+ newSepsis: boolean;
20
+ }
21
+ /** Seconds per day — base unit for all per-day rates. */
22
+ export declare const SECONDS_PER_DAY = 86400;
23
+ /**
24
+ * Surface-damage healing rate [Q/day].
25
+ * At q(0.01)/day, a fully surface-damaged region takes ~100 days to heal.
26
+ */
27
+ export declare const SURFACE_HEAL_Q_PER_DAY: Q;
28
+ /**
29
+ * Internal-damage healing rate [Q/day].
30
+ * Half the surface rate — internal injuries heal more slowly.
31
+ */
32
+ export declare const INTERNAL_HEAL_Q_PER_DAY: Q;
33
+ /**
34
+ * Infection worsening rate [Q/day] applied to internalDamage while infected.
35
+ * 3× the internal heal rate — untreated infection outpaces natural recovery.
36
+ */
37
+ export declare const INFECTION_WORSEN_Q_PER_DAY: Q;
38
+ /**
39
+ * Internal-damage threshold (Q) above which an infected region is considered
40
+ * to pose a sepsis risk (systemically threatening).
41
+ */
42
+ export declare const SEPSIS_THRESHOLD: Q;
43
+ /**
44
+ * Chronic fatigue per-day rate [Q/day] applied when total permanent damage
45
+ * across all regions exceeds CHRONIC_FATIGUE_REGION_THRESHOLD.
46
+ */
47
+ export declare const CHRONIC_FATIGUE_Q_PER_DAY: Q;
48
+ /**
49
+ * Minimum total permanent damage (summed across all regions, relative to
50
+ * SCALE.Q × regionCount) to activate chronic fatigue.
51
+ * Approximately q(0.10) average per region.
52
+ */
53
+ export declare const CHRONIC_FATIGUE_THRESHOLD: Q;
54
+ /**
55
+ * Permanent-damage threshold (per region) above which a fractured region
56
+ * causes phantom pain during rest.
57
+ */
58
+ export declare const PHANTOM_PAIN_THRESHOLD: Q;
59
+ /**
60
+ * Phantom pain shock injection per day per qualifying fractured region [Q/day].
61
+ * Scaled by the region's (permanentDamage / SCALE.Q) ratio.
62
+ */
63
+ export declare const PHANTOM_PAIN_Q_PER_DAY: Q;
64
+ /**
65
+ * Trauma decay per day [Q/day] — natural recovery rate of traumaState.severity_Q.
66
+ * Slow: severe trauma takes months to fully resolve.
67
+ */
68
+ export declare const TRAUMA_DECAY_Q_PER_DAY: Q;
69
+ /**
70
+ * Minimum shock increment that registers as a traumatic event.
71
+ * Events below this threshold are too minor to compound PTSD-like symptoms.
72
+ */
73
+ export declare const TRAUMA_TRIGGER_THRESHOLD: Q;
74
+ /**
75
+ * Advance long-term wound state by `elapsedSeconds`.
76
+ *
77
+ * Intended for downtime / long-rest simulation (hours to weeks of elapsed time).
78
+ * At sub-minute resolution this function does nothing observable.
79
+ *
80
+ * Mutates:
81
+ * entity.injury.byRegion (surface/internal damage healed or worsened)
82
+ * entity.injury.shock (phantom pain)
83
+ * entity.energy.fatigue (chronic fatigue drain)
84
+ * entity.traumaState (natural severity decay)
85
+ *
86
+ * @param elapsedSeconds Wall-clock seconds elapsed (use 86400 per game-day).
87
+ * @returns WoundAgingResult summary (healed, worsened, newSepsis).
88
+ */
89
+ export declare function stepWoundAging(entity: Entity, elapsedSeconds: number): WoundAgingResult;
90
+ /**
91
+ * Record a traumatic shock event, accumulating PTSD-like severity.
92
+ *
93
+ * Only events at or above TRAUMA_TRIGGER_THRESHOLD (q(0.20)) register.
94
+ * A q(1.0) shock event contributes q(0.30) to `traumaState.severity_Q`.
95
+ *
96
+ * Mutates: entity.traumaState (created if absent).
97
+ *
98
+ * @param shockIncrement_Q The shock delta from the triggering event (Q).
99
+ */
100
+ export declare function recordTraumaEvent(entity: Entity, shockIncrement_Q: Q): void;
101
+ /**
102
+ * Derive the effective fear-threshold multiplier from accumulated trauma.
103
+ *
104
+ * Returns Q in [TRAUMA_FEAR_MUL_FLOOR, SCALE.Q]:
105
+ * q(1.0) → no trauma — fear threshold unchanged.
106
+ * q(0.50) → maximum trauma — entity triggers fear at half normal threshold.
107
+ *
108
+ * Usage (combat / morale layer):
109
+ * `effectiveFearThreshold_Q = Math.round(baseFearThreshold_Q × mul / SCALE.Q)`
110
+ */
111
+ export declare function deriveFearThresholdMul(entity: Entity): Q;
112
+ /**
113
+ * Compute aggregate sepsis risk (Q 0..SCALE.Q) from all infected regions.
114
+ *
115
+ * Risk increases with both the number of infected regions and their
116
+ * internal damage level. Returns q(0) if no infected regions.
117
+ *
118
+ * Usage: AI / medical layer reads this to prioritise treatment.
119
+ */
120
+ export declare function deriveSepsisRisk(entity: Entity): Q;
@@ -0,0 +1,223 @@
1
+ // src/sim/wound-aging.ts — Phase 54: Wound Aging & Long-Term Sequelae
2
+ //
3
+ // Extends Phase 21 (injury resolution) and Phase 9 (infection) with time-based
4
+ // wound progression relevant to multi-day / multi-week campaign simulation.
5
+ //
6
+ // Four long-term processes:
7
+ // 1. Healing — uninfected regions slowly recover surface and internal damage
8
+ // (clamped to permanentDamage floor; structural never recovers).
9
+ // 2. Infection — infected regions worsen; severe infection → sepsis flag.
10
+ // 3. Chronic fatigue — sustained permanent damage creates a baseline fatigue drain.
11
+ // 4. Phantom pain — fractured regions with significant permanent damage inject
12
+ // periodic shock increments during rest/downtime.
13
+ //
14
+ // Plus two PTSD-like trauma utilities:
15
+ // recordTraumaEvent(entity, shockQ) — accumulate trauma severity
16
+ // deriveFearThresholdMul(entity) → Q — fear multiplier from trauma
17
+ // deriveSepsisRisk(entity) → Q — aggregate infection severity
18
+ //
19
+ // Call stepWoundAging during downtime (long rests, between scenes) with the number
20
+ // of real elapsed seconds. At 1 real second this does nothing useful; at 86 400 s
21
+ // (one day) the full daily rates apply.
22
+ import { q, clampQ, SCALE } from "../units.js";
23
+ // ── Constants ─────────────────────────────────────────────────────────────────
24
+ /** Seconds per day — base unit for all per-day rates. */
25
+ export const SECONDS_PER_DAY = 86_400;
26
+ /**
27
+ * Surface-damage healing rate [Q/day].
28
+ * At q(0.01)/day, a fully surface-damaged region takes ~100 days to heal.
29
+ */
30
+ export const SURFACE_HEAL_Q_PER_DAY = q(0.01); // 100 Q/day
31
+ /**
32
+ * Internal-damage healing rate [Q/day].
33
+ * Half the surface rate — internal injuries heal more slowly.
34
+ */
35
+ export const INTERNAL_HEAL_Q_PER_DAY = q(0.005); // 50 Q/day
36
+ /**
37
+ * Infection worsening rate [Q/day] applied to internalDamage while infected.
38
+ * 3× the internal heal rate — untreated infection outpaces natural recovery.
39
+ */
40
+ export const INFECTION_WORSEN_Q_PER_DAY = q(0.015); // 150 Q/day
41
+ /**
42
+ * Internal-damage threshold (Q) above which an infected region is considered
43
+ * to pose a sepsis risk (systemically threatening).
44
+ */
45
+ export const SEPSIS_THRESHOLD = q(0.85);
46
+ /**
47
+ * Chronic fatigue per-day rate [Q/day] applied when total permanent damage
48
+ * across all regions exceeds CHRONIC_FATIGUE_REGION_THRESHOLD.
49
+ */
50
+ export const CHRONIC_FATIGUE_Q_PER_DAY = q(0.02); // 200 Q/day
51
+ /**
52
+ * Minimum total permanent damage (summed across all regions, relative to
53
+ * SCALE.Q × regionCount) to activate chronic fatigue.
54
+ * Approximately q(0.10) average per region.
55
+ */
56
+ export const CHRONIC_FATIGUE_THRESHOLD = q(0.10); // per-region average
57
+ /**
58
+ * Permanent-damage threshold (per region) above which a fractured region
59
+ * causes phantom pain during rest.
60
+ */
61
+ export const PHANTOM_PAIN_THRESHOLD = q(0.30);
62
+ /**
63
+ * Phantom pain shock injection per day per qualifying fractured region [Q/day].
64
+ * Scaled by the region's (permanentDamage / SCALE.Q) ratio.
65
+ */
66
+ export const PHANTOM_PAIN_Q_PER_DAY = q(0.02); // 200 Q/day at max permanent damage
67
+ /**
68
+ * Trauma decay per day [Q/day] — natural recovery rate of traumaState.severity_Q.
69
+ * Slow: severe trauma takes months to fully resolve.
70
+ */
71
+ export const TRAUMA_DECAY_Q_PER_DAY = q(0.002); // 20 Q/day
72
+ /**
73
+ * Minimum shock increment that registers as a traumatic event.
74
+ * Events below this threshold are too minor to compound PTSD-like symptoms.
75
+ */
76
+ export const TRAUMA_TRIGGER_THRESHOLD = q(0.20);
77
+ /**
78
+ * Fraction of a shock increment that accumulates as trauma severity.
79
+ * q(0.30) → a q(1.0) shock event contributes q(0.30) to trauma severity.
80
+ */
81
+ const TRAUMA_ACCUMULATION_RATE = q(0.30);
82
+ /**
83
+ * Maximum fear-threshold reduction from trauma (q(0.50) → trauma halves
84
+ * the effective fear threshold, making entities fearful at lower stimuli).
85
+ */
86
+ const TRAUMA_FEAR_MUL_FLOOR = q(0.50);
87
+ // ── Public API ────────────────────────────────────────────────────────────────
88
+ /**
89
+ * Advance long-term wound state by `elapsedSeconds`.
90
+ *
91
+ * Intended for downtime / long-rest simulation (hours to weeks of elapsed time).
92
+ * At sub-minute resolution this function does nothing observable.
93
+ *
94
+ * Mutates:
95
+ * entity.injury.byRegion (surface/internal damage healed or worsened)
96
+ * entity.injury.shock (phantom pain)
97
+ * entity.energy.fatigue (chronic fatigue drain)
98
+ * entity.traumaState (natural severity decay)
99
+ *
100
+ * @param elapsedSeconds Wall-clock seconds elapsed (use 86400 per game-day).
101
+ * @returns WoundAgingResult summary (healed, worsened, newSepsis).
102
+ */
103
+ export function stepWoundAging(entity, elapsedSeconds) {
104
+ const days = elapsedSeconds / SECONDS_PER_DAY;
105
+ const result = {
106
+ healedRegions: [],
107
+ worsenedRegions: [],
108
+ newSepsis: false,
109
+ };
110
+ const regions = entity.injury.byRegion;
111
+ const regionEntries = Object.entries(regions);
112
+ let totalPermanent = 0;
113
+ let regionCount = 0;
114
+ for (const [regionId, reg] of regionEntries) {
115
+ regionCount++;
116
+ const prevSurface = reg.surfaceDamage;
117
+ const prevInternal = reg.internalDamage;
118
+ const perm = reg.permanentDamage;
119
+ totalPermanent += perm;
120
+ if (reg.infectedTick !== -1) {
121
+ // ── Infection worsening ────────────────────────────────────────────────
122
+ const worsenAmount = Math.round(INFECTION_WORSEN_Q_PER_DAY * days);
123
+ reg.internalDamage = clampQ((reg.internalDamage + worsenAmount), q(0), q(1.0));
124
+ if (reg.internalDamage > prevInternal) {
125
+ result.worsenedRegions.push(regionId);
126
+ }
127
+ // Sepsis: infected region has crossed the critical threshold
128
+ if (!result.newSepsis && reg.internalDamage >= SEPSIS_THRESHOLD && prevInternal < SEPSIS_THRESHOLD) {
129
+ result.newSepsis = true;
130
+ }
131
+ }
132
+ else {
133
+ // ── Healing ───────────────────────────────────────────────────────────
134
+ const surfaceHeal = Math.round(SURFACE_HEAL_Q_PER_DAY * days);
135
+ const internalHeal = Math.round(INTERNAL_HEAL_Q_PER_DAY * days);
136
+ reg.surfaceDamage = clampQ((reg.surfaceDamage - surfaceHeal), perm, q(1.0));
137
+ reg.internalDamage = clampQ((reg.internalDamage - internalHeal), perm, q(1.0));
138
+ if (reg.surfaceDamage < prevSurface || reg.internalDamage < prevInternal) {
139
+ result.healedRegions.push(regionId);
140
+ }
141
+ }
142
+ // ── Phantom pain ──────────────────────────────────────────────────────────
143
+ if (reg.fractured && reg.permanentDamage >= PHANTOM_PAIN_THRESHOLD) {
144
+ // Shock injection scaled by permanent damage fraction
145
+ const painQ = Math.round(PHANTOM_PAIN_Q_PER_DAY * days * reg.permanentDamage / SCALE.Q);
146
+ if (painQ > 0) {
147
+ entity.injury.shock = clampQ((entity.injury.shock + painQ), q(0), SCALE.Q);
148
+ }
149
+ }
150
+ }
151
+ // ── Chronic fatigue ────────────────────────────────────────────────────────
152
+ if (regionCount > 0) {
153
+ const avgPermanent = totalPermanent / regionCount;
154
+ if (avgPermanent >= CHRONIC_FATIGUE_THRESHOLD) {
155
+ const fatigueInc = Math.round(CHRONIC_FATIGUE_Q_PER_DAY * days * avgPermanent / SCALE.Q);
156
+ if (fatigueInc > 0) {
157
+ entity.energy.fatigue = clampQ((entity.energy.fatigue + fatigueInc), q(0), SCALE.Q);
158
+ }
159
+ }
160
+ }
161
+ // ── Trauma natural decay ───────────────────────────────────────────────────
162
+ if (entity.traumaState && entity.traumaState.severity_Q > 0) {
163
+ const decayAmount = Math.round(TRAUMA_DECAY_Q_PER_DAY * days);
164
+ entity.traumaState.severity_Q = clampQ((entity.traumaState.severity_Q - decayAmount), q(0), SCALE.Q);
165
+ }
166
+ return result;
167
+ }
168
+ // ── Trauma utilities ──────────────────────────────────────────────────────────
169
+ /**
170
+ * Record a traumatic shock event, accumulating PTSD-like severity.
171
+ *
172
+ * Only events at or above TRAUMA_TRIGGER_THRESHOLD (q(0.20)) register.
173
+ * A q(1.0) shock event contributes q(0.30) to `traumaState.severity_Q`.
174
+ *
175
+ * Mutates: entity.traumaState (created if absent).
176
+ *
177
+ * @param shockIncrement_Q The shock delta from the triggering event (Q).
178
+ */
179
+ export function recordTraumaEvent(entity, shockIncrement_Q) {
180
+ if (shockIncrement_Q < TRAUMA_TRIGGER_THRESHOLD)
181
+ return;
182
+ if (!entity.traumaState) {
183
+ entity.traumaState = { severity_Q: q(0) };
184
+ }
185
+ const increment = Math.round(shockIncrement_Q * TRAUMA_ACCUMULATION_RATE / SCALE.Q);
186
+ entity.traumaState.severity_Q = clampQ((entity.traumaState.severity_Q + increment), q(0), SCALE.Q);
187
+ }
188
+ /**
189
+ * Derive the effective fear-threshold multiplier from accumulated trauma.
190
+ *
191
+ * Returns Q in [TRAUMA_FEAR_MUL_FLOOR, SCALE.Q]:
192
+ * q(1.0) → no trauma — fear threshold unchanged.
193
+ * q(0.50) → maximum trauma — entity triggers fear at half normal threshold.
194
+ *
195
+ * Usage (combat / morale layer):
196
+ * `effectiveFearThreshold_Q = Math.round(baseFearThreshold_Q × mul / SCALE.Q)`
197
+ */
198
+ export function deriveFearThresholdMul(entity) {
199
+ if (!entity.traumaState || entity.traumaState.severity_Q <= 0) {
200
+ return SCALE.Q;
201
+ }
202
+ // severity q(1.0) → reduction q(0.50); linear interpolation
203
+ const reduction = Math.round(entity.traumaState.severity_Q * (SCALE.Q - TRAUMA_FEAR_MUL_FLOOR) / SCALE.Q);
204
+ return clampQ((SCALE.Q - reduction), TRAUMA_FEAR_MUL_FLOOR, SCALE.Q);
205
+ }
206
+ /**
207
+ * Compute aggregate sepsis risk (Q 0..SCALE.Q) from all infected regions.
208
+ *
209
+ * Risk increases with both the number of infected regions and their
210
+ * internal damage level. Returns q(0) if no infected regions.
211
+ *
212
+ * Usage: AI / medical layer reads this to prioritise treatment.
213
+ */
214
+ export function deriveSepsisRisk(entity) {
215
+ let totalRisk = 0;
216
+ for (const reg of Object.values(entity.injury.byRegion)) {
217
+ if (reg.infectedTick !== -1) {
218
+ // Risk contribution: internalDamage fraction of the infected region
219
+ totalRisk += reg.internalDamage;
220
+ }
221
+ }
222
+ return clampQ(totalRisk, q(0), SCALE.Q);
223
+ }
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Phase 31 — Species & Race System
3
+ *
4
+ * Data-driven species definitions that compose Archetype + BodyPlan + innate traits
5
+ * + capabilities + physiological overrides into a single declarative record.
6
+ *
7
+ * Covers:
8
+ * Fantasy humanoids — elf, dwarf, halfling, orc, ogre, goblin, troll (7)
9
+ * Sci-fi humanoids — Vulcan, Klingon, Romulan (3)
10
+ * Mythological — dragon, centaur, satyr (3)
11
+ * Fictional — Heechee (1)
12
+ */
13
+ import type { Archetype } from "./archetypes.js";
14
+ import type { IndividualAttributes } from "./types.js";
15
+ import type { BodyPlan } from "./sim/bodyplan.js";
16
+ import type { TraitId } from "./traits.js";
17
+ import type { CapabilitySource } from "./sim/capability.js";
18
+ import type { Weapon } from "./equipment.js";
19
+ import type { SkillMap } from "./sim/skills.js";
20
+ import { type Q } from "./units.js";
21
+ /** Runtime metabolic overrides attached to Entity.physiology (Phase 31). */
22
+ export interface SpeciesPhysiology {
23
+ /** True = ectotherm; stepCoreTemp is skipped entirely in the kernel. */
24
+ coldBlooded?: boolean;
25
+ /**
26
+ * Multiply the computed BMR before caloric drain.
27
+ * q(1.0) = normal; q(0.70) = slower starvation (e.g. meditative Vulcan);
28
+ * q(1.20) = high metabolism (e.g. aggressive Klingon).
29
+ */
30
+ bmrMultiplier?: Q;
31
+ /**
32
+ * Natural fur / scales / blubber insulation added to the armour insulation sum.
33
+ * Same unit as Armour.insulation_m2KW [m²K/W].
34
+ * Troll hide ≈ 0.08, Dragon scales ≈ 0.05.
35
+ */
36
+ naturalInsulation_m2KW?: number;
37
+ }
38
+ /**
39
+ * Everything `generateSpeciesIndividual` returns — the caller uses this to
40
+ * assemble a full Entity (set attributes, physiology, bodyPlan, apply traits,
41
+ * attach capabilities, add natural weapons to loadout).
42
+ */
43
+ export interface SpeciesEntitySpec {
44
+ attributes: IndividualAttributes;
45
+ physiology?: SpeciesPhysiology;
46
+ bodyPlan?: BodyPlan;
47
+ innateTraits: TraitId[];
48
+ innateCapabilities: CapabilitySource[];
49
+ naturalWeapons: Weapon[];
50
+ skillAptitudes?: SkillMap;
51
+ }
52
+ /** Declarative species record. */
53
+ export interface SpeciesDefinition {
54
+ id: string;
55
+ name: string;
56
+ description: string;
57
+ archetype: Archetype;
58
+ bodyPlan?: BodyPlan;
59
+ innateTraits?: TraitId[];
60
+ innateCapabilities?: CapabilitySource[];
61
+ naturalWeapons?: Weapon[];
62
+ physiology?: SpeciesPhysiology;
63
+ skillAptitudes?: SkillMap;
64
+ lore?: string;
65
+ }
66
+ /**
67
+ * Generate an individual from a species definition using a deterministic seed.
68
+ * Applies innate traits via `applyTraitsToAttributes` (which deep-copies attrs).
69
+ */
70
+ export declare function generateSpeciesIndividual(species: SpeciesDefinition, seed: number): SpeciesEntitySpec;
71
+ /** Elf — graceful, keen-sensed, sylvan endurance. */
72
+ export declare const ELF_SPECIES: SpeciesDefinition;
73
+ /** Dwarf — stocky, dense-boned, underground-adapted. */
74
+ export declare const DWARF_SPECIES: SpeciesDefinition;
75
+ /** Halfling — small, nimble, with surprising resilience. */
76
+ export declare const HALFLING_SPECIES: SpeciesDefinition;
77
+ /** Orc — powerful, pain-ignorant, high metabolic rate. */
78
+ export declare const ORC_SPECIES: SpeciesDefinition;
79
+ /** Ogre — massive, brutish, very slow decision-making. */
80
+ export declare const OGRE_SPECIES: SpeciesDefinition;
81
+ /** Goblin — small, cowardly, extremely fast reactions. */
82
+ export declare const GOBLIN_SPECIES: SpeciesDefinition;
83
+ /** Troll — massive regenerator, devastatingly vulnerable to fire. */
84
+ export declare const TROLL_SPECIES: SpeciesDefinition;
85
+ /** Vulcan — disciplined, strong, meditative metabolism; very low individual variance. */
86
+ export declare const VULCAN_SPECIES: SpeciesDefinition;
87
+ /** Klingon — aggressive warrior with redundant organs and thick cranial ridges. */
88
+ export declare const KLINGON_SPECIES: SpeciesDefinition;
89
+ /** Romulan — disciplined but more emotionally variable than Vulcans. */
90
+ export declare const ROMULAN_SPECIES: SpeciesDefinition;
91
+ /** Dragon — immense fire-breathing reptilian with scales and flight capability. */
92
+ export declare const DRAGON_SPECIES: SpeciesDefinition;
93
+ /** Centaur — horse body with human torso; CENTAUR_PLAN anatomy. */
94
+ export declare const CENTAUR_SPECIES: SpeciesDefinition;
95
+ /** Satyr — goat-human hybrid with natural horn and extraordinary balance. */
96
+ export declare const SATYR_SPECIES: SpeciesDefinition;
97
+ /**
98
+ * Heechee — Fred Pohl's Gateway aliens.
99
+ * Thin, soft-bodied, technologically advanced; fragile but extraordinarily precise.
100
+ */
101
+ export declare const HEECHEE_SPECIES: SpeciesDefinition;
102
+ export declare const FANTASY_HUMANOID_SPECIES: readonly SpeciesDefinition[];
103
+ export declare const SCIFI_HUMANOID_SPECIES: readonly SpeciesDefinition[];
104
+ export declare const MYTHOLOGICAL_SPECIES: readonly SpeciesDefinition[];
105
+ export declare const FICTIONAL_SPECIES: readonly SpeciesDefinition[];
106
+ export declare const ALL_SPECIES: readonly SpeciesDefinition[];