@maka/maka-cli 5.233.0 → 5.235.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 +51 -1
- package/bundle/typescript/src/commands/game/sideQuest/models/player.js +31 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/planes.js +13 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/silent-icons.js +41 -4
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@maka/maka-cli",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.235.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.",
|
|
@@ -1455,5 +1455,55 @@
|
|
|
1455
1455
|
// the roll shows what the network lends it. Those are two different
|
|
1456
1456
|
// facts on purpose, and there is a test pinning them apart so nobody
|
|
1457
1457
|
// "fixes" one to match the other.
|
|
1458
|
-
|
|
1458
|
+
// 1.85.0 (2026-09-16): SPAMMING `look` COSTS SOMETHING NOW (p.49)
|
|
1459
|
+
// Asked directly, and it was the right question: "what is the penalty
|
|
1460
|
+
// of just spamming 'look' to eventually get the details?"
|
|
1461
|
+
// THE ANSWER WAS NONE. `look` on the grid is billed as the Complex
|
|
1462
|
+
// Action it is (p.241) -- but billAction only charges inside an
|
|
1463
|
+
// encounter, so out of combat a sweep cost nothing at all. A decker
|
|
1464
|
+
// could stand in the dark typing `look` until the dice came up, which
|
|
1465
|
+
// means every hidden icon in the game was on a TIMER rather than
|
|
1466
|
+
// behind a test, and the whole of 1.80-1.84 was theatre for anyone
|
|
1467
|
+
// willing to press a key four times. My own find-rate measurements
|
|
1468
|
+
// said "found within 1-2 looks" and I read that as the mechanic
|
|
1469
|
+
// working rather than as the mechanic being free.
|
|
1470
|
+
// - TRYING AGAIN (p.49): "each attempt after the first takes a
|
|
1471
|
+
// cumulative -2 dice pool penalty." Counted per room on
|
|
1472
|
+
// Player.sweepAttempts, and only FAILED sweeps count -- pinning
|
|
1473
|
+
// what you contested is not a retry. A 7-dice sweeper gets 7, 5, 3,
|
|
1474
|
+
// 1, then nothing.
|
|
1475
|
+
// - AND IT REACHES ZERO. The base pool floors at 1 so wounds and
|
|
1476
|
+
// noise never lock you out, but the retry penalty is allowed
|
|
1477
|
+
// through that floor, because that is the part that has to stop the
|
|
1478
|
+
// grind: a pool of nothing cannot be rolled. The line says so
|
|
1479
|
+
// rather than printing a mystery 0d6.
|
|
1480
|
+
// - THE BREAK is the one piece p.49 hands to the table ("left to
|
|
1481
|
+
// gamemaster discretion"), so it was asked rather than guessed.
|
|
1482
|
+
// Ruling: JACKING OUT, and nothing less -- not moving node, not
|
|
1483
|
+
// spending a turn on something else. So clearing a stack of failed
|
|
1484
|
+
// sweeps costs your position, your part-made marks and a fresh
|
|
1485
|
+
// entry.
|
|
1486
|
+
// - NO OVERWATCH COST, deliberately. OS rises on Attack and Sleaze
|
|
1487
|
+
// actions (p.231-232) and Matrix Perception is neither. Charging
|
|
1488
|
+
// one would be inventing a rule to fix a balance problem canon
|
|
1489
|
+
// already fixes.
|
|
1490
|
+
// Nothing here is new to this engine: clue-reading has used p.49 and
|
|
1491
|
+
// the same -2 since 1.40. It had simply never been pointed at the one
|
|
1492
|
+
// test a player can repeat by holding down a key.
|
|
1493
|
+
// 1.85.1 (2026-09-16): THE GRID WAS ANNOUNCED BUT NEVER CHARGED
|
|
1494
|
+
// Asked while reading a sweep transcript: "is the grid type being
|
|
1495
|
+
// applied?" The banner says it plainly --
|
|
1496
|
+
// "Riding the public grid (-2 on everything you do, p.233)"
|
|
1497
|
+
// -- and the sweep was not paying it. Player.matrixActionPenalty is
|
|
1498
|
+
// ONLY the running-silent -2; the grid modifier is a separate helper
|
|
1499
|
+
// (grids.ts gridActionModifier) that every other Matrix verb calls
|
|
1500
|
+
// and spotHiddenIcons never did. So the -2 was printed on screen and
|
|
1501
|
+
// then left out of the one roll the player was watching, which is the
|
|
1502
|
+
// same class of defect as the Firewall label a version ago: the text
|
|
1503
|
+
// made a claim the dice did not honour.
|
|
1504
|
+
// The sweep now takes it, and the mechanics line shows '[public grid
|
|
1505
|
+
// -2]' where it applied. Inside a host it is correctly nothing -- a
|
|
1506
|
+
// host's interior is not on a grid -- and it stacks with p.49's retry
|
|
1507
|
+
// penalty, so a public-grid decker gets 5, 3, 1, none.
|
|
1508
|
+
export const ENGINE_VERSION = '1.85.1';
|
|
1459
1509
|
//# sourceMappingURL=engine-version.js.map
|
|
@@ -717,6 +717,37 @@ export class Player extends AbstractPlayer {
|
|
|
717
717
|
* (-2 per retry). In memory only: a save and reload is the "break"
|
|
718
718
|
* the rule says clears it. See utilities/clue-reading.ts. */
|
|
719
719
|
readAttempts = new Map();
|
|
720
|
+
/**
|
|
721
|
+
* FAILED MATRIX PERCEPTION SWEEPS, by room name -- p.49's Trying Again
|
|
722
|
+
* pointed at the one test a player can repeat for free.
|
|
723
|
+
*
|
|
724
|
+
* Asked directly (2026-09-16): "what is the penalty of just spamming
|
|
725
|
+
* 'look' to eventually get the details?" The answer was NONE. `look`
|
|
726
|
+
* is billed as the Complex Action it is (p.241), but billAction only
|
|
727
|
+
* charges inside an encounter, so out of combat a sweep cost nothing
|
|
728
|
+
* at all and a decker could stand in the dark typing `look` until the
|
|
729
|
+
* dice came up. Every hidden icon in the game was on a timer rather
|
|
730
|
+
* than behind a test.
|
|
731
|
+
*
|
|
732
|
+
* p.49: "you can try again, but each attempt after the first takes a
|
|
733
|
+
* cumulative -2 dice pool penalty ... a sufficient break lets you
|
|
734
|
+
* begin again with no penalty." Not invented here and not new to this
|
|
735
|
+
* engine either -- clue-reading has used the same rule and the same
|
|
736
|
+
* citation since 1.40. A sweeper at 7 dice gets 7, 5, 3, 1: four looks
|
|
737
|
+
* and brute force is spent, which is the point.
|
|
738
|
+
*
|
|
739
|
+
* NO OVERWATCH COST, deliberately. OS rises on Attack and Sleaze
|
|
740
|
+
* actions (p.231-232) and Matrix Perception is neither, so charging
|
|
741
|
+
* one would be inventing a rule to solve a balance problem that canon
|
|
742
|
+
* already solves.
|
|
743
|
+
*
|
|
744
|
+
* WHAT COUNTS AS THE BREAK is the one part p.49 hands to the table
|
|
745
|
+
* ("left to gamemaster discretion"), so it was asked and ruled on
|
|
746
|
+
* rather than guessed: JACKING OUT, and nothing less (user ruling
|
|
747
|
+
* 2026-09-16). Not moving node, not spending a turn elsewhere. See
|
|
748
|
+
* planes.ts leaveMatrix, which is the only thing that clears this.
|
|
749
|
+
*/
|
|
750
|
+
sweepAttempts = new Map();
|
|
720
751
|
/** True for the one Electronics item that is a trode net (p.439-440). */
|
|
721
752
|
static isTrodeNet(item) {
|
|
722
753
|
// The item's OWN row, not Item.effects: that getter folds fitted
|
|
@@ -222,6 +222,19 @@ export function leaveMatrix(scene, actor, opts) {
|
|
|
222
222
|
// bricked, Scramble, convergence -- is no longer a participant. Before
|
|
223
223
|
// endPersona clears the position the arena is read off.
|
|
224
224
|
scene.encounterFor?.(actor)?.leave(actor);
|
|
225
|
+
// THE BREAK p.49 DESCRIBES, and the book hands this one to the table:
|
|
226
|
+
// "if the character takes a sufficient break from the task -- the
|
|
227
|
+
// length of which is left to gamemaster discretion." Asked directly
|
|
228
|
+
// (user ruling 2026-09-16, "what is a break?"), and the answer was the
|
|
229
|
+
// strictest of the four on offer: NOTHING SHORT OF JACKING OUT.
|
|
230
|
+
//
|
|
231
|
+
// Not moving to another node, not spending a turn on something else.
|
|
232
|
+
// So a stack of failed sweeps costs you your position on the grid,
|
|
233
|
+
// whatever marks you were part-way through, and a fresh entry -- which
|
|
234
|
+
// makes a dark room genuinely expensive rather than a typing exercise.
|
|
235
|
+
// Optional-chained because leaveMatrix is reached from a dozen places
|
|
236
|
+
// with stub actors that are not full Players.
|
|
237
|
+
actor.sweepAttempts?.clear();
|
|
225
238
|
if (opts?.forced) {
|
|
226
239
|
lines.push(...applyDumpshock(actor, opts.reason ?? `The connection is severed from the other side.`));
|
|
227
240
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { rollPool, formatRoll } from './dice.js';
|
|
2
2
|
import { deviceHidePool, wanHidePool } from './matrix-intrusion.js';
|
|
3
3
|
import { isWatched, cameraMasterHost } from './surveillance.js';
|
|
4
|
+
import { gridActionModifier, gridNote } from './grids.js';
|
|
4
5
|
function hiddenDevice(device, master) {
|
|
5
6
|
// p.235-236: the hider rolls LOGIC + SLEAZE. Not Firewall -- that
|
|
6
7
|
// resists an intrusion (p.238/p.240) and has nothing to do with being
|
|
@@ -116,8 +117,30 @@ export function spotHiddenIcons(scene, actor, room) {
|
|
|
116
117
|
// sweeper's own silence, wounds and sustaining the way every other
|
|
117
118
|
// Matrix action in this engine does.
|
|
118
119
|
const computer = actor.skillRating('computer');
|
|
119
|
-
|
|
120
|
-
|
|
120
|
+
// TRYING AGAIN (p.49): "each attempt after the first takes a
|
|
121
|
+
// cumulative -2 dice pool penalty." Without it, spamming `look` was
|
|
122
|
+
// free outside a fight -- billAction charges a Complex Action only
|
|
123
|
+
// inside an encounter -- so every hidden icon was on a timer instead
|
|
124
|
+
// of behind a test. Counted per room and cleared by a break
|
|
125
|
+
// (Player.sweepAttempts).
|
|
126
|
+
const retries = actor.sweepAttempts.get(room.name) ?? 0;
|
|
127
|
+
// The base floors at 1 -- wounds and noise grind you down but never
|
|
128
|
+
// out. The RETRY penalty is allowed through that floor to zero,
|
|
129
|
+
// because that is what stops the grind: a pool reduced to nothing
|
|
130
|
+
// cannot be rolled, so after enough failures you are not looking
|
|
131
|
+
// harder, you are done looking until you take the break p.49 names.
|
|
132
|
+
// THE GRID YOU ARE RIDING (p.233), which the banner has been promising
|
|
133
|
+
// and the dice were not paying: "Riding the public grid (-2 on
|
|
134
|
+
// everything you do)". matrixActionPenalty is ONLY the running-silent
|
|
135
|
+
// -2 -- the grid modifier is a separate helper that every other Matrix
|
|
136
|
+
// verb calls and this sweep never did, so the public grid's -2 was
|
|
137
|
+
// announced on screen and then quietly left out of the one roll the
|
|
138
|
+
// player was watching. Inside a host it is correctly nothing: a host's
|
|
139
|
+
// interior is not on a grid.
|
|
140
|
+
const grid = gridActionModifier(actor.currentGrid, !!actor.hostInside, actor.currentGrid);
|
|
141
|
+
const base = Math.max(1, actor.intuition + (computer > 0 ? computer : -1)
|
|
142
|
+
+ actor.matrixActionPenalty + grid.total + actor.woundModifier - actor.sustainingPenalty);
|
|
143
|
+
const pool = Math.max(0, base - 2 * retries);
|
|
121
144
|
const roll = rollPool(pool, actor.matrixAttribute('dataProcessing'), { gremlins: actor.deckGremlins });
|
|
122
145
|
const found = [];
|
|
123
146
|
let missed = 0;
|
|
@@ -139,7 +162,14 @@ export function spotHiddenIcons(scene, actor, room) {
|
|
|
139
162
|
against.push({ roll: resist });
|
|
140
163
|
}
|
|
141
164
|
}
|
|
142
|
-
|
|
165
|
+
// p.49 counts FAILED attempts. A sweep that pinned everything it
|
|
166
|
+
// contested was not a failure, so it costs the next one nothing --
|
|
167
|
+
// and an icon you already found is not in `hidden` to be re-rolled.
|
|
168
|
+
if (missed > 0)
|
|
169
|
+
actor.sweepAttempts.set(room.name, retries + 1);
|
|
170
|
+
else
|
|
171
|
+
actor.sweepAttempts.delete(room.name);
|
|
172
|
+
return { found, missed, roll, retries, grid: gridNote(grid), against };
|
|
143
173
|
}
|
|
144
174
|
/**
|
|
145
175
|
* The mechanics lines for a sweep.
|
|
@@ -153,8 +183,15 @@ export function spotHiddenIcons(scene, actor, room) {
|
|
|
153
183
|
* Perception HIT buys).
|
|
154
184
|
*/
|
|
155
185
|
export function spotMechanics(outcome) {
|
|
186
|
+
// Said out loud, because a pool that quietly shrinks every time you
|
|
187
|
+
// type the same word reads as a bug rather than as p.49.
|
|
188
|
+
const again = outcome.roll.pool === 0
|
|
189
|
+
? ` -- NO DICE LEFT (p.49: -${outcome.retries * 2} for ${outcome.retries} failed attempts). Staring harder will not do it; break off and come back.`
|
|
190
|
+
: outcome.retries > 0
|
|
191
|
+
? ` -- trying again, -${outcome.retries * 2} (p.49: -2 per failed attempt; a break clears it)`
|
|
192
|
+
: '';
|
|
156
193
|
return [
|
|
157
|
-
`Matrix Perception, silent icons (Computer + Intuition [Data Processing]): ${formatRoll(outcome.roll)}`,
|
|
194
|
+
`Matrix Perception, silent icons (Computer + Intuition [Data Processing]): ${formatRoll(outcome.roll)}${outcome.grid}${again}`,
|
|
158
195
|
...outcome.against.map(a => (a.name
|
|
159
196
|
? ` ${a.name} hides (${a.label}): ${formatRoll(a.roll)}`
|
|
160
197
|
: ` something holds its cover: ${formatRoll(a.roll)}`)),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@maka/maka-cli",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.235.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.",
|