@maka/maka-cli 5.231.0 → 5.232.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/engine-version.js +38 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/matrix-intrusion.js +52 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/silent-icons.js +36 -15
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@maka/maka-cli",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.232.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"summary": "A command line tool for scaffolding Meteor 3.x applications using either React.",
|
|
6
6
|
"description": "A command line tool for scaffolding Meteor 3.x applications using React.",
|
|
@@ -1418,5 +1418,42 @@
|
|
|
1418
1418
|
// alone would be a fresh canon violation wearing a feature's clothes.
|
|
1419
1419
|
// A technomancer still comes up on the living persona, which is what
|
|
1420
1420
|
// the reporter's point 4 asks for.
|
|
1421
|
-
|
|
1421
|
+
// 1.84.0 (2026-09-16): HIDING IS SLEAZE, NOT FIREWALL
|
|
1422
|
+
// (eJANPpm7qCaCAJBJw, fourth rejection.) The reporter read the
|
|
1423
|
+
// mechanics line and did the arithmetic out loud:
|
|
1424
|
+
// "Device Rating + Firewall on the Camera is 2d6? so, the firewall
|
|
1425
|
+
// of the host is a 1 (1 + 1 = 2 dice)?"
|
|
1426
|
+
// No -- and the question exposed something bigger than the number.
|
|
1427
|
+
// FIREWALL WAS NEVER THE RIGHT ATTRIBUTE. p.235-236 and p.241 both
|
|
1428
|
+
// give the opposed roll as Computer + Intuition [Data Processing] v.
|
|
1429
|
+
// LOGIC + SLEAZE. Firewall resists an INTRUSION (p.238/p.240) and has
|
|
1430
|
+
// nothing to do with being seen. silent-icons.ts had been reusing
|
|
1431
|
+
// deviceDefensePool -- the intrusion pool -- as the hide pool since
|
|
1432
|
+
// 1.80.0, so every hide roll in the game rolled the wrong attribute
|
|
1433
|
+
// and then printed its name on the line the reporter was reading.
|
|
1434
|
+
// The 2d6 was Device Rating twice (1 + 1), not a host Firewall of 1.
|
|
1435
|
+
// - A PLAIN DEVICE HAS NO SLEAZE AT ALL (p.226: "most devices have
|
|
1436
|
+
// only two Matrix attributes: Data Processing and Firewall" --
|
|
1437
|
+
// Attack and Sleaze belong to decks and hosts). So a LOOSE camera
|
|
1438
|
+
// or maglock hides behind one number: its rating standing in for
|
|
1439
|
+
// the Logic it has not got. A p.356 camera with no host rolls a
|
|
1440
|
+
// single die, which is right. A stray lens is not hard to find.
|
|
1441
|
+
// - A SLAVED one borrows, and this is the reporter's ruling on p.233:
|
|
1442
|
+
// "either its own or its master's rating for each rating in the
|
|
1443
|
+
// test ... whichever is higher." Its Sleaze of nothing loses to the
|
|
1444
|
+
// host's, which p.247 gives as a real number off the Host Rating
|
|
1445
|
+
// array. A lens on a HR 3 host now hides behind Rating 3 + Sleaze 3
|
|
1446
|
+
// = 6 dice, and the line says so.
|
|
1447
|
+
// THIS IS WHY 1.80.1 WAS WRONG TO REMOVE THE BORROW. The first cut
|
|
1448
|
+
// handed cameras their master's FIREWALL and produced 16 dice at HR 8
|
|
1449
|
+
// against a sweep capped near 5 -- zero finds in twelve looks -- and
|
|
1450
|
+
// the fix was to cut the host out entirely. The borrow was never the
|
|
1451
|
+
// mistake; the attribute was. With Sleaze it is the same rule that
|
|
1452
|
+
// makes a corporate lens hard and a stray one easy, instead of a
|
|
1453
|
+
// balance knob pretending to be canon.
|
|
1454
|
+
// The icon still prints the LENS's own rating ([DR 1], p.356) while
|
|
1455
|
+
// the roll shows what the network lends it. Those are two different
|
|
1456
|
+
// facts on purpose, and there is a test pinning them apart so nobody
|
|
1457
|
+
// "fixes" one to match the other.
|
|
1458
|
+
export const ENGINE_VERSION = '1.84.0';
|
|
1422
1459
|
//# sourceMappingURL=engine-version.js.map
|
|
@@ -92,6 +92,58 @@ export function parseMarkDeclaration(words) {
|
|
|
92
92
|
export function deviceDefensePool(device) {
|
|
93
93
|
return { label: 'Device Rating + Firewall', pool: Math.max(0, device.rating * 2) };
|
|
94
94
|
}
|
|
95
|
+
/**
|
|
96
|
+
* WHAT A SILENT ICON ROLLS TO STAY HIDDEN -- and it is NOT a Firewall
|
|
97
|
+
* test (eJANPpm7qCaCAJBJw, fourth rejection: "Device Rating + Firewall
|
|
98
|
+
* on the Camera is 2d6? so, the firewall of the host is a 1?").
|
|
99
|
+
*
|
|
100
|
+
* The reporter was reading the label and doing the arithmetic, and the
|
|
101
|
+
* label was naming the wrong attribute. p.235-236 and p.241 both give
|
|
102
|
+
* the opposed roll as Computer + Intuition [Data Processing] v. LOGIC +
|
|
103
|
+
* SLEAZE. Firewall resists an intrusion (p.238/p.240); it has nothing
|
|
104
|
+
* to do with being seen. silent-icons.ts was reusing deviceDefensePool
|
|
105
|
+
* -- the intrusion pool -- for the hiding roll, so every hide test in
|
|
106
|
+
* the game rolled the wrong attribute and printed its name.
|
|
107
|
+
*
|
|
108
|
+
* AND A PLAIN DEVICE HAS NO SLEAZE AT ALL. p.226: "most devices have
|
|
109
|
+
* only two Matrix attributes: Data Processing and Firewall" -- Attack
|
|
110
|
+
* and Sleaze belong to decks and hosts. So a loose camera or maglock
|
|
111
|
+
* hides behind its Device Rating standing in for the Logic it has not
|
|
112
|
+
* got, and nothing more. One die for a p.356 camera, which is correct:
|
|
113
|
+
* a lens with no host behind it is not a hard thing to find.
|
|
114
|
+
*/
|
|
115
|
+
export function deviceHidePool(device) {
|
|
116
|
+
return { label: 'Device Rating for Logic; p.226 gives it no Sleaze', pool: Math.max(0, device.rating) };
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* A SLAVED icon hiding, which is where the dice actually come from
|
|
120
|
+
* (reporter's ruling 2026-09-16, on p.233): "whenever a slaved device is
|
|
121
|
+
* called on to make a defense test, it uses either its own or its
|
|
122
|
+
* master's rating for each rating in the test ... whichever is higher in
|
|
123
|
+
* each instance." Resisting a sweep IS the slave defending, so it
|
|
124
|
+
* borrows per rating: its own Rating against the host's Rating, and its
|
|
125
|
+
* own Sleaze -- which p.226 says is nothing -- against the host's, which
|
|
126
|
+
* p.247 gives as a real number off the Host Rating array.
|
|
127
|
+
*
|
|
128
|
+
* That is what makes a corporate lens hard to find and a loose one easy,
|
|
129
|
+
* out of one rule rather than a balance knob. 1.80.1 removed the host's
|
|
130
|
+
* contribution entirely because the first version borrowed the host's
|
|
131
|
+
* FIREWALL and produced 16 dice against a sweep capped near 5 (zero
|
|
132
|
+
* finds in twelve looks). The borrow was never the mistake; the
|
|
133
|
+
* attribute was.
|
|
134
|
+
*
|
|
135
|
+
* Only from the grid: inside the host you are directly connected and a
|
|
136
|
+
* slave "cannot use its master's ratings" (p.233), which is
|
|
137
|
+
* deviceHidePool.
|
|
138
|
+
*/
|
|
139
|
+
export function wanHidePool(device, host) {
|
|
140
|
+
const rating = Math.max(device.rating, host.rating);
|
|
141
|
+
// The device's own Sleaze is 0 (p.226), so the master's always wins
|
|
142
|
+
// this half -- written as a max anyway, because the rule is per
|
|
143
|
+
// rating and a future device WITH a Sleaze must not lose it.
|
|
144
|
+
const sleaze = Math.max(0, host.attributes().sleaze);
|
|
145
|
+
return { label: "Rating + Sleaze, the master's where higher, p.233", pool: Math.max(0, rating + sleaze) };
|
|
146
|
+
}
|
|
95
147
|
/**
|
|
96
148
|
* A SLAVE ATTACKED THROUGH ITS MASTER (SR5 p.233, PANs and WANs):
|
|
97
149
|
* "Whenever a slaved device is called on to make a defense test, it
|
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
import { rollPool, formatRoll } from './dice.js';
|
|
2
|
-
import {
|
|
3
|
-
import { isWatched } from './surveillance.js';
|
|
4
|
-
function hiddenDevice(device) {
|
|
2
|
+
import { deviceHidePool, wanHidePool } from './matrix-intrusion.js';
|
|
3
|
+
import { isWatched, cameraMasterHost } from './surveillance.js';
|
|
4
|
+
function hiddenDevice(device, master) {
|
|
5
|
+
// p.235-236: the hider rolls LOGIC + SLEAZE. Not Firewall -- that
|
|
6
|
+
// resists an intrusion (p.238/p.240) and has nothing to do with being
|
|
7
|
+
// seen. This used to call deviceDefensePool, the INTRUSION pool, so
|
|
8
|
+
// the hide test rolled the wrong attribute and then printed its name
|
|
9
|
+
// (eJANPpm7qCaCAJBJw: "Device Rating + Firewall on the Camera is 2d6?
|
|
10
|
+
// so, the firewall of the host is a 1?").
|
|
11
|
+
const hide = master ? wanHidePool(device, master) : deviceHidePool(device);
|
|
5
12
|
return {
|
|
6
13
|
name: device.name,
|
|
7
|
-
|
|
8
|
-
// (p.237-238) -- the same pool it defends an intrusion with.
|
|
9
|
-
hide: { pool: deviceDefensePool(device).pool, label: 'Device Rating (no Logic to hide behind)' },
|
|
14
|
+
hide: { pool: hide.pool, label: hide.label },
|
|
10
15
|
reveal: (viewer) => { device.spottedBy.add(viewer); },
|
|
11
16
|
};
|
|
12
17
|
}
|
|
@@ -28,20 +33,22 @@ function hiddenPersona(actor) {
|
|
|
28
33
|
* body does.
|
|
29
34
|
*/
|
|
30
35
|
export function hiddenIconsIn(scene, room, viewer) {
|
|
36
|
+
// A device in a room with a host is slaved to it (p.233), and from
|
|
37
|
+
// the grid it borrows the master's ratings. Inside the host you are
|
|
38
|
+
// directly connected and it stands alone -- deviceHidePool.
|
|
39
|
+
const deviceMaster = viewer.hostInside ? undefined : room.host;
|
|
31
40
|
const out = room.devices
|
|
32
41
|
.filter(d => d.isHiddenFrom(viewer.name))
|
|
33
|
-
.map(hiddenDevice);
|
|
42
|
+
.map(d => hiddenDevice(d, deviceMaster));
|
|
34
43
|
// THE CAMERAS, which p.217 names FIRST. They are not a Device -- the
|
|
35
44
|
// cluster is derived from the room (surveillance.ts isWatched) -- so
|
|
36
45
|
// the rating rides the ROOM (Room.cameraRating), seeded per site.
|
|
37
46
|
//
|
|
38
|
-
// THE FIRST CUT GAVE THEM THEIR MASTER HOST'S
|
|
39
|
-
//
|
|
40
|
-
//
|
|
41
|
-
//
|
|
42
|
-
//
|
|
43
|
-
// on any corporate host was not hard to find, it was impossible --
|
|
44
|
-
// measured at zero finds in twelve looks.
|
|
47
|
+
// THE FIRST CUT GAVE THEM THEIR MASTER HOST'S FIREWALL, and the
|
|
48
|
+
// borrow was right while the attribute was wrong -- which took three
|
|
49
|
+
// versions to see. A rating-8 host gave its lenses 16 dice against a
|
|
50
|
+
// sweep the Data Processing limit caps near 5: not hard to find,
|
|
51
|
+
// impossible, measured at zero finds in twelve looks.
|
|
45
52
|
//
|
|
46
53
|
// THE SECOND CUT hard-coded a 4 in here, which fixed the arithmetic
|
|
47
54
|
// and left the engine holding THREE answers to one question: this
|
|
@@ -51,9 +58,23 @@ export function hiddenIconsIn(scene, room, viewer) {
|
|
|
51
58
|
// printed. One seeded number feeds all three now, so what the player
|
|
52
59
|
// reads is what it rolls (reporter's ruling: per-site, not global).
|
|
53
60
|
if (isWatched(room) && !room.camerasSpottedBy.has(viewer.name)) {
|
|
61
|
+
// THE THIRD CUT, and the reporter found it by doing the arithmetic
|
|
62
|
+
// out loud: "Device Rating + Firewall on the Camera is 2d6? so, the
|
|
63
|
+
// firewall of the host is a 1?" No -- Firewall was never the right
|
|
64
|
+
// attribute. p.235-236 hides behind Logic + Sleaze, p.226 gives a
|
|
65
|
+
// plain device no Sleaze at all, and p.233 lets a slave borrow its
|
|
66
|
+
// master's rating for each rating in the test. So a lens on a host
|
|
67
|
+
// hides behind the HOST's Rating and Sleaze, and a loose one behind
|
|
68
|
+
// its own single die. That is why a corporate camera is hard and a
|
|
69
|
+
// stray one is easy -- one rule, not a balance knob (reporter's
|
|
70
|
+
// ruling 2026-09-16).
|
|
71
|
+
const masterRoom = scene ? cameraMasterHost(scene.getRooms(), room) : undefined;
|
|
72
|
+
const master = viewer.hostInside ? undefined : masterRoom?.host;
|
|
73
|
+
const lens = { rating: room.cameraRating };
|
|
74
|
+
const hide = master ? wanHidePool(lens, master) : deviceHidePool(lens);
|
|
54
75
|
out.push({
|
|
55
76
|
name: 'Camera cluster',
|
|
56
|
-
hide: { pool:
|
|
77
|
+
hide: { pool: hide.pool, label: hide.label },
|
|
57
78
|
reveal: (v) => { room.camerasSpottedBy.add(v); },
|
|
58
79
|
});
|
|
59
80
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@maka/maka-cli",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.232.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"summary": "A command line tool for scaffolding Meteor 3.x applications using either React.",
|
|
6
6
|
"description": "A command line tool for scaffolding Meteor 3.x applications using React.",
|