@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,64 @@
|
|
|
1
|
+
import { BodyRegion } from "./body";
|
|
2
|
+
import { BodySegmentId } from "./bodyplan";
|
|
3
|
+
/** Commands are player/AI intentions */
|
|
4
|
+
export declare const CommandKinds: {
|
|
5
|
+
readonly Move: "move";
|
|
6
|
+
readonly Attack: "attack";
|
|
7
|
+
readonly AttackNearest: "attackNearest";
|
|
8
|
+
readonly Defend: "defend";
|
|
9
|
+
readonly Grapple: "grapple";
|
|
10
|
+
readonly BreakGrapple: "breakGrapple";
|
|
11
|
+
readonly BreakBind: "breakBind";
|
|
12
|
+
readonly Shoot: "shoot";
|
|
13
|
+
readonly Treat: "treat";
|
|
14
|
+
readonly SetProne: "setProne";
|
|
15
|
+
readonly Activate: "activate";
|
|
16
|
+
};
|
|
17
|
+
export type CommandKind = typeof CommandKinds[keyof typeof CommandKinds];
|
|
18
|
+
/** Trace events are engine observations */
|
|
19
|
+
export declare const TraceKinds: {
|
|
20
|
+
readonly TickStart: "tickStart";
|
|
21
|
+
readonly TickEnd: "tickEnd";
|
|
22
|
+
readonly Intent: "intent";
|
|
23
|
+
readonly Move: "move";
|
|
24
|
+
readonly Injury: "injury";
|
|
25
|
+
readonly Attack: "attack";
|
|
26
|
+
readonly AttackAttempt: "attackAttempt";
|
|
27
|
+
readonly Grapple: "grapple";
|
|
28
|
+
readonly KO: "ko";
|
|
29
|
+
readonly Death: "death";
|
|
30
|
+
readonly WeaponBind: "weaponBind";
|
|
31
|
+
readonly WeaponBindBreak: "weaponBindBreak";
|
|
32
|
+
readonly ProjectileHit: "projectileHit";
|
|
33
|
+
readonly MoraleRoute: "moraleRoute";
|
|
34
|
+
readonly MoraleRally: "moraleRally";
|
|
35
|
+
readonly Fracture: "fracture";
|
|
36
|
+
readonly TreatmentApplied: "treatmentApplied";
|
|
37
|
+
readonly BlastHit: "blastHit";
|
|
38
|
+
readonly CapabilityActivated: "capabilityActivated";
|
|
39
|
+
readonly CapabilitySuppressed: "capabilitySuppressed";
|
|
40
|
+
readonly CastInterrupted: "castInterrupted";
|
|
41
|
+
};
|
|
42
|
+
export type TraceKind = typeof TraceKinds[keyof typeof TraceKinds];
|
|
43
|
+
export type AllKinds = CommandKind | TraceKind;
|
|
44
|
+
export declare const MoveModes: {
|
|
45
|
+
readonly Walk: "walk";
|
|
46
|
+
readonly Run: "run";
|
|
47
|
+
readonly Sprint: "sprint";
|
|
48
|
+
readonly Crawl: "crawl";
|
|
49
|
+
readonly Hover: "hover";
|
|
50
|
+
};
|
|
51
|
+
export type MoveMode = typeof MoveModes[keyof typeof MoveModes];
|
|
52
|
+
export declare const DefenceModes: {
|
|
53
|
+
readonly None: "none";
|
|
54
|
+
readonly Block: "block";
|
|
55
|
+
readonly Parry: "parry";
|
|
56
|
+
readonly Dodge: "dodge";
|
|
57
|
+
};
|
|
58
|
+
export type DefenceMode = typeof DefenceModes[keyof typeof DefenceModes];
|
|
59
|
+
export declare const EngageModes: {
|
|
60
|
+
readonly None: "none";
|
|
61
|
+
readonly Strike: "strike";
|
|
62
|
+
};
|
|
63
|
+
export type EngageMode = typeof EngageModes[keyof typeof EngageModes];
|
|
64
|
+
export type HitArea = BodyRegion | BodySegmentId;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// src/sim/kinds.ts
|
|
2
|
+
/** Commands are player/AI intentions */
|
|
3
|
+
export const CommandKinds = {
|
|
4
|
+
Move: "move",
|
|
5
|
+
Attack: "attack",
|
|
6
|
+
AttackNearest: "attackNearest",
|
|
7
|
+
Defend: "defend",
|
|
8
|
+
Grapple: "grapple",
|
|
9
|
+
BreakGrapple: "breakGrapple",
|
|
10
|
+
BreakBind: "breakBind", // Phase 2C
|
|
11
|
+
Shoot: "shoot", // Phase 3
|
|
12
|
+
Treat: "treat", // Phase 9
|
|
13
|
+
SetProne: "setProne",
|
|
14
|
+
Activate: "activate", // Phase 12: use a capability source effect
|
|
15
|
+
};
|
|
16
|
+
/** Trace events are engine observations */
|
|
17
|
+
export const TraceKinds = {
|
|
18
|
+
TickStart: "tickStart",
|
|
19
|
+
TickEnd: "tickEnd",
|
|
20
|
+
Intent: "intent",
|
|
21
|
+
Move: "move",
|
|
22
|
+
Injury: "injury",
|
|
23
|
+
Attack: "attack",
|
|
24
|
+
AttackAttempt: "attackAttempt",
|
|
25
|
+
Grapple: "grapple",
|
|
26
|
+
KO: "ko",
|
|
27
|
+
Death: "death",
|
|
28
|
+
WeaponBind: "weaponBind", // Phase 2C
|
|
29
|
+
WeaponBindBreak: "weaponBindBreak", // Phase 2C
|
|
30
|
+
ProjectileHit: "projectileHit", // Phase 3
|
|
31
|
+
MoraleRoute: "moraleRoute", // Phase 5
|
|
32
|
+
MoraleRally: "moraleRally", // Phase 18
|
|
33
|
+
Fracture: "fracture", // Phase 9
|
|
34
|
+
TreatmentApplied: "treatmentApplied", // Phase 9
|
|
35
|
+
BlastHit: "blastHit", // Phase 10
|
|
36
|
+
CapabilityActivated: "capabilityActivated", // Phase 12
|
|
37
|
+
CapabilitySuppressed: "capabilitySuppressed", // Phase 12
|
|
38
|
+
CastInterrupted: "castInterrupted", // Phase 12
|
|
39
|
+
};
|
|
40
|
+
export const MoveModes = {
|
|
41
|
+
Walk: "walk",
|
|
42
|
+
Run: "run",
|
|
43
|
+
Sprint: "sprint",
|
|
44
|
+
Crawl: "crawl",
|
|
45
|
+
Hover: "hover",
|
|
46
|
+
};
|
|
47
|
+
export const DefenceModes = {
|
|
48
|
+
None: "none",
|
|
49
|
+
Block: "block",
|
|
50
|
+
Parry: "parry",
|
|
51
|
+
Dodge: "dodge",
|
|
52
|
+
};
|
|
53
|
+
export const EngageModes = {
|
|
54
|
+
None: "none",
|
|
55
|
+
Strike: "strike",
|
|
56
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { Entity } from "./entity.js";
|
|
2
|
+
/** Effective Δv at which a target begins to stumble (0.5 m/s in SCALE.mps units). */
|
|
3
|
+
export declare const STAGGER_THRESHOLD_mps: number;
|
|
4
|
+
/** Effective Δv at which a target is knocked prone (2.0 m/s in SCALE.mps units). */
|
|
5
|
+
export declare const PRONE_THRESHOLD_mps: number;
|
|
6
|
+
/** Ticks of reduced-action window while staggered. */
|
|
7
|
+
export declare const STAGGER_TICKS = 3;
|
|
8
|
+
export interface KnockbackResult {
|
|
9
|
+
/** Raw impulse in real Newton-seconds (diagnostic; not used in further simulation math). */
|
|
10
|
+
impulse_Ns: number;
|
|
11
|
+
/** Effective velocity delta in SCALE.mps units, after stability reduction. Applied to target. */
|
|
12
|
+
knockback_v: number;
|
|
13
|
+
/** True when effective_v ≥ STAGGER_THRESHOLD and entity is not knocked prone. */
|
|
14
|
+
staggered: boolean;
|
|
15
|
+
/** True when effective_v ≥ PRONE_THRESHOLD. Implies staggered. */
|
|
16
|
+
prone: boolean;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Derive knockback result from an impact.
|
|
20
|
+
*
|
|
21
|
+
* Physics derivation:
|
|
22
|
+
* impulse = sqrt(2 × E × m_eff) [N·s — same as p = m_eff × v_head]
|
|
23
|
+
* raw_Δv = impulse / m_target [m/s]
|
|
24
|
+
* effective_v = raw_Δv × (1 − stabilityQ)
|
|
25
|
+
*
|
|
26
|
+
* Calibration:
|
|
27
|
+
* 5.56 mm (4 g, 1760 J, 75 kg target): Δv ≈ 0.05 m/s — negligible ✓
|
|
28
|
+
* 12-gauge slug (28 g, 2100 J, 75 kg): Δv ≈ 0.25 m/s raw — stagger on low-stability target
|
|
29
|
+
* Large creature kick (50 kg eff, 400 J, 75 kg): Δv ≈ 2.67 m/s raw — prone on low-stability
|
|
30
|
+
*
|
|
31
|
+
* @param energy_J Impact energy (raw joules; SCALE.J = 1).
|
|
32
|
+
* @param massEff_kg Effective striking mass in SCALE.kg units (wpn + body fraction, or projectile).
|
|
33
|
+
* @param target Target entity (reads mass_kg and stabilityQ).
|
|
34
|
+
*/
|
|
35
|
+
export declare function computeKnockback(energy_J: number, massEff_kg: number, target: Entity): KnockbackResult;
|
|
36
|
+
/**
|
|
37
|
+
* Apply knockback result to an entity.
|
|
38
|
+
*
|
|
39
|
+
* - Adds `result.knockback_v` to the entity's velocity in the hit direction.
|
|
40
|
+
* - Sets `condition.prone = true` when result.prone.
|
|
41
|
+
* - Sets `action.staggerTicks = STAGGER_TICKS` when result.staggered.
|
|
42
|
+
*
|
|
43
|
+
* @param entity Target entity (mutated in-place).
|
|
44
|
+
* @param result Result from `computeKnockback`.
|
|
45
|
+
* @param dir Direction from attacker to target in SCALE.m coordinates (unnormalised).
|
|
46
|
+
*/
|
|
47
|
+
export declare function applyKnockback(entity: Entity, result: KnockbackResult, dir: {
|
|
48
|
+
dx: number;
|
|
49
|
+
dy: number;
|
|
50
|
+
}): void;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
// src/sim/knockback.ts — Phase 26: Momentum Transfer & Knockback
|
|
2
|
+
//
|
|
3
|
+
// Impulse-momentum model for melee and ranged impacts.
|
|
4
|
+
// Physics: impulse = sqrt(2 × E × m_eff); Δv = impulse / m_target
|
|
5
|
+
// Stability modifier reduces effective knockback before threshold checks.
|
|
6
|
+
//
|
|
7
|
+
// Math.sqrt is used for impulse calculation — acceptable per project convention
|
|
8
|
+
// (already used in kernel.ts for velocity magnitude computations).
|
|
9
|
+
import { SCALE, qMul } from "../units.js";
|
|
10
|
+
import { normaliseDirCheapQ } from "./vec3.js";
|
|
11
|
+
import { mulDiv } from "../units.js";
|
|
12
|
+
// ── Constants ─────────────────────────────────────────────────────────────────
|
|
13
|
+
/** Effective Δv at which a target begins to stumble (0.5 m/s in SCALE.mps units). */
|
|
14
|
+
export const STAGGER_THRESHOLD_mps = Math.trunc(0.5 * SCALE.mps); // 5 000
|
|
15
|
+
/** Effective Δv at which a target is knocked prone (2.0 m/s in SCALE.mps units). */
|
|
16
|
+
export const PRONE_THRESHOLD_mps = Math.trunc(2.0 * SCALE.mps); // 20 000
|
|
17
|
+
/** Ticks of reduced-action window while staggered. */
|
|
18
|
+
export const STAGGER_TICKS = 3;
|
|
19
|
+
// ── computeKnockback ──────────────────────────────────────────────────────────
|
|
20
|
+
/**
|
|
21
|
+
* Derive knockback result from an impact.
|
|
22
|
+
*
|
|
23
|
+
* Physics derivation:
|
|
24
|
+
* impulse = sqrt(2 × E × m_eff) [N·s — same as p = m_eff × v_head]
|
|
25
|
+
* raw_Δv = impulse / m_target [m/s]
|
|
26
|
+
* effective_v = raw_Δv × (1 − stabilityQ)
|
|
27
|
+
*
|
|
28
|
+
* Calibration:
|
|
29
|
+
* 5.56 mm (4 g, 1760 J, 75 kg target): Δv ≈ 0.05 m/s — negligible ✓
|
|
30
|
+
* 12-gauge slug (28 g, 2100 J, 75 kg): Δv ≈ 0.25 m/s raw — stagger on low-stability target
|
|
31
|
+
* Large creature kick (50 kg eff, 400 J, 75 kg): Δv ≈ 2.67 m/s raw — prone on low-stability
|
|
32
|
+
*
|
|
33
|
+
* @param energy_J Impact energy (raw joules; SCALE.J = 1).
|
|
34
|
+
* @param massEff_kg Effective striking mass in SCALE.kg units (wpn + body fraction, or projectile).
|
|
35
|
+
* @param target Target entity (reads mass_kg and stabilityQ).
|
|
36
|
+
*/
|
|
37
|
+
export function computeKnockback(energy_J, massEff_kg, target) {
|
|
38
|
+
const zero = { impulse_Ns: 0, knockback_v: 0, staggered: false, prone: false };
|
|
39
|
+
if (energy_J <= 0 || massEff_kg <= 0)
|
|
40
|
+
return zero;
|
|
41
|
+
// Convert to real units for physics calculation
|
|
42
|
+
const massEff_real = massEff_kg / SCALE.kg; // real kg
|
|
43
|
+
const massTarget_real = Math.max(0.001, target.attributes.morphology.mass_kg / SCALE.kg); // real kg
|
|
44
|
+
// impulse = sqrt(2 × E × m_eff) [N·s]
|
|
45
|
+
const impulse_Ns = Math.sqrt(2 * energy_J * massEff_real);
|
|
46
|
+
// raw Δv in SCALE.mps units
|
|
47
|
+
const raw_v = Math.trunc((impulse_Ns / massTarget_real) * SCALE.mps);
|
|
48
|
+
// Stability modifier: higher stability → less effective knockback
|
|
49
|
+
const stabilityQ = target.attributes.control.stability;
|
|
50
|
+
const knockback_v = Math.trunc(qMul(raw_v, SCALE.Q - stabilityQ));
|
|
51
|
+
const prone = knockback_v >= PRONE_THRESHOLD_mps;
|
|
52
|
+
const staggered = !prone && knockback_v >= STAGGER_THRESHOLD_mps;
|
|
53
|
+
return { impulse_Ns, knockback_v, staggered, prone };
|
|
54
|
+
}
|
|
55
|
+
// ── applyKnockback ────────────────────────────────────────────────────────────
|
|
56
|
+
/**
|
|
57
|
+
* Apply knockback result to an entity.
|
|
58
|
+
*
|
|
59
|
+
* - Adds `result.knockback_v` to the entity's velocity in the hit direction.
|
|
60
|
+
* - Sets `condition.prone = true` when result.prone.
|
|
61
|
+
* - Sets `action.staggerTicks = STAGGER_TICKS` when result.staggered.
|
|
62
|
+
*
|
|
63
|
+
* @param entity Target entity (mutated in-place).
|
|
64
|
+
* @param result Result from `computeKnockback`.
|
|
65
|
+
* @param dir Direction from attacker to target in SCALE.m coordinates (unnormalised).
|
|
66
|
+
*/
|
|
67
|
+
export function applyKnockback(entity, result, dir) {
|
|
68
|
+
if (result.knockback_v === 0)
|
|
69
|
+
return;
|
|
70
|
+
if (dir.dx === 0 && dir.dy === 0)
|
|
71
|
+
return;
|
|
72
|
+
// Cheap Chebyshev normalisation — no float division in the hot path
|
|
73
|
+
const dirQ = normaliseDirCheapQ({ x: dir.dx, y: dir.dy, z: 0 });
|
|
74
|
+
entity.velocity_mps.x += mulDiv(result.knockback_v, dirQ.x, SCALE.Q);
|
|
75
|
+
entity.velocity_mps.y += mulDiv(result.knockback_v, dirQ.y, SCALE.Q);
|
|
76
|
+
if (result.prone) {
|
|
77
|
+
entity.condition.prone = true;
|
|
78
|
+
}
|
|
79
|
+
if (result.staggered) {
|
|
80
|
+
entity.action.staggerTicks = Math.max(entity.action.staggerTicks ?? 0, STAGGER_TICKS);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase 32B — Multi-Limb Granularity
|
|
3
|
+
*
|
|
4
|
+
* Per-limb state for entities whose body plan has multiple manipulation segments
|
|
5
|
+
* (octopoids, arachnids, multi-armed creatures). Integrates with grapple resolution
|
|
6
|
+
* by reducing effective contest force when limbs are severed or fatigued.
|
|
7
|
+
*
|
|
8
|
+
* Backward-compatible: entities without a limbStates field behave identically to
|
|
9
|
+
* the existing single-pool grapple model.
|
|
10
|
+
*/
|
|
11
|
+
import { type Q, type I32 } from "../units.js";
|
|
12
|
+
import type { BodyPlan } from "./bodyplan.js";
|
|
13
|
+
import type { InjuryState } from "./injury.js";
|
|
14
|
+
export interface LimbState {
|
|
15
|
+
/** Matches a BodySegment.id in the entity's body plan. */
|
|
16
|
+
segmentId: string;
|
|
17
|
+
/** Current grip quality on this limb (0 = no grip, q(1.0) = full grip). */
|
|
18
|
+
gripQ: Q;
|
|
19
|
+
/** Entity id currently held by this limb; 0 = limb is free. */
|
|
20
|
+
engagedWith: number;
|
|
21
|
+
/** Float fatigue accumulator [same unit as energy_J]. Sub-unit precision. */
|
|
22
|
+
fatigueJ: number;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Build initial LimbState[] from a BodyPlan.
|
|
26
|
+
* Only segments with `manipulationRole === "primary"` are included.
|
|
27
|
+
* Returns an empty array if no such segments exist.
|
|
28
|
+
*/
|
|
29
|
+
export declare function buildLimbStates(plan: BodyPlan): LimbState[];
|
|
30
|
+
/**
|
|
31
|
+
* Compute the effective force multiplier given current limb states and injury.
|
|
32
|
+
*
|
|
33
|
+
* A limb is excluded when its body segment has structural damage at SCALE.Q
|
|
34
|
+
* (fully destroyed / severed). The result is:
|
|
35
|
+
* (activeLimbs / totalLimbs) × averageGripQ
|
|
36
|
+
*
|
|
37
|
+
* Returns q(1.0) when limbStates is empty (degenerate case, caller should not
|
|
38
|
+
* invoke this function if limb count is zero).
|
|
39
|
+
*/
|
|
40
|
+
export declare function effectiveLimbForceMul(limbStates: LimbState[], injury: InjuryState): Q;
|
|
41
|
+
/**
|
|
42
|
+
* Tick fatigue for engaged limbs. Each active engaged limb drains
|
|
43
|
+
* `peakForce_N / limbCount` energy per second (sub-unit float accumulator).
|
|
44
|
+
*
|
|
45
|
+
* The accumulated fatigueJ is informational for host use; it does not directly
|
|
46
|
+
* reduce gripQ here (that is a host-side policy decision, e.g. after a threshold).
|
|
47
|
+
*/
|
|
48
|
+
export declare function stepLimbFatigue(limbStates: LimbState[], peakForce_N: I32, delta_s: number): void;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase 32B — Multi-Limb Granularity
|
|
3
|
+
*
|
|
4
|
+
* Per-limb state for entities whose body plan has multiple manipulation segments
|
|
5
|
+
* (octopoids, arachnids, multi-armed creatures). Integrates with grapple resolution
|
|
6
|
+
* by reducing effective contest force when limbs are severed or fatigued.
|
|
7
|
+
*
|
|
8
|
+
* Backward-compatible: entities without a limbStates field behave identically to
|
|
9
|
+
* the existing single-pool grapple model.
|
|
10
|
+
*/
|
|
11
|
+
import { q, SCALE, clampQ, qMul, mulDiv } from "../units.js";
|
|
12
|
+
// ── Limb initialisation ───────────────────────────────────────────────────────
|
|
13
|
+
/**
|
|
14
|
+
* Build initial LimbState[] from a BodyPlan.
|
|
15
|
+
* Only segments with `manipulationRole === "primary"` are included.
|
|
16
|
+
* Returns an empty array if no such segments exist.
|
|
17
|
+
*/
|
|
18
|
+
export function buildLimbStates(plan) {
|
|
19
|
+
return plan.segments
|
|
20
|
+
.filter(s => s.manipulationRole === "primary")
|
|
21
|
+
.map(s => ({
|
|
22
|
+
segmentId: s.id,
|
|
23
|
+
gripQ: q(0),
|
|
24
|
+
engagedWith: 0,
|
|
25
|
+
fatigueJ: 0,
|
|
26
|
+
}));
|
|
27
|
+
}
|
|
28
|
+
// ── Force contribution ────────────────────────────────────────────────────────
|
|
29
|
+
/**
|
|
30
|
+
* Compute the effective force multiplier given current limb states and injury.
|
|
31
|
+
*
|
|
32
|
+
* A limb is excluded when its body segment has structural damage at SCALE.Q
|
|
33
|
+
* (fully destroyed / severed). The result is:
|
|
34
|
+
* (activeLimbs / totalLimbs) × averageGripQ
|
|
35
|
+
*
|
|
36
|
+
* Returns q(1.0) when limbStates is empty (degenerate case, caller should not
|
|
37
|
+
* invoke this function if limb count is zero).
|
|
38
|
+
*/
|
|
39
|
+
export function effectiveLimbForceMul(limbStates, injury) {
|
|
40
|
+
const total = limbStates.length;
|
|
41
|
+
if (total === 0)
|
|
42
|
+
return q(1.0);
|
|
43
|
+
let activeCount = 0;
|
|
44
|
+
let gripSum = 0;
|
|
45
|
+
for (const ls of limbStates) {
|
|
46
|
+
const region = injury.byRegion?.[ls.segmentId];
|
|
47
|
+
const structDmg = region?.structuralDamage ?? 0;
|
|
48
|
+
if (structDmg >= SCALE.Q)
|
|
49
|
+
continue; // severed / destroyed
|
|
50
|
+
activeCount++;
|
|
51
|
+
gripSum += ls.gripQ;
|
|
52
|
+
}
|
|
53
|
+
if (activeCount === 0)
|
|
54
|
+
return q(0);
|
|
55
|
+
const activeFrac = mulDiv(activeCount, SCALE.Q, total); // e.g. 6/8 = q(0.75)
|
|
56
|
+
const avgGrip = Math.trunc(gripSum / activeCount);
|
|
57
|
+
// If all grips are 0 (entity not currently grappling) return activeFrac directly
|
|
58
|
+
if (avgGrip === 0)
|
|
59
|
+
return activeFrac;
|
|
60
|
+
return clampQ(qMul(activeFrac, avgGrip), q(0), q(1.0));
|
|
61
|
+
}
|
|
62
|
+
// ── Fatigue accumulation ──────────────────────────────────────────────────────
|
|
63
|
+
/**
|
|
64
|
+
* Tick fatigue for engaged limbs. Each active engaged limb drains
|
|
65
|
+
* `peakForce_N / limbCount` energy per second (sub-unit float accumulator).
|
|
66
|
+
*
|
|
67
|
+
* The accumulated fatigueJ is informational for host use; it does not directly
|
|
68
|
+
* reduce gripQ here (that is a host-side policy decision, e.g. after a threshold).
|
|
69
|
+
*/
|
|
70
|
+
export function stepLimbFatigue(limbStates, peakForce_N, delta_s) {
|
|
71
|
+
const activeEngaged = limbStates.filter(ls => ls.engagedWith !== 0);
|
|
72
|
+
if (activeEngaged.length === 0)
|
|
73
|
+
return;
|
|
74
|
+
const drainPerLimb = (peakForce_N / limbStates.length) * delta_s;
|
|
75
|
+
for (const ls of activeEngaged) {
|
|
76
|
+
ls.fatigueJ += drainPerLimb;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type Q } from "../units.js";
|
|
2
|
+
import type { TechCapability } from "./tech.js";
|
|
3
|
+
/**
|
|
4
|
+
* Capability tier of the equipment used during treatment.
|
|
5
|
+
* Passed on TreatCommand; the kernel scales effectiveness accordingly.
|
|
6
|
+
*/
|
|
7
|
+
export type MedicalTier = "none" | "bandage" | "surgicalKit" | "autodoc" | "nanomedicine";
|
|
8
|
+
/** Ordinal rank used for minimum-tier comparisons. Higher = more capable. */
|
|
9
|
+
export declare const TIER_RANK: Record<MedicalTier, number>;
|
|
10
|
+
/**
|
|
11
|
+
* Effectiveness multiplier per tier.
|
|
12
|
+
* Applied as: reduction = BASE_RATE × TIER_MUL × (medSkill.treatmentRateMul / SCALE.Q)
|
|
13
|
+
*/
|
|
14
|
+
export declare const TIER_MUL: Record<MedicalTier, Q>;
|
|
15
|
+
/**
|
|
16
|
+
* Available treatment actions.
|
|
17
|
+
*
|
|
18
|
+
* tourniquet — zeroes bleedingRate in one region immediately; requires ≥ bandage tier
|
|
19
|
+
* bandage — reduces bleedingRate per tick; requires ≥ bandage tier
|
|
20
|
+
* surgery — reduces structuralDamage per tick; clears fracture when healed; requires ≥ surgicalKit
|
|
21
|
+
* fluidReplacement — restores fluidLoss per tick; requires ≥ autodoc
|
|
22
|
+
*/
|
|
23
|
+
export type MedicalAction = "tourniquet" | "bandage" | "surgery" | "fluidReplacement";
|
|
24
|
+
/** Minimum tier required for each action. */
|
|
25
|
+
export declare const ACTION_MIN_TIER: Record<MedicalAction, MedicalTier>;
|
|
26
|
+
/**
|
|
27
|
+
* Phase 11: TechCapability that must be available in TechContext to use equipment at this tier.
|
|
28
|
+
* When ctx.techCtx is provided and the capability is absent, treatment is blocked.
|
|
29
|
+
*
|
|
30
|
+
* Tiers not listed here have no technology requirement (they work in any era).
|
|
31
|
+
*/
|
|
32
|
+
export declare const TIER_TECH_REQ: Partial<Record<MedicalTier, TechCapability>>;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// src/sim/medical.ts — Phase 9: medical treatment types; Phase 11: tech gating
|
|
2
|
+
import { q } from "../units.js";
|
|
3
|
+
/** Ordinal rank used for minimum-tier comparisons. Higher = more capable. */
|
|
4
|
+
export const TIER_RANK = {
|
|
5
|
+
none: 0, bandage: 1, surgicalKit: 2, autodoc: 3, nanomedicine: 4,
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Effectiveness multiplier per tier.
|
|
9
|
+
* Applied as: reduction = BASE_RATE × TIER_MUL × (medSkill.treatmentRateMul / SCALE.Q)
|
|
10
|
+
*/
|
|
11
|
+
export const TIER_MUL = {
|
|
12
|
+
none: q(0),
|
|
13
|
+
bandage: q(0.50),
|
|
14
|
+
surgicalKit: q(0.80),
|
|
15
|
+
autodoc: q(1.00),
|
|
16
|
+
nanomedicine: q(1.20),
|
|
17
|
+
};
|
|
18
|
+
/** Minimum tier required for each action. */
|
|
19
|
+
export const ACTION_MIN_TIER = {
|
|
20
|
+
tourniquet: "bandage",
|
|
21
|
+
bandage: "bandage",
|
|
22
|
+
surgery: "surgicalKit",
|
|
23
|
+
fluidReplacement: "autodoc",
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Phase 11: TechCapability that must be available in TechContext to use equipment at this tier.
|
|
27
|
+
* When ctx.techCtx is provided and the capability is absent, treatment is blocked.
|
|
28
|
+
*
|
|
29
|
+
* Tiers not listed here have no technology requirement (they work in any era).
|
|
30
|
+
*/
|
|
31
|
+
export const TIER_TECH_REQ = {
|
|
32
|
+
nanomedicine: "NanomedicalRepair",
|
|
33
|
+
};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase 5 — Morale and Psychological State
|
|
3
|
+
*
|
|
4
|
+
* Pure fixed-point functions. No Math.random(), no Entity imports.
|
|
5
|
+
* All randomness via eventSeed + caller-supplied seed.
|
|
6
|
+
*/
|
|
7
|
+
import type { Q } from "../units.js";
|
|
8
|
+
/** Fear added per tick of active suppression (incoming near-miss fire). */
|
|
9
|
+
export declare const FEAR_PER_SUPPRESSION_TICK: Q;
|
|
10
|
+
/** Fear added when a nearby ally is killed in the same tick. */
|
|
11
|
+
export declare const FEAR_FOR_ALLY_DEATH: Q;
|
|
12
|
+
/** Multiplier: fear added per tick = shock × this. */
|
|
13
|
+
export declare const FEAR_INJURY_MUL: Q;
|
|
14
|
+
/** Fear added per tick when enemies outnumber allies in awareness radius. */
|
|
15
|
+
export declare const FEAR_OUTNUMBERED: Q;
|
|
16
|
+
/** Fear added to a defender per surprise attack (attacker undetected). */
|
|
17
|
+
export declare const FEAR_SURPRISE: Q;
|
|
18
|
+
/** Fear added per tick when >50% of own team is already routing. */
|
|
19
|
+
export declare const FEAR_ROUTING_CASCADE: Q;
|
|
20
|
+
/** Additional fear decay per leader within AURA_RADIUS_m. */
|
|
21
|
+
export declare const LEADER_AURA_FEAR_REDUCTION: Q;
|
|
22
|
+
/** Additional fear decay per standard-bearer within AURA_RADIUS_m. */
|
|
23
|
+
export declare const BANNER_AURA_FEAR_REDUCTION: Q;
|
|
24
|
+
/** Radius within which leader/banner auras apply (SCALE.m units). */
|
|
25
|
+
export declare const AURA_RADIUS_m: number;
|
|
26
|
+
/** Ticks of attack suppression after recovering from routing. */
|
|
27
|
+
export declare const RALLY_COOLDOWN_TICKS = 60;
|
|
28
|
+
/** Base fear decay per tick, multiplied by distressTolerance. */
|
|
29
|
+
export declare const BASE_DECAY: Q;
|
|
30
|
+
/** Additional fear decay per nearby living ally (cohesion effect). */
|
|
31
|
+
export declare const ALLY_COHESION: Q;
|
|
32
|
+
/** Additional fear decay per ally in a tight formation (Phase 32E). */
|
|
33
|
+
export declare const FORMATION_COHESION: Q;
|
|
34
|
+
/**
|
|
35
|
+
* Fear decay rate per tick.
|
|
36
|
+
* Scales with distressTolerance (stoic entities recover faster)
|
|
37
|
+
* and with nearby living ally count (cohesion effect).
|
|
38
|
+
*
|
|
39
|
+
* Returns a Q value to subtract from fearQ each tick.
|
|
40
|
+
*/
|
|
41
|
+
export declare function fearDecayPerTick(distressTolerance: Q, nearbyAllyCount: number, formationAllyCount?: number): Q;
|
|
42
|
+
/**
|
|
43
|
+
* Routing threshold — minimum fear to trigger retreat behaviour.
|
|
44
|
+
* Higher distressTolerance → bolder → threshold is higher.
|
|
45
|
+
*
|
|
46
|
+
* Range: q(0.50) at tolerance=0 → q(0.80) at tolerance=1.
|
|
47
|
+
*/
|
|
48
|
+
export declare function moraleThreshold(distressTolerance: Q): Q;
|
|
49
|
+
/**
|
|
50
|
+
* Whether an entity is currently routing.
|
|
51
|
+
*/
|
|
52
|
+
export declare function isRouting(fearQ: Q, distressTolerance: Q): boolean;
|
|
53
|
+
/**
|
|
54
|
+
* Effective pain level from shock (0..1), reduced by distress tolerance.
|
|
55
|
+
*
|
|
56
|
+
* painLevel = shock × (1 − distressTolerance)
|
|
57
|
+
*
|
|
58
|
+
* Returns a Q value representing probability that pain blocks voluntary action.
|
|
59
|
+
*/
|
|
60
|
+
export declare function painLevel(shock: Q, distressTolerance: Q): Q;
|
|
61
|
+
/**
|
|
62
|
+
* Deterministic pain suppression check.
|
|
63
|
+
* Returns true if pain prevents the entity from initiating an attack this tick.
|
|
64
|
+
*
|
|
65
|
+
* @param seed - Caller supplies eventSeed(..., 0xPA15); value drives the roll.
|
|
66
|
+
* @param shock - Entity's current shock level.
|
|
67
|
+
* @param distressTolerance - Entity's pain tolerance.
|
|
68
|
+
*/
|
|
69
|
+
export declare function painBlocksAction(seed: number, shock: Q, distressTolerance: Q): boolean;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase 5 — Morale and Psychological State
|
|
3
|
+
*
|
|
4
|
+
* Pure fixed-point functions. No Math.random(), no Entity imports.
|
|
5
|
+
* All randomness via eventSeed + caller-supplied seed.
|
|
6
|
+
*/
|
|
7
|
+
import { SCALE, q, clampQ, qMul } from "../units.js";
|
|
8
|
+
// ── Fear increment constants ──────────────────────────────────────────────────
|
|
9
|
+
/** Fear added per tick of active suppression (incoming near-miss fire). */
|
|
10
|
+
export const FEAR_PER_SUPPRESSION_TICK = q(0.020);
|
|
11
|
+
/** Fear added when a nearby ally is killed in the same tick. */
|
|
12
|
+
export const FEAR_FOR_ALLY_DEATH = q(0.150);
|
|
13
|
+
/** Multiplier: fear added per tick = shock × this. */
|
|
14
|
+
export const FEAR_INJURY_MUL = q(0.012);
|
|
15
|
+
/** Fear added per tick when enemies outnumber allies in awareness radius. */
|
|
16
|
+
export const FEAR_OUTNUMBERED = q(0.010);
|
|
17
|
+
/** Fear added to a defender per surprise attack (attacker undetected). */
|
|
18
|
+
export const FEAR_SURPRISE = q(0.080);
|
|
19
|
+
/** Fear added per tick when >50% of own team is already routing. */
|
|
20
|
+
export const FEAR_ROUTING_CASCADE = q(0.030);
|
|
21
|
+
// ── Phase 5 extension constants ───────────────────────────────────────────────
|
|
22
|
+
/** Additional fear decay per leader within AURA_RADIUS_m. */
|
|
23
|
+
export const LEADER_AURA_FEAR_REDUCTION = q(0.015);
|
|
24
|
+
/** Additional fear decay per standard-bearer within AURA_RADIUS_m. */
|
|
25
|
+
export const BANNER_AURA_FEAR_REDUCTION = q(0.010);
|
|
26
|
+
/** Radius within which leader/banner auras apply (SCALE.m units). */
|
|
27
|
+
export const AURA_RADIUS_m = Math.trunc(20 * SCALE.m);
|
|
28
|
+
/** Ticks of attack suppression after recovering from routing. */
|
|
29
|
+
export const RALLY_COOLDOWN_TICKS = 60;
|
|
30
|
+
// ── Fear decay constants ──────────────────────────────────────────────────────
|
|
31
|
+
/** Base fear decay per tick, multiplied by distressTolerance. */
|
|
32
|
+
export const BASE_DECAY = q(0.008);
|
|
33
|
+
/** Additional fear decay per nearby living ally (cohesion effect). */
|
|
34
|
+
export const ALLY_COHESION = q(0.002);
|
|
35
|
+
/** Additional fear decay per ally in a tight formation (Phase 32E). */
|
|
36
|
+
export const FORMATION_COHESION = q(0.003);
|
|
37
|
+
// ── Pure functions ────────────────────────────────────────────────────────────
|
|
38
|
+
/**
|
|
39
|
+
* Fear decay rate per tick.
|
|
40
|
+
* Scales with distressTolerance (stoic entities recover faster)
|
|
41
|
+
* and with nearby living ally count (cohesion effect).
|
|
42
|
+
*
|
|
43
|
+
* Returns a Q value to subtract from fearQ each tick.
|
|
44
|
+
*/
|
|
45
|
+
export function fearDecayPerTick(distressTolerance, nearbyAllyCount, formationAllyCount) {
|
|
46
|
+
const base = qMul(BASE_DECAY, distressTolerance);
|
|
47
|
+
const cohesion = Math.min(nearbyAllyCount * ALLY_COHESION, q(0.020)); // cap at q(0.020)
|
|
48
|
+
const formation = formationAllyCount
|
|
49
|
+
? Math.min(formationAllyCount * FORMATION_COHESION, q(0.015)) // cap at q(0.015)
|
|
50
|
+
: 0;
|
|
51
|
+
return clampQ(base + cohesion + formation, 0, q(0.040));
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Routing threshold — minimum fear to trigger retreat behaviour.
|
|
55
|
+
* Higher distressTolerance → bolder → threshold is higher.
|
|
56
|
+
*
|
|
57
|
+
* Range: q(0.50) at tolerance=0 → q(0.80) at tolerance=1.
|
|
58
|
+
*/
|
|
59
|
+
export function moraleThreshold(distressTolerance) {
|
|
60
|
+
return clampQ(q(0.50) + qMul(distressTolerance, q(0.30)), q(0.50), q(0.80));
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Whether an entity is currently routing.
|
|
64
|
+
*/
|
|
65
|
+
export function isRouting(fearQ, distressTolerance) {
|
|
66
|
+
return fearQ >= moraleThreshold(distressTolerance);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Effective pain level from shock (0..1), reduced by distress tolerance.
|
|
70
|
+
*
|
|
71
|
+
* painLevel = shock × (1 − distressTolerance)
|
|
72
|
+
*
|
|
73
|
+
* Returns a Q value representing probability that pain blocks voluntary action.
|
|
74
|
+
*/
|
|
75
|
+
export function painLevel(shock, distressTolerance) {
|
|
76
|
+
// shock × (SCALE.Q - distressTolerance) / SCALE.Q
|
|
77
|
+
return clampQ(qMul(shock, (SCALE.Q - distressTolerance)), 0, SCALE.Q);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Deterministic pain suppression check.
|
|
81
|
+
* Returns true if pain prevents the entity from initiating an attack this tick.
|
|
82
|
+
*
|
|
83
|
+
* @param seed - Caller supplies eventSeed(..., 0xPA15); value drives the roll.
|
|
84
|
+
* @param shock - Entity's current shock level.
|
|
85
|
+
* @param distressTolerance - Entity's pain tolerance.
|
|
86
|
+
*/
|
|
87
|
+
export function painBlocksAction(seed, shock, distressTolerance) {
|
|
88
|
+
const pain = painLevel(shock, distressTolerance);
|
|
89
|
+
if (pain <= 0)
|
|
90
|
+
return false;
|
|
91
|
+
return (seed % SCALE.Q) < pain;
|
|
92
|
+
}
|