@maka/maka-cli 5.117.0 → 5.119.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/sideQuest/commands/attack.js +6 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/attack.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/cast.js +9 -2
- package/bundle/typescript/src/commands/game/sideQuest/commands/cast.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/compile.js +3 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/compile.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/deck.d.ts +14 -2
- package/bundle/typescript/src/commands/game/sideQuest/commands/deck.js +73 -38
- package/bundle/typescript/src/commands/game/sideQuest/commands/deck.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/decompile.js +3 -6
- package/bundle/typescript/src/commands/game/sideQuest/commands/decompile.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/docwagon.js +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/docwagon.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/download.js +4 -3
- package/bundle/typescript/src/commands/game/sideQuest/commands/download.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/enter-host.d.ts +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/enter-host.js +10 -8
- package/bundle/typescript/src/commands/game/sideQuest/commands/enter-host.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/equip.js +17 -7
- package/bundle/typescript/src/commands/game/sideQuest/commands/equip.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/equipment.d.ts +10 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/equipment.js +72 -20
- package/bundle/typescript/src/commands/game/sideQuest/commands/equipment.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/go.js +8 -3
- package/bundle/typescript/src/commands/game/sideQuest/commands/go.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/hack.js +30 -14
- package/bundle/typescript/src/commands/game/sideQuest/commands/hack.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/haggle.js +14 -2
- package/bundle/typescript/src/commands/game/sideQuest/commands/haggle.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/hop.d.ts +16 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/hop.js +95 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/hop.js.map +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/inv.js +6 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/inv.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/jack.js +3 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/jack.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/jackpoint.js +5 -7
- package/bundle/typescript/src/commands/game/sideQuest/commands/jackpoint.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/look.js +24 -4
- package/bundle/typescript/src/commands/game/sideQuest/commands/look.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/map.js +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/map.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/mark.js +20 -6
- package/bundle/typescript/src/commands/game/sideQuest/commands/mark.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/reboot.js +7 -6
- package/bundle/typescript/src/commands/game/sideQuest/commands/reboot.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/reload.js +6 -3
- package/bundle/typescript/src/commands/game/sideQuest/commands/reload.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/rest.js +3 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/rest.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/say.js +8 -5
- package/bundle/typescript/src/commands/game/sideQuest/commands/say.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/sheet.js +4 -3
- package/bundle/typescript/src/commands/game/sideQuest/commands/sheet.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/sin.js +11 -3
- package/bundle/typescript/src/commands/game/sideQuest/commands/sin.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/stance.js +5 -3
- package/bundle/typescript/src/commands/game/sideQuest/commands/stance.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/take.js +20 -2
- package/bundle/typescript/src/commands/game/sideQuest/commands/take.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/tap.js +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/tap.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/thread.js +2 -5
- package/bundle/typescript/src/commands/game/sideQuest/commands/thread.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/engine-version.d.ts +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/engine-version.js +17 -1
- package/bundle/typescript/src/commands/game/sideQuest/engine-version.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/factories/chargen-factory.d.ts +6 -0
- package/bundle/typescript/src/commands/game/sideQuest/factories/chargen-factory.js +17 -4
- package/bundle/typescript/src/commands/game/sideQuest/factories/chargen-factory.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/factories/scene-chunks.js +1 -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 +2 -0
- package/bundle/typescript/src/commands/game/sideQuest/factories/scene-factory.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/game.d.ts +22 -0
- package/bundle/typescript/src/commands/game/sideQuest/game.js +132 -29
- package/bundle/typescript/src/commands/game/sideQuest/game.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/models/host.d.ts +80 -0
- package/bundle/typescript/src/commands/game/sideQuest/models/host.js +98 -0
- package/bundle/typescript/src/commands/game/sideQuest/models/host.js.map +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/models/item.d.ts +50 -1
- package/bundle/typescript/src/commands/game/sideQuest/models/item.js +78 -2
- package/bundle/typescript/src/commands/game/sideQuest/models/item.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/models/player.d.ts +133 -3
- package/bundle/typescript/src/commands/game/sideQuest/models/player.js +381 -85
- package/bundle/typescript/src/commands/game/sideQuest/models/player.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/models/room.d.ts +40 -9
- package/bundle/typescript/src/commands/game/sideQuest/models/room.js +73 -12
- package/bundle/typescript/src/commands/game/sideQuest/models/room.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/models/scene.d.ts +3 -0
- package/bundle/typescript/src/commands/game/sideQuest/models/scene.js +3 -0
- package/bundle/typescript/src/commands/game/sideQuest/models/scene.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/qualities.d.ts +34 -1
- package/bundle/typescript/src/commands/game/sideQuest/qualities.js +58 -26
- package/bundle/typescript/src/commands/game/sideQuest/qualities.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/types/player-equipment.d.ts +8 -12
- package/bundle/typescript/src/commands/game/sideQuest/types/save-file.d.ts +14 -1
- package/bundle/typescript/src/commands/game/sideQuest/types/seed/room-seed.d.ts +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/types/seed/scene-seed.d.ts +2 -0
- package/bundle/typescript/src/commands/game/sideQuest/types/shared/equipment-enum.d.ts +22 -16
- package/bundle/typescript/src/commands/game/sideQuest/types/shared/equipment-enum.js +22 -16
- package/bundle/typescript/src/commands/game/sideQuest/types/shared/equipment-enum.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/ui.js +2 -2
- package/bundle/typescript/src/commands/game/sideQuest/ui.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/auto-fight.js +13 -8
- package/bundle/typescript/src/commands/game/sideQuest/utilities/auto-fight.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/catalog-data.d.ts +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/catalog-data.js +8 -7
- package/bundle/typescript/src/commands/game/sideQuest/utilities/catalog-data.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/combat-exchange.js +61 -16
- package/bundle/typescript/src/commands/game/sideQuest/utilities/combat-exchange.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/condition-report.d.ts +23 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/condition-report.js +111 -11
- package/bundle/typescript/src/commands/game/sideQuest/utilities/condition-report.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/dice.d.ts +5 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/dice.js +5 -27
- package/bundle/typescript/src/commands/game/sideQuest/utilities/dice.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/grid-reach.js +2 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/grid-reach.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/grid-view.d.ts +11 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/grid-view.js +56 -8
- package/bundle/typescript/src/commands/game/sideQuest/utilities/grid-view.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/grids.d.ts +72 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/grids.js +100 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/grids.js.map +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/harm-note.d.ts +25 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/harm-note.js +10 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/harm-note.js.map +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/harm-settlement.d.ts +29 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/harm-settlement.js +64 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/harm-settlement.js.map +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/ic-actors.d.ts +9 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/ic-actors.js +98 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/ic-actors.js.map +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/ic.d.ts +3 -2
- package/bundle/typescript/src/commands/game/sideQuest/utilities/ic.js +34 -6
- package/bundle/typescript/src/commands/game/sideQuest/utilities/ic.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/marks.d.ts +42 -2
- package/bundle/typescript/src/commands/game/sideQuest/utilities/marks.js +75 -4
- package/bundle/typescript/src/commands/game/sideQuest/utilities/marks.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/matrix-roster.d.ts +62 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/matrix-roster.js +97 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/matrix-roster.js.map +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/overwatch.js +3 -3
- package/bundle/typescript/src/commands/game/sideQuest/utilities/overwatch.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/persistence.d.ts +1 -3
- package/bundle/typescript/src/commands/game/sideQuest/utilities/persistence.js +85 -7
- package/bundle/typescript/src/commands/game/sideQuest/utilities/persistence.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/planes.d.ts +10 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/planes.js +39 -23
- package/bundle/typescript/src/commands/game/sideQuest/utilities/planes.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/programs.d.ts +16 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/programs.js +12 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/programs.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/sin.d.ts +2 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/sin.js +23 -4
- package/bundle/typescript/src/commands/game/sideQuest/utilities/sin.js.map +1 -1
- package/package.json +1 -1
|
@@ -14,7 +14,47 @@ export declare const MAX_MARKS = 3;
|
|
|
14
14
|
/** Everything this placer has marked, gone at once -- their reboot,
|
|
15
15
|
* jack-out, or GOD convergence (all reboot the persona). */
|
|
16
16
|
export declare function clearMarksPlacedBy(scene: Scene, placerName: string): void;
|
|
17
|
-
/**
|
|
18
|
-
|
|
17
|
+
/**
|
|
18
|
+
* A target rebooting shakes every mark off itself -- "all of your marks,
|
|
19
|
+
* as well as the ones others may have put on your icon, are erased"
|
|
20
|
+
* (p.242, RAG-checked 2026-09-02). With a scene that is every persona on
|
|
21
|
+
* the PAN ledger AND every host's entry for this persona (web report:
|
|
22
|
+
* after a jack-out the ledger still read "The Circuit Bazaar host x2").
|
|
23
|
+
* Returns how many placers were shaken off.
|
|
24
|
+
*/
|
|
25
|
+
export declare function clearMarksOn(actor: Player, scene?: Scene): number;
|
|
26
|
+
/**
|
|
27
|
+
* THE REBOOT, as far as marks go -- one door for every route that reboots
|
|
28
|
+
* the persona: "reboot", jack-out (p.240 reboots the device), a forced
|
|
29
|
+
* dump, GOD's convergence. Both ledgers go (p.242) and the sheet hears it.
|
|
30
|
+
*/
|
|
31
|
+
export declare function rebootWipe(scene: Scene, actor: Player): {
|
|
32
|
+
placed: void;
|
|
33
|
+
on: number;
|
|
34
|
+
};
|
|
19
35
|
/** The placer's standing marks, for the bare "mark" listing. */
|
|
20
36
|
export declare function describeMarks(scene: Scene, placerName: string): string[];
|
|
37
|
+
/**
|
|
38
|
+
* The marks this persona HOLDS, for the live sheet (contract 2026-09-02,
|
|
39
|
+
* web accepts first): every host and PAN it has marked, named the way
|
|
40
|
+
* describeMarks prints them, count 1..3. Read at beat time, so the reboot
|
|
41
|
+
* clear and convergence show on the next beat with no clear-site wiring.
|
|
42
|
+
* The site caps the list at 24 entries.
|
|
43
|
+
*/
|
|
44
|
+
export declare function marksPlaced(scene: Scene, placerName: string): {
|
|
45
|
+
target: string;
|
|
46
|
+
count: number;
|
|
47
|
+
}[];
|
|
48
|
+
/**
|
|
49
|
+
* WHO HOLDS MARKS ON THIS PERSONA, one row each, for the live sheet
|
|
50
|
+
* (contract 2026-09-02). Every host in the scene that MADE the persona --
|
|
51
|
+
* not only the one it stands inside: a host's mark on you outlives your
|
|
52
|
+
* exit and dies with your reboot (p.236 -- marks last the session; the
|
|
53
|
+
* ledger is Host.marksOn, cleared by clearMarksOn). A session log showed
|
|
54
|
+
* three marks across two hosts while the inside-host number could show
|
|
55
|
+
* one host's worth. Plus every persona on the PAN ledger.
|
|
56
|
+
*/
|
|
57
|
+
export declare function marksOnYou(scene: Scene, player: Player): {
|
|
58
|
+
placer: string;
|
|
59
|
+
count: number;
|
|
60
|
+
}[];
|
|
@@ -27,12 +27,40 @@ export function clearMarksPlacedBy(scene, placerName) {
|
|
|
27
27
|
Logger.getInstance().write(`Marks: ${placerName}'s ${cleared} marked icon(s) cleared (persona reboot).`);
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
|
-
/**
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
/**
|
|
31
|
+
* A target rebooting shakes every mark off itself -- "all of your marks,
|
|
32
|
+
* as well as the ones others may have put on your icon, are erased"
|
|
33
|
+
* (p.242, RAG-checked 2026-09-02). With a scene that is every persona on
|
|
34
|
+
* the PAN ledger AND every host's entry for this persona (web report:
|
|
35
|
+
* after a jack-out the ledger still read "The Circuit Bazaar host x2").
|
|
36
|
+
* Returns how many placers were shaken off.
|
|
37
|
+
*/
|
|
38
|
+
export function clearMarksOn(actor, scene) {
|
|
39
|
+
// Optional chaining: test stubs stand in for a Player here (link-lock.test.ts).
|
|
40
|
+
let had = [...(actor.panMarksBy?.values() ?? [])].filter(n => n > 0).length;
|
|
41
|
+
actor.panMarksBy?.clear();
|
|
42
|
+
if (scene) {
|
|
43
|
+
for (const room of Object.values(scene.getRooms())) {
|
|
44
|
+
if ((room.host?.marksOn.get(actor.name) ?? 0) > 0)
|
|
45
|
+
had++;
|
|
46
|
+
room.host?.marksOn.delete(actor.name);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
34
49
|
return had;
|
|
35
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* THE REBOOT, as far as marks go -- one door for every route that reboots
|
|
53
|
+
* the persona: "reboot", jack-out (p.240 reboots the device), a forced
|
|
54
|
+
* dump, GOD's convergence. Both ledgers go (p.242) and the sheet hears it.
|
|
55
|
+
*/
|
|
56
|
+
export function rebootWipe(scene, actor) {
|
|
57
|
+
const placed = clearMarksPlacedBy(scene, actor.name);
|
|
58
|
+
const on = clearMarksOn(actor, scene);
|
|
59
|
+
if (on > 0)
|
|
60
|
+
Logger.getInstance().write(`Marks: ${on} placer(s) shaken off ${actor.name} (persona reboot).`);
|
|
61
|
+
actor.noteConditionChanged?.();
|
|
62
|
+
return { placed, on };
|
|
63
|
+
}
|
|
36
64
|
/** The placer's standing marks, for the bare "mark" listing. */
|
|
37
65
|
export function describeMarks(scene, placerName) {
|
|
38
66
|
const lines = [];
|
|
@@ -48,4 +76,47 @@ export function describeMarks(scene, placerName) {
|
|
|
48
76
|
}
|
|
49
77
|
return lines;
|
|
50
78
|
}
|
|
79
|
+
/**
|
|
80
|
+
* The marks this persona HOLDS, for the live sheet (contract 2026-09-02,
|
|
81
|
+
* web accepts first): every host and PAN it has marked, named the way
|
|
82
|
+
* describeMarks prints them, count 1..3. Read at beat time, so the reboot
|
|
83
|
+
* clear and convergence show on the next beat with no clear-site wiring.
|
|
84
|
+
* The site caps the list at 24 entries.
|
|
85
|
+
*/
|
|
86
|
+
export function marksPlaced(scene, placerName) {
|
|
87
|
+
const out = [];
|
|
88
|
+
for (const room of Object.values(scene.getRooms())) {
|
|
89
|
+
const n = room.hostMarksBy.get(placerName) ?? 0;
|
|
90
|
+
if (n > 0)
|
|
91
|
+
out.push({ target: hostLabel(room, { capital: true }), count: n });
|
|
92
|
+
}
|
|
93
|
+
for (const a of scene.allActors) {
|
|
94
|
+
const n = a.panMarksBy.get(placerName) ?? 0;
|
|
95
|
+
if (n > 0)
|
|
96
|
+
out.push({ target: `${a.name}'s PAN`, count: n });
|
|
97
|
+
}
|
|
98
|
+
return out.slice(0, 24);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* WHO HOLDS MARKS ON THIS PERSONA, one row each, for the live sheet
|
|
102
|
+
* (contract 2026-09-02). Every host in the scene that MADE the persona --
|
|
103
|
+
* not only the one it stands inside: a host's mark on you outlives your
|
|
104
|
+
* exit and dies with your reboot (p.236 -- marks last the session; the
|
|
105
|
+
* ledger is Host.marksOn, cleared by clearMarksOn). A session log showed
|
|
106
|
+
* three marks across two hosts while the inside-host number could show
|
|
107
|
+
* one host's worth. Plus every persona on the PAN ledger.
|
|
108
|
+
*/
|
|
109
|
+
export function marksOnYou(scene, player) {
|
|
110
|
+
const out = [];
|
|
111
|
+
for (const room of Object.values(scene.getRooms())) {
|
|
112
|
+
const n = room.host?.marksOn.get(player.name) ?? 0;
|
|
113
|
+
if (n > 0)
|
|
114
|
+
out.push({ placer: hostLabel(room, { capital: true }), count: n });
|
|
115
|
+
}
|
|
116
|
+
for (const [placer, count] of player.panMarksBy.entries()) {
|
|
117
|
+
if (count > 0)
|
|
118
|
+
out.push({ placer, count });
|
|
119
|
+
}
|
|
120
|
+
return out.slice(0, 24);
|
|
121
|
+
}
|
|
51
122
|
//# sourceMappingURL=marks.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"marks.js","sourceRoot":"","sources":["../../../../../../../src/commands/game/sideQuest/utilities/marks.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC;;;;;;;;;GASG;AAEH,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,CAAC;AAE3B;6DAC6D;AAC7D,MAAM,UAAU,kBAAkB,CAAC,KAAY,EAAE,UAAkB;IACjE,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,EAAE,CAAC;QACnD,IAAI,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,UAAU,CAAC;YAAE,OAAO,EAAE,CAAC;IACrD,CAAC;IACD,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;QAChC,IAAI,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,UAAU,CAAC;YAAE,OAAO,EAAE,CAAC;IACjD,CAAC;IACD,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;QAChB,MAAM,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,UAAU,UAAU,MAAM,OAAO,2CAA2C,CAAC,CAAC;IAC3G,CAAC;AACH,CAAC;AAED
|
|
1
|
+
{"version":3,"file":"marks.js","sourceRoot":"","sources":["../../../../../../../src/commands/game/sideQuest/utilities/marks.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { Player } from '../models/player.js';
|
|
2
|
+
import type { Item } from '../models/item.js';
|
|
3
|
+
import type { Room } from '../models/room.js';
|
|
4
|
+
import { NPC } from '../models/npc.js';
|
|
5
|
+
import type { Scene } from '../models/scene.js';
|
|
6
|
+
import type { Host } from '../models/host.js';
|
|
7
|
+
/**
|
|
8
|
+
* WHO A PERSONA CAN REACH (increment 2 of the Matrix position model,
|
|
9
|
+
* 2026-09-02). The persona's position is `Player.matrixPosition` -- on a
|
|
10
|
+
* grid, or inside a Host -- and its body stays in `currentLocation` on
|
|
11
|
+
* every plane. So a persona inside a host is NOT in the host room's
|
|
12
|
+
* actor set any more, and the nine verbs that used to read
|
|
13
|
+
* `getActorsInRoom(room)` + `sameHostSide` for Matrix targets read these
|
|
14
|
+
* instead. One utility, one answer, both sides of the wall (SR5 p.246:
|
|
15
|
+
* inside a host you see and touch only what is inside it; outside, you
|
|
16
|
+
* cannot touch the interior).
|
|
17
|
+
*/
|
|
18
|
+
/** The wall test: same host, or both out on a grid, or both off-Matrix (undefined === undefined stays deliberately harmless). */
|
|
19
|
+
export declare function sameMatrixSide(a: Player, b: Player): boolean;
|
|
20
|
+
/** Everyone whose persona is inside this host -- players, ice, sprites, agents. */
|
|
21
|
+
export declare function personasInside(scene: Scene, host: Host): (Player | NPC)[];
|
|
22
|
+
/** Matrix-plane actors on the persona's side of the wall, excluding the persona. */
|
|
23
|
+
export declare function personasOnMySide(scene: Scene, actor: Player): (Player | NPC)[];
|
|
24
|
+
/** Constructs a spike or a decompile can reach: NPC icons on my side, still running. */
|
|
25
|
+
export declare function matrixConstructsInReach(scene: Scene, actor: Player): NPC[];
|
|
26
|
+
/** Cybercombat targets: icons on my side that share the combat plane. */
|
|
27
|
+
export declare function cybercombatCandidates(scene: Scene, actor: Player): (Player | NPC)[];
|
|
28
|
+
/** Who hears a persona speak: every persona on its side of the wall. Bodies hear nothing. */
|
|
29
|
+
export declare function speechAudience(scene: Scene, actor: Player): (Player | NPC)[];
|
|
30
|
+
/** Delivers a persona's words to its audience, the way Room.say delivers a body's. */
|
|
31
|
+
export declare function speakOnTheGrid(scene: Scene, actor: Player, message: string): (Player | NPC)[];
|
|
32
|
+
/**
|
|
33
|
+
* The combat exchange's "same place": on the matrix plane it is the
|
|
34
|
+
* same side of the host wall (distance is noise, not range); in the meat
|
|
35
|
+
* it is the same room, as it always was.
|
|
36
|
+
*/
|
|
37
|
+
export declare function samePlace(a: Player, b: Player): boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Sprites and agents ride with their owner's persona: across a host wall
|
|
40
|
+
* on enter/exit, and between grids on a hop. Bodies do not move.
|
|
41
|
+
*/
|
|
42
|
+
export declare function movePersonaWith(game: {
|
|
43
|
+
companions: {
|
|
44
|
+
kind: string;
|
|
45
|
+
npc: NPC;
|
|
46
|
+
}[];
|
|
47
|
+
} | undefined, actor: Player): NPC[];
|
|
48
|
+
/**
|
|
49
|
+
* WHERE A NAMED THING IS, when it is not where the persona stands: the
|
|
50
|
+
* first room in reach holding an item by that name, and what stands
|
|
51
|
+
* between the persona and it. 'offline' = an air-gapped server (only a
|
|
52
|
+
* body in that room reaches it, p.233); 'host' = inside a host's vault
|
|
53
|
+
* (enter first, p.246); 'open' = loose on the grid, a dim icon at the
|
|
54
|
+
* noise the distance costs; 'meat' = a physical thing, not an icon.
|
|
55
|
+
*/
|
|
56
|
+
export declare function whereIsThat(rooms: Record<string, Room>, actor: Player, name: string): {
|
|
57
|
+
room: Room;
|
|
58
|
+
item: Item;
|
|
59
|
+
reach: 'offline' | 'host' | 'open' | 'meat';
|
|
60
|
+
noise: number;
|
|
61
|
+
remembered: boolean;
|
|
62
|
+
} | undefined;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { roomsInReach } from './grid-reach.js';
|
|
2
|
+
import { NPC } from '../models/npc.js';
|
|
3
|
+
/**
|
|
4
|
+
* WHO A PERSONA CAN REACH (increment 2 of the Matrix position model,
|
|
5
|
+
* 2026-09-02). The persona's position is `Player.matrixPosition` -- on a
|
|
6
|
+
* grid, or inside a Host -- and its body stays in `currentLocation` on
|
|
7
|
+
* every plane. So a persona inside a host is NOT in the host room's
|
|
8
|
+
* actor set any more, and the nine verbs that used to read
|
|
9
|
+
* `getActorsInRoom(room)` + `sameHostSide` for Matrix targets read these
|
|
10
|
+
* instead. One utility, one answer, both sides of the wall (SR5 p.246:
|
|
11
|
+
* inside a host you see and touch only what is inside it; outside, you
|
|
12
|
+
* cannot touch the interior).
|
|
13
|
+
*/
|
|
14
|
+
/** The wall test: same host, or both out on a grid, or both off-Matrix (undefined === undefined stays deliberately harmless). */
|
|
15
|
+
export function sameMatrixSide(a, b) {
|
|
16
|
+
return a.hostInside === b.hostInside;
|
|
17
|
+
}
|
|
18
|
+
/** Everyone whose persona is inside this host -- players, ice, sprites, agents. */
|
|
19
|
+
export function personasInside(scene, host) {
|
|
20
|
+
return scene.allActors.filter(a => a.plane === 'matrix' && a.hostInside === host);
|
|
21
|
+
}
|
|
22
|
+
/** Matrix-plane actors on the persona's side of the wall, excluding the persona. */
|
|
23
|
+
export function personasOnMySide(scene, actor) {
|
|
24
|
+
return scene.allActors.filter(a => a !== actor && a.plane === 'matrix' && sameMatrixSide(actor, a));
|
|
25
|
+
}
|
|
26
|
+
/** Constructs a spike or a decompile can reach: NPC icons on my side, still running. */
|
|
27
|
+
export function matrixConstructsInReach(scene, actor) {
|
|
28
|
+
return personasOnMySide(scene, actor).filter((a) => a instanceof NPC && !a.deathClaimed);
|
|
29
|
+
}
|
|
30
|
+
/** Cybercombat targets: icons on my side that share the combat plane. */
|
|
31
|
+
export function cybercombatCandidates(scene, actor) {
|
|
32
|
+
return personasOnMySide(scene, actor).filter(a => a.sharesCombatPlane(actor));
|
|
33
|
+
}
|
|
34
|
+
/** Who hears a persona speak: every persona on its side of the wall. Bodies hear nothing. */
|
|
35
|
+
export function speechAudience(scene, actor) {
|
|
36
|
+
return personasOnMySide(scene, actor);
|
|
37
|
+
}
|
|
38
|
+
/** Delivers a persona's words to its audience, the way Room.say delivers a body's. */
|
|
39
|
+
export function speakOnTheGrid(scene, actor, message) {
|
|
40
|
+
const audience = speechAudience(scene, actor);
|
|
41
|
+
for (const recipient of audience) {
|
|
42
|
+
void Promise.resolve(recipient.hear(actor, message, { broadcast: true })).catch(() => undefined);
|
|
43
|
+
}
|
|
44
|
+
return audience;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* The combat exchange's "same place": on the matrix plane it is the
|
|
48
|
+
* same side of the host wall (distance is noise, not range); in the meat
|
|
49
|
+
* it is the same room, as it always was.
|
|
50
|
+
*/
|
|
51
|
+
export function samePlace(a, b) {
|
|
52
|
+
if (a.plane === 'matrix' || b.plane === 'matrix') {
|
|
53
|
+
return a.plane === b.plane && sameMatrixSide(a, b);
|
|
54
|
+
}
|
|
55
|
+
return a.currentLocation === b.currentLocation;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Sprites and agents ride with their owner's persona: across a host wall
|
|
59
|
+
* on enter/exit, and between grids on a hop. Bodies do not move.
|
|
60
|
+
*/
|
|
61
|
+
export function movePersonaWith(game, actor) {
|
|
62
|
+
const moved = [];
|
|
63
|
+
for (const c of game?.companions ?? []) {
|
|
64
|
+
if ((c.kind === 'sprite' || c.kind === 'agent') && c.npc.plane === 'matrix') {
|
|
65
|
+
c.npc.matrixPosition = actor.matrixPosition;
|
|
66
|
+
moved.push(c.npc);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return moved;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* WHERE A NAMED THING IS, when it is not where the persona stands: the
|
|
73
|
+
* first room in reach holding an item by that name, and what stands
|
|
74
|
+
* between the persona and it. 'offline' = an air-gapped server (only a
|
|
75
|
+
* body in that room reaches it, p.233); 'host' = inside a host's vault
|
|
76
|
+
* (enter first, p.246); 'open' = loose on the grid, a dim icon at the
|
|
77
|
+
* noise the distance costs; 'meat' = a physical thing, not an icon.
|
|
78
|
+
*/
|
|
79
|
+
export function whereIsThat(rooms, actor, name) {
|
|
80
|
+
const q = name.trim().toLowerCase();
|
|
81
|
+
for (const { room, noise } of roomsInReach(rooms, actor)) {
|
|
82
|
+
const item = room.inventory.getAllItems().find(i => i.name.toLowerCase() === q)
|
|
83
|
+
?? room.inventory.getAllItems().find(i => i.name.toLowerCase().includes(q));
|
|
84
|
+
if (!item)
|
|
85
|
+
continue;
|
|
86
|
+
const reach = item.plane !== 'matrix' ? 'meat'
|
|
87
|
+
: room.offlineServer ? 'offline'
|
|
88
|
+
: room.host && !room.host.cracked ? 'host'
|
|
89
|
+
: 'open';
|
|
90
|
+
// A room is named only from MEMORY (p.243: the grid does not give away
|
|
91
|
+
// a device's address): the runner has stood in it, or searched it.
|
|
92
|
+
const remembered = room.visitedBy.has(actor.name) || room.searchedBy.has(actor.name) || room === actor.currentLocation;
|
|
93
|
+
return { room, item, reach, noise, remembered };
|
|
94
|
+
}
|
|
95
|
+
return undefined;
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=matrix-roster.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"matrix-roster.js","sourceRoot":"","sources":["../../../../../../../src/commands/game/sideQuest/utilities/matrix-roster.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Logger } from './logger.js';
|
|
2
2
|
import { rollPool, formatRoll } from './dice.js';
|
|
3
|
-
import {
|
|
3
|
+
import { rebootWipe } from './marks.js';
|
|
4
4
|
/**
|
|
5
5
|
* GOD -- the Grid Overwatch Division (canon p.221/231-232, player go
|
|
6
6
|
* 2026-08-23). Every illegal Matrix action (Attack or Sleaze) leaves
|
|
@@ -102,8 +102,8 @@ function converge(scene, actor) {
|
|
|
102
102
|
lines.push(` You shed the hammerblow -- barely.`);
|
|
103
103
|
}
|
|
104
104
|
resetOverwatch(actor, 'convergence force-reboot');
|
|
105
|
-
// "Erasing all of your marks" (p.231-232) --
|
|
106
|
-
|
|
105
|
+
// "Erasing all of your marks" (p.231-232) -- and the ones on you (p.242).
|
|
106
|
+
rebootWipe(scene, actor);
|
|
107
107
|
actor.addNotoriety(`GOD converged on their persona -- location burned to the authorities`);
|
|
108
108
|
scene.addWorldEvent(`GOD converged on ${actor.name} -- their physical location in ${actor.bodyRoom?.name ?? actor.currentLocation.name} is burned to the authorities.`);
|
|
109
109
|
// "Reported to the authorities" now MEANS something: the district's
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"overwatch.js","sourceRoot":"","sources":["../../../../../../../src/commands/game/sideQuest/utilities/overwatch.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"overwatch.js","sourceRoot":"","sources":["../../../../../../../src/commands/game/sideQuest/utilities/overwatch.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExC;;;;;;;;;;;;;;;;GAgBG;AAEH,MAAM,CAAC,MAAM,cAAc,GAAG,EAAE,CAAC;AACjC,MAAM,OAAO,GAAG,EAAE,GAAG,MAAM,CAAC;AAC5B,oEAAoE;AACpE,yBAAyB;AACzB,MAAM,iBAAiB,GAAG,CAAC,CAAC;AAE5B,SAAS,EAAE;IACT,OAAO,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;AAC3C,CAAC;AAED,4EAA4E;AAC5E,SAAS,QAAQ,CAAC,KAAa;IAC7B,IAAI,KAAK,CAAC,cAAc,IAAI,CAAC,IAAI,KAAK,CAAC,iBAAiB,KAAK,CAAC;QAAE,OAAO;IACvE,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,iBAAiB,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,iBAAiB,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IACxG,IAAI,KAAK,IAAI,CAAC;QAAE,OAAO;IACvB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE;QAAE,KAAK,CAAC,cAAc,IAAI,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC;IACpE,KAAK,CAAC,iBAAiB,IAAI,KAAK,GAAG,OAAO,CAAC;IAC3C,MAAM,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,cAAc,KAAK,CAAC,IAAI,gBAAgB,KAAK,kBAAkB,KAAK,CAAC,cAAc,GAAG,CAAC,CAAC;AACrH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,KAAY,EAAE,KAAa,EAAE,WAAmB,EAAE,GAAW;IAC3F,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC;IACpC,IAAI,KAAK,CAAC,iBAAiB,KAAK,CAAC;QAAE,KAAK,CAAC,iBAAiB,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACxE,QAAQ,CAAC,KAAK,CAAC,CAAC;IAChB,MAAM,MAAM,GAAG,KAAK,CAAC,cAAc,CAAC;IACpC,KAAK,CAAC,cAAc,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC;IACjD,MAAM,CAAC,KAAK,CAAC,cAAc,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,WAAW,CAAC,KAAK,GAAG,WAAW,KAAK,CAAC,cAAc,GAAG,CAAC,CAAC;IAE9G,IAAI,KAAK,CAAC,cAAc,IAAI,cAAc,EAAE,CAAC;QAC3C,OAAO,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;IAC5D,CAAC;IACD,mEAAmE;IACnE,uDAAuD;IACvD,IAAI,MAAM,GAAG,EAAE,IAAI,KAAK,CAAC,cAAc,IAAI,EAAE,EAAE,CAAC;QAC9C,OAAO,EAAE,KAAK,EAAE,CAAC,6JAA6J,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;IACtM,CAAC;IACD,IAAI,MAAM,GAAG,EAAE,IAAI,KAAK,CAAC,cAAc,IAAI,EAAE,EAAE,CAAC;QAC9C,OAAO,EAAE,KAAK,EAAE,CAAC,4IAA4I,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;IACrL,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;AACzC,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,YAAY,CAAC,KAAa;IACxC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAChB,OAAO,KAAK,CAAC,cAAc,CAAC;AAC9B,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,cAAc,CAAC,KAAa,EAAE,GAAW;IACvD,IAAI,KAAK,CAAC,cAAc,GAAG,CAAC,EAAE,CAAC;QAC7B,MAAM,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,cAAc,KAAK,CAAC,IAAI,kBAAkB,KAAK,CAAC,cAAc,KAAK,GAAG,IAAI,CAAC,CAAC;IACzG,CAAC;IACD,KAAK,CAAC,cAAc,GAAG,CAAC,CAAC;IACzB,KAAK,CAAC,iBAAiB,GAAG,CAAC,CAAC;AAC9B,CAAC;AAED;qEACqE;AACrE,SAAS,QAAQ,CAAC,KAAY,EAAE,KAAa;IAC3C,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC;IACpC,MAAM,KAAK,GAAG,CAAC,yIAAyI,CAAC,CAAC;IAC1J,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC;IAC7C,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;IAC5C,IAAI,KAAK,CAAC,iBAAiB,CAAC,KAAK,CAAC,EAAE,CAAC;QACnC,MAAM,CAAC,IAAI,CAAC,gCAAgC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACpE,CAAC;IACD,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;QACd,IAAI,KAAK,CAAC,OAAO,KAAK,KAAK,IAAI,KAAK,CAAC,cAAc,EAAE,EAAE,CAAC;YACtD,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;YACtB,KAAK,CAAC,IAAI,CAAC,8CAA8C,KAAK,wBAAwB,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QAC/G,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC;YAC9B,KAAK,CAAC,IAAI,CAAC,mCAAmC,KAAK,OAAO,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,KAAK,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;QACjH,CAAC;IACH,CAAC;SAAM,CAAC;QACN,KAAK,CAAC,IAAI,CAAC,sCAAsC,CAAC,CAAC;IACrD,CAAC;IACD,cAAc,CAAC,KAAK,EAAE,0BAA0B,CAAC,CAAC;IAClD,0EAA0E;IAC1E,UAAU,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IACzB,KAAK,CAAC,YAAY,CAAC,sEAAsE,CAAC,CAAC;IAC3F,KAAK,CAAC,aAAa,CAAC,oBAAoB,KAAK,CAAC,IAAI,kCAAkC,KAAK,CAAC,QAAQ,EAAE,IAAI,IAAI,KAAK,CAAC,eAAe,CAAC,IAAI,gCAAgC,CAAC,CAAC;IACxK,oEAAoE;IACpE,qEAAqE;IACrE,KAAK,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,EAAE,sBAAsB,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;IAChE,KAAK,CAAC,IAAI,CAAC,sHAAsH,CAAC,CAAC;IACnI,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -88,9 +88,7 @@ export declare function serializeItem(item: Item): ISavedItem;
|
|
|
88
88
|
export declare function restoreItem(json: ISavedItem): Item;
|
|
89
89
|
type EquipmentShape = Player['equipment'];
|
|
90
90
|
export declare function serializeEquipment(eq: EquipmentShape): ISavedEquipment;
|
|
91
|
-
|
|
92
|
-
* is authoritative), then lays in the saved blobs. */
|
|
93
|
-
export declare function restoreEquipment(eq: EquipmentShape, saved: ISavedEquipment): void;
|
|
91
|
+
export declare function restoreEquipment(eq: EquipmentShape, saved: ISavedEquipment, spill?: (item: Item) => void): void;
|
|
94
92
|
export declare function replaceInventory(inv: Inventory, items: ISavedItem[]): void;
|
|
95
93
|
export declare function serializePlayer(p: Player): ISavedPlayer;
|
|
96
94
|
/**
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as fs from 'fs';
|
|
2
|
+
import { normalizeStance } from '../models/player.js';
|
|
2
3
|
import { resolveSpot } from './spots.js';
|
|
3
4
|
import { isAspectKey } from '../aspects.js';
|
|
4
5
|
import * as path from 'path';
|
|
@@ -157,6 +158,8 @@ export function serializeItem(item) {
|
|
|
157
158
|
out.quantity = item.quantity;
|
|
158
159
|
if (item.isFirearm() && item.ammo !== Item.MAGAZINE_CAPACITY)
|
|
159
160
|
out.ammo = item.ammo;
|
|
161
|
+
if (item.loadedAmmo)
|
|
162
|
+
out.loadedAmmo = item.loadedAmmo;
|
|
160
163
|
if (item.jammed)
|
|
161
164
|
out.jammed = true;
|
|
162
165
|
if (item.deckDamage > 0)
|
|
@@ -165,6 +168,12 @@ export function serializeItem(item) {
|
|
|
165
168
|
out.droneDamage = item.droneDamage;
|
|
166
169
|
if (item.loadedPrograms.length > 0)
|
|
167
170
|
out.loadedPrograms = [...item.loadedPrograms];
|
|
171
|
+
if (item.storedPrograms.length > 0)
|
|
172
|
+
out.storedPrograms = [...item.storedPrograms];
|
|
173
|
+
if (item.papers.length > 0)
|
|
174
|
+
out.papers = item.papers.map(serializeItem);
|
|
175
|
+
if (item.linkedSin)
|
|
176
|
+
out.linkedSin = item.linkedSin;
|
|
168
177
|
if (item.isCyberdeck() && item.deckOrder.join() !== '0,1,2,3')
|
|
169
178
|
out.deckOrder = item.deckOrder;
|
|
170
179
|
return out;
|
|
@@ -200,6 +209,8 @@ export function restoreItem(json) {
|
|
|
200
209
|
item.quantity = json.quantity;
|
|
201
210
|
if (json.ammo !== undefined)
|
|
202
211
|
item.ammo = json.ammo;
|
|
212
|
+
if (json.loadedAmmo)
|
|
213
|
+
item.loadedAmmo = json.loadedAmmo;
|
|
203
214
|
if (json.jammed)
|
|
204
215
|
item.jammed = true;
|
|
205
216
|
if (json.deckDamage)
|
|
@@ -208,6 +219,16 @@ export function restoreItem(json) {
|
|
|
208
219
|
item.takeDroneDamage(json.droneDamage);
|
|
209
220
|
if (json.loadedPrograms)
|
|
210
221
|
item.loadedPrograms = [...json.loadedPrograms];
|
|
222
|
+
if (json.storedPrograms)
|
|
223
|
+
item.storedPrograms = [...json.storedPrograms];
|
|
224
|
+
if (json.papers)
|
|
225
|
+
item.papers = json.papers.map(restoreItem);
|
|
226
|
+
if (json.linkedSin)
|
|
227
|
+
item.linkedSin = json.linkedSin;
|
|
228
|
+
// A running program is in storage by definition -- saves from before
|
|
229
|
+
// storage existed carried only the running set.
|
|
230
|
+
for (const k of item.loadedPrograms)
|
|
231
|
+
item.installProgram(k);
|
|
211
232
|
if (json.deckOrder)
|
|
212
233
|
item.configureDeck(json.deckOrder);
|
|
213
234
|
return item;
|
|
@@ -226,7 +247,27 @@ export function serializeEquipment(eq) {
|
|
|
226
247
|
}
|
|
227
248
|
/** Clears EVERY slot first (an NPC auto-equips at synthesis; the save
|
|
228
249
|
* is authoritative), then lays in the saved blobs. */
|
|
229
|
-
|
|
250
|
+
/**
|
|
251
|
+
* The paired slots collapsed to one per region on 2026-09-02 (canon has no
|
|
252
|
+
* sides). A save from before carries the old keys; each lands on the new
|
|
253
|
+
* slot, and a second item for the same region goes to the bag via `spill`
|
|
254
|
+
* rather than to nowhere.
|
|
255
|
+
*/
|
|
256
|
+
/** The three skillsoft rows pulled from the shelf on 2026-09-02, at the price they sold for. */
|
|
257
|
+
const SKILLSOFT_REFUNDS = [
|
|
258
|
+
{ test: /^Activesoft/i, nuyen: 15000 },
|
|
259
|
+
{ test: /^Knowsoft/i, nuyen: 6000 },
|
|
260
|
+
{ test: /^Linguasoft/i, nuyen: 3000 },
|
|
261
|
+
];
|
|
262
|
+
const LEGACY_SLOTS = {
|
|
263
|
+
'torso.leftShoulder': 'torso.shoulder', 'torso.rightShoulder': 'torso.shoulder',
|
|
264
|
+
'legs.leftHip': 'legs.hip', 'legs.rightHip': 'legs.hip',
|
|
265
|
+
'feet.leftAnkle': 'feet.ankle', 'feet.rightAnkle': 'feet.ankle',
|
|
266
|
+
'arms.leftForearm': 'arms.forearm', 'arms.rightForearm': 'arms.forearm',
|
|
267
|
+
'arms.leftBicept': 'arms.bicep', 'arms.rightBicept': 'arms.bicep',
|
|
268
|
+
'gloves.leftWrist': 'gloves.wrist', 'gloves.rightWrist': 'gloves.wrist',
|
|
269
|
+
};
|
|
270
|
+
export function restoreEquipment(eq, saved, spill) {
|
|
230
271
|
for (const group of Object.values(eq)) {
|
|
231
272
|
if (!group)
|
|
232
273
|
continue;
|
|
@@ -237,13 +278,23 @@ export function restoreEquipment(eq, saved) {
|
|
|
237
278
|
for (const [pathKey, savedItem] of Object.entries(saved)) {
|
|
238
279
|
if (!savedItem)
|
|
239
280
|
continue;
|
|
240
|
-
|
|
281
|
+
let key = LEGACY_SLOTS[pathKey] ?? pathKey;
|
|
282
|
+
// A pair of gloves used to sit on the wrist; it has its own slot now.
|
|
283
|
+
if (key === 'gloves.wrist' && savedItem.category === 'Gloves')
|
|
284
|
+
key = 'gloves.gloves';
|
|
285
|
+
const [groupKey, slotKey] = key.split('.');
|
|
241
286
|
const group = eq[groupKey];
|
|
242
287
|
if (!group || !(slotKey in group)) {
|
|
243
288
|
Logger.getInstance().write(`restoreEquipment: unknown slot "${pathKey}" -- item "${savedItem.name}" dropped to nowhere, skipping.`);
|
|
244
289
|
continue;
|
|
245
290
|
}
|
|
246
|
-
|
|
291
|
+
const item = restoreItem(savedItem);
|
|
292
|
+
if (group[slotKey]) {
|
|
293
|
+
Logger.getInstance().write(`restoreEquipment: "${item.name}" (${pathKey}) -- ${key} already holds ${group[slotKey].name}; ${spill ? 'bagged' : 'dropped'}.`);
|
|
294
|
+
spill?.(item);
|
|
295
|
+
continue;
|
|
296
|
+
}
|
|
297
|
+
group[slotKey] = item;
|
|
247
298
|
}
|
|
248
299
|
}
|
|
249
300
|
export function replaceInventory(inv, items) {
|
|
@@ -287,6 +338,7 @@ export function serializePlayer(p) {
|
|
|
287
338
|
augmentations: [...p.augmentations],
|
|
288
339
|
augmentationGrades: [...p.augGrades.entries()],
|
|
289
340
|
qualities: [...p.qualities],
|
|
341
|
+
qualityRatings: [...p.qualityRatings.entries()],
|
|
290
342
|
activeSin: p.activeSin,
|
|
291
343
|
metamagics: [...p.metamagics],
|
|
292
344
|
initiationGrade: p.initiationGrade,
|
|
@@ -318,8 +370,11 @@ export function serializePlayer(p) {
|
|
|
318
370
|
*/
|
|
319
371
|
export function restorePlayer(p, s) {
|
|
320
372
|
const logger = Logger.getInstance();
|
|
373
|
+
// Ratings ride beside the keys (contract 2026-09-02); a legacy "<key>-1"
|
|
374
|
+
// resolves inside addQuality to the rated key at 1.
|
|
375
|
+
const ratings = new Map(s.qualityRatings ?? []);
|
|
321
376
|
for (const q of s.qualities)
|
|
322
|
-
p.addQuality(q);
|
|
377
|
+
p.addQuality(q, ratings.get(q));
|
|
323
378
|
p.activeSin = s.activeSin;
|
|
324
379
|
p.baseMagic = s.baseMagic;
|
|
325
380
|
p.baseResonance = s.baseResonance;
|
|
@@ -459,7 +514,7 @@ export function restorePlayer(p, s) {
|
|
|
459
514
|
p.sleepStreak = s.needs.sleepStreak;
|
|
460
515
|
p.edgeRemaining = s.edgeRemaining;
|
|
461
516
|
p.haggledThisJob = s.haggledThisJob;
|
|
462
|
-
p.autoStance = s.autoStance;
|
|
517
|
+
p.autoStance = normalizeStance(s.autoStance);
|
|
463
518
|
if (s.archetypeName)
|
|
464
519
|
p.archetypeName = s.archetypeName;
|
|
465
520
|
if (s.gender)
|
|
@@ -470,7 +525,30 @@ export function restorePlayer(p, s) {
|
|
|
470
525
|
for (const name of s.visitedRooms ?? [])
|
|
471
526
|
p.visitedRooms.add(name);
|
|
472
527
|
replaceInventory(p.inventory, s.inventory);
|
|
473
|
-
|
|
528
|
+
// PROGRAMS LIVE ON THE DECK (p.227; 2026-09-02): a save from before
|
|
529
|
+
// carried its library as loose chips. They move into the carried deck
|
|
530
|
+
// here, once, and the log says how many.
|
|
531
|
+
// SKILLSOFTS BOUGHT BEFORE THE SHELF WAS FIXED are refunded at the price
|
|
532
|
+
// paid: nothing in the engine could ever run them (catalog-data.ts note).
|
|
533
|
+
for (const chip of [...p.inventory.getAllItems()]) {
|
|
534
|
+
const refund = SKILLSOFT_REFUNDS.find(r => chip.category === Category.Software && r.test.test(chip.name));
|
|
535
|
+
if (!refund)
|
|
536
|
+
continue;
|
|
537
|
+
p.inventory.removeItem(chip.name);
|
|
538
|
+
p.adjustCurrency(refund.nuyen);
|
|
539
|
+
Logger.getInstance().write(`restorePlayer: ${chip.name} refunded (${refund.nuyen} nuyen) -- no skillwires or skilljack exist to run it.`);
|
|
540
|
+
}
|
|
541
|
+
// PAPERS LIVE ON THE COMMLINK (p.443; 2026-09-02): a save from before
|
|
542
|
+
// carried fake SINs and licenses loose in the pack. They move onto the
|
|
543
|
+
// carried commlink (or deck) here, once; a loose license links to the
|
|
544
|
+
// best fake SIN, and the log says what moved.
|
|
545
|
+
const papers = p.sweepPapersOntoDevice();
|
|
546
|
+
if (papers > 0)
|
|
547
|
+
Logger.getInstance().write(`restorePlayer: ${papers} paper(s) moved onto ${p.paperDevice()?.name ?? 'the device'} (papers live on the commlink now).`);
|
|
548
|
+
const swept = p.sweepProgramChipsIntoDeck();
|
|
549
|
+
if (swept > 0)
|
|
550
|
+
Logger.getInstance().write(`restorePlayer: ${swept} program chip(s) installed into ${p.getAnyCyberdeck()?.name ?? 'the deck'} (programs live in deck storage now).`);
|
|
551
|
+
restoreEquipment(p.equipment, s.equipment, item => p.addInventory(item));
|
|
474
552
|
}
|
|
475
553
|
// ============================= Hub world =============================
|
|
476
554
|
function serializeRoomOverlay(room, player) {
|
|
@@ -669,7 +747,7 @@ export function applyHubOverlay(scene, saved, player, homeRoom) {
|
|
|
669
747
|
npc.setObjective(overlay.objective);
|
|
670
748
|
npc.restoreHistory(overlay.history);
|
|
671
749
|
replaceInventory(npc.inventory, overlay.inventory);
|
|
672
|
-
restoreEquipment(npc.equipment, overlay.equipment);
|
|
750
|
+
restoreEquipment(npc.equipment, overlay.equipment, item => npc.inventory.addItem(item));
|
|
673
751
|
}
|
|
674
752
|
// 4. Devices: the one flag -- door lock state was restored in step 2,
|
|
675
753
|
// so a door relocked after its device opened stays relocked.
|