@maka/maka-cli 5.117.0 → 5.118.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/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/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/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/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 +14 -11
- package/bundle/typescript/src/commands/game/sideQuest/commands/hack.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/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 +8 -4
- package/bundle/typescript/src/commands/game/sideQuest/commands/mark.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/rest.js +2 -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 +2 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/sheet.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/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 +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 +4 -0
- package/bundle/typescript/src/commands/game/sideQuest/game.js +40 -13
- 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 +91 -0
- package/bundle/typescript/src/commands/game/sideQuest/models/host.js.map +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/models/player.d.ts +45 -1
- package/bundle/typescript/src/commands/game/sideQuest/models/player.js +79 -35
- 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/types/save-file.d.ts +2 -0
- 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/utilities/combat-exchange.js +30 -10
- package/bundle/typescript/src/commands/game/sideQuest/utilities/combat-exchange.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/condition-report.js +64 -11
- package/bundle/typescript/src/commands/game/sideQuest/utilities/condition-report.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/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 +26 -6
- package/bundle/typescript/src/commands/game/sideQuest/utilities/ic.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/planes.d.ts +10 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/planes.js +24 -19
- package/bundle/typescript/src/commands/game/sideQuest/utilities/planes.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type { Room } from './room.js';
|
|
2
|
+
import type { NPC } from './npc.js';
|
|
3
|
+
import type { Door } from './door.js';
|
|
4
|
+
import type { Item } from './item.js';
|
|
5
|
+
import type { Grid } from '../utilities/grids.js';
|
|
6
|
+
/**
|
|
7
|
+
* A HOST (SR5 p.246-247), as its own object. Increment 1 of the Matrix
|
|
8
|
+
* position model (plan 2026-09-02): the host state that used to live as
|
|
9
|
+
* loose fields on Room moves here, and Room keeps delegating accessors
|
|
10
|
+
* so every existing reader and writer compiles and behaves unchanged.
|
|
11
|
+
*
|
|
12
|
+
* `over` is the physical room the host stands over in this engine: the
|
|
13
|
+
* site systems it masters bind through it -- a crack releases that room's
|
|
14
|
+
* maglocks and unseals the matrix items in its inventory, and the room's
|
|
15
|
+
* cameras answer to it (utilities/surveillance.ts). Canon puts no host at
|
|
16
|
+
* a physical address (p.246, "hosts don't have a physical location"); the
|
|
17
|
+
* anchor is the engine's mapping of "the network that runs this place",
|
|
18
|
+
* not a claim about where the host is.
|
|
19
|
+
*
|
|
20
|
+
* `grid` is optional and unset by default: canon says hosts are reached
|
|
21
|
+
* from any grid and pay to be accessible from all of them (p.246, Data
|
|
22
|
+
* Trails p.15); a seed may declare one, and only then does the cross-grid
|
|
23
|
+
* penalty apply to actions against it (increment 3).
|
|
24
|
+
*
|
|
25
|
+
* What persists: `cracked` only (utilities/persistence.ts). Marks, alert,
|
|
26
|
+
* running IC and the patrol clock are session state by design.
|
|
27
|
+
*/
|
|
28
|
+
export declare class Host {
|
|
29
|
+
static readonly DEFAULT_RATING = 3;
|
|
30
|
+
static readonly MIN_RATING = 1;
|
|
31
|
+
static readonly MAX_RATING = 12;
|
|
32
|
+
/** SR5 p.247: Host Rating 1-12; anything else is the default. */
|
|
33
|
+
static clampRating(rating: number | undefined): number;
|
|
34
|
+
readonly over: Room;
|
|
35
|
+
rating: number;
|
|
36
|
+
grid?: Grid;
|
|
37
|
+
/** The seed's word for the grid ('public' | 'local' | 'global:<corp>'); resolved against the scene's local grid by the factory. */
|
|
38
|
+
gridSeed?: string;
|
|
39
|
+
/** The one persisted field. A sanctioned host never remembers a crack. */
|
|
40
|
+
cracked: boolean;
|
|
41
|
+
/** player name -> marks the player holds on this host (max 3, p.236). */
|
|
42
|
+
marksBy: Map<string, number>;
|
|
43
|
+
/** player name -> marks the host holds on that player. */
|
|
44
|
+
marksOn: Map<string, number>;
|
|
45
|
+
/** Walls up: the host holds a mark on an intruder and its ice is hunting. */
|
|
46
|
+
alert: boolean;
|
|
47
|
+
/** IC running now, by kind name. Names, not actors -- until increment 5. */
|
|
48
|
+
runningIC: string[];
|
|
49
|
+
/** The running IC as actors, by kind (utilities/ic-actors.ts). Empty where no scene could host them. */
|
|
50
|
+
iceActors: Map<string, NPC>;
|
|
51
|
+
/** Kinds crashed this turn; the host relaunches them next turn (p.355-356). */
|
|
52
|
+
relaunchQueue: string[];
|
|
53
|
+
patrolCountdown?: number;
|
|
54
|
+
/** A haven (jackpoint.ts): never hunts, shows no rating, forgets cracks. */
|
|
55
|
+
sanctioned: boolean;
|
|
56
|
+
constructor(over: Room, opts?: {
|
|
57
|
+
rating?: number;
|
|
58
|
+
grid?: Grid;
|
|
59
|
+
sanctioned?: boolean;
|
|
60
|
+
});
|
|
61
|
+
/** The host is named for the place it stands over -- every alias the game prints derives from this. */
|
|
62
|
+
get name(): string;
|
|
63
|
+
/** So a Host can stand in for a Room wherever a reader only asks "is there a host here?". */
|
|
64
|
+
get hasNode(): true;
|
|
65
|
+
/**
|
|
66
|
+
* SR5 p.247: a host's four Matrix attributes are Host Rating, +1, +2, +3
|
|
67
|
+
* in some order. This engine's fixed order: Attack +1, Sleaze +0, Data
|
|
68
|
+
* Processing +3, Firewall +2.
|
|
69
|
+
*/
|
|
70
|
+
attributes(): {
|
|
71
|
+
attack: number;
|
|
72
|
+
sleaze: number;
|
|
73
|
+
dataProcessing: number;
|
|
74
|
+
firewall: number;
|
|
75
|
+
};
|
|
76
|
+
/** The matrix-plane items the host keeps, from the room it stands over (until seeds carry host files). */
|
|
77
|
+
files(): Item[];
|
|
78
|
+
/** The locked doors of the room it stands over -- what a crack releases. */
|
|
79
|
+
maglocks(): Door[];
|
|
80
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A HOST (SR5 p.246-247), as its own object. Increment 1 of the Matrix
|
|
3
|
+
* position model (plan 2026-09-02): the host state that used to live as
|
|
4
|
+
* loose fields on Room moves here, and Room keeps delegating accessors
|
|
5
|
+
* so every existing reader and writer compiles and behaves unchanged.
|
|
6
|
+
*
|
|
7
|
+
* `over` is the physical room the host stands over in this engine: the
|
|
8
|
+
* site systems it masters bind through it -- a crack releases that room's
|
|
9
|
+
* maglocks and unseals the matrix items in its inventory, and the room's
|
|
10
|
+
* cameras answer to it (utilities/surveillance.ts). Canon puts no host at
|
|
11
|
+
* a physical address (p.246, "hosts don't have a physical location"); the
|
|
12
|
+
* anchor is the engine's mapping of "the network that runs this place",
|
|
13
|
+
* not a claim about where the host is.
|
|
14
|
+
*
|
|
15
|
+
* `grid` is optional and unset by default: canon says hosts are reached
|
|
16
|
+
* from any grid and pay to be accessible from all of them (p.246, Data
|
|
17
|
+
* Trails p.15); a seed may declare one, and only then does the cross-grid
|
|
18
|
+
* penalty apply to actions against it (increment 3).
|
|
19
|
+
*
|
|
20
|
+
* What persists: `cracked` only (utilities/persistence.ts). Marks, alert,
|
|
21
|
+
* running IC and the patrol clock are session state by design.
|
|
22
|
+
*/
|
|
23
|
+
export class Host {
|
|
24
|
+
static DEFAULT_RATING = 3;
|
|
25
|
+
static MIN_RATING = 1;
|
|
26
|
+
static MAX_RATING = 12;
|
|
27
|
+
/** SR5 p.247: Host Rating 1-12; anything else is the default. */
|
|
28
|
+
static clampRating(rating) {
|
|
29
|
+
if (typeof rating !== 'number' || !Number.isFinite(rating))
|
|
30
|
+
return Host.DEFAULT_RATING;
|
|
31
|
+
return Math.min(Host.MAX_RATING, Math.max(Host.MIN_RATING, Math.round(rating)));
|
|
32
|
+
}
|
|
33
|
+
over;
|
|
34
|
+
rating;
|
|
35
|
+
grid;
|
|
36
|
+
/** The seed's word for the grid ('public' | 'local' | 'global:<corp>'); resolved against the scene's local grid by the factory. */
|
|
37
|
+
gridSeed;
|
|
38
|
+
/** The one persisted field. A sanctioned host never remembers a crack. */
|
|
39
|
+
cracked = false;
|
|
40
|
+
/** player name -> marks the player holds on this host (max 3, p.236). */
|
|
41
|
+
marksBy = new Map();
|
|
42
|
+
/** player name -> marks the host holds on that player. */
|
|
43
|
+
marksOn = new Map();
|
|
44
|
+
/** Walls up: the host holds a mark on an intruder and its ice is hunting. */
|
|
45
|
+
alert = false;
|
|
46
|
+
/** IC running now, by kind name. Names, not actors -- until increment 5. */
|
|
47
|
+
runningIC = [];
|
|
48
|
+
/** The running IC as actors, by kind (utilities/ic-actors.ts). Empty where no scene could host them. */
|
|
49
|
+
iceActors = new Map();
|
|
50
|
+
/** Kinds crashed this turn; the host relaunches them next turn (p.355-356). */
|
|
51
|
+
relaunchQueue = [];
|
|
52
|
+
patrolCountdown;
|
|
53
|
+
/** A haven (jackpoint.ts): never hunts, shows no rating, forgets cracks. */
|
|
54
|
+
sanctioned = false;
|
|
55
|
+
constructor(over, opts = {}) {
|
|
56
|
+
this.over = over;
|
|
57
|
+
this.rating = Host.clampRating(opts.rating);
|
|
58
|
+
this.grid = opts.grid;
|
|
59
|
+
this.sanctioned = opts.sanctioned ?? false;
|
|
60
|
+
}
|
|
61
|
+
/** The host is named for the place it stands over -- every alias the game prints derives from this. */
|
|
62
|
+
get name() {
|
|
63
|
+
return this.over.name;
|
|
64
|
+
}
|
|
65
|
+
/** So a Host can stand in for a Room wherever a reader only asks "is there a host here?". */
|
|
66
|
+
get hasNode() {
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* SR5 p.247: a host's four Matrix attributes are Host Rating, +1, +2, +3
|
|
71
|
+
* in some order. This engine's fixed order: Attack +1, Sleaze +0, Data
|
|
72
|
+
* Processing +3, Firewall +2.
|
|
73
|
+
*/
|
|
74
|
+
attributes() {
|
|
75
|
+
const hr = this.rating;
|
|
76
|
+
return { attack: hr + 1, sleaze: hr, dataProcessing: hr + 3, firewall: hr + 2 };
|
|
77
|
+
}
|
|
78
|
+
/** The matrix-plane items the host keeps, from the room it stands over (until seeds carry host files). */
|
|
79
|
+
files() {
|
|
80
|
+
return this.over.inventory.getAllItems().filter(i => i.plane === 'matrix');
|
|
81
|
+
}
|
|
82
|
+
/** The locked doors of the room it stands over -- what a crack releases. */
|
|
83
|
+
maglocks() {
|
|
84
|
+
return Array.from(this.over.exits.values())
|
|
85
|
+
.filter((exit) => isDoor(exit) && exit.checkIfLocked());
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
function isDoor(exit) {
|
|
89
|
+
return typeof exit === 'object' && exit !== null && typeof exit.checkIfLocked === 'function';
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=host.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host.js","sourceRoot":"","sources":["../../../../../../../src/commands/game/sideQuest/models/host.ts"],"names":[],"mappings":"AAMA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,OAAO,IAAI;IACf,MAAM,CAAU,cAAc,GAAG,CAAC,CAAC;IACnC,MAAM,CAAU,UAAU,GAAG,CAAC,CAAC;IAC/B,MAAM,CAAU,UAAU,GAAG,EAAE,CAAC;IAEhC,iEAAiE;IACjE,MAAM,CAAC,WAAW,CAAC,MAA0B;QAC3C,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;YAAE,OAAO,IAAI,CAAC,cAAc,CAAC;QACvF,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAClF,CAAC;IAEQ,IAAI,CAAO;IACpB,MAAM,CAAS;IACf,IAAI,CAAQ;IACZ,mIAAmI;IACnI,QAAQ,CAAU;IAClB,0EAA0E;IAC1E,OAAO,GAAG,KAAK,CAAC;IAChB,yEAAyE;IACzE,OAAO,GAAG,IAAI,GAAG,EAAkB,CAAC;IACpC,0DAA0D;IAC1D,OAAO,GAAG,IAAI,GAAG,EAAkB,CAAC;IACpC,6EAA6E;IAC7E,KAAK,GAAG,KAAK,CAAC;IACd,4EAA4E;IAC5E,SAAS,GAAa,EAAE,CAAC;IACzB,wGAAwG;IACxG,SAAS,GAAG,IAAI,GAAG,EAAe,CAAC;IACnC,+EAA+E;IAC/E,aAAa,GAAa,EAAE,CAAC;IAC7B,eAAe,CAAU;IACzB,4EAA4E;IAC5E,UAAU,GAAG,KAAK,CAAC;IAEnB,YAAY,IAAU,EAAE,OAA+D,EAAE;QACvF,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC5C,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QACtB,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,KAAK,CAAC;IAC7C,CAAC;IAED,uGAAuG;IACvG,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;IACxB,CAAC;IAED,6FAA6F;IAC7F,IAAI,OAAO;QACT,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;OAIG;IACH,UAAU;QACR,MAAM,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC;QACvB,OAAO,EAAE,MAAM,EAAE,EAAE,GAAG,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,cAAc,EAAE,EAAE,GAAG,CAAC,EAAE,QAAQ,EAAE,EAAE,GAAG,CAAC,EAAE,CAAC;IAClF,CAAC;IAED,0GAA0G;IAC1G,KAAK;QACH,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC;IAC7E,CAAC;IAED,4EAA4E;IAC5E,QAAQ;QACN,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;aACxC,MAAM,CAAC,CAAC,IAAI,EAAgB,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC,CAAC;IAC1E,CAAC;;AAGH,SAAS,MAAM,CAAC,IAAa;IAC3B,OAAO,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,IAAI,OAAQ,IAAa,CAAC,aAAa,KAAK,UAAU,CAAC;AACzG,CAAC"}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { PlayerEquipment } from '../types/player-equipment.js';
|
|
2
|
+
import type { Grid } from '../utilities/grids.js';
|
|
3
|
+
import type { Host } from './host.js';
|
|
2
4
|
import { type Aspect } from '../aspects.js';
|
|
3
5
|
import { LifestyleChoices } from '../types/seed/lifestyle-seed.js';
|
|
4
6
|
import { Logger } from '../utilities/logger.js';
|
|
@@ -51,6 +53,19 @@ export declare function isPhysicalPlane(plane: Plane): boolean;
|
|
|
51
53
|
* actors out of a Matrix target list; this function answers one question
|
|
52
54
|
* and is not a second plane check.
|
|
53
55
|
*/
|
|
56
|
+
/**
|
|
57
|
+
* A persona's place in the Matrix (SR5 p.239, p.246): out on a grid, or
|
|
58
|
+
* inside a host it entered from one -- and never on a street. See
|
|
59
|
+
* Player.matrixPosition.
|
|
60
|
+
*/
|
|
61
|
+
export type MatrixPosition = {
|
|
62
|
+
kind: 'grid';
|
|
63
|
+
grid?: Grid;
|
|
64
|
+
} | {
|
|
65
|
+
kind: 'host';
|
|
66
|
+
host: Host;
|
|
67
|
+
from?: Grid;
|
|
68
|
+
};
|
|
54
69
|
export declare function sameHostSide(actor: Player, other: Player): boolean;
|
|
55
70
|
export type SimMode = 'cold' | 'hot';
|
|
56
71
|
/**
|
|
@@ -435,7 +450,32 @@ export declare class Player extends AbstractPlayer {
|
|
|
435
450
|
* Session state like hostAlert and linkLockedBy: leaving the Matrix
|
|
436
451
|
* ends it, so nothing here is persisted.
|
|
437
452
|
*/
|
|
438
|
-
|
|
453
|
+
/**
|
|
454
|
+
* WHERE THE PERSONA IS (increment 2 of the Matrix position model): on a
|
|
455
|
+
* grid, or inside a host it entered from one. Session-only, like
|
|
456
|
+
* bodyRoom. The body stays in currentLocation on every plane -- the
|
|
457
|
+
* persona never writes it. The setter fires the live-sheet beat, which
|
|
458
|
+
* is the beat the currentLocation setter used to fire on enter/exit.
|
|
459
|
+
* `grid` may be unknown (fixtures, and increment 2 itself): unknown is
|
|
460
|
+
* not "another grid", so it costs nothing.
|
|
461
|
+
*/
|
|
462
|
+
private _matrixPosition?;
|
|
463
|
+
get matrixPosition(): MatrixPosition | undefined;
|
|
464
|
+
set matrixPosition(v: MatrixPosition | undefined);
|
|
465
|
+
/** The grid the persona rides, when it is on one. */
|
|
466
|
+
get currentGrid(): Grid | undefined;
|
|
467
|
+
/** The host the persona is inside, when it is inside one. */
|
|
468
|
+
get hostInside(): Host | undefined;
|
|
469
|
+
/**
|
|
470
|
+
* @deprecated compat through increment 4 -- read hostInside / write
|
|
471
|
+
* matrixPosition. The room a host stands over, when inside one. The
|
|
472
|
+
* setter still builds the position so every old writer keeps working.
|
|
473
|
+
*/
|
|
474
|
+
private _compatInsideRoom?;
|
|
475
|
+
get insideHost(): Room | undefined;
|
|
476
|
+
set insideHost(room: Room | undefined);
|
|
477
|
+
/** The grid last stood on, so an exit built through the old setter returns there. */
|
|
478
|
+
private get lastGrid();
|
|
439
479
|
/**
|
|
440
480
|
* MATRIX ATTRIBUTES BURNED OFF BY IC (p.248): Acid eats Firewall,
|
|
441
481
|
* Binder eats Data Processing, Jammer eats Attack, Marker eats Sleaze.
|
|
@@ -571,6 +611,10 @@ export declare class Player extends AbstractPlayer {
|
|
|
571
611
|
private static readonly ATTR_EATER;
|
|
572
612
|
private static readonly ATTR_NAME;
|
|
573
613
|
/** The undamaged array, before any IC reduction. */
|
|
614
|
+
/** Set on an IC actor (utilities/ic-actors.ts): "IC uses the Matrix attributes of its host" (p.247). */
|
|
615
|
+
icHost?: Host;
|
|
616
|
+
/** The IC kind an IC actor was launched as -- the name the host's running list carries. */
|
|
617
|
+
icKind?: string;
|
|
574
618
|
baseMatrixAttribute(kind: 'attack' | 'sleaze' | 'dataProcessing' | 'firewall'): number;
|
|
575
619
|
/**
|
|
576
620
|
* THE LIVE LINK -- what makes this runner reachable and lit (p.223,
|
|
@@ -16,40 +16,11 @@ export const STANCE_CYCLE = ['manual', 'guarded', 'aggressive'];
|
|
|
16
16
|
export function isPhysicalPlane(plane) {
|
|
17
17
|
return plane === 'meat' || plane === 'drone';
|
|
18
18
|
}
|
|
19
|
-
/**
|
|
20
|
-
* ARE THESE TWO STANDING ON THE SAME SIDE OF A HOST'S WALL?
|
|
21
|
-
*
|
|
22
|
-
* The companion to fileReach, and it exists for the same reason: the
|
|
23
|
-
* boundary was being asked about in more than one place and the copies
|
|
24
|
-
* disagreed. fileReach settled it for FILES; nothing settled it for
|
|
25
|
-
* ICONS, so `look` honoured insideHost while every verb that picks a
|
|
26
|
-
* target read the room's raw actor list and saw straight through the
|
|
27
|
-
* wall. A technomancer standing inside a host was told "Empty
|
|
28
|
-
* architecture -- turning geometry and nothing in it worth the trip" by
|
|
29
|
-
* one surface and offered those same two IC as spike targets by the
|
|
30
|
-
* next.
|
|
31
|
-
*
|
|
32
|
-
* CANON MAKES THE PANEL BINDING, not the target list. Inside a host you
|
|
33
|
-
* see and interact with the icons inside it and not the ones outside,
|
|
34
|
-
* and from the grid the inside is unreachable (p.246) -- and threading
|
|
35
|
-
* adds its own half of the same rule: "You can only use complex forms
|
|
36
|
-
* on icons you've spotted" (p.251). An icon the room refuses to name is
|
|
37
|
-
* an icon nobody has spotted, so targeting it was never legal.
|
|
38
|
-
*
|
|
39
|
-
* BOTH IN THE SAME ROOM IS THE PRECONDITION, and every caller has it --
|
|
40
|
-
* these are room-scoped target lists. Given that, comparing insideHost
|
|
41
|
-
* directly is the whole rule: both undefined means both are out on the
|
|
42
|
-
* open grid, both equal to the room means both are inside its
|
|
43
|
-
* architecture. There is deliberately no third state.
|
|
44
|
-
*
|
|
45
|
-
* MEAT AND ASTRAL ACTORS PASS TRIVIALLY, which is correct and not an
|
|
46
|
-
* oversight: insideHost is persona state, so a body in the room has
|
|
47
|
-
* none. The plane filters the callers already apply are what keep those
|
|
48
|
-
* actors out of a Matrix target list; this function answers one question
|
|
49
|
-
* and is not a second plane check.
|
|
50
|
-
*/
|
|
51
19
|
export function sameHostSide(actor, other) {
|
|
52
|
-
|
|
20
|
+
// A real Player answers with its Host; a bare fixture ({ insideHost })
|
|
21
|
+
// answers with whatever it carries. Both sides read the same way.
|
|
22
|
+
const sideOf = (p) => p.hostInside ?? p.insideHost;
|
|
23
|
+
return sideOf(actor) === sideOf(other);
|
|
53
24
|
}
|
|
54
25
|
export const SKILL_NAMES = [
|
|
55
26
|
'blades', 'clubs', 'unarmed', 'archery', 'free-fall',
|
|
@@ -426,7 +397,68 @@ export class Player extends AbstractPlayer {
|
|
|
426
397
|
* Session state like hostAlert and linkLockedBy: leaving the Matrix
|
|
427
398
|
* ends it, so nothing here is persisted.
|
|
428
399
|
*/
|
|
429
|
-
|
|
400
|
+
/**
|
|
401
|
+
* WHERE THE PERSONA IS (increment 2 of the Matrix position model): on a
|
|
402
|
+
* grid, or inside a host it entered from one. Session-only, like
|
|
403
|
+
* bodyRoom. The body stays in currentLocation on every plane -- the
|
|
404
|
+
* persona never writes it. The setter fires the live-sheet beat, which
|
|
405
|
+
* is the beat the currentLocation setter used to fire on enter/exit.
|
|
406
|
+
* `grid` may be unknown (fixtures, and increment 2 itself): unknown is
|
|
407
|
+
* not "another grid", so it costs nothing.
|
|
408
|
+
*/
|
|
409
|
+
_matrixPosition;
|
|
410
|
+
get matrixPosition() { return this._matrixPosition; }
|
|
411
|
+
set matrixPosition(v) {
|
|
412
|
+
const same = v === this._matrixPosition
|
|
413
|
+
|| (v !== undefined && this._matrixPosition !== undefined && v.kind === this._matrixPosition.kind
|
|
414
|
+
&& (v.kind === 'host' ? v.host === this._matrixPosition.host
|
|
415
|
+
: v.grid?.key === this._matrixPosition.grid?.key));
|
|
416
|
+
if (same)
|
|
417
|
+
return;
|
|
418
|
+
this._matrixPosition = v;
|
|
419
|
+
this.noteConditionChanged();
|
|
420
|
+
}
|
|
421
|
+
/** The grid the persona rides, when it is on one. */
|
|
422
|
+
get currentGrid() {
|
|
423
|
+
return this._matrixPosition?.kind === 'grid' ? this._matrixPosition.grid : undefined;
|
|
424
|
+
}
|
|
425
|
+
/** The host the persona is inside, when it is inside one. */
|
|
426
|
+
get hostInside() {
|
|
427
|
+
return this._matrixPosition?.kind === 'host' ? this._matrixPosition.host : undefined;
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* @deprecated compat through increment 4 -- read hostInside / write
|
|
431
|
+
* matrixPosition. The room a host stands over, when inside one. The
|
|
432
|
+
* setter still builds the position so every old writer keeps working.
|
|
433
|
+
*/
|
|
434
|
+
_compatInsideRoom;
|
|
435
|
+
get insideHost() { return this.hostInside?.over ?? this._compatInsideRoom; }
|
|
436
|
+
set insideHost(room) {
|
|
437
|
+
if (room) {
|
|
438
|
+
// A room you are inside of IS a host. Fixtures (and older callers)
|
|
439
|
+
// set insideHost on a plain Room; install the Host they meant.
|
|
440
|
+
if (!room.host)
|
|
441
|
+
room.hasNode = true;
|
|
442
|
+
const host = room.host;
|
|
443
|
+
if (!host) {
|
|
444
|
+
// Not a real Room (a fixture stub): remember it so the getter and
|
|
445
|
+
// sameHostSide still answer, without a position to stand on.
|
|
446
|
+
this._compatInsideRoom = room;
|
|
447
|
+
return;
|
|
448
|
+
}
|
|
449
|
+
this._compatInsideRoom = undefined;
|
|
450
|
+
this.matrixPosition = { kind: 'host', host, from: this.currentGrid ?? this.lastGrid };
|
|
451
|
+
}
|
|
452
|
+
else {
|
|
453
|
+
this._compatInsideRoom = undefined;
|
|
454
|
+
if (this._matrixPosition?.kind === 'host')
|
|
455
|
+
this.matrixPosition = { kind: 'grid', grid: this._matrixPosition.from };
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
/** The grid last stood on, so an exit built through the old setter returns there. */
|
|
459
|
+
get lastGrid() {
|
|
460
|
+
return this._matrixPosition?.kind === 'host' ? this._matrixPosition.from : this._matrixPosition?.grid;
|
|
461
|
+
}
|
|
430
462
|
/**
|
|
431
463
|
* MATRIX ATTRIBUTES BURNED OFF BY IC (p.248): Acid eats Firewall,
|
|
432
464
|
* Binder eats Data Processing, Jammer eats Attack, Marker eats Sleaze.
|
|
@@ -647,7 +679,13 @@ export class Player extends AbstractPlayer {
|
|
|
647
679
|
dataProcessing: 'Data Processing', firewall: 'Firewall',
|
|
648
680
|
};
|
|
649
681
|
/** The undamaged array, before any IC reduction. */
|
|
682
|
+
/** Set on an IC actor (utilities/ic-actors.ts): "IC uses the Matrix attributes of its host" (p.247). */
|
|
683
|
+
icHost;
|
|
684
|
+
/** The IC kind an IC actor was launched as -- the name the host's running list carries. */
|
|
685
|
+
icKind;
|
|
650
686
|
baseMatrixAttribute(kind) {
|
|
687
|
+
if (this.icHost)
|
|
688
|
+
return this.icHost.attributes()[kind];
|
|
651
689
|
if (this.isTechnomancer()) {
|
|
652
690
|
switch (kind) {
|
|
653
691
|
case 'attack': return this.charisma;
|
|
@@ -922,7 +960,13 @@ export class Player extends AbstractPlayer {
|
|
|
922
960
|
/** Routes Matrix combat damage into the jacked-in deck's hardware track. */
|
|
923
961
|
takeMatrixDamage(boxes) {
|
|
924
962
|
const deck = this.getAnyCyberdeck();
|
|
925
|
-
|
|
963
|
+
const taken = deck ? deck.takeDeckDamage(boxes) : 0;
|
|
964
|
+
// DECK DAMAGE BEATS (web report 2026-09-02: "the damage to the deck is not moving in realtime"):
|
|
965
|
+
// the Item has no path to its owner, so the owner fires here, and the
|
|
966
|
+
// exchange and rest fire on their own deck writes.
|
|
967
|
+
if (taken > 0)
|
|
968
|
+
this.noteConditionChanged();
|
|
969
|
+
return taken;
|
|
926
970
|
}
|
|
927
971
|
get matrixCrashed() {
|
|
928
972
|
return this.getAnyCyberdeck()?.isBricked ?? false;
|