@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,237 @@
1
+ // src/faction.ts — Phase 24: Faction & Reputation System
2
+ //
3
+ // Tracks faction membership, inter-faction standing, entity reputation, and
4
+ // the witness system that propagates reputation deltas from combat events.
5
+ //
6
+ // No kernel import — pure data-management module.
7
+ import { SCALE, q, clampQ } from "./units.js";
8
+ import { TraceKinds } from "./sim/kinds.js";
9
+ import { canDetect, DEFAULT_SENSORY_ENV } from "./sim/sensory.js";
10
+ // ── Standing constants ────────────────────────────────────────────────────────
11
+ export const STANDING_EXALTED = q(1.0); // Intra-faction default
12
+ export const STANDING_ALLY = q(0.70); // Allied faction default
13
+ export const STANDING_NEUTRAL = q(0.50); // Unknown faction default
14
+ export const STANDING_RIVAL = q(0.20); // Rival faction default
15
+ export const STANDING_KOS = q(0.0); // Kill on sight
16
+ /** Standing below this → AI treats target as hostile. */
17
+ export const STANDING_HOSTILE_THRESHOLD = q(0.30);
18
+ /** Standing above this → AI will not initiate combat. */
19
+ export const STANDING_FRIENDLY_THRESHOLD = q(0.70);
20
+ /** Minimum detection quality for an entity to witness an event. */
21
+ export const WITNESS_DETECTION_THRESHOLD = q(0.60);
22
+ // ── Witness event delta magnitudes ────────────────────────────────────────────
23
+ const DELTA_KILL = q(-0.15);
24
+ const DELTA_ASSAULT = q(-0.05);
25
+ const DELTA_AID = q(0.08);
26
+ // ── Map-aware serialisation helpers ──────────────────────────────────────────
27
+ const MAP_MARKER = "__ananke_map__";
28
+ const SET_MARKER = "__ananke_set__";
29
+ function replacer(_key, value) {
30
+ if (value instanceof Map) {
31
+ return { [MAP_MARKER]: true, entries: [...value.entries()] };
32
+ }
33
+ if (value instanceof Set) {
34
+ return { [SET_MARKER]: true, values: [...value.values()] };
35
+ }
36
+ return value;
37
+ }
38
+ function reviver(_key, value) {
39
+ if (value !== null && typeof value === "object") {
40
+ const v = value;
41
+ if (v[MAP_MARKER] === true) {
42
+ return new Map(v.entries);
43
+ }
44
+ if (v[SET_MARKER] === true) {
45
+ return new Set(v.values);
46
+ }
47
+ }
48
+ return value;
49
+ }
50
+ // ── Factory ───────────────────────────────────────────────────────────────────
51
+ /**
52
+ * Create a FactionRegistry pre-populated with rival/ally default standings.
53
+ *
54
+ * Only direct relations need to be specified; symmetric standings are NOT
55
+ * applied automatically (enemy of A is not necessarily enemy of B).
56
+ */
57
+ export function createFactionRegistry(factions) {
58
+ const factionMap = new Map(factions.map(f => [f.id, f]));
59
+ const globalStanding = new Map();
60
+ for (const f of factions) {
61
+ const row = new Map();
62
+ for (const rival of f.rivals)
63
+ row.set(rival, STANDING_RIVAL);
64
+ for (const ally of f.allies)
65
+ row.set(ally, STANDING_ALLY);
66
+ globalStanding.set(f.id, row);
67
+ }
68
+ return {
69
+ factions: factionMap,
70
+ globalStanding,
71
+ entityReputations: new Map(),
72
+ };
73
+ }
74
+ // ── Standing computation ──────────────────────────────────────────────────────
75
+ /**
76
+ * Compute effective standing of entity `a` toward entity `b`.
77
+ *
78
+ * Priority (highest first):
79
+ * 1. Same faction → STANDING_EXALTED
80
+ * 2. Entity-level reputation (`registry.entityReputations.get(a.id)?.get(b.faction)`)
81
+ * combined with faction default — max of the two is used.
82
+ * 3. Global faction-to-faction standing
83
+ * 4. Rival / ally default from faction definition
84
+ * 5. STANDING_NEUTRAL (q(0.50)) for all unknown combinations
85
+ */
86
+ export function effectiveStanding(registry, a, b) {
87
+ const aFaction = a.faction;
88
+ const bFaction = b.faction;
89
+ // Same faction → exalted
90
+ if (aFaction && bFaction && aFaction === bFaction)
91
+ return STANDING_EXALTED;
92
+ // Entity-level reputation of a toward b's faction
93
+ const personalQ = bFaction
94
+ ? registry.entityReputations.get(a.id)?.get(bFaction)
95
+ : undefined;
96
+ // Faction-level standing of a's faction toward b's faction
97
+ let factionQ;
98
+ if (aFaction && bFaction) {
99
+ factionQ = registry.globalStanding.get(aFaction)?.get(bFaction);
100
+ }
101
+ // Combined: max of personal and faction (most favourable wins)
102
+ if (personalQ !== undefined && factionQ !== undefined) {
103
+ return Math.max(personalQ, factionQ);
104
+ }
105
+ if (personalQ !== undefined)
106
+ return personalQ;
107
+ if (factionQ !== undefined)
108
+ return factionQ;
109
+ return STANDING_NEUTRAL;
110
+ }
111
+ // ── Witness event application ─────────────────────────────────────────────────
112
+ /**
113
+ * Apply a witness event: adjust the actor's standing within the specified faction.
114
+ *
115
+ * Deltas are clamped to [0, SCALE.Q]. A kill of a faction member reduces the
116
+ * actor's standing with that faction; aiding a member increases it.
117
+ */
118
+ export function applyWitnessEvent(registry, event) {
119
+ let reps = registry.entityReputations.get(event.actorId);
120
+ if (!reps) {
121
+ reps = new Map();
122
+ registry.entityReputations.set(event.actorId, reps);
123
+ }
124
+ const current = reps.get(event.factionId) ?? STANDING_NEUTRAL;
125
+ reps.set(event.factionId, clampQ(current + event.delta, 0, SCALE.Q));
126
+ }
127
+ // ── Witness extraction ────────────────────────────────────────────────────────
128
+ /**
129
+ * Scan a TraceEvent stream and produce WitnessEvents for reputation-relevant
130
+ * actions (kills, assaults, aid).
131
+ *
132
+ * Only events where at least one bystander entity (not the actor or target) can
133
+ * detect the actor (`detectionQ ≥ WITNESS_DETECTION_THRESHOLD`) are included.
134
+ *
135
+ * Deduplication: at most one event per (actorId, eventType) per tick.
136
+ *
137
+ * @param factions Map of entityId → factionId for the current scenario.
138
+ */
139
+ export function extractWitnessEvents(events, world, factions) {
140
+ // First pass: collect which entities die each tick
141
+ const deaths = new Set();
142
+ for (const ev of events) {
143
+ if (ev.kind === TraceKinds.Death) {
144
+ deaths.add(`${ev.entityId}:${ev.tick}`);
145
+ }
146
+ }
147
+ const results = [];
148
+ const seen = new Set(); // dedupKey = `${actorId}:${eventType}:${tick}`
149
+ for (const ev of events) {
150
+ let actorId;
151
+ let targetId;
152
+ let eventType;
153
+ let delta;
154
+ if (ev.kind === TraceKinds.Attack && !ev.blocked && !ev.parried && ev.energy_J > 0) {
155
+ actorId = ev.attackerId;
156
+ targetId = ev.targetId;
157
+ const isKill = deaths.has(`${ev.targetId}:${ev.tick}`);
158
+ eventType = isKill ? "kill" : "assault";
159
+ delta = isKill ? DELTA_KILL : DELTA_ASSAULT;
160
+ }
161
+ else if (ev.kind === TraceKinds.TreatmentApplied) {
162
+ actorId = ev.treaterId;
163
+ targetId = ev.targetId;
164
+ eventType = "aid";
165
+ delta = DELTA_AID;
166
+ }
167
+ if (actorId === undefined || targetId === undefined || !eventType || delta === undefined) {
168
+ continue;
169
+ }
170
+ const dedupKey = `${actorId}:${eventType}:${ev.tick}`;
171
+ if (seen.has(dedupKey))
172
+ continue;
173
+ // Faction that cares: the target's faction
174
+ const targetFactionId = factions.get(targetId);
175
+ if (!targetFactionId)
176
+ continue;
177
+ // Check for at least one bystander witness
178
+ const actor = world.entities.find(e => e.id === actorId);
179
+ if (!actor)
180
+ continue;
181
+ let hasWitness = false;
182
+ for (const witness of world.entities) {
183
+ if (witness.id === actorId || witness.id === targetId)
184
+ continue;
185
+ if (witness.injury.dead)
186
+ continue;
187
+ if (canDetect(witness, actor, DEFAULT_SENSORY_ENV) >= WITNESS_DETECTION_THRESHOLD) {
188
+ hasWitness = true;
189
+ break;
190
+ }
191
+ }
192
+ if (!hasWitness)
193
+ continue;
194
+ seen.add(dedupKey);
195
+ results.push({
196
+ actorId,
197
+ targetId,
198
+ eventType,
199
+ factionId: targetFactionId,
200
+ delta,
201
+ tick: ev.tick,
202
+ });
203
+ }
204
+ return results;
205
+ }
206
+ // ── Faction-level standing mutation ──────────────────────────────────────────
207
+ /**
208
+ * Adjust the global faction-to-faction standing of `factionAId` toward
209
+ * `factionBId` by `delta`, clamped to [0, SCALE.Q].
210
+ *
211
+ * Used by the Polity diplomacy system (Phase 61) to apply `standingDelta`
212
+ * from `resolveDiplomacy`. The relation is one-directional; call twice with
213
+ * swapped arguments for a symmetric update.
214
+ */
215
+ export function applyFactionStanding(registry, factionAId, factionBId, delta) {
216
+ let row = registry.globalStanding.get(factionAId);
217
+ if (!row) {
218
+ row = new Map();
219
+ registry.globalStanding.set(factionAId, row);
220
+ }
221
+ const current = row.get(factionBId) ?? STANDING_NEUTRAL;
222
+ row.set(factionBId, clampQ(current + delta, 0, SCALE.Q));
223
+ }
224
+ // ── Serialisation ─────────────────────────────────────────────────────────────
225
+ /**
226
+ * Serialise a FactionRegistry to a JSON string.
227
+ * Handles all nested Map and Set fields (rivals, allies, globalStanding, entityReputations).
228
+ */
229
+ export function serialiseFactionRegistry(registry) {
230
+ return JSON.stringify(registry, replacer);
231
+ }
232
+ /**
233
+ * Deserialise a FactionRegistry from a JSON string produced by `serialiseFactionRegistry`.
234
+ */
235
+ export function deserialiseFactionRegistry(json) {
236
+ return JSON.parse(json, reviver);
237
+ }
@@ -0,0 +1,35 @@
1
+ import type { IndividualAttributes } from "./types.js";
2
+ import type { Archetype } from "./archetypes.js";
3
+ /**
4
+ * Signed bias applied to a character-generation axis, range [−1, 1].
5
+ *
6
+ * `+1` strongly skews toward the high end of the archetype's natural spread;
7
+ * `−1` toward the low end. Values outside [−1, 1] are clamped internally.
8
+ * A biased character is still drawn from the population — just from a
9
+ * different part of the tail — so physical plausibility is preserved.
10
+ *
11
+ * Fields map to these generation axes:
12
+ * `strength` peakForce_N, peakPower_W, continuousPower_W, actuatorScale
13
+ * `speed` reactionTime_s (positive bias → faster; i.e. lower time)
14
+ * `resilience` distressTolerance, shockTolerance, concussionTolerance,
15
+ * surface/bulk/structureIntegrity, recoveryRate
16
+ * (positive bias also reduces fatigueRate)
17
+ * `agility` controlQuality, fineControl, stability
18
+ * `size` stature_m, mass_kg (also influences reach)
19
+ *
20
+ * Note: per-individual cognitive variance (`intellect` bias) is reserved for
21
+ * a future phase once `Archetype.cognition` gains per-individual draws.
22
+ */
23
+ export interface NarrativeBias {
24
+ /** Biases physical force and power output. */
25
+ strength?: number;
26
+ /** Biases reaction speed. Positive = faster (lower reactionTime_s). */
27
+ speed?: number;
28
+ /** Biases damage tolerance and recovery. Positive = tougher. */
29
+ resilience?: number;
30
+ /** Biases motor control precision and stability. */
31
+ agility?: number;
32
+ /** Biases body size (stature and mass). */
33
+ size?: number;
34
+ }
35
+ export declare function generateIndividual(seedU32: number, arch: Archetype, bias?: NarrativeBias): IndividualAttributes;
@@ -0,0 +1,166 @@
1
+ /*
2
+ Morphology scaling philosophy:
3
+
4
+ We intentionally damp size → strength scaling.
5
+
6
+ Real biology:
7
+ - strength ∝ cross-section (~mass^(2/3))
8
+ - mass ∝ volume
9
+ - energy cost grows faster than usable force
10
+
11
+ Gameplay:
12
+ - prevents giants from dominating
13
+ - keeps small entities viable
14
+ - allows cross-species balance
15
+
16
+ Therefore:
17
+ Most morphology scaling uses PARTIAL influence
18
+ (~20–35% of raw geometric scaling)
19
+ */
20
+ import { makeRng } from "./rng.js";
21
+ import { SCALE, clampQ, q, qMul, mulDiv } from "./units.js";
22
+ import { triSym, biasedTriSym, mulFromVariation, skewUp } from "./dist.js";
23
+ // Math.cos is allowed here: generation path, not simulation path.
24
+ function halfArcCosQ(arcDeg) {
25
+ const halfRad = (arcDeg / 2) * (Math.PI / 180);
26
+ return Math.round(Math.cos(halfRad) * SCALE.Q);
27
+ }
28
+ function applyMultI32(base, multQ) {
29
+ return mulDiv(base, multQ, SCALE.Q);
30
+ }
31
+ function clampI32(x, lo, hi) {
32
+ return Math.max(lo, Math.min(hi, x));
33
+ }
34
+ function sqrtNear1Q(mult) {
35
+ return (mult + SCALE.Q) >>> 1;
36
+ }
37
+ export function generateIndividual(seedU32, arch, bias) {
38
+ const rng = makeRng(seedU32 >>> 0, SCALE.Q);
39
+ // Convenience: biasedTriSym(rng, 0) === triSym(rng), so unbiased calls
40
+ // are identical to the previous behaviour when bias is undefined.
41
+ const sz = bias?.size ?? 0;
42
+ const str = bias?.strength ?? 0;
43
+ const spd = bias?.speed ?? 0;
44
+ const res = bias?.resilience ?? 0;
45
+ const agi = bias?.agility ?? 0;
46
+ const statureMult = mulFromVariation(biasedTriSym(rng, sz), arch.statureVar);
47
+ const massMult = mulFromVariation(biasedTriSym(rng, sz), arch.massVar);
48
+ const reachMult = mulFromVariation(biasedTriSym(rng, sz), arch.reachVar);
49
+ const actuatorScaleBase = mulFromVariation(biasedTriSym(rng, str), arch.actuatorScaleVar);
50
+ // Combine stature + mass into a single “size composite”.
51
+ // We use sqrt scaling to avoid extreme linear growth:
52
+ // - doubling mass should NOT double strength directly
53
+ // - tall + heavy should scale sub-linearly
54
+ const sizeComposite = qMul(sqrtNear1Q(statureMult), sqrtNear1Q(massMult));
55
+ /*
56
+ Actuator scaling rule:
57
+
58
+ We do NOT apply full sizeComposite directly to force/power.
59
+ Instead we apply only ~25% of size deviation from baseline.
60
+
61
+ Why:
62
+ - Prevent giant entities becoming absurdly strong
63
+ - Prevent small entities becoming unusably weak
64
+ - Maintain cross-species balance
65
+ - Keep simulation numerically stable
66
+
67
+ Formula:
68
+ effectiveScale = 1 + (sizeComposite - 1) * 1.34
69
+
70
+ 51% geometric scaling (damped).
71
+ */
72
+ const actuatorScale = clampQ(qMul(actuatorScaleBase, (SCALE.Q + mulDiv(sizeComposite - SCALE.Q, q(1.34), SCALE.Q))), q(0.6), // lower bound: still functional
73
+ q(1.8) // upper bound: avoid runaway strength
74
+ );
75
+ const structureScaleBase = mulFromVariation(biasedTriSym(rng, res), arch.structureScaleVar);
76
+ const structureScale = clampQ(qMul(structureScaleBase, (SCALE.Q + ((sizeComposite - SCALE.Q) >>> 3))), q(0.7), q(2.0));
77
+ const stature_m = applyMultI32(arch.stature_m, statureMult);
78
+ const mass_kg = applyMultI32(arch.mass_kg, massMult);
79
+ const actuatorFracVar = mulFromVariation(biasedTriSym(rng, str), arch.actuatorMassVar);
80
+ const actuatorFrac = clampQ(qMul(arch.actuatorMassFrac, actuatorFracVar), q(0.15), q(0.70));
81
+ const actuatorMass_kg_raw = mulDiv(mass_kg, actuatorFrac, SCALE.Q);
82
+ const actuatorMass_kg = clampI32(actuatorMass_kg_raw, mulDiv(mass_kg, q(0.15), SCALE.Q), mulDiv(mass_kg, q(0.70), SCALE.Q));
83
+ const forceRand = mulFromVariation(biasedTriSym(rng, str), arch.peakForceVar);
84
+ const forceCouple = clampQ(qMul(actuatorScale, (SCALE.Q + ((actuatorFrac - arch.actuatorMassFrac) >> 1))), q(0.6), q(2.2));
85
+ const peakForceMult = clampQ(qMul(forceRand, forceCouple), q(0.5), q(2.5));
86
+ const powerRand = mulFromVariation(biasedTriSym(rng, str), arch.peakPowerVar);
87
+ const powerMult = clampQ(skewUp(qMul(powerRand, actuatorScale), 1), q(0.5), q(3.0));
88
+ const contRand = mulFromVariation(biasedTriSym(rng, str), arch.continuousPowerVar);
89
+ const contMult = clampQ(qMul(contRand, sqrtNear1Q(actuatorFrac)), q(0.4), q(3.0));
90
+ const reserveRand = mulFromVariation(biasedTriSym(rng, res), arch.reserveEnergyVar);
91
+ const reserveMult = clampQ(qMul(reserveRand, sqrtNear1Q(actuatorFrac)), q(0.3), q(4.0));
92
+ const effMult = mulFromVariation(biasedTriSym(rng, str), arch.efficiencyVar);
93
+ const conversionEfficiency = clampQ(qMul(arch.conversionEfficiency, effMult), q(0.45), q(0.98));
94
+ const peakForce_N = applyMultI32(arch.peakForce_N, peakForceMult);
95
+ const peakPower_W = applyMultI32(arch.peakPower_W, powerMult);
96
+ const continuousPower_W = applyMultI32(arch.continuousPower_W, contMult);
97
+ const reserveEnergy_J = applyMultI32(arch.reserveEnergy_J, reserveMult);
98
+ const controlMult = mulFromVariation(biasedTriSym(rng, agi), arch.controlVar);
99
+ const controlQuality = clampQ(qMul(arch.controlQuality, controlMult), q(0.15), q(0.98));
100
+ // speed bias is negated: +speed → shorter (faster) reactionTime
101
+ const reactMult = mulFromVariation(biasedTriSym(rng, -spd), arch.reactionTimeVar);
102
+ const reactCouple = clampQ((SCALE.Q + ((SCALE.Q - controlQuality) >>> 2)), q(0.75), q(1.30));
103
+ const reactionTime_s = applyMultI32(arch.reactionTime_s, qMul(reactMult, reactCouple));
104
+ const stability = clampQ(qMul(arch.stability, mulFromVariation(biasedTriSym(rng, agi), arch.stabilityVar)), q(0.05), q(0.99));
105
+ const rawFineControl = clampQ(qMul(arch.fineControl, mulFromVariation(biasedTriSym(rng, agi), arch.fineControlVar)), q(0.05), q(0.99));
106
+ // Phase 33: bodilyKinesthetic sets a floor on fine motor precision
107
+ const bkFloor = arch.cognition ? qMul(arch.cognition.bodilyKinesthetic, q(0.80)) : q(0);
108
+ const fineControl = clampQ(Math.max(rawFineControl, bkFloor), q(0.05), q(0.99));
109
+ const surfaceIntegrity = clampQ(qMul(arch.surfaceIntegrity, mulFromVariation(biasedTriSym(rng, res), arch.surfaceVar)), q(0.4), q(3.0));
110
+ const bulkIntegrity = clampQ(qMul(arch.bulkIntegrity, mulFromVariation(biasedTriSym(rng, res), arch.bulkVar)), q(0.4), q(3.0));
111
+ const structureIntegrity = clampQ(qMul(arch.structureIntegrity, mulFromVariation(biasedTriSym(rng, res), arch.structVar)), q(0.4), q(3.0));
112
+ const distressTolerance = clampQ(qMul(arch.distressTolerance, mulFromVariation(biasedTriSym(rng, res), arch.distressVar)), q(0.01), q(0.98));
113
+ const shockTolerance = clampQ(qMul(arch.shockTolerance, mulFromVariation(biasedTriSym(rng, res), arch.shockVar)), q(0.01), q(0.98));
114
+ const concussionTolerance = clampQ(qMul(arch.concussionTolerance, mulFromVariation(biasedTriSym(rng, res), arch.concVar)), q(0.01), q(0.98));
115
+ const heatTolerance = clampQ(qMul(arch.heatTolerance, mulFromVariation(triSym(rng), arch.heatVar)), q(0.01), q(0.98));
116
+ const coldTolerance = clampQ(qMul(arch.coldTolerance, mulFromVariation(triSym(rng), arch.coldVar)), q(0.01), q(0.98));
117
+ // positive resilience bias → lower fatigue rate (better endurance), so bias is negated
118
+ const fatigueRate = clampQ(qMul(arch.fatigueRate, mulFromVariation(biasedTriSym(rng, -res), arch.fatigueVar)), q(0.4), q(2.5));
119
+ const recoveryRate = clampQ(qMul(arch.recoveryRate, mulFromVariation(biasedTriSym(rng, res), arch.recoveryVar)), q(0.4), q(2.5));
120
+ return {
121
+ morphology: {
122
+ stature_m,
123
+ mass_kg,
124
+ actuatorMass_kg,
125
+ actuatorScale,
126
+ structureScale,
127
+ reachScale: reachMult,
128
+ },
129
+ performance: {
130
+ peakForce_N,
131
+ peakPower_W,
132
+ continuousPower_W,
133
+ reserveEnergy_J,
134
+ conversionEfficiency,
135
+ },
136
+ control: {
137
+ controlQuality,
138
+ reactionTime_s,
139
+ stability,
140
+ fineControl,
141
+ },
142
+ resilience: {
143
+ surfaceIntegrity,
144
+ bulkIntegrity,
145
+ structureIntegrity,
146
+ distressTolerance,
147
+ shockTolerance,
148
+ concussionTolerance,
149
+ heatTolerance,
150
+ coldTolerance,
151
+ fatigueRate,
152
+ recoveryRate,
153
+ },
154
+ perception: {
155
+ visionRange_m: arch.visionRange_m,
156
+ visionArcDeg: arch.visionArcDeg,
157
+ halfArcCosQ: halfArcCosQ(arch.visionArcDeg),
158
+ hearingRange_m: arch.hearingRange_m,
159
+ decisionLatency_s: arch.decisionLatency_s,
160
+ attentionDepth: arch.attentionDepth,
161
+ threatHorizon_m: arch.threatHorizon_m,
162
+ },
163
+ // Phase 33: pass through species-typical cognition (no per-individual variance)
164
+ ...(arch.cognition ? { cognition: arch.cognition } : {}),
165
+ };
166
+ }
@@ -0,0 +1,42 @@
1
+ export * from "./units.js";
2
+ export * from "./types.js";
3
+ export * from "./archetypes.js";
4
+ export * from "./generate.js";
5
+ export * from "./equipment.js";
6
+ export * from "./sim/vec3.js";
7
+ export * from "./sim/condition.js";
8
+ export * from "./sim/injury.js";
9
+ export * from "./sim/entity.js";
10
+ export * from "./sim/commands.js";
11
+ export * from "./sim/kernel.js";
12
+ export * from "./sim/body.js";
13
+ export * from "./sim/world.js";
14
+ export * from "./model3d.js";
15
+ export * from "./replay.js";
16
+ export * from "./bridge/index.js";
17
+ export * from "./channels.js";
18
+ export * from "./traits.js";
19
+ export * from "./derive.js";
20
+ export * from "./sim/intent.js";
21
+ export * from "./sim/action.js";
22
+ export * from "./sim/combat.js";
23
+ export * from "./quest.js";
24
+ export * from "./quest-generators.js";
25
+ export * from "./relationships.js";
26
+ export * from "./relationships-effects.js";
27
+ export * from "./inventory.js";
28
+ export * from "./item-durability.js";
29
+ export * from "./settlement.js";
30
+ export * from "./settlement-services.js";
31
+ export * from "./chronicle.js";
32
+ export * from "./story-arcs.js";
33
+ export * from "./narrative-render.js";
34
+ export * from "./world-generation.js";
35
+ export * from "./sim/trace.js";
36
+ export * from "./rng.js";
37
+ export * from "./dist.js";
38
+ export * from "./lod.js";
39
+ export * from "./sim/impairment.js";
40
+ export * from "./sim/indexing.js";
41
+ export * from "./sim/tuning.js";
42
+ export * from "./sim/testing.js";
@@ -0,0 +1,54 @@
1
+ // ── Tier 1 — Stable host API ─────────────────────────────────────────────────
2
+ // These exports form the public integration surface. Breaking changes require
3
+ // a major semver bump (x.0.0) and a migration guide in CHANGELOG.md.
4
+ // Safe to import directly in host applications and typed as stable in STABLE_API.md.
5
+ export * from "./units.js"; // q(), SCALE, qMul, mulDiv — fixed-point arithmetic
6
+ export * from "./types.js"; // IndividualAttributes, core scalar types
7
+ export * from "./archetypes.js"; // Archetype, BodyPlan, built-in species presets
8
+ export * from "./generate.js"; // generateIndividual()
9
+ export * from "./equipment.js"; // WEAPONS database, EquipmentCatalogue
10
+ export * from "./sim/vec3.js"; // Vec3, lerpVec3, addVec3 — 3-D vector helpers
11
+ export * from "./sim/condition.js"; // ConditionSnapshot, condition constants
12
+ export * from "./sim/injury.js"; // InjuryRegion, BodyRegion, injury constants
13
+ export * from "./sim/entity.js"; // Entity (stable fields: id, pos, mass_kg, attributes…)
14
+ export * from "./sim/commands.js"; // CommandMap, EntityCommand, action verbs
15
+ export * from "./sim/kernel.js"; // stepWorld(), applyImpactToInjury(), applyExplosion()
16
+ export * from "./sim/body.js"; // BodyPlan, BodySegment, humanoid / quadruped plans
17
+ export * from "./sim/world.js"; // WorldState, KernelContext, createWorld()
18
+ export * from "./model3d.js"; // extractRigSnapshots(), deriveAnimationHints(), RigSnapshot, AnimationHints, GrapplePoseConstraint
19
+ export * from "./replay.js"; // ReplayRecorder, replayTo(), serializeReplay(), deserializeReplay()
20
+ export * from "./bridge/index.js"; // BridgeEngine, InterpolatedState, BridgeConfig — 3D renderer bridge
21
+ // ── Tier 2 — Advanced / experimental API ─────────────────────────────────────
22
+ // Tested and usable subsystems under active development. May change between
23
+ // minor versions (0.x.0); CHANGELOG.md will document any breaking change.
24
+ // Reference STABLE_API.md §Tier 2 for the full export list per module.
25
+ export * from "./channels.js"; // damage channel constants (BLUNT, SLASH, …)
26
+ export * from "./traits.js"; // trait descriptors
27
+ export * from "./derive.js"; // derived attribute helpers
28
+ export * from "./sim/intent.js"; // IntentMap, buildIntent()
29
+ export * from "./sim/action.js"; // ActionResult, resolveAction()
30
+ export * from "./sim/combat.js"; // resolveHit(), resolveParry(), applyCombat()
31
+ export * from "./quest.js"; // Quest, QuestObjective, questStep()
32
+ export * from "./quest-generators.js"; // generateQuest(), generateQuestChain()
33
+ export * from "./relationships.js"; // RelationshipMap, updateRelationship()
34
+ export * from "./relationships-effects.js"; // applyRelationshipEffect()
35
+ export * from "./inventory.js"; // Inventory, equipItem(), addItemToInventory()
36
+ export * from "./item-durability.js"; // durability helpers, resolveRepair()
37
+ export * from "./settlement.js"; // Settlement, stepSettlement()
38
+ export * from "./settlement-services.js"; // service resolution helpers
39
+ export * from "./chronicle.js"; // ChronicleEntry, addChronicleEntry()
40
+ export * from "./story-arcs.js"; // StoryArc, detectArcs()
41
+ export * from "./narrative-render.js"; // renderEntry(), renderChronicle(), generateNarrative()
42
+ export * from "./world-generation.js"; // WorldTemplate, generateWorld()
43
+ export * from "./sim/trace.js"; // SimTrace, traceStep() — debugging / profiling
44
+ // ── Tier 3 — Internal / kernel API ───────────────────────────────────────────
45
+ // Exported for power users and diagnostic tooling. Not stability-guaranteed;
46
+ // may change at any time without a changelog entry. Prefer Tier 1/2 surfaces
47
+ // in production host code. See STABLE_API.md §Tier 3 for rationale.
48
+ export * from "./rng.js"; // makeRng(), eventSeed() — RNG internals
49
+ export * from "./dist.js"; // distribution primitives
50
+ export * from "./lod.js"; // level-of-detail helpers
51
+ export * from "./sim/impairment.js"; // low-level impairment accumulators
52
+ export * from "./sim/indexing.js"; // SpatialIndex internals
53
+ export * from "./sim/tuning.js"; // kernel tuning constants (may be adjusted)
54
+ export * from "./sim/testing.js"; // mkHumanoidEntity() and other test helpers
@@ -0,0 +1,69 @@
1
+ import type { Q } from "./units.js";
2
+ import type { Entity } from "./sim/entity.js";
3
+ import type { CampaignState } from "./campaign.js";
4
+ import type { RelationshipGraph } from "./relationships.js";
5
+ export interface InheritanceSpec {
6
+ deceasedId: number;
7
+ heirId: number;
8
+ /**
9
+ * Fraction of relationship trust / affinity that passes to the heir.
10
+ * q(1.0) = full copy; q(0.50) = half strength; q(0) = no inheritance.
11
+ * Default: q(0.50).
12
+ */
13
+ relationshipTransferRate_Q?: Q;
14
+ }
15
+ export interface InheritanceReport {
16
+ /** Number of loadout items moved from deceased to heir. */
17
+ itemsTransferred: number;
18
+ /** Number of new relationship entries created for the heir. */
19
+ relationshipsTransferred: number;
20
+ /** Inventory items (itemId → count) transferred from deceased to heir. */
21
+ inventoryTransferred: Map<string, number>;
22
+ }
23
+ /**
24
+ * Move all loadout items from deceased to heir.
25
+ * Heir's existing items are preserved (deceased's items are appended).
26
+ * Deceased's loadout is cleared.
27
+ *
28
+ * @returns Number of items transferred.
29
+ */
30
+ export declare function transferEquipment(deceased: Entity, heir: Entity): number;
31
+ /**
32
+ * Partially copy the deceased's relationships to the heir.
33
+ *
34
+ * For each relationship R(deceased, X):
35
+ * heir's trust_Q = R.trust_Q × transferRate_Q
36
+ * heir's affinity_Q = |R.affinity_Q| × transferRate_Q (sign preserved)
37
+ *
38
+ * Existing heir–X relationships are not overwritten.
39
+ * The deceased's relationships are left in the graph unmodified.
40
+ *
41
+ * @returns Number of new heir relationships created.
42
+ */
43
+ export declare function transferRelationships(graph: RelationshipGraph, deceasedId: number, heirId: number, transferRate_Q: Q): number;
44
+ /**
45
+ * Transfer all campaign inventory items from deceased to heir.
46
+ * Stacks merge: heir's existing counts are summed with deceased's amounts.
47
+ * The deceased's campaign inventory entry is deleted after transfer.
48
+ *
49
+ * @returns Map of transferred items (itemId → count transferred).
50
+ */
51
+ export declare function transferInventory(campaign: CampaignState, deceasedId: number, heirId: number): Map<string, number>;
52
+ /**
53
+ * Apply the full inheritance process when a character dies and an heir takes over.
54
+ *
55
+ * Steps performed:
56
+ * 1. Transfers loadout equipment from deceased to heir entity.
57
+ * 2. Transfers campaign inventory (deceased → heir, with stack merging).
58
+ * 3. Partially transfers relationships (if `graph` is provided).
59
+ * 4. Moves the deceased's campaign location to the heir.
60
+ * 5. Registers the heir in the campaign; removes the deceased.
61
+ * 6. Logs the event to `campaign.log`.
62
+ *
63
+ * Both deceased (via `campaign.entities`) and heir (provided directly) must be
64
+ * supplied. The deceased entity is updated in-place before being removed so
65
+ * that equipment is properly cleared.
66
+ *
67
+ * @returns InheritanceReport with counts of transferred items and relationships.
68
+ */
69
+ export declare function applyInheritance(campaign: CampaignState, graph: RelationshipGraph | undefined, spec: InheritanceSpec, heir: Entity): InheritanceReport;