@maka/maka-cli 5.232.0 → 5.234.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/pan.js +11 -3
- package/bundle/typescript/src/commands/game/sideQuest/engine-version.js +36 -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 +30 -3
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@maka/maka-cli",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.234.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.",
|
|
@@ -87,10 +87,18 @@ export class PanCommand extends Command {
|
|
|
87
87
|
return bill;
|
|
88
88
|
item.wirelessOn = on;
|
|
89
89
|
if (!on) {
|
|
90
|
-
|
|
90
|
+
const lines = [
|
|
91
91
|
`${item.name} drops off the network -- wireless OFF.`,
|
|
92
|
-
`It broadcasts nothing now: no bonus, no icon, nothing to hack
|
|
93
|
-
]
|
|
92
|
+
`It broadcasts nothing now: no bonus, no icon, nothing to hack.`,
|
|
93
|
+
];
|
|
94
|
+
// The borrowing line is only true of a SLAVE. Said of the master
|
|
95
|
+
// itself -- the commlink the whole PAN hangs off -- it was simply
|
|
96
|
+
// false, and switching your only link off is exactly when a player
|
|
97
|
+
// is reading carefully.
|
|
98
|
+
lines.push(a.getPanMaster()
|
|
99
|
+
? `It also stops borrowing the master's ratings to defend itself (p.233), which is only a loss if anyone was looking.`
|
|
100
|
+
: `That was the master, so there is no PAN left at all -- nothing of yours is on the Matrix now.`);
|
|
101
|
+
return lines.join('\n');
|
|
94
102
|
}
|
|
95
103
|
const over = a.panOverflow();
|
|
96
104
|
const lines = [`${item.name} joins the network -- wireless ON.`];
|
|
@@ -1455,5 +1455,40 @@
|
|
|
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
|
+
export const ENGINE_VERSION = '1.85.0';
|
|
1459
1494
|
//# 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
|
}
|
|
@@ -116,8 +116,21 @@ export function spotHiddenIcons(scene, actor, room) {
|
|
|
116
116
|
// sweeper's own silence, wounds and sustaining the way every other
|
|
117
117
|
// Matrix action in this engine does.
|
|
118
118
|
const computer = actor.skillRating('computer');
|
|
119
|
-
|
|
119
|
+
// TRYING AGAIN (p.49): "each attempt after the first takes a
|
|
120
|
+
// cumulative -2 dice pool penalty." Without it, spamming `look` was
|
|
121
|
+
// free outside a fight -- billAction charges a Complex Action only
|
|
122
|
+
// inside an encounter -- so every hidden icon was on a timer instead
|
|
123
|
+
// of behind a test. Counted per room and cleared by a break
|
|
124
|
+
// (Player.sweepAttempts).
|
|
125
|
+
const retries = actor.sweepAttempts.get(room.name) ?? 0;
|
|
126
|
+
// The base floors at 1 -- wounds and noise grind you down but never
|
|
127
|
+
// out. The RETRY penalty is allowed through that floor to zero,
|
|
128
|
+
// because that is what stops the grind: a pool reduced to nothing
|
|
129
|
+
// cannot be rolled, so after enough failures you are not looking
|
|
130
|
+
// harder, you are done looking until you take the break p.49 names.
|
|
131
|
+
const base = Math.max(1, actor.intuition + (computer > 0 ? computer : -1)
|
|
120
132
|
+ actor.matrixActionPenalty + actor.woundModifier - actor.sustainingPenalty);
|
|
133
|
+
const pool = Math.max(0, base - 2 * retries);
|
|
121
134
|
const roll = rollPool(pool, actor.matrixAttribute('dataProcessing'), { gremlins: actor.deckGremlins });
|
|
122
135
|
const found = [];
|
|
123
136
|
let missed = 0;
|
|
@@ -139,7 +152,14 @@ export function spotHiddenIcons(scene, actor, room) {
|
|
|
139
152
|
against.push({ roll: resist });
|
|
140
153
|
}
|
|
141
154
|
}
|
|
142
|
-
|
|
155
|
+
// p.49 counts FAILED attempts. A sweep that pinned everything it
|
|
156
|
+
// contested was not a failure, so it costs the next one nothing --
|
|
157
|
+
// and an icon you already found is not in `hidden` to be re-rolled.
|
|
158
|
+
if (missed > 0)
|
|
159
|
+
actor.sweepAttempts.set(room.name, retries + 1);
|
|
160
|
+
else
|
|
161
|
+
actor.sweepAttempts.delete(room.name);
|
|
162
|
+
return { found, missed, roll, retries, against };
|
|
143
163
|
}
|
|
144
164
|
/**
|
|
145
165
|
* The mechanics lines for a sweep.
|
|
@@ -153,8 +173,15 @@ export function spotHiddenIcons(scene, actor, room) {
|
|
|
153
173
|
* Perception HIT buys).
|
|
154
174
|
*/
|
|
155
175
|
export function spotMechanics(outcome) {
|
|
176
|
+
// Said out loud, because a pool that quietly shrinks every time you
|
|
177
|
+
// type the same word reads as a bug rather than as p.49.
|
|
178
|
+
const again = outcome.roll.pool === 0
|
|
179
|
+
? ` -- NO DICE LEFT (p.49: -${outcome.retries * 2} for ${outcome.retries} failed attempts). Staring harder will not do it; break off and come back.`
|
|
180
|
+
: outcome.retries > 0
|
|
181
|
+
? ` -- trying again, -${outcome.retries * 2} (p.49: -2 per failed attempt; a break clears it)`
|
|
182
|
+
: '';
|
|
156
183
|
return [
|
|
157
|
-
`Matrix Perception, silent icons (Computer + Intuition [Data Processing]): ${formatRoll(outcome.roll)}`,
|
|
184
|
+
`Matrix Perception, silent icons (Computer + Intuition [Data Processing]): ${formatRoll(outcome.roll)}${again}`,
|
|
158
185
|
...outcome.against.map(a => (a.name
|
|
159
186
|
? ` ${a.name} hides (${a.label}): ${formatRoll(a.roll)}`
|
|
160
187
|
: ` 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.234.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.",
|