@maka/maka-cli 5.379.1 → 5.380.1
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/call.js +50 -23
- package/bundle/typescript/src/commands/game/sideQuest/commands/jobs.js +12 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/journal.js +5 -3
- package/bundle/typescript/src/commands/game/sideQuest/commands/pan.js +73 -38
- package/bundle/typescript/src/commands/game/sideQuest/engine-version.js +24 -1
- package/bundle/typescript/src/commands/game/sideQuest/game.js +34 -5
- package/bundle/typescript/src/commands/game/sideQuest/utilities/condition-report.js +13 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/pan-status.js +147 -0
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@maka/maka-cli",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.380.1",
|
|
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.",
|
|
@@ -233,30 +233,43 @@ export class CallCommand extends Command {
|
|
|
233
233
|
// runner unable to travel with the arc still pointing at it. The
|
|
234
234
|
// cab takes them home and the homecoming settles it as failed.
|
|
235
235
|
const jobDead = this.scene.jobDead;
|
|
236
|
+
// The wire, when this cab already crossed it (errand branch below)
|
|
237
|
+
// -- carried into the homecoming's text, whose own checkpoint
|
|
238
|
+
// then finds the heat spent.
|
|
239
|
+
let wireLine = '';
|
|
240
|
+
let busted = false;
|
|
236
241
|
if (!wrapped && !this.game.walkOutArmed && !jobDead) {
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
242
|
+
// THE ERRAND CAB IS A RIDE HOME TOO (5Qi7jZsRnz6BwKY5C: "this
|
|
243
|
+
// is contradictory" -- the cab took them home while the HUD
|
|
244
|
+
// still said "they'll be waiting at the checkpoint"). The heat
|
|
245
|
+
// band promises the wire between the site and home; this leg
|
|
246
|
+
// crosses it exactly as the homecoming's does, and settles the
|
|
247
|
+
// heat the same way.
|
|
248
|
+
//
|
|
249
|
+
// ROLLED BEFORE THE ERRAND, not after (aPwBWKPfrbioj2keC: "too
|
|
250
|
+
// much heat" is a FAILED job, user ruling 2026-10-04). A runner
|
|
251
|
+
// in zip ties is not coming back for it, so a bust takes the
|
|
252
|
+
// homecoming road below -- which ends the job -- instead of
|
|
253
|
+
// leaving it standing.
|
|
254
|
+
const checkpoint = this.game.checkpointOnRideHome();
|
|
255
|
+
if (checkpoint)
|
|
256
|
+
this.game.requestSave('venue-bust');
|
|
257
|
+
busted = this.game.rideHomeBusted;
|
|
258
|
+
wireLine = checkpoint;
|
|
259
|
+
const errand = busted ? undefined : this.game.leaveRunForErrand();
|
|
245
260
|
if (errand !== undefined) {
|
|
261
|
+
const FARE_OUT = 80;
|
|
262
|
+
const paidOut = Math.min(this.actor.currency, FARE_OUT);
|
|
263
|
+
const owedOut = FARE_OUT - paidOut;
|
|
264
|
+
if (paidOut > 0)
|
|
265
|
+
this.actor.adjustCurrency(-paidOut, 'cab home, job left standing');
|
|
266
|
+
if (owedOut > 0)
|
|
267
|
+
this.game.rentDebt += owedOut;
|
|
246
268
|
this.game?.wipeConsoleFor(this.actor);
|
|
247
269
|
this.actor.performAction('calls a taxi', 'to run an errand, leaving the job open');
|
|
248
270
|
const meter = owedOut === 0
|
|
249
271
|
? `The meter takes its ${FARE_OUT}.`
|
|
250
272
|
: `The meter takes what you have; ${owedOut} goes on the tab.`;
|
|
251
|
-
// THE ERRAND CAB IS A RIDE HOME TOO (5Qi7jZsRnz6BwKY5C: "this
|
|
252
|
-
// is contradictory" -- the cab took them home while the HUD
|
|
253
|
-
// still said "they'll be waiting at the checkpoint"). The heat
|
|
254
|
-
// band promises the wire between the site and home; this leg
|
|
255
|
-
// crosses it exactly as the homecoming's does, and settles the
|
|
256
|
-
// heat the same way.
|
|
257
|
-
const checkpoint = this.game.checkpointOnRideHome();
|
|
258
|
-
if (checkpoint)
|
|
259
|
-
this.game.requestSave('venue-bust');
|
|
260
273
|
return `A cab noses out of the dark. "Back to the pad, chummer?" ${meter}\n`
|
|
261
274
|
+ `The job stays where you left it -- nobody has called it off.${errand ? `\n${errand}` : ''}${checkpoint ? `\n${checkpoint}` : ''}\n`
|
|
262
275
|
+ hint(`("call taxi" again takes you back to it. To WALK OUT for good -- forfeiting the pay and taking the Notoriety -- "abandon".)`);
|
|
@@ -285,7 +298,7 @@ export class CallCommand extends Command {
|
|
|
285
298
|
if (owed > 0)
|
|
286
299
|
this.game.rentDebt += owed;
|
|
287
300
|
this.game?.wipeConsoleFor(this.actor);
|
|
288
|
-
this.actor.performAction('calls a taxi', wrapped ? 'for the ride home' : 'and walks away from the job');
|
|
301
|
+
this.actor.performAction('calls a taxi', wrapped ? 'for the ride home' : busted ? 'and is pinched at the wire' : 'and walks away from the job');
|
|
289
302
|
const home = await this.game.continueToNextScene();
|
|
290
303
|
const meterLine = owed === 0
|
|
291
304
|
? `The meter takes its ${FARE}.`
|
|
@@ -298,7 +311,12 @@ export class CallCommand extends Command {
|
|
|
298
311
|
// "Refusing to finish a run" is on the book's own notoriety list
|
|
299
312
|
// (SR5e p.368) -- each abandoned job is its own incident.
|
|
300
313
|
let walkLine = '';
|
|
301
|
-
if (!wrapped &&
|
|
314
|
+
if (!wrapped && busted) {
|
|
315
|
+
// Failed at the wire, not walked out on: the arrest already
|
|
316
|
+
// charged what it costs (processArrest).
|
|
317
|
+
walkLine = `The job's blown -- Knight Errant has your face now, and nobody pays a runner who got pinched on the way home.\n`;
|
|
318
|
+
}
|
|
319
|
+
else if (!wrapped && jobDead) {
|
|
302
320
|
// Not a refusal to finish (p.368's walk-out): the job ended on
|
|
303
321
|
// site. Killing the Johnson already charged its own notoriety.
|
|
304
322
|
walkLine = `The job died back there -- there's nothing left to finish and nobody left to pay for it.\n`;
|
|
@@ -307,7 +325,7 @@ export class CallCommand extends Command {
|
|
|
307
325
|
const stained = this.actor.addNotoriety(`walked out on "${this.game.currentJobName ?? 'a job'}"`);
|
|
308
326
|
walkLine = `You're leaving the job on the table -- no payout follows you home${stained ? `, and word WILL travel. (+1 Notoriety, now ${this.actor.notoriety})` : '.'}\n`;
|
|
309
327
|
}
|
|
310
|
-
return `${curbLine}${walkLine}A cab noses out of the dark and finds you like it always knew where you'd be. ${meterLine}\n${home}`;
|
|
328
|
+
return `${curbLine}${walkLine}A cab noses out of the dark and finds you like it always knew where you'd be. ${meterLine}${wireLine ? `\n${wireLine}` : ''}\n${home}`;
|
|
311
329
|
}
|
|
312
330
|
// A LIVE CREW INVITE (Phase C M4): someone else's job, your seat.
|
|
313
331
|
// The taxi is the join handshake -- same cab, different table.
|
|
@@ -489,8 +507,10 @@ export class CallCommand extends Command {
|
|
|
489
507
|
// roles): he names the client and the neighborhood of the rate,
|
|
490
508
|
// but the details and the number itself belong to the meet.
|
|
491
509
|
// An operation's chapter on the table is its JOHNSON's to pitch
|
|
492
|
-
// (operationDealer), so Krow skips it and takes an order instead
|
|
493
|
-
|
|
510
|
+
// (operationDealer), so Krow skips it and takes an order instead --
|
|
511
|
+
// until it is ACCEPTED: a chapter the runner shook on is the job
|
|
512
|
+
// they are on, and Krow says so rather than taking an order.
|
|
513
|
+
const pending = this.game.operationDealer && !this.game.pendingRunAccepted ? undefined : this.game.pendingRun;
|
|
494
514
|
if (pending) {
|
|
495
515
|
await this.dropAnyPlayerLine(); // one line at a time -- the far side hears the click
|
|
496
516
|
this.actor.activeCallPartner = target;
|
|
@@ -498,7 +518,14 @@ export class CallCommand extends Command {
|
|
|
498
518
|
// Already shook on it (see commands/job-offer.ts): no re-pitch,
|
|
499
519
|
// just the broker reminding you the meter's running.
|
|
500
520
|
if (this.game.pendingRunAccepted) {
|
|
501
|
-
|
|
521
|
+
// A JOB LEFT STANDING is still the job (aPwBWKPfrbioj2keC): the
|
|
522
|
+
// runner went out on it and came home on an errand, and Krow
|
|
523
|
+
// knows it is not done -- never the size menu.
|
|
524
|
+
const standing = this.game.hasOpenRun;
|
|
525
|
+
const note = standing
|
|
526
|
+
? `[System note: ${this.actor.name} is ON "${pending.name}" -- they went out on it, left it standing, and are home on an errand. The job is still theirs and still open. One clipped line: finish it -- the client's still waiting. Never re-pitch, never offer other work.]`
|
|
527
|
+
: `[System note: ${this.actor.name} already ACCEPTED "${pending.name}" and is calling back BEFORE heading out. One clipped line: the deal stands, the client's waiting, the cab's on their account -- get moving. Never re-pitch.]`;
|
|
528
|
+
void Promise.resolve(target.hear(this.actor, note)).catch(err => {
|
|
502
529
|
this.logger.error(`${target.name} failed to field the callback: ${err}`);
|
|
503
530
|
});
|
|
504
531
|
return `${CALL_ICON} ${FIXER_NAME} picks up.${hint(` (The job's locked -- "call taxi" when you're ready.)`)}`;
|
|
@@ -58,9 +58,14 @@ export class JobsCommand extends Command {
|
|
|
58
58
|
// ...EXCEPT a crew job filed from a hosted hub (Gdou2JNdn3kwYNWdi):
|
|
59
59
|
// the engine's cab cannot start a shared session in a host, so the
|
|
60
60
|
// ride out is the site's second act and the row says where.
|
|
61
|
+
// A JOB LEFT STANDING (aPwBWKPfrbioj2keC: "jobs" showed nothing
|
|
62
|
+
// on an errand home) is still the runner's, and the row says where.
|
|
63
|
+
const standingAt = game.hasOpenRun ? game.openRunSceneName : undefined;
|
|
61
64
|
const accepted = game.crewJobRidesFromTheSheet
|
|
62
65
|
? ` -- ACCEPTED. ${CREW_JOB_RIDE_LINE}`
|
|
63
|
-
:
|
|
66
|
+
: game.hasOpenRun
|
|
67
|
+
? ` -- IN PROGRESS, left standing${standingAt ? ` at ${standingAt}` : ''}; "call taxi" goes back`
|
|
68
|
+
: ' -- ACCEPTED, "call taxi" rolls';
|
|
64
69
|
const unheard = ` -- "call ${this.fixerName()}" to hear it`;
|
|
65
70
|
const tail = game.pendingRunAccepted ? accepted : unheard;
|
|
66
71
|
// Whose job it is: one job per Johnson (2026-10-01).
|
|
@@ -168,6 +173,12 @@ export class JobsCommand extends Command {
|
|
|
168
173
|
this.logger.write(`Jobs board: took "${entry.name}" from the drawer.`);
|
|
169
174
|
return `"${entry.name}" is on the table.${hint(` ("call ${dealer}" to hear it -- "accept" or "decline" once you have.)`)}`;
|
|
170
175
|
}
|
|
176
|
+
// AN ACCEPTED JOB IS NEVER SWAPPED ASIDE (aPwBWKPfrbioj2keC): only
|
|
177
|
+
// finishing, failing or walking it ends it -- the same refusal the
|
|
178
|
+
// drawer swap gives (Game.takeFromDrawer).
|
|
179
|
+
if (game.pendingRun && game.pendingRunAccepted) {
|
|
180
|
+
return `You've already shaken on "${game.pendingRun.name}" -- finish it, or "abandon" it, before you take another off the board.`;
|
|
181
|
+
}
|
|
171
182
|
// Swap the current offer aside (the server draft behind a CREW offer
|
|
172
183
|
// survives -- fingerprint reuse brings it back to the board).
|
|
173
184
|
if (game.pendingRun) {
|
|
@@ -157,9 +157,11 @@ export class JournalCommand extends Command {
|
|
|
157
157
|
const lines = [`{bold}THE JOURNAL{/bold}`, `You're home. No run on the clock.`];
|
|
158
158
|
const pending = game.pendingRun;
|
|
159
159
|
if (pending) {
|
|
160
|
-
lines.push(game.
|
|
161
|
-
? `${BULLET}{bold}
|
|
162
|
-
:
|
|
160
|
+
lines.push(game.hasOpenRun
|
|
161
|
+
? `${BULLET}{bold}In progress:{/bold} "${pending.name}" -- left standing. ("call taxi" goes back.)`
|
|
162
|
+
: game.pendingRunAccepted
|
|
163
|
+
? `${BULLET}{bold}Next:{/bold} "${pending.name}" -- ACCEPTED. ("call taxi" rolls.)`
|
|
164
|
+
: `${BULLET}{bold}On offer:{/bold} "${pending.name}" -- not shaken on yet.`);
|
|
163
165
|
}
|
|
164
166
|
if (game.rentDebt > 0) {
|
|
165
167
|
lines.push(`${BULLET}{bold}Owed:{/bold} ${game.rentDebt.toLocaleString()}¥ on the tab`);
|
|
@@ -3,10 +3,11 @@ import { hint } from '../utilities/hints.js';
|
|
|
3
3
|
import { Player } from '../models/player.js';
|
|
4
4
|
import { Category } from '../types/shared/item-enum.js';
|
|
5
5
|
import { billAction } from '../utilities/action-cost.js';
|
|
6
|
-
import { reachableDevices
|
|
6
|
+
import { reachableDevices } from '../utilities/pan-devices.js';
|
|
7
7
|
import { leaveMatrix } from '../utilities/planes.js';
|
|
8
8
|
import { findWirelessImplant, implantTrack } from '../utilities/implant-matrix.js';
|
|
9
9
|
import { augFor } from '../utilities/catalog.js';
|
|
10
|
+
import { panStatus } from '../utilities/pan-status.js';
|
|
10
11
|
/**
|
|
11
12
|
* The PAN dashboard: your personal area network at a glance -- master
|
|
12
13
|
* device and its firewall, every slaved device with what it grants while
|
|
@@ -299,28 +300,32 @@ export class PanCommand extends Command {
|
|
|
299
300
|
`No devices, no PAN. You are unhackable and unreachable -- the monk's build.`,
|
|
300
301
|
].join('\n');
|
|
301
302
|
}
|
|
302
|
-
//
|
|
303
|
-
//
|
|
304
|
-
//
|
|
305
|
-
//
|
|
306
|
-
//
|
|
307
|
-
//
|
|
308
|
-
//
|
|
309
|
-
//
|
|
310
|
-
//
|
|
311
|
-
|
|
312
|
-
const
|
|
313
|
-
? `{
|
|
314
|
-
:
|
|
315
|
-
|
|
316
|
-
: a.arOffline
|
|
317
|
-
? `{red-fg}LOUD, AR CUT{/red-fg} -- someone hacked your overlay dark ("reboot")`
|
|
318
|
-
: `{green-fg}LOUD{/green-fg} -- full bonuses, and hackable`;
|
|
303
|
+
// FOUR SWITCHES, FOUR ROWS (player 2026-10-04: "running loud isn't
|
|
304
|
+
// the same as wireless bonus"). This was one "Broadcast:" ladder whose
|
|
305
|
+
// LOUD rung read "full bonuses", as if being loud paid them; and its
|
|
306
|
+
// SILENT rung promised "+2 firewall", which p.235-236 does not grant
|
|
307
|
+
// (RAG-checked 2026-10-04: a silent icon must be FOUND first, and
|
|
308
|
+
// that is the whole of the protection). Wireless decides the bonuses
|
|
309
|
+
// (p.421), silence decides whether you can be targeted (p.235), AR is
|
|
310
|
+
// what you receive (p.229), and the grid charges its own toll (p.233).
|
|
311
|
+
// utilities/pan-status.ts answers all four -- the web card reads it too.
|
|
312
|
+
const st = panStatus(a);
|
|
313
|
+
const arLine = st.ar
|
|
314
|
+
? `{green-fg}ON{/green-fg}`
|
|
315
|
+
: `{white-fg}OFF{/white-fg} -- ${AR_WHY[st.arWhy ?? ''] ?? 'no overlay'}`;
|
|
316
|
+
const gridToll = st.modifiers.find(m => m.source === 'the public grid');
|
|
319
317
|
const slaves = a.panSlaves();
|
|
320
318
|
const lines = [
|
|
321
319
|
`PAN: ${a.name.toUpperCase()}`,
|
|
322
320
|
'',
|
|
323
|
-
`
|
|
321
|
+
`Wireless: ${st.wireless === 'on'
|
|
322
|
+
? `{green-fg}ON{/green-fg} -- wireless bonuses paid, and every device on the air is hackable (p.421)${hint(' ("wireless off")')}`
|
|
323
|
+
: `{white-fg}OFF{/white-fg} -- no bonuses, no calls, nothing to hack (p.421)${hint(' ("wireless on")')}`}`,
|
|
324
|
+
`Silent: ${st.silent
|
|
325
|
+
? `{magenta-fg}ON{/magenta-fg} -- your icon must be found before it can be targeted; -2 dice on your Matrix actions (p.235). Wireless bonuses untouched.`
|
|
326
|
+
: `OFF -- your icon is in plain view of any decker in reach${hint(' ("silent")')}`}`,
|
|
327
|
+
`AR: ${arLine}`,
|
|
328
|
+
`Grid: ${st.grid.name}${st.grid.on ? '' : ' (where "jack in" lands you)'}${gridToll ? ` -- {yellow-fg}${gridToll.value} on ${gridToll.applies} (${gridToll.cite}){/yellow-fg}` : ''}`,
|
|
324
329
|
// WHICH ICON IS YOU. The master and the persona are two different
|
|
325
330
|
// facts and they come apart exactly where this item lives: a
|
|
326
331
|
// technomancer's commlink masters their gear while their MIND runs
|
|
@@ -362,7 +367,13 @@ export class PanCommand extends Command {
|
|
|
362
367
|
lines.push(' (none -- the master is the whole network)');
|
|
363
368
|
}
|
|
364
369
|
for (const item of slaves) {
|
|
365
|
-
lines.push(` • ${this.slaveLine(item)}`);
|
|
370
|
+
lines.push(` • ${this.slaveLine(item, st.devices.find(d => d.name === item.name))}`);
|
|
371
|
+
}
|
|
372
|
+
// The master earns its own wireless bonus too (the AR initiative add
|
|
373
|
+
// rides the live link, which is usually the master).
|
|
374
|
+
const masterRow = st.devices.find(d => d.role === 'master');
|
|
375
|
+
if (masterRow?.bonus) {
|
|
376
|
+
lines.splice(lines.indexOf('Slaved devices:'), 0, `Master's wireless bonus: ${bonusText(masterRow)}`, '');
|
|
366
377
|
}
|
|
367
378
|
const over = a.panOverflow();
|
|
368
379
|
if (over > 0) {
|
|
@@ -376,17 +387,24 @@ export class PanCommand extends Command {
|
|
|
376
387
|
lines.push('');
|
|
377
388
|
lines.push('Switched off:');
|
|
378
389
|
for (const item of off) {
|
|
379
|
-
|
|
390
|
+
const lost = st.devices.find(d => d.name === item.name)?.bonus;
|
|
391
|
+
lines.push(` · ${item.name} -- wireless OFF, no icon, nothing to hack${lost ? ` -- {white-fg}forgoing ${lost}{/white-fg}` : ''}${hint(` ("pan on ${item.name}")`)}`);
|
|
380
392
|
}
|
|
381
393
|
}
|
|
394
|
+
// Wireless chrome has no Item, so it is listed apart.
|
|
395
|
+
const chrome = st.devices.filter(d => d.role === 'implant');
|
|
396
|
+
if (chrome.length > 0) {
|
|
397
|
+
lines.push('');
|
|
398
|
+
lines.push('Wireless implants:');
|
|
399
|
+
for (const d of chrome)
|
|
400
|
+
lines.push(` • ${d.name} -- wireless ${d.wireless ? 'ON' : 'OFF'}${d.note ? ` {red-fg}${d.note}{/red-fg}` : ''}`);
|
|
401
|
+
}
|
|
382
402
|
lines.push('');
|
|
383
403
|
// THE TWO SWITCHES, NAMED APART. A player reading this screen is
|
|
384
404
|
// deciding between them, and until this item they had only one verb.
|
|
385
|
-
lines.push(
|
|
386
|
-
? `
|
|
387
|
-
:
|
|
388
|
-
? `Silent running: enemy deckers must FIND you before they can crack you -- but a good one can force you loud.${hint(' "wireless off" is the harder version: no icon at all, and no bonuses either.')}`
|
|
389
|
-
: `Running loud: any decker in reach can try your firewall -- jammed guns and dead AR are how that feels.${hint(' "silent" hides your icon; "wireless off" kills the broadcast outright.')}`);
|
|
405
|
+
lines.push(a.runningSilent
|
|
406
|
+
? `Silent running: enemy deckers must FIND you before they can crack you -- but a good one can force you loud.${hint(' "wireless off" is the harder version: no icon at all, and no bonuses either.')}`
|
|
407
|
+
: `Running loud: any decker in reach can try your firewall -- jammed guns and dead AR are how that feels.${hint(' "silent" hides your icon and keeps your bonuses; "wireless off" kills the broadcast and the bonuses with it.')}`);
|
|
390
408
|
return lines.join('\n');
|
|
391
409
|
}
|
|
392
410
|
/** The one line that says which icon on the grid is actually you. */
|
|
@@ -401,34 +419,51 @@ export class PanCommand extends Command {
|
|
|
401
419
|
const muted = a.resonanceMuted() ? ` -- {red-fg}Resonance MUTED{/red-fg} while you ride it (p.251)` + hint(` ("pan link persona")`) : '';
|
|
402
420
|
return `${rig.name} [DR ${rig.deviceRating}] -- ${how}${muted}`;
|
|
403
421
|
}
|
|
404
|
-
/**
|
|
405
|
-
|
|
422
|
+
/**
|
|
423
|
+
* What one slaved device is and what its WIRELESS buys it.
|
|
424
|
+
*
|
|
425
|
+
* A SLAVE'S BONUS DIES WITH ITS OWN RADIO, NOT WITH SILENCE (p.421 vs
|
|
426
|
+
* p.235, RXPvXqTwEyH9v3Zk7). The bonus text and whether it is being
|
|
427
|
+
* paid come from pan-status.ts, the same rows the web card draws.
|
|
428
|
+
*/
|
|
429
|
+
slaveLine(item, row) {
|
|
406
430
|
const a = this.actor;
|
|
407
|
-
|
|
408
|
-
// p.235, RXPvXqTwEyH9v3Zk7). This asked `a.runningSilent`, which is
|
|
409
|
-
// the one thing canon says does NOT cost you wireless bonuses.
|
|
410
|
-
const inactive = !item.wirelessOn || a.arOffline;
|
|
431
|
+
const bonus = row?.bonus ? ` -- wireless: ${bonusText(row)}` : '';
|
|
411
432
|
if (item.isCyberdeck()) {
|
|
412
|
-
return `${item.name} (cyberdeck) -- Matrix access; ${item.deckSummary()}${item.isBricked ? ' BRICKED (rest to repair)' : ''}`;
|
|
433
|
+
return `${item.name} (cyberdeck) -- Matrix access; ${item.deckSummary()}${item.isBricked ? ' BRICKED (rest to repair)' : ''}${bonus}`;
|
|
413
434
|
}
|
|
414
435
|
if (item.category === Category.Commlink) {
|
|
415
|
-
|
|
416
|
-
return `${item.name} (commlink) -- calls; ${bonus}`;
|
|
436
|
+
return `${item.name} (commlink) -- calls${bonus}`;
|
|
417
437
|
}
|
|
418
438
|
// Only a SMARTGUN is on the PAN (p.433; catalog v13): a plain gun has
|
|
419
439
|
// nothing to broadcast and nothing to crack.
|
|
420
440
|
if (item.isFirearm()) {
|
|
421
|
-
return `${item.name} (smartgun)
|
|
441
|
+
return `${item.name} (smartgun)${item.jammed ? ' -- {red-fg}JAMMED -- smartlink cracked ("reboot"){/red-fg}' : ''}${bonus}`;
|
|
422
442
|
}
|
|
423
443
|
if (item.isRcc()) {
|
|
424
444
|
return `${item.name} (RCC) -- slaved, not mastering: its drone network is idle${hint(` ("pan link ${item.name.toLowerCase()}")`)}`;
|
|
425
445
|
}
|
|
426
446
|
if (item.category === Category.Drone) {
|
|
427
447
|
return a.rccMaster()
|
|
428
|
-
? `${item.name} (drone)
|
|
448
|
+
? `${item.name} (drone)${bonus}${hint(' ("order drones ...", "jump <drone>")')}`
|
|
429
449
|
: `${item.name} (drone) -- recon uplink${hint(' ("drone")')}`;
|
|
430
450
|
}
|
|
431
|
-
return `${item.name} (${item.category})`;
|
|
451
|
+
return `${item.name} (${item.category})${bonus}`;
|
|
432
452
|
}
|
|
433
453
|
}
|
|
454
|
+
/** Why the overlay is down, in the dashboard's words (pan-status arWhy). */
|
|
455
|
+
const AR_WHY = {
|
|
456
|
+
muted: 'you muted it ("ar on")',
|
|
457
|
+
hacked: '{red-fg}someone hacked your overlay dark{/red-fg} ("reboot")',
|
|
458
|
+
'no-display': 'nothing to see it on -- glasses, contacts, cybereyes or a DNI',
|
|
459
|
+
'no-pan': 'no PAN master to feed it',
|
|
460
|
+
'off-plane': 'you are not in your body',
|
|
461
|
+
};
|
|
462
|
+
/** One device's wireless bonus, green while paid, dim with the reason when not. */
|
|
463
|
+
function bonusText(row) {
|
|
464
|
+
if (row.bonusLive)
|
|
465
|
+
return `{green-fg}${row.bonus}{/green-fg}`;
|
|
466
|
+
const why = !row.wireless ? 'wireless OFF' : row.role === 'overflow' ? 'over capacity' : 'not paid';
|
|
467
|
+
return `{white-fg}${row.bonus} -- ${why}{/white-fg}`;
|
|
468
|
+
}
|
|
434
469
|
//# sourceMappingURL=pan.js.map
|
|
@@ -3253,5 +3253,28 @@
|
|
|
3253
3253
|
// written to a chip -- a persona is not a device, and a datachip has no
|
|
3254
3254
|
// wireless to write through. Reaches only the deviceless technomancer;
|
|
3255
3255
|
// one with a commlink copies onto it and keeps their Resonance.
|
|
3256
|
-
|
|
3256
|
+
// 1.192.0 (2026-10-04): THE PAN, FOUR SWITCHES APART.
|
|
3257
|
+
// - "pan" prints Wireless / Silent / AR / Grid as four rows instead of
|
|
3258
|
+
// one Broadcast ladder whose LOUD rung read "full bonuses" -- being loud
|
|
3259
|
+
// pays nothing; wireless does (p.421). The SILENT rung's "+2 firewall"
|
|
3260
|
+
// is gone from the text: p.235-236 grants no such thing.
|
|
3261
|
+
// - Every device says what its wireless buys and whether it is being
|
|
3262
|
+
// paid: the smartgun's +1/+2 dice (p.433), the live link's AR initiative
|
|
3263
|
+
// add (engine rule), the RCC's drone network (p.267).
|
|
3264
|
+
// - The condition beat carries `pan` (utilities/pan-status.ts) for the
|
|
3265
|
+
// web sheet's PAN card; same rows as the verb.
|
|
3266
|
+
// 1.192.1 (2026-10-04): A JOB STAYS ON THE BOOKS UNTIL IT ENDS
|
|
3267
|
+
// (aPwBWKPfrbioj2keC; ruling: never cleared unless abandoned or failed).
|
|
3268
|
+
// - The ride out no longer clears the accepted job: it stays the
|
|
3269
|
+
// runner's through the run and every errand home, and is saved with
|
|
3270
|
+
// them, so a quit mid-errand comes back with it accepted and "call
|
|
3271
|
+
// taxi" rides it again. Only the homecoming ends it -- wrapped, walked
|
|
3272
|
+
// out ("abandon"), died on site, or pinched at the wire.
|
|
3273
|
+
// - The errand cab rolls the KE checkpoint FIRST: a bust there fails the
|
|
3274
|
+
// job and takes the homecoming road instead of leaving it standing.
|
|
3275
|
+
// - "jobs", the journal and Krow's callback name a job left standing
|
|
3276
|
+
// ("IN PROGRESS") instead of "Nothing on offer" and the size menu.
|
|
3277
|
+
// - A standing draft ("jobs take") and a crew change no longer swap an
|
|
3278
|
+
// accepted job aside; a ride that never shows keeps the job.
|
|
3279
|
+
export const ENGINE_VERSION = '1.192.1';
|
|
3257
3280
|
//# sourceMappingURL=engine-version.js.map
|
|
@@ -538,6 +538,13 @@ export default class Game {
|
|
|
538
538
|
scrapPendingRunForCrewChange() {
|
|
539
539
|
if (!this._pendingRunSeed)
|
|
540
540
|
return '';
|
|
541
|
+
// A QUOTE, not a job: once accepted it is the runner's until it ends
|
|
542
|
+
// (aPwBWKPfrbioj2keC) -- a hire made on an errand home must not
|
|
543
|
+
// void the job they are halfway through.
|
|
544
|
+
// (A CREW quote is the server's draft for a seated party, and the
|
|
545
|
+
// crew-change ruling still voids it.)
|
|
546
|
+
if (this.pendingRunAccepted && !this.pendingSharedRun)
|
|
547
|
+
return '';
|
|
541
548
|
this.clearPendingRun({ keepServerDraft: true });
|
|
542
549
|
return `\nThe standing job was quoted for a different crew -- ${FIXER_NAME} needs a fresh call.`;
|
|
543
550
|
}
|
|
@@ -3766,9 +3773,20 @@ export default class Game {
|
|
|
3766
3773
|
_pendingRunTier;
|
|
3767
3774
|
// The explicit handshake (player ruling, commands/job-offer.ts):
|
|
3768
3775
|
// "accept" locks the offer -- rate final, haggle closed, decline
|
|
3769
|
-
// refused
|
|
3770
|
-
//
|
|
3776
|
+
// refused. Reset wherever the pending seed changes hands.
|
|
3777
|
+
//
|
|
3778
|
+
// AN ACCEPTED JOB STAYS ON THE BOOKS UNTIL IT ENDS (aPwBWKPfrbioj2keC,
|
|
3779
|
+
// user ruling 2026-10-04: "NEVER clear a job unless it is abandoned or
|
|
3780
|
+
// failed"). The ride out no longer clears it: the seed stays here,
|
|
3781
|
+
// accepted, for the whole run and every errand home, and only the
|
|
3782
|
+
// homecoming (returnToHub -- wrapped, walked out, died on site, busted
|
|
3783
|
+
// at the wire) ends it. That is what lets the board, Krow and the save
|
|
3784
|
+
// all still see a job the runner left standing; a quit mid-errand
|
|
3785
|
+
// comes back with it accepted and "call taxi" rides it again.
|
|
3771
3786
|
pendingRunAccepted = false;
|
|
3787
|
+
/** Set by checkpointOnRideHome when the wire ends in an arrest: a ride
|
|
3788
|
+
* that ends in zip ties is a failed job, never an errand (call.ts). */
|
|
3789
|
+
rideHomeBusted = false;
|
|
3772
3790
|
/**
|
|
3773
3791
|
* The words the player ACTUALLY said, when speech routed itself to
|
|
3774
3792
|
* `accept` (commands/say.ts). It rides into the fixer's signoff note
|
|
@@ -7122,6 +7140,12 @@ ${client.name} won't be remembering anything. Dead Johnsons pay nothing -- and t
|
|
|
7122
7140
|
const wrappedRun = this.scene !== hub && this.scene.isCompleted();
|
|
7123
7141
|
// And its name, for the same reason: the operation matches on it.
|
|
7124
7142
|
const jobNameBefore = this.scene !== hub ? this.currentJobName : undefined;
|
|
7143
|
+
// THE ONE PLACE A RIDDEN JOB COMES OFF THE BOOKS (aPwBWKPfrbioj2keC):
|
|
7144
|
+
// this homecoming is wrapped, walked out on, died on site or busted at
|
|
7145
|
+
// the wire -- every way a job ends. The ride out and the errand cab
|
|
7146
|
+
// leave it standing (see pendingRunAccepted).
|
|
7147
|
+
if (this.scene !== hub)
|
|
7148
|
+
this.clearPendingRun({ keepServerDraft: true });
|
|
7125
7149
|
// A LOUD RUN PUTS YOUR FACE ON A FEED (TRqb2zBphwpDkeXP4, Maka: "the
|
|
7126
7150
|
// alarm was exciting, but nothing came of it").
|
|
7127
7151
|
//
|
|
@@ -7568,6 +7592,7 @@ ${client.name} won't be remembering anything. Dead Johnsons pay nothing -- and t
|
|
|
7568
7592
|
checkpointOnRideHome() {
|
|
7569
7593
|
const heat = this._runHeat;
|
|
7570
7594
|
this._runHeat = 0;
|
|
7595
|
+
this.rideHomeBusted = false;
|
|
7571
7596
|
if (heat < Game.CHECKPOINT_HEAT)
|
|
7572
7597
|
return '';
|
|
7573
7598
|
const p = this.player;
|
|
@@ -7604,6 +7629,7 @@ ${client.name} won't be remembering anything. Dead Johnsons pay nothing -- and t
|
|
|
7604
7629
|
p.inventory.removeItem(fake.item.name);
|
|
7605
7630
|
lines.push(`You hand over the Rating ${fake.rating} fake. The wand chews... and SPITS. "This SIN is flagged as of now." The fake is BURNED -- worthless in every database at once.`);
|
|
7606
7631
|
lines.push(processArrest(p, heat));
|
|
7632
|
+
this.rideHomeBusted = true;
|
|
7607
7633
|
return lines.join('\n');
|
|
7608
7634
|
}
|
|
7609
7635
|
const con = p.skillRating('con');
|
|
@@ -7616,6 +7642,7 @@ ${client.name} won't be remembering anything. Dead Johnsons pay nothing -- and t
|
|
|
7616
7642
|
}
|
|
7617
7643
|
lines.push(`No SIN, and no story that holds. Zip ties.`);
|
|
7618
7644
|
lines.push(processArrest(p, heat));
|
|
7645
|
+
this.rideHomeBusted = true;
|
|
7619
7646
|
return lines.join('\n');
|
|
7620
7647
|
}
|
|
7621
7648
|
/**
|
|
@@ -8164,16 +8191,18 @@ ${client.name} won't be remembering anything. Dead Johnsons pay nothing -- and t
|
|
|
8164
8191
|
// job's negotiation with the job, so anything still set when a ride
|
|
8165
8192
|
// is called genuinely belongs to the offer in hand.
|
|
8166
8193
|
const haggledAtOffer = this.player.haggledThisJob;
|
|
8194
|
+
// NOT CLEARED HERE (aPwBWKPfrbioj2keC): the accepted job rides along
|
|
8195
|
+
// and stays on the books until the homecoming ends it -- see
|
|
8196
|
+
// pendingRunAccepted. A ride that never shows ends nothing either:
|
|
8197
|
+
// the job is still the runner's, and the next cab tries again.
|
|
8167
8198
|
try {
|
|
8168
8199
|
const banner = await this.activateRunScene(seed, tier, { startInHideout: false });
|
|
8169
|
-
this.clearPendingRun();
|
|
8170
8200
|
this.player.haggledThisJob = haggledAtOffer;
|
|
8171
8201
|
return `You travel to ${this.player.currentLocation.name}.\n${banner}`;
|
|
8172
8202
|
}
|
|
8173
8203
|
catch (err) {
|
|
8174
|
-
this.clearPendingRun();
|
|
8175
8204
|
Logger.getInstance().error(`launchPendingRun failed: ${err}`);
|
|
8176
|
-
return `The ride never shows
|
|
8205
|
+
return `The ride never shows -- the dispatcher lost the address. The job's still yours; "call taxi" to try again.`;
|
|
8177
8206
|
}
|
|
8178
8207
|
}
|
|
8179
8208
|
/**
|
|
@@ -7,6 +7,7 @@ import { overlaid } from './overlay-fill.js';
|
|
|
7
7
|
import { PLAYER_GLYPH } from './map-glyphs.js';
|
|
8
8
|
import { headcountBand } from './crowd.js';
|
|
9
9
|
import { pending, contractorName } from './law-response.js';
|
|
10
|
+
import { panStatus } from './pan-status.js';
|
|
10
11
|
/**
|
|
11
12
|
* THE LIVE CONDITION EMITTER -- the CLI half of the realtime sheet lane
|
|
12
13
|
* (contract agreed with maka-cli.com, 2026-09-01). On every condition
|
|
@@ -303,6 +304,17 @@ export function buildConditionReport(player, deps) {
|
|
|
303
304
|
// The ONE honest AR answer (2026-09-01): muted, cut, and no-rig
|
|
304
305
|
// all collapse into arSightUp, computed at fire time.
|
|
305
306
|
ar: arSightUp(player),
|
|
307
|
+
// THE PAN CARD (player 2026-10-04: "I don't see any of my matrix
|
|
308
|
+
// modifiers. When silent, I don't see on the sheet 'silent'"): wireless,
|
|
309
|
+
// silent, AR and grid as four separate facts, and every device's
|
|
310
|
+
// wireless bonus with whether it is being paid -- utilities/pan-status.ts,
|
|
311
|
+
// the same rows the `pan` verb prints. A decoration never kills the beat.
|
|
312
|
+
...(() => { try {
|
|
313
|
+
return { pan: panStatus(player) };
|
|
314
|
+
}
|
|
315
|
+
catch {
|
|
316
|
+
return {};
|
|
317
|
+
} })(),
|
|
306
318
|
// THE HEADER'S NUMBERS (contract 2026-09-10, web accepted first;
|
|
307
319
|
// ZpgTTPgX4Hn7qL5M7: the play page's HUD shows the sheet header). A
|
|
308
320
|
// browser run writes no mid-run save and its roster summary is
|
|
@@ -453,7 +465,7 @@ function noteRoster(report) {
|
|
|
453
465
|
const ADDITIVE_FIELDS = [
|
|
454
466
|
'ar', 'actors', 'deckLine', 'deckDamage', 'astralPerceiving', 'bodyRoom', 'sustainingPenalty',
|
|
455
467
|
'matrix', 'panMarks', 'hostMarksOnYou', 'marksPlaced', 'marksOnYou', 'deckStored', 'droneDamage', 'companions', 'pools', 'initiative',
|
|
456
|
-
'karma', 'nuyen', 'edge', 'grid', 'bodies', 'phaseActor', 'crowd', 'overflowMax', 'stabilized', 'brink', 'gear',
|
|
468
|
+
'karma', 'nuyen', 'edge', 'grid', 'bodies', 'phaseActor', 'crowd', 'overflowMax', 'stabilized', 'brink', 'gear', 'pan',
|
|
457
469
|
];
|
|
458
470
|
export function crowdReport(player) {
|
|
459
471
|
const room = player.currentLocation;
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { Category } from '../types/shared/item-enum.js';
|
|
2
|
+
import { switchableDevices, radioIsDark } from './pan-devices.js';
|
|
3
|
+
import { arSightUp } from './ar.js';
|
|
4
|
+
import { homeGridFor } from './planes.js';
|
|
5
|
+
import { hostLabel } from './grid-names.js';
|
|
6
|
+
import { wirelessImplants, implantTrack } from './implant-matrix.js';
|
|
7
|
+
function kindOf(item) {
|
|
8
|
+
if (item.isCyberdeck())
|
|
9
|
+
return 'cyberdeck';
|
|
10
|
+
if (item.isRcc())
|
|
11
|
+
return 'rcc';
|
|
12
|
+
if (item.category === Category.Commlink)
|
|
13
|
+
return 'commlink';
|
|
14
|
+
if (item.isFirearm())
|
|
15
|
+
return 'smartgun';
|
|
16
|
+
if (item.category === Category.Drone)
|
|
17
|
+
return 'drone';
|
|
18
|
+
return 'device';
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* THE WIRELESS BONUS ONE DEVICE EARNS -- only the ones the engine pays,
|
|
22
|
+
* read from the same places the pools read them, so a line here is never
|
|
23
|
+
* a promise the dice do not keep.
|
|
24
|
+
*/
|
|
25
|
+
function bonusOf(a, item) {
|
|
26
|
+
const radio = item.wirelessOn;
|
|
27
|
+
// p.433: "+1 if you're using gear with a smartlink or +2 if you're
|
|
28
|
+
// using an augmentation for which you paid Essence" -- Player
|
|
29
|
+
// getAttackPool's `smartlink` term, same tier, same chrome dice.
|
|
30
|
+
if (item.isFirearm() && item.isSmartgun) {
|
|
31
|
+
const tier = a.smartlinkTier();
|
|
32
|
+
if (!tier)
|
|
33
|
+
return { bonus: 'no smartlink to talk to -- no dice', live: false };
|
|
34
|
+
const dice = tier === 'gear' ? 1 : a.augBonus('firearms');
|
|
35
|
+
return { bonus: `+${dice} ${dice === 1 ? 'die' : 'dice'} to attacks (smartlink ${tier === 'gear' ? 'gear' : 'implant'}, p.433)`, live: radio };
|
|
36
|
+
}
|
|
37
|
+
// The AR overlay's initiative add (Player.getInitiativeAttribute): an
|
|
38
|
+
// ENGINE ADDITION, not canon -- p.474 gives AR a bare Reaction +
|
|
39
|
+
// Intuition -- paid by the live link alone, gated on its radio and on
|
|
40
|
+
// nobody having hacked the overlay dark.
|
|
41
|
+
if (a.liveLink() === item && item.qualityBonus > 0) {
|
|
42
|
+
return { bonus: `+${item.qualityBonus} initiative in AR (engine rule)`, live: radio && !a.arOffline };
|
|
43
|
+
}
|
|
44
|
+
// p.266-267: one order reaches every slaved drone, frame to frame.
|
|
45
|
+
if (item.isRcc()) {
|
|
46
|
+
return a.rccMaster() === item
|
|
47
|
+
? { bonus: 'drone network: group orders, frame-to-frame jumps (p.267)', live: radio }
|
|
48
|
+
: { bonus: 'drone network idle -- not mastering', live: false };
|
|
49
|
+
}
|
|
50
|
+
if (item.category === Category.Drone && a.rccMaster()) {
|
|
51
|
+
return { bonus: 'on the console: group orders (p.267)', live: radio };
|
|
52
|
+
}
|
|
53
|
+
return {};
|
|
54
|
+
}
|
|
55
|
+
function arWhy(a) {
|
|
56
|
+
if (arSightUp(a))
|
|
57
|
+
return undefined;
|
|
58
|
+
if (a.plane !== 'meat')
|
|
59
|
+
return 'off-plane';
|
|
60
|
+
if (a.arMuted)
|
|
61
|
+
return 'muted';
|
|
62
|
+
if (a.arOffline)
|
|
63
|
+
return 'hacked';
|
|
64
|
+
if (!a.getPanMaster() && !a.isTechnomancer())
|
|
65
|
+
return 'no-pan';
|
|
66
|
+
return 'no-display';
|
|
67
|
+
}
|
|
68
|
+
function gridOf(a) {
|
|
69
|
+
if (a.plane === 'matrix') {
|
|
70
|
+
const host = a.hostInside;
|
|
71
|
+
if (host)
|
|
72
|
+
return { name: hostLabel(host.over), kind: 'host', on: true };
|
|
73
|
+
if (a.currentGrid)
|
|
74
|
+
return { name: a.currentGrid.name, kind: a.currentGrid.kind, on: true };
|
|
75
|
+
}
|
|
76
|
+
const scene = a.currentLocation?.scene;
|
|
77
|
+
if (scene) {
|
|
78
|
+
const g = homeGridFor(scene, a);
|
|
79
|
+
return { name: g.name, kind: g.kind, on: false };
|
|
80
|
+
}
|
|
81
|
+
return { name: 'the public grid', kind: 'public', on: false };
|
|
82
|
+
}
|
|
83
|
+
/** The persona line without colour tags -- pan.ts adds its own. */
|
|
84
|
+
function personaOf(a) {
|
|
85
|
+
const rig = a.personaRig();
|
|
86
|
+
if (!rig)
|
|
87
|
+
return a.isTechnomancer() ? `living persona (Resonance ${a.resonance})` : 'none';
|
|
88
|
+
return `${rig.name} [DR ${rig.deviceRating}]${a.resonanceMuted() ? ' -- Resonance muted' : ''}`;
|
|
89
|
+
}
|
|
90
|
+
export function panStatus(a) {
|
|
91
|
+
const devices = switchableDevices(a);
|
|
92
|
+
const master = a.getPanMaster();
|
|
93
|
+
const slaves = new Set(a.panSlaves());
|
|
94
|
+
const silent = a.runningSilent;
|
|
95
|
+
const grid = gridOf(a);
|
|
96
|
+
const modifiers = [];
|
|
97
|
+
if (silent)
|
|
98
|
+
modifiers.push({ source: 'running silent', value: '-2 dice', applies: 'your Matrix actions', cite: 'p.235' });
|
|
99
|
+
// Inside a host the grid does not matter (p.246) -- gridOf says 'host'.
|
|
100
|
+
if (grid.kind === 'public')
|
|
101
|
+
modifiers.push({ source: 'the public grid', value: '-2 dice', applies: 'your Matrix actions', cite: 'p.233' });
|
|
102
|
+
const rows = devices.map(item => {
|
|
103
|
+
const role = item === master ? 'master'
|
|
104
|
+
: !item.wirelessOn ? 'off'
|
|
105
|
+
: slaves.has(item) ? 'slave' : 'overflow';
|
|
106
|
+
const { bonus, live } = bonusOf(a, item);
|
|
107
|
+
const note = item.isBricked ? 'BRICKED' : item.jammed ? 'JAMMED -- smartlink cracked ("reboot")' : undefined;
|
|
108
|
+
return {
|
|
109
|
+
name: item.name,
|
|
110
|
+
kind: kindOf(item),
|
|
111
|
+
role,
|
|
112
|
+
wireless: item.wirelessOn,
|
|
113
|
+
...(bonus ? { bonus, bonusLive: Boolean(live) && role !== 'overflow' } : {}),
|
|
114
|
+
...(note ? { note } : {}),
|
|
115
|
+
};
|
|
116
|
+
});
|
|
117
|
+
// WIRELESS CHROME (implant-matrix.ts): on the air or not, no Item to carry.
|
|
118
|
+
for (const key of wirelessImplants(a)) {
|
|
119
|
+
const t = implantTrack(a, key);
|
|
120
|
+
if (!t || t.item)
|
|
121
|
+
continue;
|
|
122
|
+
rows.push({
|
|
123
|
+
name: t.name,
|
|
124
|
+
kind: 'implant',
|
|
125
|
+
role: 'implant',
|
|
126
|
+
wireless: t.wirelessOn,
|
|
127
|
+
...(t.bricked ? { note: 'BRICKED' } : {}),
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
return {
|
|
131
|
+
wireless: devices.length === 0 ? 'none' : radioIsDark(a) ? 'off' : 'on',
|
|
132
|
+
silent,
|
|
133
|
+
ar: arSightUp(a),
|
|
134
|
+
...(arWhy(a) ? { arWhy: arWhy(a) } : {}),
|
|
135
|
+
grid,
|
|
136
|
+
persona: personaOf(a),
|
|
137
|
+
...(master ? { master: { name: master.name, deviceRating: master.deviceRating } } : {}),
|
|
138
|
+
slaved: slaves.size,
|
|
139
|
+
capacity: a.panCapacity(),
|
|
140
|
+
...(master || a.isTechnomancer()
|
|
141
|
+
? { defence: { sleaze: a.panDefenceLine('sleaze'), attack: a.panDefenceLine('attack') } }
|
|
142
|
+
: {}),
|
|
143
|
+
modifiers,
|
|
144
|
+
devices: rows,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=pan-status.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@maka/maka-cli",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.380.1",
|
|
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.",
|