@adatechnology/game-stories 0.2.8 → 0.3.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.
@@ -0,0 +1,1124 @@
1
+ import { TestableModule } from '@adatechnology/game-contracts';
2
+
3
+ /** Where a person stands in the world. The kit's ids; a game names them in its own words through the text tables. */
4
+ type StateId = 'ok' | 'hurt' | 'bitten' | 'undead' | 'dead' | 'missing' | 'party' | 'hostile' | 'moved' | 'left' | 'unborn';
5
+ type PersonState = {
6
+ state: StateId;
7
+ note: string;
8
+ base: string;
9
+ };
10
+ /** Every person's state, by id, in the order they came into the world. */
11
+ type States = Record<string, PersonState>;
12
+ /**
13
+ * A person of the world: someone the game wrote, someone the casting drew from the name pools, or someone the life simulation brought (a
14
+ * newcomer, a baby). `personality` is courage, empathy, loyalty, greed and stability, 0 to 100 (the Personagens axes).
15
+ */
16
+ type Person = {
17
+ readonly id: string;
18
+ readonly name: string;
19
+ /** The name the texts use (default: the quoted nickname, else the first name after an honorific). */
20
+ readonly nick?: string;
21
+ /** Years; a person without a number counts as `LifeNumbers.unknownAge`. */
22
+ readonly age?: number;
23
+ readonly female?: boolean;
24
+ readonly personality?: readonly number[];
25
+ /** The base (group) the person lives in. */
26
+ readonly base: string;
27
+ /** How the person starts the world (default ok, no note). */
28
+ readonly start?: {
29
+ readonly state: StateId;
30
+ readonly note: string;
31
+ };
32
+ /** Not in the pool of people a newcomer is related to (a baby to be born, a group of children). */
33
+ readonly extra?: boolean;
34
+ readonly profession?: string;
35
+ readonly tags?: readonly string[];
36
+ /** Who the casting or the life simulation made them for, and how. */
37
+ readonly bond?: string;
38
+ readonly relation?: string;
39
+ readonly baby?: boolean;
40
+ readonly mother?: string;
41
+ readonly father?: string;
42
+ /** The role this person was cast for, when the casting made them. */
43
+ readonly role?: string;
44
+ /** True for people made during the world (casting, newcomers, babies). */
45
+ readonly generated?: boolean;
46
+ };
47
+ /** A base: where people live together, with its defence (0 to 1, lowers the daily risk inside) and food in days. */
48
+ type Group = {
49
+ readonly name: string;
50
+ readonly defence: number;
51
+ readonly food: number;
52
+ };
53
+ /** A relation the world starts with: the two people, the kind (`LifeNumbers.affinity` keys) and a note. */
54
+ type Relation = readonly [a: string, b: string, kind: string, note?: string];
55
+ /** The player's actions so far, by id (an action that was done is truthy). */
56
+ type Actions = Readonly<Record<string, unknown>>;
57
+ /** The flags the stories raised, by id. */
58
+ type Flags = Record<string, unknown>;
59
+ /**
60
+ * A test on the world, as data: on the states of the people (through their roles), on the flags the stories raised and on the player's actions.
61
+ * Inside a beat, `value` asks whether a named value is set, `self` whether the person being listed plays that role, and `changed` whether the beat's
62
+ * changes so far name that role. Inside an `each`, the role `self` is the person being listed.
63
+ */
64
+ type Condition = {
65
+ readonly all: readonly Condition[];
66
+ } | {
67
+ readonly any: readonly Condition[];
68
+ } | {
69
+ readonly not: Condition;
70
+ } | {
71
+ readonly action: string;
72
+ } | {
73
+ readonly flag: string;
74
+ } | {
75
+ readonly state: string;
76
+ readonly is: StateId | readonly StateId[];
77
+ } | {
78
+ readonly living: string;
79
+ } | {
80
+ readonly base: string;
81
+ readonly is: string;
82
+ } | {
83
+ readonly value: string;
84
+ } | {
85
+ readonly self: string;
86
+ } | {
87
+ readonly changed: string;
88
+ } | {
89
+ readonly remembers: string;
90
+ readonly entry: string;
91
+ };
92
+ /** A piece of a beat's text: plain text, a conditional piece, a named value, the number of the beat's changes, or a person's short name. */
93
+ type TextPart = string | {
94
+ readonly when: Condition;
95
+ readonly text: string | readonly TextPart[];
96
+ readonly else?: string | readonly TextPart[];
97
+ } | {
98
+ readonly value: string;
99
+ } | {
100
+ readonly count: 'changes';
101
+ } | {
102
+ readonly name: string;
103
+ };
104
+ /** A change the beat makes: the role, the new state, the note, and optionally the new base (or the base another role is in now). */
105
+ type Change = {
106
+ readonly role: string;
107
+ readonly state: StateId;
108
+ readonly note: string;
109
+ readonly base?: string | {
110
+ readonly baseOf: string;
111
+ };
112
+ };
113
+ /** A change, a group of changes under a condition, or one change for each of a list of people that pass a test. */
114
+ type ChangeItem = Change | {
115
+ readonly when: Condition;
116
+ readonly changes: readonly ChangeItem[];
117
+ } | {
118
+ readonly each: {
119
+ readonly roles?: readonly string[];
120
+ readonly cast?: boolean;
121
+ readonly where?: Condition;
122
+ readonly except?: readonly string[];
123
+ };
124
+ readonly change: {
125
+ readonly state: StateId;
126
+ readonly note: string;
127
+ readonly base?: string;
128
+ };
129
+ };
130
+ /** One way a beat can go: the first variant whose `when` holds is taken; `none` means the beat does not happen. */
131
+ type BeatVariant = {
132
+ readonly when?: Condition;
133
+ readonly none?: boolean;
134
+ readonly text?: readonly TextPart[];
135
+ /** Joins the text parts (default nothing: the parts carry their own spaces). */
136
+ readonly join?: string;
137
+ readonly changes?: readonly ChangeItem[];
138
+ readonly flags?: Readonly<Record<string, unknown>>;
139
+ /** The other path: the one a player action opened (the team's `alt`). */
140
+ readonly alt?: boolean;
141
+ /** The beat happens only if it changes someone. */
142
+ readonly needsChanges?: boolean;
143
+ };
144
+ /** A beat of a story on a day: who it is about, named values, the variants, or a code beat the game registered (`run`). */
145
+ type StoryBeat = {
146
+ readonly id: string;
147
+ readonly day: number;
148
+ readonly title: string;
149
+ /** The roles the beat is about (the team's `who`): they are held out of the life simulation's risks for the week before it. */
150
+ readonly roles: readonly string[];
151
+ readonly values?: Readonly<Record<string, readonly {
152
+ readonly when?: Condition;
153
+ readonly value: string;
154
+ }[]>>;
155
+ readonly variants?: readonly BeatVariant[];
156
+ readonly run?: string;
157
+ };
158
+ /** A role a story needs: a person the game names (`person`), or one the casting draws, from the people or the name pools. */
159
+ type Role = {
160
+ readonly id: string;
161
+ readonly person?: string;
162
+ readonly tags?: readonly string[];
163
+ readonly needs?: {
164
+ readonly age?: readonly [number, number];
165
+ readonly sex?: 'f' | 'm';
166
+ readonly profession?: readonly string[];
167
+ readonly base?: string;
168
+ readonly tags?: readonly string[];
169
+ };
170
+ /** Made for someone already cast: their kinship word, the same surname, the same base. */
171
+ readonly bond?: {
172
+ readonly role: string;
173
+ readonly relation?: string;
174
+ readonly sameSurname?: boolean;
175
+ readonly sameBase?: boolean;
176
+ };
177
+ /** Never drawn from the people: always a new person from the name pools. */
178
+ readonly create?: boolean;
179
+ };
180
+ /** A story: its roles, its beats and the stories it crosses (they share roles and flags). */
181
+ type Story = {
182
+ readonly id: string;
183
+ readonly roles: readonly Role[];
184
+ readonly beats: readonly StoryBeat[];
185
+ readonly crosses?: readonly string[];
186
+ readonly example?: boolean;
187
+ };
188
+ /** What a code beat sees and gives back: the states, the actions, the flags; null when it does not happen. */
189
+ type CodeBeat = (context: {
190
+ readonly states: States;
191
+ readonly actions: Actions;
192
+ readonly flags: Flags;
193
+ readonly cast: (role: string) => string;
194
+ }) => BeatOutcome | null;
195
+ type BeatOutcome = {
196
+ readonly text: string;
197
+ readonly alt?: boolean;
198
+ readonly changes?: readonly ResolvedChange[];
199
+ readonly flags?: Readonly<Record<string, unknown>>;
200
+ };
201
+ /** A change on a person (the role already resolved). */
202
+ type ResolvedChange = {
203
+ readonly id: string;
204
+ readonly state: StateId;
205
+ readonly note: string;
206
+ readonly base?: string;
207
+ };
208
+ /** One line of the chronicle: a story beat or a rule of the life simulation, its text and what it changed. */
209
+ type ChronicleEntry = {
210
+ readonly day: number;
211
+ readonly kind: 'story' | 'life';
212
+ /** The beat id, or the life rule (`risk`, `bond`, `birth`...). */
213
+ readonly id: string;
214
+ readonly title: string;
215
+ readonly text: string;
216
+ readonly alt?: boolean;
217
+ readonly changes: readonly ResolvedChange[];
218
+ /** The people it is about (the beat's cast, or who the rule touched). */
219
+ readonly people: readonly string[];
220
+ /** The life rules mark the base whose news it is (none for comings and goings). */
221
+ readonly base?: string;
222
+ };
223
+
224
+ var sources$2 = {
225
+ file: "specs/001-migracao-entregas-dos-times/sources/sobreviventes__os-vivos-do-vale.js (site/pages/sobreviventes/os-vivos-do-vale.html)",
226
+ states: "LIVE (line 368) for living; life() alive (line 628) for active",
227
+ affinity: "life() aff, line 634: fam 80, ali 60, odio -60, seg 10, medo -20; unknown pairs 10 + ((empathy a + empathy b)/2 - 50)/5",
228
+ clocks: "life() step 1, lines 643-656: heal in 3 + floor(R·8) days, a bite turns in 2, the missing come back in 2 + floor(R·5) days with chance 0.6; birth with a midwife 3% mother / 5% baby, without 15% / 20%",
229
+ risk: "life() step 2, lines 660-668: base risk by place (REG, default 0.006), exposure by person (EXPO, default 0.3; newcomers 0.05 under 12, else 0.35), ×(1 - defence), ×1.5 under 2 days of food, ×2 hurt; draw < 0.5 hurt, < 0.8 bitten, < 0.95 dead, else missing",
230
+ bonds: "life() step 3, lines 671-692: from 16 years; drift ((empathy a + empathy c)/2 - 50)/120 + (food < 5 ? -(greed a + greed c)/250 : 0.1) + (R - 0.5)·3; quiet 2 days after news; couple from 18, at most 15 years apart, affinity 65, chance 3%, then 90; pregnancy with 8 days of food, mother up to 42, 2%, due in 45 days, no story beat in 20 days; adoption 1%; rivalry at -50; fight at -70 with courage 60, 20%, affinity -40, < 0.6 hurt (heal 3 + floor(R·5)), < 0.7 dead, else the less loyal leaves",
231
+ betrayal: "life() lines 694-697: loyalty < 35, greed > 60, food < 5, 3%; takes 4 days of food; affinity -40 with everyone of the base",
232
+ food: "life() step 4, line 701: each day -0.11 (by option per base), between 0 and 60",
233
+ caravan: "lines 703-708: a base under 5 days of food, a host base over 12, someone there with affinity 55, 12%; 5 days of food, affinity +10; 8% the carrier is hurt (heal in 4)",
234
+ raid: "lines 709-718: 3% a day, not within 10 days of the last, targets with 3 days of food, the weakest defence first with ±0.15 of noise; up to 5 days of food; a hero with courage 70 and affinity 60 arrives with chance 50%; else 25% dead; heal in 5; affinity +20",
235
+ arrivals: "step 5, lines 721-737: every 5 days, chance 0.5 (0.25 after day 60) of 1 + (30% 1 more); population cap 104 (CAP), 8 per base (ROOM); first names unique up to 30; age 18 + floor(R·42); personality 20 + R·70 (greed 10 + R·70); the bond from 16 years; affinity 75; 20% a partner (age max(18, age + floor(R·9) - 4)), 35% pregnant if up to 42, due in 10 + floor(R·30)",
236
+ fill: "simulate() O.fill, lines 746-749: up to 8 per base, age 18 + floor(R·40), personality 20 + R·70",
237
+ infection: "the bitten band and the turn are the apocalypse layer: off by default (normal world first), the bitten band then hurts"
238
+ };
239
+ var unknownAge = 8;
240
+ var livingStates = [
241
+ "ok",
242
+ "hurt",
243
+ "party",
244
+ "hostile",
245
+ "moved"
246
+ ];
247
+ var activeStates = [
248
+ "ok",
249
+ "hurt",
250
+ "moved",
251
+ "hostile"
252
+ ];
253
+ var affinity = {
254
+ family: 80,
255
+ trust: 60,
256
+ hatred: -60,
257
+ secret: 10,
258
+ fear: -20
259
+ };
260
+ var rivalKind = "hatred";
261
+ var unknownAffinity = {
262
+ base: 10,
263
+ divisor: 5
264
+ };
265
+ var clocks = {
266
+ healBase: 3,
267
+ healSpread: 8,
268
+ turnDays: 2,
269
+ backBase: 2,
270
+ backSpread: 5,
271
+ backChance: 0.6
272
+ };
273
+ var birth = {
274
+ motherWithMidwife: 0.03,
275
+ motherAlone: 0.15,
276
+ babyWithMidwife: 0.05,
277
+ babyAlone: 0.2,
278
+ girl: 0.5
279
+ };
280
+ var risk = {
281
+ defaultPlace: 0.006,
282
+ defaultExposure: 0.3,
283
+ newcomerChild: 0.05,
284
+ newcomerAdult: 0.35,
285
+ childAge: 12,
286
+ hungryBelow: 2,
287
+ hungry: 1.5,
288
+ hurt: 2,
289
+ bands: {
290
+ hurt: 0.5,
291
+ bitten: 0.8,
292
+ dead: 0.95
293
+ }
294
+ };
295
+ var bonds = {
296
+ minAge: 16,
297
+ quietDays: 2,
298
+ driftEmpathy: 120,
299
+ lowFood: 5,
300
+ driftGreed: 250,
301
+ driftFed: 0.1,
302
+ driftNoise: 3,
303
+ coupleAge: 18,
304
+ coupleGap: 15,
305
+ coupleAffinity: 65,
306
+ coupleChance: 0.03,
307
+ coupledAffinity: 90,
308
+ pregnancyFood: 8,
309
+ pregnancyAge: 42,
310
+ pregnancyChance: 0.02,
311
+ pregnancyDays: 45,
312
+ pregnancyStoryWindow: 20,
313
+ adoptionChance: 0.01,
314
+ rivalryAt: -50,
315
+ fightAt: -70,
316
+ fightCourage: 60,
317
+ fightChance: 0.2,
318
+ afterFight: -40,
319
+ fightHurt: 0.6,
320
+ fightDead: 0.7,
321
+ fightHealSpread: 5
322
+ };
323
+ var betrayal = {
324
+ loyaltyBelow: 35,
325
+ greedAbove: 60,
326
+ foodBelow: 5,
327
+ chance: 0.03,
328
+ takes: 4,
329
+ affinity: -40
330
+ };
331
+ var food = {
332
+ drift: -0.11,
333
+ max: 60
334
+ };
335
+ var caravan = {
336
+ below: 5,
337
+ hostAbove: 12,
338
+ affinity: 55,
339
+ chance: 0.12,
340
+ carries: 5,
341
+ bond: 10,
342
+ hurtChance: 0.08,
343
+ healDays: 4
344
+ };
345
+ var raid = {
346
+ chance: 0.03,
347
+ cooldown: 10,
348
+ targetFood: 3,
349
+ noise: 0.3,
350
+ loot: 5,
351
+ heroCourage: 70,
352
+ heroAffinity: 60,
353
+ heroChance: 0.5,
354
+ deadChance: 0.25,
355
+ healDays: 5,
356
+ heroBond: 20
357
+ };
358
+ var arrivals = {
359
+ every: 5,
360
+ chance: 0.5,
361
+ lateChance: 0.25,
362
+ lateAfter: 60,
363
+ secondChance: 0.3,
364
+ cap: 104,
365
+ room: 8,
366
+ uniqueNames: 30,
367
+ ageBase: 18,
368
+ ageSpread: 42,
369
+ bondAge: 16,
370
+ bondAffinity: 75,
371
+ pairChance: 0.2,
372
+ pairAgeSpread: 9,
373
+ pairAgeShift: 4,
374
+ pregnantChance: 0.35,
375
+ pregnantDueBase: 10,
376
+ pregnantDueSpread: 30
377
+ };
378
+ var fill = {
379
+ perBase: 8,
380
+ ageBase: 18,
381
+ ageSpread: 40
382
+ };
383
+ var personality = {
384
+ base: 20,
385
+ spread: 70,
386
+ greedBase: 10
387
+ };
388
+ var infection = false;
389
+ var lifeNumbers = {
390
+ sources: sources$2,
391
+ unknownAge: unknownAge,
392
+ livingStates: livingStates,
393
+ activeStates: activeStates,
394
+ affinity: affinity,
395
+ rivalKind: rivalKind,
396
+ unknownAffinity: unknownAffinity,
397
+ clocks: clocks,
398
+ birth: birth,
399
+ risk: risk,
400
+ bonds: bonds,
401
+ betrayal: betrayal,
402
+ food: food,
403
+ caravan: caravan,
404
+ raid: raid,
405
+ arrivals: arrivals,
406
+ fill: fill,
407
+ personality: personality,
408
+ infection: infection
409
+ };
410
+
411
+ var sources$1 = {
412
+ file: "specs/001-migracao-entregas-dos-times/sources/sobreviventes__os-vivos-do-vale.js (site/pages/sobreviventes/os-vivos-do-vale.html), life(), lines 619-739",
413
+ "pt-BR": "the team's texts, verbatim; {name}, {a}, {b}... are the people's short names (NICK, short), {o} the gender ending (o(id))",
414
+ en: "translation of the pt-BR texts"
415
+ };
416
+ var en = {
417
+ titles: {
418
+ turn: "Turns",
419
+ back: "Back",
420
+ lost: "Never back",
421
+ birth: "Birth",
422
+ risk: "Risk",
423
+ bond: "Bond",
424
+ pregnancy: "Pregnancy",
425
+ adoption: "Adoption",
426
+ rivalry: "Rivalry",
427
+ fight: "Fight",
428
+ betrayal: "Betrayal",
429
+ caravan: "Between bases",
430
+ raid: "Raid",
431
+ arrival: "Arrival"
432
+ },
433
+ notes: {
434
+ healed: "healed",
435
+ undead_street: "named undead in the street",
436
+ undead_near: "named undead near {place}",
437
+ came_back: "came back after going missing",
438
+ came_back_short: "came back",
439
+ never_back: "never came back",
440
+ newborn: "newborn",
441
+ childbirth: "in childbirth",
442
+ hurt_out: "hurt outside the base",
443
+ bitten_out: "bitten outside the base",
444
+ hides_bite: "hides the bite",
445
+ dead_out: "dead outside the base",
446
+ did_not_return: "did not return",
447
+ missing_out: "went missing on a run",
448
+ missing_short: "missing",
449
+ fight_with: "fight with {other}",
450
+ fight: "fight",
451
+ dead_fight: "killed in a fight with {other}",
452
+ left_after_fight: "left after the fight",
453
+ betrayed: "robbed {from} and went to {to}",
454
+ betrayed_short: "betrayed the base",
455
+ hurt_caravan: "hurt on the caravan",
456
+ caravan: "caravan",
457
+ hurt_raid: "hurt in the raid",
458
+ dead_raid: "killed in the raid of {from}",
459
+ raid: "raid",
460
+ arrived: "arrived{origin}",
461
+ pair_of: "partner of {first}"
462
+ },
463
+ lines: {
464
+ loses: " {partner} loses {name}.",
465
+ turn: "{name} comes back and wanders the old routine.",
466
+ back: "{name} shows up at the gate, thin and without boots, after days missing.",
467
+ lost: "They find {name}'s things in a ditch by the road.{loss}",
468
+ birth: "{name} gives birth at {place}{help}.",
469
+ birth_help: " with help from someone who knows how",
470
+ birth_alone: ", with no one who knows how to deliver a baby",
471
+ baby_dies: " The baby does not breathe. They bury it beside the base.",
472
+ baby_born: " {baby} is born.",
473
+ mother_dies: "{loss} {name} does not survive the birth.",
474
+ risk_hurt: "{name} comes back hurt from a run near {place}.",
475
+ risk_bitten: "{name} comes back with a bite on the forearm and tells no one.",
476
+ risk_dead: "{name} does not come back from a run near {place}.{loss}",
477
+ risk_missing: "{name} goes missing on a run near {place}.",
478
+ couple: "{a} and {b} {line}.",
479
+ pregnancy: "{a} and {b} are going to have a baby. Due in about {days} days.",
480
+ adoption: "{a} and {b} adopt {child}.",
481
+ rivalry: "{a} and {b} {line}. They are rivals now.",
482
+ fight_hurt: "The rivalry blows up: {winner} breaks {loser}'s nose in the yard.",
483
+ fight_dead: "The rivalry ends with a knife: {loser} dies and {winner} carries that death for the rest of their life.{loss}",
484
+ fight_leaves: "{name} packs up and goes to {to} after the fight with {other}.",
485
+ betrayal: "{name} vanishes before dawn with the pantry's food and the radio of {from}. Days later they are seen at {to}.",
486
+ caravan: "Caravan: {carrier} crosses town with food from {from} to {to}, where {host} lives.",
487
+ caravan_hurt: " On the way back, {carrier} is attacked on the avenue and arrives hurt.",
488
+ raid: "{who} raid {target} before dawn and take {loot} days of food.",
489
+ raid_hero: " {hero}, from {heroBase}, hears the shots and arrives in time: {victim} is only hurt.",
490
+ raid_dead: "{loss} {victim} dies at the door.",
491
+ raid_grazed: " {victim} is grazed by a bullet.",
492
+ arrival: "{first}, {relation} of {bond}, arrives{origin}{note}.",
493
+ arrival_gone: " They were looking for {bond} and learn that {bond} {fate}. They stay at {base}.",
494
+ arrival_party: " They ask for {bond} and learn that they are with the player. They stay at {base}, waiting.",
495
+ arrival_found: " They find {bond} at {base} and stay.",
496
+ arrival_elsewhere: " They learn that {bond} is at {where} and would rather stay at {base}.",
497
+ arrival_pair_pregnant: " They come with {pair}, and {mother} is pregnant.",
498
+ arrival_pair: " They come with {pair}."
499
+ },
500
+ pools: {
501
+ couple: [
502
+ "start sharing the watch, and then the mattress",
503
+ "kiss on the roof during the 8 pm radio",
504
+ "go public in front of the whole base"
505
+ ],
506
+ rivalry: [
507
+ "fight over the last tin of sardines",
508
+ "shout about who sleeps by the door",
509
+ "accuse each other of stealing rations"
510
+ ]
511
+ },
512
+ fates: {
513
+ dead: "died",
514
+ undead: "became one of the dead",
515
+ left: "left on the bus",
516
+ missing: "went missing",
517
+ bitten: "was bitten",
518
+ other: "is not here any more"
519
+ },
520
+ places: {
521
+ where_died: "where they died",
522
+ road: "the road",
523
+ open_field: "the open field",
524
+ nowhere: "nowhere"
525
+ },
526
+ gender: {
527
+ female: "",
528
+ male: ""
529
+ },
530
+ honorifics: [
531
+ "Mrs.",
532
+ "Mr.",
533
+ "Dr.",
534
+ "Lieutenant",
535
+ "Sergeant",
536
+ "Private",
537
+ "Pastor",
538
+ "Corporal",
539
+ "Captain",
540
+ "Major"
541
+ ]
542
+ };
543
+ var lifeText = {
544
+ sources: sources$1,
545
+ "pt-BR": {
546
+ titles: {
547
+ turn: "Reanima",
548
+ back: "Volta",
549
+ lost: "Sem volta",
550
+ birth: "Nascimento",
551
+ risk: "Risco",
552
+ bond: "Laço",
553
+ pregnancy: "Gravidez",
554
+ adoption: "Adoção",
555
+ rivalry: "Rixa",
556
+ fight: "Briga",
557
+ betrayal: "Traição",
558
+ caravan: "Entre bases",
559
+ raid: "Ataque",
560
+ arrival: "Chegada"
561
+ },
562
+ notes: {
563
+ healed: "curado",
564
+ undead_street: "zumbi nomeado na rua",
565
+ undead_near: "zumbi nomeado perto de {place}",
566
+ came_back: "voltou depois de sumir",
567
+ came_back_short: "voltou",
568
+ never_back: "nunca voltou",
569
+ newborn: "recém-nascido",
570
+ childbirth: "no parto",
571
+ hurt_out: "ferido fora da base",
572
+ bitten_out: "mordido fora da base",
573
+ hides_bite: "esconde a mordida",
574
+ dead_out: "morto fora da base",
575
+ did_not_return: "não voltou",
576
+ missing_out: "sumiu numa saída",
577
+ missing_short: "sumiu",
578
+ fight_with: "briga com {other}",
579
+ fight: "briga",
580
+ dead_fight: "morto numa briga com {other}",
581
+ left_after_fight: "foi embora depois da briga",
582
+ betrayed: "roubou {from} e foi para {to}",
583
+ betrayed_short: "traiu a base",
584
+ hurt_caravan: "ferido na caravana",
585
+ caravan: "caravana",
586
+ hurt_raid: "ferido no ataque",
587
+ dead_raid: "morto no ataque de {from}",
588
+ raid: "ataque",
589
+ arrived: "chegou{origin}",
590
+ pair_of: "par de {first}"
591
+ },
592
+ lines: {
593
+ loses: " {partner} perde {name}.",
594
+ turn: "{name} reanima e passa a vagar pela rotina antiga.",
595
+ back: "{name} aparece no portão, magro e sem as botas, depois de dias sumido.",
596
+ lost: "Acham as coisas de {name} numa vala da estrada.{loss}",
597
+ birth: "{name} dá à luz em {place}{help}.",
598
+ birth_help: " com ajuda de quem sabe",
599
+ birth_alone: ", sem ninguém que saiba fazer parto",
600
+ baby_dies: " O bebê não respira. Enterram ao lado da base.",
601
+ baby_born: " Nasce {baby}.",
602
+ mother_dies: "{loss} {name} não resiste ao parto.",
603
+ risk_hurt: "{name} volta ferid{o} de uma saída perto de {place}.",
604
+ risk_bitten: "{name} volta com uma mordida no antebraço e não conta a ninguém.",
605
+ risk_dead: "{name} não volta de uma saída perto de {place}.{loss}",
606
+ risk_missing: "{name} some numa saída perto de {place}.",
607
+ couple: "{a} e {b} {line}.",
608
+ pregnancy: "{a} e {b} vão ter um bebê. Nasce em uns {days} dias de jogo.",
609
+ adoption: "{a} e {b} adotam {child}.",
610
+ rivalry: "{a} e {b} {line}. Viraram rivais.",
611
+ fight_hurt: "A rixa explode: {winner} quebra o nariz de {loser} no pátio.",
612
+ fight_dead: "A rixa termina com faca: {loser} morre e {winner} carrega a morte para o resto da vida.{loss}",
613
+ fight_leaves: "{name} junta as coisas e vai para {to} depois da briga com {other}.",
614
+ betrayal: "{name} some de madrugada com a comida da despensa e o rádio de {from}. Dias depois é visto em {to}.",
615
+ caravan: "Caravana: {carrier} atravessa a cidade com comida de {from} para {to}, onde mora {host}.",
616
+ caravan_hurt: " Na volta, {carrier} é atacad{o} na avenida e chega ferid{o}.",
617
+ raid: "{who} atacam {target} de madrugada e levam {loot} dias de comida.",
618
+ raid_hero: " {hero}, de {heroBase}, ouve os tiros e chega a tempo: {victim} sai só ferid{o}.",
619
+ raid_dead: "{loss} {victim} morre na porta.",
620
+ raid_grazed: " {victim} leva um tiro de raspão.",
621
+ arrival: "{first}, {relation} de {bond}, chega{origin}{note}.",
622
+ arrival_gone: " Vinha procurando {bond} e descobre que {bond} {fate}. Fica em {base}.",
623
+ arrival_party: " Pergunta por {bond} e descobre que está com o jogador. Fica em {base} esperando.",
624
+ arrival_found: " Encontra {bond} em {base} e fica.",
625
+ arrival_elsewhere: " Descobre que {bond} está em {where} e prefere ficar em {base}.",
626
+ arrival_pair_pregnant: " Vem com {pair}, e {mother} está grávida.",
627
+ arrival_pair: " Vem com {pair}."
628
+ },
629
+ pools: {
630
+ couple: [
631
+ "começam a dividir o turno de vigia, e depois o colchão",
632
+ "se beijam no telhado durante a rádio das 20h",
633
+ "assumem o namoro na frente da base inteira"
634
+ ],
635
+ rivalry: [
636
+ "brigam pela última lata de sardinha",
637
+ "discutem aos gritos sobre quem dorme perto da porta",
638
+ "se acusam de roubar ração"
639
+ ]
640
+ },
641
+ fates: {
642
+ dead: "morreu",
643
+ undead: "virou um dos mortos",
644
+ left: "saiu do vale no ônibus",
645
+ missing: "sumiu",
646
+ bitten: "foi mordido",
647
+ other: "não está mais aqui"
648
+ },
649
+ places: {
650
+ where_died: "onde morreu",
651
+ road: "a estrada",
652
+ open_field: "campo aberto",
653
+ nowhere: "lugar nenhum"
654
+ },
655
+ gender: {
656
+ female: "a",
657
+ male: "o"
658
+ },
659
+ honorifics: [
660
+ "Dona",
661
+ "Seu",
662
+ "Dr.",
663
+ "Tenente",
664
+ "Sargento",
665
+ "Soldado",
666
+ "Pastora",
667
+ "Cabo",
668
+ "Capitão",
669
+ "Major"
670
+ ]
671
+ },
672
+ en: en
673
+ };
674
+
675
+ type Numbers = Omit<typeof lifeNumbers, 'sources' | 'livingStates' | 'activeStates' | 'infection'>;
676
+ /** Every number of the life simulation (`data/life.json`, each with its source line). */
677
+ type LifeNumbers = Numbers & {
678
+ readonly livingStates: readonly StateId[];
679
+ readonly activeStates: readonly StateId[];
680
+ readonly infection: boolean;
681
+ };
682
+ type DeepPartial<T> = {
683
+ [K in keyof T]?: T[K] extends readonly unknown[] ? T[K] : T[K] extends object ? DeepPartial<T[K]> : T[K];
684
+ };
685
+ type LifeNumbersPatch = DeepPartial<LifeNumbers>;
686
+ /** The texts of the life simulation in one language (`data/life-text.json`). */
687
+ type LifeText = (typeof lifeText)['pt-BR'];
688
+ type LifeTextPatch = {
689
+ [K in keyof LifeText]?: Partial<LifeText[K]>;
690
+ };
691
+ /** A rule of the life simulation: what each chronicle line of the simulation is. */
692
+ type LifeRule = keyof LifeText['titles'];
693
+ /**
694
+ * What a game tells the life simulation about its world. All of it is optional: without places, exposure, raids or origins the simulation runs on the
695
+ * defaults (a normal world: no bites, no raids unless the game lists them).
696
+ */
697
+ type LifeOptions = {
698
+ readonly numbers?: LifeNumbersPatch;
699
+ readonly text?: LifeTextPatch;
700
+ /** The bases people live in (the team's `GROUPS`). The nomads' base is one of them. */
701
+ readonly groups: Readonly<Record<string, Group>>;
702
+ /** The relations the world starts with (`RELS`); `kind` is a key of `numbers.affinity`. */
703
+ readonly relations?: readonly Relation[];
704
+ /** Couples the world starts with. */
705
+ readonly couples?: readonly (readonly [string, string])[];
706
+ /** Couples a flag forms (the team's `F.casalRT`), when neither has a partner. */
707
+ readonly flagCouples?: readonly {
708
+ readonly flag: string;
709
+ readonly a: string;
710
+ readonly b: string;
711
+ }[];
712
+ /** The daily risk of each base (`REG`); others take `numbers.risk.defaultPlace`. */
713
+ readonly placeRisk?: Readonly<Record<string, number>>;
714
+ /** How much each person goes out (`EXPO`); others take `numbers.risk.defaultExposure`. */
715
+ readonly exposure?: Readonly<Record<string, number>>;
716
+ /** Flags that multiply everyone's risk (the team's `F.radioMuda ? 1.3 : 1`). */
717
+ readonly riskFlags?: Readonly<Record<string, number>>;
718
+ /** Bases nobody moves to or trades with: always (`true`) or while a condition holds (`HOSTB`). */
719
+ readonly hostileBases?: Readonly<Record<string, true | Condition>>;
720
+ /** Bases nobody is sent to by the simulation (besides the nomads' own). */
721
+ readonly closedBases?: readonly string[];
722
+ /** Bases a raid never targets. */
723
+ readonly raidImmune?: readonly string[];
724
+ readonly nomadBase?: string;
725
+ /** The base of the people who are with the player (`grupo` → `jogador`). */
726
+ readonly playerBase?: string;
727
+ /** The people whose presence at a base makes a birth safe. */
728
+ readonly midwives?: readonly string[];
729
+ /** People kept out of the daily risk until a day (the team's `id === 'taina' && d < 38`). */
730
+ readonly anchors?: readonly {
731
+ readonly id: string;
732
+ readonly beforeDay: number;
733
+ }[];
734
+ /** People who stand for orphans a couple can adopt, with the words the text uses for one of them. */
735
+ readonly orphans?: Readonly<Record<string, string>>;
736
+ /** Each base's daily food change instead of `numbers.food.drift`; `{ flag, value }` applies while the flag is set. */
737
+ readonly foodDrift?: Readonly<Record<string, number | {
738
+ readonly flag: string;
739
+ readonly value: number;
740
+ }>>;
741
+ /** Where a traitor goes: the first whose condition holds and is not their own base; else the nomads. */
742
+ readonly traitorDestinations?: readonly {
743
+ readonly base: string;
744
+ readonly when?: Condition;
745
+ }[];
746
+ /** The raiders: from which base, while what holds, and who they are in the text. */
747
+ readonly raids?: readonly {
748
+ readonly from: string;
749
+ readonly when: Condition;
750
+ readonly who: string;
751
+ }[];
752
+ /** Newcomers: the ways in, a note a way in adds while a condition holds, and the announcements. `false` turns arrivals off. */
753
+ readonly arrivals?: false | {
754
+ readonly origins?: readonly string[];
755
+ readonly notes?: readonly {
756
+ readonly origin: string;
757
+ readonly when: Condition;
758
+ readonly text: string;
759
+ }[];
760
+ readonly announcements?: readonly {
761
+ readonly when: Condition;
762
+ readonly text: string;
763
+ }[];
764
+ };
765
+ };
766
+ type LifeStats = {
767
+ births: number;
768
+ arrivals: number;
769
+ deaths: number;
770
+ couples: number;
771
+ fights: number;
772
+ betrayals: number;
773
+ caravans: number;
774
+ raids: number;
775
+ pregnancies: number;
776
+ };
777
+ type LifeTimer = {
778
+ heal?: number;
779
+ turn?: number;
780
+ back?: number;
781
+ due?: number;
782
+ father?: string;
783
+ };
784
+ /** The world the life simulation keeps (the team's `W`). */
785
+ type LifeWorld = {
786
+ readonly raid: Record<string, number>;
787
+ readonly food: Record<string, number>;
788
+ readonly defence: Record<string, number>;
789
+ readonly affinity: Record<string, number>;
790
+ readonly partner: Record<string, string>;
791
+ readonly rival: Record<string, 1>;
792
+ readonly adopted: Record<string, 1>;
793
+ readonly timers: Record<string, LifeTimer>;
794
+ /** The people the simulation made (newcomers, babies, the fill), by id. */
795
+ readonly made: Record<string, Person>;
796
+ count: number;
797
+ readonly lastNews: Record<string, number>;
798
+ readonly stats: LifeStats;
799
+ readonly usedNames: Set<string>;
800
+ };
801
+
802
+ /** A text in each language the content ships (`en` and `pt-BR` in `game-characters-people`). */
803
+ type LocalizedText = Readonly<Record<string, string>>;
804
+ /** The name pools of one language: first names, surnames, babies' names and the kinship words a newcomer is introduced with. */
805
+ type NamePools = {
806
+ readonly male: readonly string[];
807
+ readonly female: readonly string[];
808
+ readonly surnames: readonly string[];
809
+ readonly babyMale: readonly string[];
810
+ readonly babyFemale: readonly string[];
811
+ readonly kinship: {
812
+ readonly male: readonly string[];
813
+ readonly female: readonly string[];
814
+ };
815
+ };
816
+ type SheetAttributeId = 'strength' | 'vigor' | 'agility' | 'perception' | 'intellect' | 'presence';
817
+ type SheetAttribute = {
818
+ readonly id: SheetAttributeId;
819
+ readonly key: string;
820
+ readonly name: LocalizedText;
821
+ readonly description: LocalizedText;
822
+ };
823
+ type SheetSkillGroup = {
824
+ readonly id: string;
825
+ readonly name: LocalizedText;
826
+ readonly skills: readonly string[];
827
+ };
828
+ /** A skill with what it unlocks at each milestone level (`SheetRuleset.milestoneLevels`). */
829
+ type SheetSkill = {
830
+ readonly id: string;
831
+ readonly group: string;
832
+ readonly name: LocalizedText;
833
+ readonly milestones: readonly LocalizedText[];
834
+ };
835
+ /** A profession's sheet rule: its points in the point buy (negative costs, positive gives), the starting skill levels, its bonus and kit. */
836
+ type SheetProfession = {
837
+ readonly id: string;
838
+ readonly key: string;
839
+ readonly points: number;
840
+ readonly skills: Readonly<Record<string, number>>;
841
+ readonly bonus: LocalizedText;
842
+ readonly kit: string;
843
+ };
844
+ /** A trait: its cost in the point buy (negative costs points, positive gives them) and the traits it cannot be taken with. */
845
+ type SheetTrait = {
846
+ readonly id: string;
847
+ readonly key: string;
848
+ readonly cost: number;
849
+ readonly excludes: readonly string[];
850
+ readonly name: LocalizedText;
851
+ readonly effect: LocalizedText;
852
+ };
853
+ /** A derived value: `(base + Σ per[attribute]·value + Σ add) · Π mul · scale`, the adds and products of the traits the sheet has, in order. */
854
+ type SheetDerived = {
855
+ readonly id: string;
856
+ readonly base: number;
857
+ readonly per: Readonly<Partial<Record<SheetAttributeId, number>>>;
858
+ readonly traits: readonly {
859
+ readonly trait: string;
860
+ readonly add?: number;
861
+ readonly mul?: number;
862
+ }[];
863
+ readonly scale?: number;
864
+ readonly unit?: string;
865
+ readonly name: LocalizedText;
866
+ readonly source: string;
867
+ };
868
+ type SheetRuleset = {
869
+ readonly pointBuy: {
870
+ readonly start: number;
871
+ readonly pool: number;
872
+ readonly min: number;
873
+ readonly max: number;
874
+ };
875
+ readonly milestoneLevels: readonly number[];
876
+ readonly attributes: readonly SheetAttribute[];
877
+ readonly skillGroups: readonly SheetSkillGroup[];
878
+ readonly skills: readonly SheetSkill[];
879
+ readonly professions: readonly SheetProfession[];
880
+ readonly traits: readonly SheetTrait[];
881
+ readonly derived: readonly SheetDerived[];
882
+ };
883
+
884
+ /** Who plays each role, and everyone in the world after the casting (the people given, then the people it made). */
885
+ type Casting = {
886
+ readonly roles: Readonly<Record<string, string>>;
887
+ readonly people: readonly Person[];
888
+ /** The role of a person the casting made, or the first role a given person plays. */
889
+ readonly roleOf: (id: string) => string | undefined;
890
+ };
891
+ type CastOptions = {
892
+ readonly stories: readonly Story[];
893
+ readonly people?: readonly Person[];
894
+ readonly names: NamePools;
895
+ readonly random: () => number;
896
+ /** The base of a made person whose role names none and has no bond (default the first base of a given person, else 'nomad'). */
897
+ readonly defaultBase?: string;
898
+ };
899
+ /**
900
+ * Casts every story's roles at the world's creation (decision P9: who plays each role is drawn, so every game is different). A role the game pins
901
+ * (`person`) is that person; another is drawn among the people not cast yet who fit its needs; with none (or `create`), a new person is made from the
902
+ * name pools: the sex and age the role needs (else drawn as a newcomer's: half and half, 18 + 0..41 years), the bond's surname and base when the role
903
+ * asks, the newcomer's personality draw. Roles with the same id in two stories are the same person: that is how stories cross.
904
+ */
905
+ declare function castStories(options: CastOptions): Casting;
906
+
907
+ /** The world's chronicle: every story beat and every rule of the life simulation that happened, in order. */
908
+ type Chronicle = {
909
+ readonly entries: readonly ChronicleEntry[];
910
+ add(entry: ChronicleEntry): void;
911
+ /** The lines of one day. */
912
+ onDay(day: number): readonly ChronicleEntry[];
913
+ /** The lines about a person: those that name them or change them. */
914
+ about(id: string): readonly ChronicleEntry[];
915
+ /** The lines up to a day. */
916
+ until(day: number): readonly ChronicleEntry[];
917
+ /** Follows the new lines. Returns the unsubscribe function. */
918
+ on(listener: (entry: ChronicleEntry) => void): () => void;
919
+ };
920
+ declare function createChronicle(): Chronicle;
921
+
922
+ var sources = {
923
+ page: "site/pages/zumbis-personagens/personagens.html, \"Memória e opinião\" and \"Modelo de dados\"",
924
+ memories: "\"Cada NPC guarda até 30 lembranças com peso e data\"; memorias: [{ evento, alvoId, peso, dia }] // máx 30",
925
+ opinion: "\"A opinião sobre cada jogador vai de −100 a +100 e decai devagar para o neutro. Em +60 o NPC aceita entrar no grupo; abaixo de −60 pode roubar, delatar a base a outro grupo ou atacar à noite.\"",
926
+ decayPerDay: "not in the document (\"decai devagar\"): 1 point a day is the kit's reversible default, listed as a question",
927
+ memoryDrop: "not in the document: past 30, the lightest memory goes (the oldest first on a tie), listed as a question"
928
+ };
929
+ var memories = {
930
+ max: 30
931
+ };
932
+ var opinion = {
933
+ min: -100,
934
+ max: 100,
935
+ joins: 60,
936
+ hostile: -60,
937
+ decayPerDay: 1
938
+ };
939
+ var sheetNumbers = {
940
+ sources: sources,
941
+ memories: memories,
942
+ opinion: opinion
943
+ };
944
+
945
+ type SheetNumbers = Omit<typeof sheetNumbers, 'sources'>;
946
+ /** One thing the person lived: a decision, a story beat, an event of the world. Every one is kept (P13). */
947
+ type SheetEntry = {
948
+ readonly kind: 'decision' | 'story' | 'event';
949
+ readonly id: string;
950
+ readonly day: number;
951
+ readonly weight?: number;
952
+ readonly about?: string;
953
+ };
954
+ /** A memory (Personagens "Memória e opinião"): what happened, about whom, how much it weighs and when. */
955
+ type Memory = {
956
+ readonly id: string;
957
+ readonly about?: string;
958
+ readonly weight: number;
959
+ readonly day: number;
960
+ };
961
+ type SheetInput = {
962
+ readonly profession?: string;
963
+ readonly attributes?: Partial<Record<SheetAttributeId, number>>;
964
+ readonly traits?: readonly string[];
965
+ readonly personality?: readonly number[];
966
+ readonly skills?: Readonly<Record<string, number>>;
967
+ };
968
+ type CharacterSheet = {
969
+ readonly profession: string;
970
+ readonly attributes: Readonly<Record<SheetAttributeId, number>>;
971
+ readonly traits: readonly string[];
972
+ /** Skill levels: the profession's start, plus what was given. */
973
+ readonly skills: Readonly<Record<string, number>>;
974
+ /** The milestones reached at the current skill levels. */
975
+ milestones(skill: string): readonly number[];
976
+ /** Points left in the point buy (Personagens `pool()`): base + profession + traits − spent. Negative means the sheet is over budget. */
977
+ pool(): number;
978
+ /** Whether the sheet follows the point buy (attributes in range, points not over, no excluded traits together). */
979
+ valid(): boolean;
980
+ /** Every derived value of the ruleset (`derived()`), by id. */
981
+ derived(): Readonly<Record<string, number>>;
982
+ /** Courage, empathy, loyalty, greed, stability, 0..100. */
983
+ readonly personality: readonly number[];
984
+ readonly memories: readonly Memory[];
985
+ /** What this person thinks of others, −100..100. */
986
+ readonly opinions: Readonly<Record<string, number>>;
987
+ /** Everything the person lived, in order. */
988
+ readonly history: readonly SheetEntry[];
989
+ /** Keeps an entry; one with a weight is also a memory (the lightest, then the oldest, goes past the limit). */
990
+ record(entry: SheetEntry): void;
991
+ /** Whether the person lived this entry id. */
992
+ remembers(id: string): boolean;
993
+ /** Moves the opinion of someone by `delta`, inside −100..100. */
994
+ opine(about: string, delta: number): number;
995
+ /** The opinions decay towards neutral by `days` (Personagens: "decai devagar para o neutro"). */
996
+ decay(days: number): void;
997
+ /** What the opinion means: joins the group at +60, may rob, betray or attack below −60. */
998
+ stance(about: string): 'joins' | 'hostile' | 'neutral';
999
+ };
1000
+ /** `ruleset` is content: `SHEET_RULESET` of `game-characters-people`, or `defaultStoryContent().ruleset` of `game-kit-defaults`. Default `SHEET_RULESET`; the default is deprecated and removed in the next major. */
1001
+ type SheetOptions = SheetInput & {
1002
+ readonly ruleset?: SheetRuleset;
1003
+ readonly numbers?: Partial<SheetNumbers>;
1004
+ };
1005
+ /** A character sheet on a ruleset (the Personagens one is `SHEET_RULESET` of `game-characters-people`), with the memory and opinion rules of the document. */
1006
+ declare function createSheet(options?: SheetOptions): CharacterSheet;
1007
+ /**
1008
+ * A sheet drawn at a person's creation (P13: drawn on creation): the person's profession or one drawn, the pool spent one point at a time on an
1009
+ * attribute drawn among those under the maximum. No traits unless given.
1010
+ */
1011
+ declare function drawSheet(random: () => number, input?: SheetInput & {
1012
+ readonly ruleset?: SheetRuleset;
1013
+ }): CharacterSheet;
1014
+
1015
+ type StoryWorldOptions = {
1016
+ readonly stories?: readonly Story[];
1017
+ /** The people the game wrote, in order (named people first; `extra` ones are left out of the newcomers' bonds). */
1018
+ readonly people?: readonly Person[];
1019
+ /** The name pools of the language (`getNamePools` of `game-characters-people`, or `defaultStoryContent(locale).names` of `game-kit-defaults`). Default `getNamePools(locale)`; the default is deprecated and removed in the next major. */
1020
+ readonly names?: NamePools;
1021
+ /** The character sheet ruleset (`SHEET_RULESET` of `game-characters-people`, or `defaultStoryContent().ruleset`). Default `SHEET_RULESET`; the default is deprecated and removed in the next major. */
1022
+ readonly ruleset?: SheetRuleset;
1023
+ /** The seed of the world's stream (default 1). The life simulation draws from it as the team's page draws from `rng(seed)`. */
1024
+ readonly seed?: number;
1025
+ /** The life simulation's own stream, instead of `createRng(seed)` (a game with one stream for everything passes it). */
1026
+ readonly random?: () => number;
1027
+ /** The life simulation; without it only the stories happen (the team's page without "vale vivo"). */
1028
+ readonly life?: LifeOptions;
1029
+ /** Fills the world with ordinary people up to this many living ones (the team's `fill`). Needs `life`. */
1030
+ readonly fill?: number;
1031
+ /** Code beats the game registers, by id (a beat with `run`). */
1032
+ readonly codeBeats?: Readonly<Record<string, CodeBeat>>;
1033
+ /** The base of the people who join the player (default the life simulation's `playerBase`, else 'player'). */
1034
+ readonly playerBase?: string;
1035
+ /** The player's actions at the start (more come through `act`). */
1036
+ readonly actions?: Actions;
1037
+ readonly locale?: string;
1038
+ };
1039
+ type StoryWorld = {
1040
+ readonly states: States;
1041
+ readonly flags: Flags;
1042
+ readonly actions: Actions;
1043
+ readonly casting: Casting;
1044
+ readonly chronicle: Chronicle;
1045
+ /** The life simulation's world (food, affinities, partners, the people it made), or null without `life`. */
1046
+ readonly life: LifeWorld | null;
1047
+ /** The last day run (0 before the first). */
1048
+ readonly day: number;
1049
+ /** The person, given, cast or made by the life simulation. */
1050
+ person(id: string): Person | undefined;
1051
+ /** Everyone, in the order they came into the world. */
1052
+ people(): readonly Person[];
1053
+ /** The short name the texts use. */
1054
+ nameOf(id: string): string;
1055
+ /** The person who plays a role. */
1056
+ cast(role: string): string;
1057
+ /** A player action: from now on the stories see it. */
1058
+ act(id: string): void;
1059
+ /** Runs the next day: that day's beats of every story, in order, then a day of the life simulation. */
1060
+ advance(): void;
1061
+ /** Runs days up to `day`. */
1062
+ runTo(day: number): void;
1063
+ /** The person's sheet (drawn on first ask from the person's own stream: the same world, the same sheet). */
1064
+ sheet(id: string): CharacterSheet;
1065
+ };
1066
+ /** The text table of a locale with a game's patch over it. */
1067
+ declare const lifeTextOf: (locale: string, patch?: LifeOptions["text"]) => LifeText;
1068
+ /** The life numbers with a game's patch over them. */
1069
+ declare const lifeNumbersOf: (patch?: LifeOptions["numbers"]) => LifeNumbers;
1070
+ /**
1071
+ * A world of stories (Os Vivos do Vale `simulate`, lines 744-756, made generic): the stories cast at creation, then day by day every story's beats of
1072
+ * that day in order (each beat's changes applied, its flags raised, its line in the chronicle) and a day of the life simulation. What each person
1073
+ * lived goes into their sheet, so the next stories can read it.
1074
+ */
1075
+ declare function createStoryWorld(options?: StoryWorldOptions): StoryWorld;
1076
+ /** Runs a world `days` days (the team's `simulate(day, A, O)`). */
1077
+ declare function simulateStories(days: number, options?: StoryWorldOptions): StoryWorld;
1078
+
1079
+ /** What the bench runs: people, stories, the player's actions it offers and the life simulation. */
1080
+ type StoriesContent = {
1081
+ readonly people?: readonly Person[];
1082
+ readonly stories: readonly Story[];
1083
+ readonly actions?: readonly {
1084
+ readonly id: string;
1085
+ readonly name: string;
1086
+ }[];
1087
+ readonly life?: LifeOptions;
1088
+ readonly fill?: number;
1089
+ readonly playerBase?: string;
1090
+ /** How many days the scenarios run (default 90). */
1091
+ readonly days?: number;
1092
+ /** The kit's own example content (not a game's). */
1093
+ readonly example?: boolean;
1094
+ };
1095
+ /** The content packs the bench runs on: the name pools and the sheet ruleset, and how a profession is called (`defaultStoryContent` of `game-kit-defaults` has the kit's own). */
1096
+ type StoriesTestModuleOptions = {
1097
+ readonly names?: NamePools;
1098
+ readonly ruleset?: SheetRuleset;
1099
+ /** The name of a profession in the language; default its id. */
1100
+ readonly professionName?: (professionId: string, locale: string) => string | undefined;
1101
+ readonly content?: StoriesContent;
1102
+ readonly locale?: string;
1103
+ readonly seed?: number;
1104
+ };
1105
+ interface StoriesScenarioLike {
1106
+ expect(condition: boolean, label: string, data?: Record<string, unknown>): void;
1107
+ }
1108
+ type StoriesTestModule = TestableModule<StoriesScenarioLike> & {
1109
+ /** The world as the bench left it (seed, day, actions). */
1110
+ readonly world: StoryWorld;
1111
+ /** Swaps the content (a game's stories, the zombiada slice) and starts again. */
1112
+ load(content: StoriesContent): void;
1113
+ };
1114
+ declare const STORIES_AREA_ID = "stories_area";
1115
+ /**
1116
+ * The stories area of a test room, against the generic contracts only, with no 3D: the seed and the day slider run a world of stories, the chronicle
1117
+ * of the day and one person's character sheet go to the host's sheet panel. The player's actions are switches. The kit ships two tiny example stories
1118
+ * (marked `example`); `load` takes a game's own content.
1119
+ */
1120
+ declare function createStoriesTestModule(options?: StoriesTestModuleOptions): StoriesTestModule;
1121
+
1122
+ declare const STORIES_EXAMPLE: Readonly<Record<'pt-BR' | 'en', StoriesContent>>;
1123
+
1124
+ export { type StoryWorldOptions as $, type Actions as A, type BeatOutcome as B, type Condition as C, type SheetAttributeId as D, type SheetDerived as E, type Flags as F, type Group as G, type SheetEntry as H, type SheetInput as I, type SheetNumbers as J, type SheetOptions as K, type LifeOptions as L, type Memory as M, type NamePools as N, type SheetProfession as O, type Person as P, type SheetRuleset as Q, type ResolvedChange as R, type States as S, type SheetSkill as T, type SheetSkillGroup as U, type SheetTrait as V, type StoriesContent as W, type StoriesTestModule as X, type StoriesTestModuleOptions as Y, type Story as Z, type StoryWorld as _, type StateId as a, type TextPart as a0, castStories as a1, createChronicle as a2, createSheet as a3, createStoriesTestModule as a4, createStoryWorld as a5, drawSheet as a6, lifeNumbersOf as a7, lifeTextOf as a8, simulateStories as a9, type CodeBeat as b, type StoryBeat as c, type LifeNumbers as d, type LifeWorld as e, type LifeText as f, type ChronicleEntry as g, type BeatVariant as h, type CastOptions as i, type Casting as j, type Change as k, type ChangeItem as l, type CharacterSheet as m, type Chronicle as n, type LifeNumbersPatch as o, type LifeRule as p, type LifeStats as q, type LifeTextPatch as r, type LifeTimer as s, type LocalizedText as t, type PersonState as u, type Relation as v, type Role as w, STORIES_AREA_ID as x, STORIES_EXAMPLE as y, type SheetAttribute as z };