@adam0white/human-framework 2.5.0 → 2.6.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/dist/body/body.d.ts +12 -1
- package/dist/body/body.js +33 -4
- package/dist/cognition/cognition.d.ts +3 -0
- package/dist/cognition/cognition.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/migrate.js +6 -1
- package/dist/person.js +7 -2
- package/dist/prospection/forecast.d.ts +8 -8
- package/dist/prospection/forecast.js +10 -10
- package/dist/types.d.ts +8 -1
- package/dist/types.js +1 -1
- package/package.json +1 -1
package/dist/body/body.d.ts
CHANGED
|
@@ -30,6 +30,15 @@ export declare const BODY_DEFAULTS: {
|
|
|
30
30
|
exertionRiseHalfLife: number;
|
|
31
31
|
exertionRecoverHalfLife: number;
|
|
32
32
|
exertionRecoverHalfLifeAsleep: number;
|
|
33
|
+
/** Fatigue store (2.6.0, opt-in): depletion per hour at full effort (× (1 - 0.5 fitness) × (1 - depletion)). */
|
|
34
|
+
depletionPerHour: number;
|
|
35
|
+
/** Effort below which the store does not fill and recovers while awake. */
|
|
36
|
+
depletionFloor: number;
|
|
37
|
+
/** Half-life of depletion at rest awake and asleep (minutes, divided by the life-course recovery factor). */
|
|
38
|
+
depletionRestHalfLife: number;
|
|
39
|
+
depletionSleepHalfLife: number;
|
|
40
|
+
/** How much a full store adds to felt fatigue: fatigue = 1 - (1 - exertion)(1 - 0.5 s)(1 - weight × depletion). */
|
|
41
|
+
depletionFatigueWeight: number;
|
|
33
42
|
/** Effort above which fitness trains. */
|
|
34
43
|
trainingEffort: number;
|
|
35
44
|
/** Detraining half-life (min) toward fitnessFloor. */
|
|
@@ -116,6 +125,8 @@ export interface BodyPerceptionContext {
|
|
|
116
125
|
fastingDays: number;
|
|
117
126
|
}
|
|
118
127
|
export type BodyParams = typeof BODY_DEFAULTS;
|
|
128
|
+
/** Turn on the fatigue store (2.6.0): accumulated exertion that recovers with rest and sleep. Idempotent. */
|
|
129
|
+
export declare function enableFatigueStore(p: Person): void;
|
|
119
130
|
export declare function createBody(init: PersonSpec['body'] | undefined, now: Minute): BodyState;
|
|
120
131
|
/**
|
|
121
132
|
* Advance `p.body` over `dt` minutes under `load`. Call with `p.now` at the start of the interval: a mode
|
|
@@ -205,4 +216,4 @@ export declare function forecastBody(p: Person, spans: readonly {
|
|
|
205
216
|
label: string;
|
|
206
217
|
duration: number;
|
|
207
218
|
load: BodyLoad;
|
|
208
|
-
}[], mods: LifeModifiers, params?: BodyParams, step?: number): BodyForecastSpan[];
|
|
219
|
+
}[], mods: LifeModifiers, params?: BodyParams, step?: number, perception?: BodyPerceptionContext): BodyForecastSpan[];
|
package/dist/body/body.js
CHANGED
|
@@ -76,6 +76,15 @@ export const BODY_DEFAULTS = {
|
|
|
76
76
|
exertionRiseHalfLife: 40,
|
|
77
77
|
exertionRecoverHalfLife: 45,
|
|
78
78
|
exertionRecoverHalfLifeAsleep: 25,
|
|
79
|
+
/** Fatigue store (2.6.0, opt-in): depletion per hour at full effort (× (1 - 0.5 fitness) × (1 - depletion)). */
|
|
80
|
+
depletionPerHour: 0.3,
|
|
81
|
+
/** Effort below which the store does not fill and recovers while awake. */
|
|
82
|
+
depletionFloor: 0.3,
|
|
83
|
+
/** Half-life of depletion at rest awake and asleep (minutes, divided by the life-course recovery factor). */
|
|
84
|
+
depletionRestHalfLife: 8 * 60,
|
|
85
|
+
depletionSleepHalfLife: 3 * 60,
|
|
86
|
+
/** How much a full store adds to felt fatigue: fatigue = 1 - (1 - exertion)(1 - 0.5 s)(1 - weight × depletion). */
|
|
87
|
+
depletionFatigueWeight: 1,
|
|
79
88
|
/** Effort above which fitness trains. */
|
|
80
89
|
trainingEffort: 0.4,
|
|
81
90
|
/** Detraining half-life (min) toward fitnessFloor. */
|
|
@@ -229,6 +238,13 @@ export function sanitizeBody(b, now) {
|
|
|
229
238
|
delete b.lastSleep;
|
|
230
239
|
if (b.lastDowned !== undefined && !span(b.lastDowned))
|
|
231
240
|
delete b.lastDowned;
|
|
241
|
+
if (b.depletion !== undefined)
|
|
242
|
+
b.depletion = typeof b.depletion === 'number' && Number.isFinite(b.depletion) ? clamp01(b.depletion) : 0;
|
|
243
|
+
}
|
|
244
|
+
/** Turn on the fatigue store (2.6.0): accumulated exertion that recovers with rest and sleep. Idempotent. */
|
|
245
|
+
export function enableFatigueStore(p) {
|
|
246
|
+
if (p.body.depletion === undefined)
|
|
247
|
+
p.body.depletion = 0;
|
|
232
248
|
}
|
|
233
249
|
/**
|
|
234
250
|
* Repair the optional chronic fields of saved illnesses in place: a non-finite or out-of-range `baseline` is
|
|
@@ -367,6 +383,18 @@ function subStep(b, h, load, mods, P) {
|
|
|
367
383
|
? P.exertionRiseHalfLife
|
|
368
384
|
: (asleep ? P.exertionRecoverHalfLifeAsleep : P.exertionRecoverHalfLife) / recovery;
|
|
369
385
|
b.exertion = clamp01(decay(b.exertion, h, hl, target));
|
|
386
|
+
// Fatigue store (2.6.0, opt-in): fills with sustained effort above the floor, empties with rest and sleep.
|
|
387
|
+
if (b.depletion !== undefined) {
|
|
388
|
+
const d = clamp01(Number.isFinite(b.depletion) ? b.depletion : 0);
|
|
389
|
+
if (effortUsed > P.depletionFloor) {
|
|
390
|
+
const rate = (P.depletionPerHour * (effortUsed - P.depletionFloor)) / (1 - P.depletionFloor);
|
|
391
|
+
b.depletion = clamp01(d + (rate * (1 - 0.5 * b.fitness) * (1 - d) * h) / 60);
|
|
392
|
+
}
|
|
393
|
+
else {
|
|
394
|
+
const half = (asleep ? P.depletionSleepHalfLife : P.depletionRestHalfLife) / recovery;
|
|
395
|
+
b.depletion = clamp01(decay(d, h, half, 0));
|
|
396
|
+
}
|
|
397
|
+
}
|
|
370
398
|
// Fitness: dF/dt = -kd (F - floor) + kt (max - F), exact for constant load.
|
|
371
399
|
const maxFit = clamp01(mods.maxFitness);
|
|
372
400
|
const kd = LN2 / P.detrainHalfLife;
|
|
@@ -501,7 +529,8 @@ export function readBody(p, params = BODY_DEFAULTS, ctx) {
|
|
|
501
529
|
const sleepiness = clamp01(params.sleepinessPressureWeight * b.sleepPressure +
|
|
502
530
|
params.sleepinessCircadianWeight * (1 - alertness) +
|
|
503
531
|
debtTerm);
|
|
504
|
-
const
|
|
532
|
+
const store = b.depletion === undefined ? 1 : 1 - params.depletionFatigueWeight * clamp01(b.depletion);
|
|
533
|
+
const fatigueOf = (s) => clamp01(1 - (1 - b.exertion) * (1 - 0.5 * s) * store);
|
|
505
534
|
const fatigue = fatigueOf(sleepiness);
|
|
506
535
|
const hunger = clamp01(1 - b.satiety);
|
|
507
536
|
const thirst = clamp01(1 - b.hydration);
|
|
@@ -767,7 +796,7 @@ export function nextBodyThreshold(p, load, mods, thresholds = { hunger: 0.7, thi
|
|
|
767
796
|
* The person's own forecast of their body through consecutive spans of known exertion, read as they perceive it
|
|
768
797
|
* (2.5.0). Simulates a cloned body in steps of at most `step` minutes; pure (does not mutate `p`).
|
|
769
798
|
*/
|
|
770
|
-
export function forecastBody(p, spans, mods, params = BODY_DEFAULTS, step = 30) {
|
|
799
|
+
export function forecastBody(p, spans, mods, params = BODY_DEFAULTS, step = 30, perception) {
|
|
771
800
|
const out = [];
|
|
772
801
|
const sim = { ...p, body: cloneBody(p.body) };
|
|
773
802
|
for (const s of spans) {
|
|
@@ -775,7 +804,7 @@ export function forecastBody(p, spans, mods, params = BODY_DEFAULTS, step = 30)
|
|
|
775
804
|
// Hard internal cap (a week) so a hostile span cannot stall a decision.
|
|
776
805
|
let left = Math.min(7 * MINUTES_PER_DAY, Math.max(0, Number.isFinite(s.duration) ? s.duration : 0));
|
|
777
806
|
advanceBody(sim, 0, s.load, mods, params);
|
|
778
|
-
const r0 = readBody(sim, params).perceived;
|
|
807
|
+
const r0 = readBody(sim, params, perception).perceived;
|
|
779
808
|
for (const k of ['fatigue', 'sleepiness', 'hunger', 'thirst'])
|
|
780
809
|
if (r0[k] > span.worst) {
|
|
781
810
|
span.worst = r0[k];
|
|
@@ -786,7 +815,7 @@ export function forecastBody(p, spans, mods, params = BODY_DEFAULTS, step = 30)
|
|
|
786
815
|
advanceBody(sim, dt, s.load, mods, params);
|
|
787
816
|
sim.now += dt;
|
|
788
817
|
left -= dt;
|
|
789
|
-
const r = readBody(sim, params).perceived;
|
|
818
|
+
const r = readBody(sim, params, perception).perceived;
|
|
790
819
|
for (const k of ['fatigue', 'sleepiness', 'hunger', 'thirst'])
|
|
791
820
|
if (r[k] > span.worst) {
|
|
792
821
|
span.worst = r[k];
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { BodyPerceptionContext } from '../body/index.ts';
|
|
1
2
|
import { type HabitContext } from '../habits/index.ts';
|
|
2
3
|
import { type PromptingSeen } from '../promptings/index.ts';
|
|
3
4
|
import type { Affordance, BodyReadout, Command, Considered, DecisionRecord, LifeModifiers, Minute, NeedReading, Person, Suggestion, Term, Unit } from '../types.ts';
|
|
@@ -100,6 +101,8 @@ export interface ConsiderContext {
|
|
|
100
101
|
* leaves the material and safety terms exactly as without it.
|
|
101
102
|
*/
|
|
102
103
|
scarcity?: Unit;
|
|
104
|
+
/** The body's perception context now (an open fast), for the bodily forecast (2.6.0). */
|
|
105
|
+
perception?: BodyPerceptionContext;
|
|
103
106
|
}
|
|
104
107
|
/**
|
|
105
108
|
* Standing advice terms for one option: per source, the strongest matching entry's weight × trust in the source
|
|
@@ -351,7 +351,7 @@ export function consider(p, aff, ctx) {
|
|
|
351
351
|
push('effort', effort);
|
|
352
352
|
// Bodily forecast (2.5.0): only offers that declare known follow-on exertion.
|
|
353
353
|
if (aff.followedBy?.length) {
|
|
354
|
-
const t = bodyForecastTerm(p, aff, ctx.mods);
|
|
354
|
+
const t = bodyForecastTerm(p, aff, ctx.mods, ctx.perception);
|
|
355
355
|
if (t)
|
|
356
356
|
push(t.source, t.value);
|
|
357
357
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** Human Framework v1 public surface. */
|
|
2
|
-
export declare const FRAMEWORK_VERSION = "2.
|
|
2
|
+
export declare const FRAMEWORK_VERSION = "2.6.0";
|
|
3
3
|
export type { CrisisEvent, PracticeKind } from './affect/index.ts';
|
|
4
4
|
export { AFFECT_DEFAULTS, actionTendencies, advanceAffect, appraise, breakAllows, breakBehaviour, breakHazard, CRISIS_DEFAULTS, checkCrisis, createAffect, easeBreak, emotionLevel, enableBreaks, feel, inBreak, readAffect, regulate, release as releaseEmotion, skipCrisis, strain, tendencyEmotions, } from './affect/index.ts';
|
|
5
5
|
export type { GoalTemplate, PrayerCalendar, PrayerSchedule, PrayerTimes, Retimer, } from './agenda/index.ts';
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** Human Framework v1 public surface. */
|
|
2
|
-
export const FRAMEWORK_VERSION = '2.
|
|
2
|
+
export const FRAMEWORK_VERSION = '2.6.0';
|
|
3
3
|
export { AFFECT_DEFAULTS, actionTendencies, advanceAffect, appraise, breakAllows, breakBehaviour, breakHazard, CRISIS_DEFAULTS, checkCrisis, createAffect, easeBreak, emotionLevel, enableBreaks, feel, inBreak, readAffect, regulate, release as releaseEmotion, skipCrisis, strain, tendencyEmotions, } from './affect/index.js';
|
|
4
4
|
// `agenda.release` collides with `affect.release`; the agenda one is re-exported under a clearer name.
|
|
5
5
|
export { AGENDA_DEFAULTS, abandonGoal, adoptGoal, advanceAgenda, agendaTerms, applyExemptions, CARE_DEFAULTS, calendarRetimer, careDuty, commitmentPressure, createAgenda, DEFAULT_PRAYER_TIMES, EID_PRAYER_IMPORTANCE, EXEMPTION_DEFAULTS, eidPrayer, eidWindow, fastWindow, iftarWindow, inMakruhTime, isUnderWay, MAKRUH_DEFAULTS, makruhWindows, missedExcuse, onFinished, owedMakeUps, PRAYER_IMPORTANCE, PURPOSE_DEFAULTS, prayerWindows, pressureReachedAt, promise, proposeGoals, RAMADAN_DEFAULTS, ramadanFast, ramadanMeals, release as releaseCommitment, retimeCommitments, revisePurposes, scheduleMakeUp, spanMeetsWindow, suhoorWindow, timesFor, violatesAbstention, } from './agenda/index.js';
|
package/dist/migrate.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* field of the optional surroundings slice (`ambient.now` → `ambient.percept`) and changes no behaviour (the optional `social.impressions` and `social.reserve`, like `retention`, are optional and start
|
|
9
9
|
* absent in a migrated save); `restore` then fills and sanitizes
|
|
10
10
|
* the slices as for any save. 2.0.0 to 2.1.0 adds optional conditional method state, absent
|
|
11
|
-
* until explicitly used, so existing hosts retain their previous behavior; that step stamps the version. 2.1.0 to 2.2.0 preserves optional method records and stamps the version; successful alternatives now retain independent support. 2.2.0 to 2.3.0 stamps the version; received consequences and temporal goals remain absent unless explicitly supplied. 2.3.0 to 2.4.0 stamps the version; promptings remain absent unless enabled. 2.4.0 to 2.5.0 stamps the version; the bodily forecast reads only offers that declare `followedBy`. A migrated save continues under the current engine's rules: it restores and runs,
|
|
11
|
+
* until explicitly used, so existing hosts retain their previous behavior; that step stamps the version. 2.1.0 to 2.2.0 preserves optional method records and stamps the version; successful alternatives now retain independent support. 2.2.0 to 2.3.0 stamps the version; received consequences and temporal goals remain absent unless explicitly supplied. 2.3.0 to 2.4.0 stamps the version; promptings remain absent unless enabled. 2.4.0 to 2.5.0 stamps the version; the bodily forecast reads only offers that declare `followedBy`. 2.5.0 to 2.6.0 stamps the version; the fatigue store stays absent unless enabled. A migrated save continues under the current engine's rules: it restores and runs,
|
|
12
12
|
* but it does not reproduce what the old engine would have done next where the rules changed (1.4.0 to 1.5.0
|
|
13
13
|
* changed how standing advice is heard; 1.8.0 to 1.9.0 changed the omission rule). Saves older than 1.4.0 and unknown versions are refused with an error.
|
|
14
14
|
*
|
|
@@ -58,6 +58,11 @@ export const MIGRATIONS = {
|
|
|
58
58
|
note: 'the surroundings field `ambient.now` is renamed `ambient.percept`; per-person retention is optional and starts absent; behaviour unchanged',
|
|
59
59
|
apply: renameAmbient,
|
|
60
60
|
},
|
|
61
|
+
'2.5.0': {
|
|
62
|
+
to: '2.6.0',
|
|
63
|
+
note: "the fatigue store (body.depletion) is optional and starts absent; the bodily forecast now applies an open fast's hunger damping, which changes only offers that declare followedBy",
|
|
64
|
+
apply: stamp,
|
|
65
|
+
},
|
|
61
66
|
'2.4.0': {
|
|
62
67
|
to: '2.5.0',
|
|
63
68
|
note: 'person shape unchanged; offers may declare followedBy spans for a bodily forecast; offers without it are unchanged',
|
package/dist/person.js
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
import { actionTendencies, advanceAffect, appraise, CRISIS_DEFAULTS, checkCrisis, createAffect, easeBreak, emotionLevel, feel, readAffect, regulate, release, skipAffect, skipCrisis, strain, tendencyEmotions, } from './affect/index.js';
|
|
23
23
|
import { advanceAgenda, createAgenda, onFinished, promise, proposeGoals, revisePurposes, } from './agenda/index.js';
|
|
24
24
|
import { advanceBeliefs, attend, believe, confirm, credence } from './beliefs/index.js';
|
|
25
|
-
import { advanceBody, BODY_DEFAULTS, checkDowned, clearDowned, consume, createBody, downedAllows, expose, injure, nextBodyThreshold, readBody, setDowned, sicken, skipBody, } from './body/index.js';
|
|
25
|
+
import { advanceBody, BODY_DEFAULTS, checkDowned, clearDowned, consume, createBody, downedAllows, enableFatigueStore, expose, injure, nextBodyThreshold, readBody, setDowned, sicken, skipBody, } from './body/index.js';
|
|
26
26
|
import { ageCharacter, enableCharacterChange, noteCharacterDay, noteCharacterSocial, } from './character/index.js';
|
|
27
27
|
import { closeDay, enableYearbook, endDay, noteAnswer, noteCommitments, noteDecision, noteMood, noteOutcome, trimChronicle, } from './chronicle/index.js';
|
|
28
28
|
import { decide as cognitionDecide, desperationOf, scoreAll } from './cognition/index.js';
|
|
@@ -154,6 +154,8 @@ export function createPerson(spec) {
|
|
|
154
154
|
enableCharacterChange(p);
|
|
155
155
|
if (on?.skillRetention)
|
|
156
156
|
enableSkillRetention(p);
|
|
157
|
+
if (on?.fatigueStore)
|
|
158
|
+
enableFatigueStore(p);
|
|
157
159
|
if (on?.promptings)
|
|
158
160
|
enablePromptings(p, on.promptings);
|
|
159
161
|
return p;
|
|
@@ -732,6 +734,9 @@ function decisionInputs(p, affordances, id, opts) {
|
|
|
732
734
|
necessity: opts.necessity ?? true,
|
|
733
735
|
tendencyEmotions: tendencyEmotions(p),
|
|
734
736
|
};
|
|
737
|
+
const perception = fastingCtx(p);
|
|
738
|
+
if (perception)
|
|
739
|
+
ctx.perception = perception;
|
|
735
740
|
if (opts.suggestion)
|
|
736
741
|
ctx.suggestion = opts.suggestion;
|
|
737
742
|
// Only set when voices were given this way, so single-voice records keep their shape.
|
|
@@ -1415,6 +1420,6 @@ export function nafsReading(p) {
|
|
|
1415
1420
|
* first-person line ("I can do it, but I'll be spent for the descent."). Empty spans without `followedBy`.
|
|
1416
1421
|
*/
|
|
1417
1422
|
export function bodyForecast(p, aff) {
|
|
1418
|
-
const spans = bodyForecastFor(p, aff, lifeModifiers(p));
|
|
1423
|
+
const spans = bodyForecastFor(p, aff, lifeModifiers(p), fastingCtx(p));
|
|
1419
1424
|
return { spans, line: forecastLine(spans) };
|
|
1420
1425
|
}
|
|
@@ -7,18 +7,18 @@
|
|
|
7
7
|
* spentAt, worst), joins the offer's utility; it is pure and draws no randomness. Offers without `followedBy`
|
|
8
8
|
* get no forecast, so existing hosts continue exactly.
|
|
9
9
|
*
|
|
10
|
-
* The forecast inherits the body model's limits and the person's misperceptions
|
|
11
|
-
* current effort
|
|
12
|
-
*
|
|
13
|
-
* sleep debt stays unfelt in the forecast;
|
|
14
|
-
*
|
|
10
|
+
* The forecast inherits the body model's limits and the person's misperceptions. Exertion relaxes toward the
|
|
11
|
+
* current effort; only a person with the opt-in fatigue store (2.6.0, `enableFatigueStore`) carries accumulated
|
|
12
|
+
* exertion, so only then does a long climb by itself leave them more spent for the descent; unfelt
|
|
13
|
+
* sleep debt stays unfelt in the forecast; an open fast's damping of hunger and thirst applies (2.6.0) as it is
|
|
14
|
+
* now, held for the whole forecast even if the fast would end during it; host surroundings are not applied (the person's own body rates and life
|
|
15
15
|
* modifiers are, but not `ambient` parameters). Existing bleeding, illness and healing run in the copy, so an
|
|
16
16
|
* open wound can read as being spent, and death in the forecast reads as fully spent. The term is absolute
|
|
17
17
|
* (see `bodyForecastTerm`). It does not plan, search routes, schedule rests on the way or
|
|
18
18
|
* predict injuries, and it is not a calibrated estimate of human anticipation. Every number is an engineering
|
|
19
19
|
* default.
|
|
20
20
|
*/
|
|
21
|
-
import { type BodyForecastSpan } from '../body/index.ts';
|
|
21
|
+
import { type BodyForecastSpan, type BodyPerceptionContext } from '../body/index.ts';
|
|
22
22
|
import type { Affordance, LifeModifiers, Person, Term } from '../types.ts';
|
|
23
23
|
export declare const FORECAST_DEFAULTS: {
|
|
24
24
|
/** Worst perceived readout during a follow-on from which the forecast starts to weigh. */
|
|
@@ -32,7 +32,7 @@ export declare const FORECAST_DEFAULTS: {
|
|
|
32
32
|
readonly maxMinutes: number;
|
|
33
33
|
};
|
|
34
34
|
/** The person's forecast for an offer: the act, then its follow-on spans. Empty without `followedBy`. Pure. */
|
|
35
|
-
export declare function bodyForecastFor(p: Person, aff: Affordance, mods: LifeModifiers): BodyForecastSpan[];
|
|
35
|
+
export declare function bodyForecastFor(p: Person, aff: Affordance, mods: LifeModifiers, perception?: BodyPerceptionContext): BodyForecastSpan[];
|
|
36
36
|
/**
|
|
37
37
|
* The `forecast:body` term for an offer, or undefined (no follow-on, or not expected to weigh). Absolute by
|
|
38
38
|
* design: it weighs being in that state *while doing* the follow-on, so a person already sleepy or thirsty is
|
|
@@ -40,6 +40,6 @@ export declare function bodyForecastFor(p: Person, aff: Affordance, mods: LifeMo
|
|
|
40
40
|
* costs more than staying home). A resting baseline was tried and rejected: thirst and sleepiness rise at rest
|
|
41
41
|
* too, which cancelled the very case the forecast exists for. Pure.
|
|
42
42
|
*/
|
|
43
|
-
export declare function bodyForecastTerm(p: Person, aff: Affordance, mods: LifeModifiers): Term | undefined;
|
|
43
|
+
export declare function bodyForecastTerm(p: Person, aff: Affordance, mods: LifeModifiers, perception?: BodyPerceptionContext): Term | undefined;
|
|
44
44
|
/** A first-person line for the forecast (narration only). */
|
|
45
45
|
export declare function forecastLine(spans: readonly BodyForecastSpan[]): string;
|
|
@@ -7,18 +7,18 @@
|
|
|
7
7
|
* spentAt, worst), joins the offer's utility; it is pure and draws no randomness. Offers without `followedBy`
|
|
8
8
|
* get no forecast, so existing hosts continue exactly.
|
|
9
9
|
*
|
|
10
|
-
* The forecast inherits the body model's limits and the person's misperceptions
|
|
11
|
-
* current effort
|
|
12
|
-
*
|
|
13
|
-
* sleep debt stays unfelt in the forecast;
|
|
14
|
-
*
|
|
10
|
+
* The forecast inherits the body model's limits and the person's misperceptions. Exertion relaxes toward the
|
|
11
|
+
* current effort; only a person with the opt-in fatigue store (2.6.0, `enableFatigueStore`) carries accumulated
|
|
12
|
+
* exertion, so only then does a long climb by itself leave them more spent for the descent; unfelt
|
|
13
|
+
* sleep debt stays unfelt in the forecast; an open fast's damping of hunger and thirst applies (2.6.0) as it is
|
|
14
|
+
* now, held for the whole forecast even if the fast would end during it; host surroundings are not applied (the person's own body rates and life
|
|
15
15
|
* modifiers are, but not `ambient` parameters). Existing bleeding, illness and healing run in the copy, so an
|
|
16
16
|
* open wound can read as being spent, and death in the forecast reads as fully spent. The term is absolute
|
|
17
17
|
* (see `bodyForecastTerm`). It does not plan, search routes, schedule rests on the way or
|
|
18
18
|
* predict injuries, and it is not a calibrated estimate of human anticipation. Every number is an engineering
|
|
19
19
|
* default.
|
|
20
20
|
*/
|
|
21
|
-
import { forecastBody } from '../body/index.js';
|
|
21
|
+
import { BODY_DEFAULTS, forecastBody, } from '../body/index.js';
|
|
22
22
|
import { clamp01, round } from '../core/index.js';
|
|
23
23
|
export const FORECAST_DEFAULTS = {
|
|
24
24
|
/** Worst perceived readout during a follow-on from which the forecast starts to weigh. */
|
|
@@ -36,7 +36,7 @@ const smooth = (a, b, x) => {
|
|
|
36
36
|
return t * t * (3 - 2 * t);
|
|
37
37
|
};
|
|
38
38
|
/** The person's forecast for an offer: the act, then its follow-on spans. Empty without `followedBy`. Pure. */
|
|
39
|
-
export function bodyForecastFor(p, aff, mods) {
|
|
39
|
+
export function bodyForecastFor(p, aff, mods, perception) {
|
|
40
40
|
const follow = aff.followedBy;
|
|
41
41
|
if (!Array.isArray(follow) || follow.length === 0 || !p.body.alive)
|
|
42
42
|
return [];
|
|
@@ -67,7 +67,7 @@ export function bodyForecastFor(p, aff, mods) {
|
|
|
67
67
|
load: { effort: clamp01(f.effort), focus: clamp01(f.focus ?? 0), mode: 'awake' },
|
|
68
68
|
});
|
|
69
69
|
}
|
|
70
|
-
return forecastBody(p, spans, mods);
|
|
70
|
+
return forecastBody(p, spans, mods, BODY_DEFAULTS, 30, perception);
|
|
71
71
|
}
|
|
72
72
|
/**
|
|
73
73
|
* The `forecast:body` term for an offer, or undefined (no follow-on, or not expected to weigh). Absolute by
|
|
@@ -76,8 +76,8 @@ export function bodyForecastFor(p, aff, mods) {
|
|
|
76
76
|
* costs more than staying home). A resting baseline was tried and rejected: thirst and sleepiness rise at rest
|
|
77
77
|
* too, which cancelled the very case the forecast exists for. Pure.
|
|
78
78
|
*/
|
|
79
|
-
export function bodyForecastTerm(p, aff, mods) {
|
|
80
|
-
const spans = bodyForecastFor(p, aff, mods).slice(1);
|
|
79
|
+
export function bodyForecastTerm(p, aff, mods, perception) {
|
|
80
|
+
const spans = bodyForecastFor(p, aff, mods, perception).slice(1);
|
|
81
81
|
if (spans.length === 0)
|
|
82
82
|
return undefined;
|
|
83
83
|
const D = FORECAST_DEFAULTS;
|
package/dist/types.d.ts
CHANGED
|
@@ -86,6 +86,11 @@ export interface BodyState {
|
|
|
86
86
|
illnesses: Illness[];
|
|
87
87
|
/** Accumulated sleep debt in hours (chronic restriction); under-perceived by the person. */
|
|
88
88
|
sleepDebt: number;
|
|
89
|
+
/**
|
|
90
|
+
* Accumulated exertion (2.6.0, opt-in via `enableFatigueStore`): 0..1, rising slowly with sustained effort and
|
|
91
|
+
* recovering with rest and faster with sleep. Raises felt fatigue and lowers capacity. Absent = no store.
|
|
92
|
+
*/
|
|
93
|
+
depletion?: Unit;
|
|
89
94
|
asleep: boolean;
|
|
90
95
|
/** Minute the current sleep or wake period began. */
|
|
91
96
|
since: Minute;
|
|
@@ -827,7 +832,7 @@ export declare const PERSON_SCHEMA = "human/person@1";
|
|
|
827
832
|
* and an activity that would cover a closing stretch is reviewed when the stretch begins (`isUnderWay`,
|
|
828
833
|
* `dutyReviewAt`). Person shape unchanged.
|
|
829
834
|
*/
|
|
830
|
-
export declare const ENGINE_VERSION = "2.
|
|
835
|
+
export declare const ENGINE_VERSION = "2.6.0";
|
|
831
836
|
/** A pregnancy carried by this person (host-driven; see `family/`). */
|
|
832
837
|
export interface Pregnancy {
|
|
833
838
|
fatherId: PersonId;
|
|
@@ -1393,6 +1398,8 @@ export interface PersonSpec {
|
|
|
1393
1398
|
yearbook?: boolean;
|
|
1394
1399
|
character?: boolean;
|
|
1395
1400
|
skillRetention?: boolean;
|
|
1401
|
+
/** Accumulated exertion (2.6.0): the same as `enableFatigueStore(p)` after creation. */
|
|
1402
|
+
fatigueStore?: boolean;
|
|
1396
1403
|
/** Promptings and turning away (2.4.0): the same as `enablePromptings(p, spec)` after creation. */
|
|
1397
1404
|
promptings?: PromptingsSpec;
|
|
1398
1405
|
};
|
package/dist/types.js
CHANGED
|
@@ -120,4 +120,4 @@ export const PERSON_SCHEMA = 'human/person@1';
|
|
|
120
120
|
* and an activity that would cover a closing stretch is reviewed when the stretch begins (`isUnderWay`,
|
|
121
121
|
* `dutyReviewAt`). Person shape unchanged.
|
|
122
122
|
*/
|
|
123
|
-
export const ENGINE_VERSION = '2.
|
|
123
|
+
export const ENGINE_VERSION = '2.6.0';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adam0white/human-framework",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.0",
|
|
4
4
|
"description": "Deterministic, explainable simulated people: body, needs, affect, memory, beliefs, skills, habits, relationships, values and a will that can refuse a suggestion",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"simulation",
|