@maka/maka-cli 5.66.0 → 5.68.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/bundle/typescript/package.json +1 -1
- package/bundle/typescript/src/commands/game/_index.d.ts +1 -0
- package/bundle/typescript/src/commands/game/_index.js +1 -0
- package/bundle/typescript/src/commands/game/_index.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/archetypes.js +6 -1
- package/bundle/typescript/src/commands/game/sideQuest/archetypes.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/ar.js +4 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/ar.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/backlog.d.ts +103 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/backlog.js +423 -25
- package/bundle/typescript/src/commands/game/sideQuest/commands/backlog.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/bluff.d.ts +15 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/bluff.js +61 -4
- package/bundle/typescript/src/commands/game/sideQuest/commands/bluff.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/companions.d.ts +39 -3
- package/bundle/typescript/src/commands/game/sideQuest/commands/companions.js +85 -4
- package/bundle/typescript/src/commands/game/sideQuest/commands/companions.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/compile.d.ts +37 -17
- package/bundle/typescript/src/commands/game/sideQuest/commands/compile.js +53 -115
- package/bundle/typescript/src/commands/game/sideQuest/commands/compile.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/decompile.d.ts +55 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/decompile.js +203 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/decompile.js.map +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/go.d.ts +23 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/go.js +42 -7
- package/bundle/typescript/src/commands/game/sideQuest/commands/go.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/hack.d.ts +27 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/hack.js +28 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/hack.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/order.js +69 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/order.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/register.d.ts +15 -2
- package/bundle/typescript/src/commands/game/sideQuest/commands/register.js +32 -6
- package/bundle/typescript/src/commands/game/sideQuest/commands/register.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/review.d.ts +39 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/review.js +48 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/review.js.map +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/sprites.d.ts +35 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/sprites.js +108 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/sprites.js.map +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/thread.d.ts +27 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/thread.js +7 -2
- package/bundle/typescript/src/commands/game/sideQuest/commands/thread.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/unravel.d.ts +57 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/unravel.js +162 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/unravel.js.map +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/engine-version.d.ts +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/engine-version.js +31 -1
- package/bundle/typescript/src/commands/game/sideQuest/engine-version.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/factories/repro-scene.d.ts +87 -0
- package/bundle/typescript/src/commands/game/sideQuest/factories/repro-scene.js +320 -0
- package/bundle/typescript/src/commands/game/sideQuest/factories/repro-scene.js.map +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/factories/scene-chunks.js +32 -0
- package/bundle/typescript/src/commands/game/sideQuest/factories/scene-chunks.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/factories/scene-factory.js +8 -1
- package/bundle/typescript/src/commands/game/sideQuest/factories/scene-factory.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/game.d.ts +98 -11
- package/bundle/typescript/src/commands/game/sideQuest/game.js +239 -35
- package/bundle/typescript/src/commands/game/sideQuest/game.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/headless-harness.d.ts +24 -0
- package/bundle/typescript/src/commands/game/sideQuest/headless-harness.js +63 -0
- package/bundle/typescript/src/commands/game/sideQuest/headless-harness.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/models/item.d.ts +9 -0
- package/bundle/typescript/src/commands/game/sideQuest/models/item.js +9 -0
- package/bundle/typescript/src/commands/game/sideQuest/models/item.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/models/npc.d.ts +57 -1
- package/bundle/typescript/src/commands/game/sideQuest/models/npc.js +62 -1
- package/bundle/typescript/src/commands/game/sideQuest/models/npc.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/models/player.d.ts +10 -3
- package/bundle/typescript/src/commands/game/sideQuest/models/player.js +5 -1
- package/bundle/typescript/src/commands/game/sideQuest/models/player.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/resonance-actions.d.ts +108 -0
- package/bundle/typescript/src/commands/game/sideQuest/resonance-actions.js +186 -0
- package/bundle/typescript/src/commands/game/sideQuest/resonance-actions.js.map +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/sprite-powers.d.ts +88 -0
- package/bundle/typescript/src/commands/game/sideQuest/sprite-powers.js +137 -0
- package/bundle/typescript/src/commands/game/sideQuest/sprite-powers.js.map +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/types/repro.d.ts +106 -0
- package/bundle/typescript/src/commands/game/sideQuest/types/repro.js +2 -0
- package/bundle/typescript/src/commands/game/sideQuest/types/repro.js.map +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/types/save-file.d.ts +32 -1
- package/bundle/typescript/src/commands/game/sideQuest/types/seed/device-seed.d.ts +12 -0
- package/bundle/typescript/src/commands/game/sideQuest/ui.d.ts +9 -0
- package/bundle/typescript/src/commands/game/sideQuest/ui.js +3 -0
- package/bundle/typescript/src/commands/game/sideQuest/ui.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/backlog-dump.d.ts +17 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/backlog-dump.js +250 -36
- package/bundle/typescript/src/commands/game/sideQuest/utilities/backlog-dump.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/backlog-review.d.ts +30 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/backlog-review.js +58 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/backlog-review.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/backlog-vocab.d.ts +85 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/backlog-vocab.js +100 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/backlog-vocab.js.map +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/backlog.d.ts +45 -3
- package/bundle/typescript/src/commands/game/sideQuest/utilities/backlog.js +45 -3
- package/bundle/typescript/src/commands/game/sideQuest/utilities/backlog.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/commit-ref.d.ts +13 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/commit-ref.js +22 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/commit-ref.js.map +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/grid-view.d.ts +13 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/grid-view.js +36 -3
- package/bundle/typescript/src/commands/game/sideQuest/utilities/grid-view.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/handoff.d.ts +42 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/handoff.js +57 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/handoff.js.map +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/persistence.js +14 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/persistence.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/repro-launch.d.ts +68 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/repro-launch.js +147 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/repro-launch.js.map +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/spots.js +39 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/spots.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest-backlog.sub.cmd.d.ts +1 -0
- package/bundle/typescript/src/commands/game/sideQuest-backlog.sub.cmd.js +46 -0
- package/bundle/typescript/src/commands/game/sideQuest-backlog.sub.cmd.js.map +1 -0
- package/bundle/typescript/src/commands/game/sideQuest.sub.cmd.d.ts +3 -1
- package/bundle/typescript/src/commands/game/sideQuest.sub.cmd.js +352 -42
- package/bundle/typescript/src/commands/game/sideQuest.sub.cmd.js.map +1 -1
- package/bundle/typescript/src/tools/log/log.class.d.ts +17 -0
- package/bundle/typescript/src/tools/log/log.class.js +30 -1
- package/bundle/typescript/src/tools/log/log.class.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
import { Direction } from '../types/shared/direction-enum.js';
|
|
2
|
+
import { ARCHETYPES, getArchetype } from '../archetypes.js';
|
|
3
|
+
/**
|
|
4
|
+
* BUILDING THE BENCH A REVIEW ITEM SHIPS WITH.
|
|
5
|
+
*
|
|
6
|
+
* Two rooms and one sealed door between them. That is the whole scene,
|
|
7
|
+
* on purpose: a repro is a bench, not a run, and every room you have to
|
|
8
|
+
* walk through to reach the thing under test is a room the reproduction
|
|
9
|
+
* can go wrong in.
|
|
10
|
+
*
|
|
11
|
+
* THIS FILE OWNS THE INVARIANTS, and that is the reason it exists
|
|
12
|
+
* rather than the specs carrying raw seed JSON. The author of a repro
|
|
13
|
+
* states INTENT -- "a guard in the doorway", "a keypad sealing north" --
|
|
14
|
+
* and everything that intent implies is derived here, once, for every
|
|
15
|
+
* repro that will ever be written.
|
|
16
|
+
*
|
|
17
|
+
* The invariant that motivated the design: an NPC marked `guarding`
|
|
18
|
+
* whose startSpot is not the sealed exit's spot. Nothing throws.
|
|
19
|
+
* `holdsGround` is simply never consulted, because doorwayOccupants
|
|
20
|
+
* reads the exit cell and the guard is not standing in it. The scene
|
|
21
|
+
* builds, the walkthrough passes, and the repro demonstrates the
|
|
22
|
+
* opposite of what it claims -- a check whose two sides fail together
|
|
23
|
+
* cannot see the failure, which is the dominant defect shape in this
|
|
24
|
+
* codebase's history. An author cannot make that mistake here, because
|
|
25
|
+
* an author never supplies the spot.
|
|
26
|
+
*
|
|
27
|
+
* The other invariants are refusals rather than derivations, and they
|
|
28
|
+
* refuse LOUDLY rather than degrading. A repro that silently does less
|
|
29
|
+
* than it says is the failure mode this whole feature is built against,
|
|
30
|
+
* so "drop the field and carry on" -- which is what the runtime does
|
|
31
|
+
* with a code on a lock -- is exactly the wrong behaviour here.
|
|
32
|
+
*/
|
|
33
|
+
/** The room the device stands in, which is also the room that declares
|
|
34
|
+
* the exit it seals. */
|
|
35
|
+
export const REPRO_BARRIER_ROOM = 'The Approach';
|
|
36
|
+
/** Through the door. */
|
|
37
|
+
export const REPRO_FAR_ROOM = 'The Far Side';
|
|
38
|
+
/** The one spot that matters, and the one an author never has to name.
|
|
39
|
+
* Both rooms have it: a doorway has two sides, and a guard posted on
|
|
40
|
+
* the far side stands in their own. */
|
|
41
|
+
export const REPRO_DOORWAY_SPOT = 'doorway';
|
|
42
|
+
/**
|
|
43
|
+
* Somewhere to stand that is NOT the doorway, so "move to the door" is
|
|
44
|
+
* a real move with a real before-state. Without it the runner starts in
|
|
45
|
+
* the doorway and the whole class of "I walked onto the guard's cell"
|
|
46
|
+
* items cannot be reproduced at all.
|
|
47
|
+
*
|
|
48
|
+
* NOT called "open floor", which was the first name and was wrong for a
|
|
49
|
+
* reason worth recording: "open floor" is the ENGINE's phrase for
|
|
50
|
+
* having no named spot at all (see move.ts -- "You peel off to the open
|
|
51
|
+
* floor"). Naming a real spot that made a positioned NPC render as
|
|
52
|
+
* "Grier at the open floor, Grier on the open floor" -- one clause from
|
|
53
|
+
* the spot, one from the generic fallback, reading exactly like a
|
|
54
|
+
* duplicate-render bug. Every reviewer sent to a bench would have filed
|
|
55
|
+
* it. A fixture must not borrow the engine's words for "none".
|
|
56
|
+
*/
|
|
57
|
+
export const REPRO_FLOOR_SPOT = 'back wall';
|
|
58
|
+
const DEFAULT_DEVICE_NAME = {
|
|
59
|
+
lock: 'Maglock',
|
|
60
|
+
panel: 'Keypad',
|
|
61
|
+
ward: 'Chalk Ward',
|
|
62
|
+
};
|
|
63
|
+
const DEFAULT_DEVICE_DESCRIPTION = {
|
|
64
|
+
lock: 'A heavy maglock, seated in the frame and holding the door shut.',
|
|
65
|
+
panel: 'A keypad on a short steel stalk, its display waiting for a code.',
|
|
66
|
+
ward: 'A ward drawn in chalk and old ash across the whole doorway, humming against your teeth.',
|
|
67
|
+
};
|
|
68
|
+
const OPPOSITE = {
|
|
69
|
+
[Direction.NORTH]: Direction.SOUTH,
|
|
70
|
+
[Direction.SOUTH]: Direction.NORTH,
|
|
71
|
+
[Direction.EAST]: Direction.WEST,
|
|
72
|
+
[Direction.WEST]: Direction.EAST,
|
|
73
|
+
[Direction.UP]: Direction.DOWN,
|
|
74
|
+
[Direction.DOWN]: Direction.UP,
|
|
75
|
+
};
|
|
76
|
+
/** Archetypes that can work a ward. `dispel` needs the Art; nothing
|
|
77
|
+
* else in the game does. */
|
|
78
|
+
const AWAKENED = new Set(['Adept', 'Combat Mage', 'Street Shaman']);
|
|
79
|
+
/** Bounds. A repro is a bench: more than this and it is a scene, and a
|
|
80
|
+
* scene is a place a reproduction gets lost in. */
|
|
81
|
+
const MAX_NPCS = 4;
|
|
82
|
+
const MAX_ITEMS = 6;
|
|
83
|
+
/** A fixture that cannot be built into an honest bench. Thrown, never
|
|
84
|
+
* swallowed -- the caller turns it into a sentence for whoever wrote
|
|
85
|
+
* the spec. */
|
|
86
|
+
export class ReproFixtureError extends Error {
|
|
87
|
+
constructor(message) {
|
|
88
|
+
super(message);
|
|
89
|
+
this.name = 'ReproFixtureError';
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function roomFor(side) {
|
|
93
|
+
return side === 'far' ? REPRO_FAR_ROOM : REPRO_BARRIER_ROOM;
|
|
94
|
+
}
|
|
95
|
+
/** A guard who is not in the doorway guards nothing, so `guarding`
|
|
96
|
+
* implies `atDoorway` rather than sitting beside it as a second flag
|
|
97
|
+
* the two could disagree about. */
|
|
98
|
+
function standsInDoorway(npc) {
|
|
99
|
+
return npc.guarding === true || npc.atDoorway === true;
|
|
100
|
+
}
|
|
101
|
+
export function buildReproScene(fixture) {
|
|
102
|
+
const warnings = [];
|
|
103
|
+
// ARCHETYPE. getArchetype falls back to ARCHETYPES[0] on a name it
|
|
104
|
+
// does not know, which is right for a launcher menu and wrong here:
|
|
105
|
+
// a ward repro silently handed a mundane Runner is a repro that
|
|
106
|
+
// cannot be run, and it would look like the fix had failed.
|
|
107
|
+
const archetypeName = fixture.archetype ?? 'Covert Ops';
|
|
108
|
+
if (!ARCHETYPES.some(a => a.name === archetypeName)) {
|
|
109
|
+
throw new ReproFixtureError(`No archetype called "${archetypeName}". One of: ${ARCHETYPES.map(a => a.name).join(', ')}.`);
|
|
110
|
+
}
|
|
111
|
+
const npcs = fixture.npcs ?? [];
|
|
112
|
+
const items = fixture.items ?? [];
|
|
113
|
+
if (npcs.length > MAX_NPCS) {
|
|
114
|
+
throw new ReproFixtureError(`A repro carries at most ${MAX_NPCS} NPCs; this one has ${npcs.length}.`);
|
|
115
|
+
}
|
|
116
|
+
if (items.length > MAX_ITEMS) {
|
|
117
|
+
throw new ReproFixtureError(`A repro carries at most ${MAX_ITEMS} items; this one has ${items.length}.`);
|
|
118
|
+
}
|
|
119
|
+
const duplicateNpc = npcs.find((n, i) => npcs.findIndex(o => o.name === n.name) !== i);
|
|
120
|
+
if (duplicateNpc) {
|
|
121
|
+
throw new ReproFixtureError(`Two NPCs are both called "${duplicateNpc.name}" -- a name has to pick one body out.`);
|
|
122
|
+
}
|
|
123
|
+
const barrier = fixture.barrier;
|
|
124
|
+
const direction = barrier?.sealsExit ?? Direction.NORTH;
|
|
125
|
+
const startSide = fixture.start ?? 'barrier';
|
|
126
|
+
const startRoom = roomFor(startSide);
|
|
127
|
+
let device;
|
|
128
|
+
if (barrier) {
|
|
129
|
+
// INVARIANT 1: a code belongs to a panel and nowhere else. The
|
|
130
|
+
// Device constructor DROPS it on a lock or a ward, silently and
|
|
131
|
+
// correctly -- that is the runtime honouring "you can't talk at a
|
|
132
|
+
// mechanical lock". Inheriting that drop here would produce a bench
|
|
133
|
+
// whose stated credential does nothing, and the reviewer would read
|
|
134
|
+
// the refusal as the bug still being present.
|
|
135
|
+
if (barrier.code && barrier.kind !== 'panel') {
|
|
136
|
+
throw new ReproFixtureError(`A ${barrier.kind} has no code -- only a panel does. Give it a keyItem, or let it be picked or dispelled.`);
|
|
137
|
+
}
|
|
138
|
+
// A panel with no code cannot be opened the way a panel opens.
|
|
139
|
+
if (barrier.kind === 'panel' && !barrier.code && !barrier.keyItem && !barrier.open) {
|
|
140
|
+
warnings.push('This panel has neither a code nor a key, so the only way through it is force.');
|
|
141
|
+
}
|
|
142
|
+
if (barrier.kind === 'ward' && !AWAKENED.has(archetypeName)) {
|
|
143
|
+
warnings.push(`A ward answers to the Art, and ${archetypeName} is mundane -- fine if the refusal is the point, otherwise use Combat Mage.`);
|
|
144
|
+
}
|
|
145
|
+
device = {
|
|
146
|
+
name: barrier.name ?? DEFAULT_DEVICE_NAME[barrier.kind],
|
|
147
|
+
description: DEFAULT_DEVICE_DESCRIPTION[barrier.kind],
|
|
148
|
+
kind: barrier.kind,
|
|
149
|
+
code: barrier.code,
|
|
150
|
+
keyItem: barrier.keyItem,
|
|
151
|
+
// INVARIANT 2: the device stands AT the doorway it seals, so
|
|
152
|
+
// reaching it is reaching the door. bypass-command resolves the
|
|
153
|
+
// spot as exitSpot(room, opensExit) ?? atSpot, and a device
|
|
154
|
+
// sitting at neither is a device you cannot walk up to.
|
|
155
|
+
atSpot: REPRO_DOORWAY_SPOT,
|
|
156
|
+
// INVARIANT 3: naming the exit is what locks the door.
|
|
157
|
+
// scene-factory only LOGS when a device names something that is
|
|
158
|
+
// not a door, which on a bench means an unsealed doorway and a
|
|
159
|
+
// reviewer concluding the barrier never worked.
|
|
160
|
+
opensExit: direction,
|
|
161
|
+
// The walkthrough test caught this being dropped, which is the
|
|
162
|
+
// point of having one: `open: true` was accepted here and went
|
|
163
|
+
// nowhere, because the seed type had no such field. A fixture
|
|
164
|
+
// that quietly does less than it says is the exact failure this
|
|
165
|
+
// whole feature exists to prevent -- so the field was added to
|
|
166
|
+
// IDeviceSeedJson rather than the intent silently discarded.
|
|
167
|
+
open: barrier.open === true,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
const spots = [
|
|
171
|
+
{ name: REPRO_DOORWAY_SPOT },
|
|
172
|
+
{ name: REPRO_FLOOR_SPOT },
|
|
173
|
+
];
|
|
174
|
+
// THE BARRIER IS NAMED IN THE PROSE, and where it stands, and which
|
|
175
|
+
// way the door runs.
|
|
176
|
+
//
|
|
177
|
+
// A device is only surfaced by `search`, which is right for a real
|
|
178
|
+
// scene -- finding things is play. On a bench it is a trap: the whole
|
|
179
|
+
// promise is "you start standing at the thing", and the first player
|
|
180
|
+
// through one reported exactly that ("There is no location for the
|
|
181
|
+
// door, so I cannot get to it"). They looked, saw two spots and no
|
|
182
|
+
// door, and concluded the fixture was broken. Nothing here should
|
|
183
|
+
// have to be discovered.
|
|
184
|
+
const barrierRoom = {
|
|
185
|
+
name: REPRO_BARRIER_ROOM,
|
|
186
|
+
description: barrier
|
|
187
|
+
? `A short concrete run ending at one door, ${direction} of you. `
|
|
188
|
+
+ `${device.name} is fixed beside the doorway${barrier.open ? ', standing open' : ', holding it shut'}. `
|
|
189
|
+
+ `There is nothing else here, which is the point -- whatever is wrong is wrong at that door.`
|
|
190
|
+
: `A short concrete run with a door ${direction} of you and nothing else in it.`,
|
|
191
|
+
roomType: 'Street',
|
|
192
|
+
size: 'medium',
|
|
193
|
+
spots,
|
|
194
|
+
isStartRoom: startSide === 'barrier',
|
|
195
|
+
exits: [{ direction, targetRoom: REPRO_FAR_ROOM, atSpot: REPRO_DOORWAY_SPOT }],
|
|
196
|
+
devices: device ? [device] : undefined,
|
|
197
|
+
};
|
|
198
|
+
const farRoom = {
|
|
199
|
+
name: REPRO_FAR_ROOM,
|
|
200
|
+
description: `The other side of the door, which lies ${OPPOSITE[direction]} of you`
|
|
201
|
+
+ `${barrier ? ` and is held from the far side by ${device.name}` : ''}. Bare, and no further out.`,
|
|
202
|
+
roomType: 'Street',
|
|
203
|
+
size: 'medium',
|
|
204
|
+
spots,
|
|
205
|
+
isStartRoom: startSide === 'far',
|
|
206
|
+
// INVARIANT 3, other half: a door has two sides. Without the return
|
|
207
|
+
// exit the far room is a one-way pocket, and "go back and try it
|
|
208
|
+
// again" -- which is most of what reviewing a fix consists of --
|
|
209
|
+
// would not work.
|
|
210
|
+
exits: [{ direction: OPPOSITE[direction], targetRoom: REPRO_BARRIER_ROOM, atSpot: REPRO_DOORWAY_SPOT }],
|
|
211
|
+
};
|
|
212
|
+
const npcSeeds = npcs.map(npc => {
|
|
213
|
+
const side = npc.side ?? 'barrier';
|
|
214
|
+
const inDoorway = standsInDoorway(npc);
|
|
215
|
+
return {
|
|
216
|
+
description: npc.concept,
|
|
217
|
+
dialogue: [],
|
|
218
|
+
player: {
|
|
219
|
+
name: npc.name,
|
|
220
|
+
startLocation: roomFor(side),
|
|
221
|
+
// THE INVARIANT THIS FILE EXISTS FOR. Derived from the
|
|
222
|
+
// direction the barrier seals, never supplied -- a guarding NPC
|
|
223
|
+
// standing anywhere else holds nothing, silently, and the
|
|
224
|
+
// walkthrough would still pass.
|
|
225
|
+
startSpot: inDoorway ? REPRO_DOORWAY_SPOT : REPRO_FLOOR_SPOT,
|
|
226
|
+
guarding: npc.guarding === true,
|
|
227
|
+
lifestyleChoices: [],
|
|
228
|
+
combat: {
|
|
229
|
+
body: 4, agility: 4, reaction: 4, combatSkill: 3, strength: 4,
|
|
230
|
+
willpower: 3, logic: 3, intuition: 3, charisma: 3, edge: 2,
|
|
231
|
+
skills: { unarmed: 3, perception: 3, negotiation: 3 },
|
|
232
|
+
},
|
|
233
|
+
},
|
|
234
|
+
};
|
|
235
|
+
});
|
|
236
|
+
const itemSeeds = items.map(it => ({
|
|
237
|
+
name: it.name,
|
|
238
|
+
description: it.description,
|
|
239
|
+
details: it.details,
|
|
240
|
+
size: 'Tiny',
|
|
241
|
+
category: 'Document',
|
|
242
|
+
shape: 'Rectangle',
|
|
243
|
+
color: 'Gray',
|
|
244
|
+
texture: 'Plain',
|
|
245
|
+
rating: 'Common',
|
|
246
|
+
weight: 0.1,
|
|
247
|
+
room: roomFor(it.side ?? 'barrier'),
|
|
248
|
+
atSpot: REPRO_FLOOR_SPOT,
|
|
249
|
+
}));
|
|
250
|
+
// INVARIANT 4: the key is on the side the runner starts on. A key
|
|
251
|
+
// behind the door it opens is a bench nobody can work, and it reads
|
|
252
|
+
// as the fix having failed rather than the fixture being wrong.
|
|
253
|
+
if (barrier?.keyItem) {
|
|
254
|
+
itemSeeds.push({
|
|
255
|
+
name: barrier.keyItem,
|
|
256
|
+
description: `The thing that opens the ${device?.name ?? 'door'}.`,
|
|
257
|
+
size: 'Tiny',
|
|
258
|
+
category: 'Key',
|
|
259
|
+
shape: 'Rectangle',
|
|
260
|
+
color: 'Steel',
|
|
261
|
+
texture: 'Milled',
|
|
262
|
+
rating: 'Common',
|
|
263
|
+
weight: 0.1,
|
|
264
|
+
room: startRoom,
|
|
265
|
+
atSpot: REPRO_FLOOR_SPOT,
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
if (barrier && !barrier.open && startSide === 'far') {
|
|
269
|
+
warnings.push(`The runner starts on the far side, so the ${device?.name} is through a shut door and cannot be worked from there -- right for testing what someone SAYS about the door, wrong for testing the door.`);
|
|
270
|
+
}
|
|
271
|
+
const seed = {
|
|
272
|
+
name: 'Repro Bench',
|
|
273
|
+
story: fixture.premise
|
|
274
|
+
?? 'A bench, not a job. One door, whatever is standing at it, and nothing else to be distracted by.',
|
|
275
|
+
currency: { type: 'nuyen', authorityRoomTags: [] },
|
|
276
|
+
residenceTiers: ['Street', 'Squatter', 'Low'],
|
|
277
|
+
rooms: [barrierRoom, farRoom],
|
|
278
|
+
npcs: npcSeeds,
|
|
279
|
+
items: itemSeeds,
|
|
280
|
+
puzzles: [],
|
|
281
|
+
player: {
|
|
282
|
+
name: 'Testbed',
|
|
283
|
+
startLocation: startRoom,
|
|
284
|
+
// NO RESIDENCE. Copied from paritySeed originally, where it is
|
|
285
|
+
// right -- that fixture models a real run. A bench models nothing
|
|
286
|
+
// and nobody lives in it; declaring a home here only invites the
|
|
287
|
+
// lifestyle machinery to have opinions about a two-room scene.
|
|
288
|
+
lifestyleChoices: [],
|
|
289
|
+
startingItems: [],
|
|
290
|
+
},
|
|
291
|
+
// NO winCondition AND NO client, deliberately. A bench cannot be
|
|
292
|
+
// won, because there is nothing to win -- adding a payout would put
|
|
293
|
+
// a wrap-up, a settlement and an offer of more work in the way of a
|
|
294
|
+
// reviewer who came to look at one door. scene1 already proves a
|
|
295
|
+
// scene boots without a client.
|
|
296
|
+
};
|
|
297
|
+
return {
|
|
298
|
+
seed,
|
|
299
|
+
names: {
|
|
300
|
+
device: device?.name,
|
|
301
|
+
npcs: npcs.map(n => n.name),
|
|
302
|
+
direction,
|
|
303
|
+
barrierRoom: REPRO_BARRIER_ROOM,
|
|
304
|
+
farRoom: REPRO_FAR_ROOM,
|
|
305
|
+
startRoom,
|
|
306
|
+
},
|
|
307
|
+
warnings,
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
/** The archetype a fixture asks for, resolved. Separate from the build
|
|
311
|
+
* because the launcher hands the NAME to the game (which rolls the
|
|
312
|
+
* character itself) while the headless walkthrough needs the spread to
|
|
313
|
+
* make a save out of. */
|
|
314
|
+
export function reproArchetypeName(fixture) {
|
|
315
|
+
return fixture.archetype ?? 'Covert Ops';
|
|
316
|
+
}
|
|
317
|
+
export function reproArchetype(fixture) {
|
|
318
|
+
return getArchetype(reproArchetypeName(fixture));
|
|
319
|
+
}
|
|
320
|
+
//# sourceMappingURL=repro-scene.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repro-scene.js","sourceRoot":"","sources":["../../../../../../../src/commands/game/sideQuest/factories/repro-scene.ts"],"names":[],"mappings":"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"}
|
|
@@ -1174,6 +1174,38 @@ function resolveDirectionCollisions(skeleton) {
|
|
|
1174
1174
|
*/
|
|
1175
1175
|
export function normalizeSkeleton(skeleton) {
|
|
1176
1176
|
const notes = [];
|
|
1177
|
+
// WHO THE CLIENT IS, before anything counts them.
|
|
1178
|
+
//
|
|
1179
|
+
// NOT a missing guard -- an audit of the four names the model writes
|
|
1180
|
+
// about other lists (2026-08-28) found all four checked: heldBy,
|
|
1181
|
+
// winCondition.toNpc and .item fail in validateSkeleton below, and
|
|
1182
|
+
// `client` fails in validateClient. The gap is narrower and it is
|
|
1183
|
+
// about COST and ORDER.
|
|
1184
|
+
//
|
|
1185
|
+
// COST: validateClient REJECTS an unresolvable client, so a one-word
|
|
1186
|
+
// near miss -- "Mr. Osprey" against a roster saying "Osprey" -- burns
|
|
1187
|
+
// a full regeneration to fix a name the skeleton already contains.
|
|
1188
|
+
// Every other name reference gained a repair on 2026-08-27; this one
|
|
1189
|
+
// did not, so it is the only near miss still paying full price.
|
|
1190
|
+
//
|
|
1191
|
+
// ORDER: the opposition floor counts hostiles as
|
|
1192
|
+
// `npcs.filter(n => n.name !== skeleton.client)` in validateSkeleton,
|
|
1193
|
+
// which runs BEFORE validateClient ever sees the assembled scene. So
|
|
1194
|
+
// an unrepaired near miss counts the CLIENT as a hostile and skews
|
|
1195
|
+
// the difficulty floor by one -- silently, and in a check whose whole
|
|
1196
|
+
// job is to notice an under-populated cast.
|
|
1197
|
+
//
|
|
1198
|
+
// Repairing here fixes both: the count is right, and a resolvable
|
|
1199
|
+
// name never reaches the rejection. What genuinely matches nothing
|
|
1200
|
+
// still falls to validateClient, which owns that verdict and words
|
|
1201
|
+
// it better than a duplicate here would.
|
|
1202
|
+
if (skeleton.client) {
|
|
1203
|
+
const canonicalClient = resolveNamedRef(skeleton.client, (skeleton.npcs ?? []).map(n => n.name), 'the scene-level "client"');
|
|
1204
|
+
if (canonicalClient && canonicalClient !== skeleton.client) {
|
|
1205
|
+
notes.push(`client "${skeleton.client}" renamed to "${canonicalClient}" to match the roster.`);
|
|
1206
|
+
skeleton.client = canonicalClient;
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1177
1209
|
// Topology before anything that reasons about topology: freeStranded-
|
|
1178
1210
|
// Rooms, clue placement and the curb all walk this graph, and they
|
|
1179
1211
|
// should walk the one the ENGINE will actually build.
|