@maka/maka-cli 5.10.0 → 5.12.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.
Files changed (119) hide show
  1. package/bundle/typescript/package.json +1 -1
  2. package/bundle/typescript/src/commands/game/sideQuest/archetypes.js +3 -1
  3. package/bundle/typescript/src/commands/game/sideQuest/archetypes.js.map +1 -1
  4. package/bundle/typescript/src/commands/game/sideQuest/commands/advance.js +6 -5
  5. package/bundle/typescript/src/commands/game/sideQuest/commands/advance.js.map +1 -1
  6. package/bundle/typescript/src/commands/game/sideQuest/commands/ask.js +1 -1
  7. package/bundle/typescript/src/commands/game/sideQuest/commands/ask.js.map +1 -1
  8. package/bundle/typescript/src/commands/game/sideQuest/commands/buy.js +1 -1
  9. package/bundle/typescript/src/commands/game/sideQuest/commands/buy.js.map +1 -1
  10. package/bundle/typescript/src/commands/game/sideQuest/commands/call.js +28 -3
  11. package/bundle/typescript/src/commands/game/sideQuest/commands/call.js.map +1 -1
  12. package/bundle/typescript/src/commands/game/sideQuest/commands/cast.js +3 -1
  13. package/bundle/typescript/src/commands/game/sideQuest/commands/cast.js.map +1 -1
  14. package/bundle/typescript/src/commands/game/sideQuest/commands/catalog.d.ts +13 -0
  15. package/bundle/typescript/src/commands/game/sideQuest/commands/catalog.js +99 -0
  16. package/bundle/typescript/src/commands/game/sideQuest/commands/catalog.js.map +1 -0
  17. package/bundle/typescript/src/commands/game/sideQuest/commands/companions.js +12 -2
  18. package/bundle/typescript/src/commands/game/sideQuest/commands/companions.js.map +1 -1
  19. package/bundle/typescript/src/commands/game/sideQuest/commands/contacts.js +14 -8
  20. package/bundle/typescript/src/commands/game/sideQuest/commands/contacts.js.map +1 -1
  21. package/bundle/typescript/src/commands/game/sideQuest/commands/deck.d.ts +30 -0
  22. package/bundle/typescript/src/commands/game/sideQuest/commands/deck.js +142 -0
  23. package/bundle/typescript/src/commands/game/sideQuest/commands/deck.js.map +1 -0
  24. package/bundle/typescript/src/commands/game/sideQuest/commands/docwagon.d.ts +14 -0
  25. package/bundle/typescript/src/commands/game/sideQuest/commands/docwagon.js +87 -0
  26. package/bundle/typescript/src/commands/game/sideQuest/commands/docwagon.js.map +1 -0
  27. package/bundle/typescript/src/commands/game/sideQuest/commands/equipment.js +1 -1
  28. package/bundle/typescript/src/commands/game/sideQuest/commands/equipment.js.map +1 -1
  29. package/bundle/typescript/src/commands/game/sideQuest/commands/go.d.ts +11 -0
  30. package/bundle/typescript/src/commands/game/sideQuest/commands/go.js +29 -3
  31. package/bundle/typescript/src/commands/game/sideQuest/commands/go.js.map +1 -1
  32. package/bundle/typescript/src/commands/game/sideQuest/commands/grapple.js +9 -3
  33. package/bundle/typescript/src/commands/game/sideQuest/commands/grapple.js.map +1 -1
  34. package/bundle/typescript/src/commands/game/sideQuest/commands/hack.js +9 -5
  35. package/bundle/typescript/src/commands/game/sideQuest/commands/hack.js.map +1 -1
  36. package/bundle/typescript/src/commands/game/sideQuest/commands/haggle.js +5 -0
  37. package/bundle/typescript/src/commands/game/sideQuest/commands/haggle.js.map +1 -1
  38. package/bundle/typescript/src/commands/game/sideQuest/commands/initiate.js +7 -6
  39. package/bundle/typescript/src/commands/game/sideQuest/commands/initiate.js.map +1 -1
  40. package/bundle/typescript/src/commands/game/sideQuest/commands/install.js +4 -1
  41. package/bundle/typescript/src/commands/game/sideQuest/commands/install.js.map +1 -1
  42. package/bundle/typescript/src/commands/game/sideQuest/commands/job-offer.d.ts +32 -0
  43. package/bundle/typescript/src/commands/game/sideQuest/commands/job-offer.js +94 -0
  44. package/bundle/typescript/src/commands/game/sideQuest/commands/job-offer.js.map +1 -0
  45. package/bundle/typescript/src/commands/game/sideQuest/commands/jump.js +1 -1
  46. package/bundle/typescript/src/commands/game/sideQuest/commands/jump.js.map +1 -1
  47. package/bundle/typescript/src/commands/game/sideQuest/commands/lead.d.ts +39 -0
  48. package/bundle/typescript/src/commands/game/sideQuest/commands/lead.js +187 -0
  49. package/bundle/typescript/src/commands/game/sideQuest/commands/lead.js.map +1 -0
  50. package/bundle/typescript/src/commands/game/sideQuest/commands/palm.d.ts +16 -0
  51. package/bundle/typescript/src/commands/game/sideQuest/commands/palm.js +86 -0
  52. package/bundle/typescript/src/commands/game/sideQuest/commands/palm.js.map +1 -0
  53. package/bundle/typescript/src/commands/game/sideQuest/commands/pan.js +3 -2
  54. package/bundle/typescript/src/commands/game/sideQuest/commands/pan.js.map +1 -1
  55. package/bundle/typescript/src/commands/game/sideQuest/commands/perform.d.ts +13 -0
  56. package/bundle/typescript/src/commands/game/sideQuest/commands/perform.js +48 -0
  57. package/bundle/typescript/src/commands/game/sideQuest/commands/perform.js.map +1 -0
  58. package/bundle/typescript/src/commands/game/sideQuest/commands/quality-trade.js +8 -7
  59. package/bundle/typescript/src/commands/game/sideQuest/commands/quality-trade.js.map +1 -1
  60. package/bundle/typescript/src/commands/game/sideQuest/commands/rest.js +8 -3
  61. package/bundle/typescript/src/commands/game/sideQuest/commands/rest.js.map +1 -1
  62. package/bundle/typescript/src/commands/game/sideQuest/commands/search.js +9 -2
  63. package/bundle/typescript/src/commands/game/sideQuest/commands/search.js.map +1 -1
  64. package/bundle/typescript/src/commands/game/sideQuest/commands/sell.js +3 -2
  65. package/bundle/typescript/src/commands/game/sideQuest/commands/sell.js.map +1 -1
  66. package/bundle/typescript/src/commands/game/sideQuest/commands/sheet.d.ts +6 -4
  67. package/bundle/typescript/src/commands/game/sideQuest/commands/sheet.js +80 -65
  68. package/bundle/typescript/src/commands/game/sideQuest/commands/sheet.js.map +1 -1
  69. package/bundle/typescript/src/commands/game/sideQuest/commands/source.d.ts +11 -0
  70. package/bundle/typescript/src/commands/game/sideQuest/commands/source.js +176 -0
  71. package/bundle/typescript/src/commands/game/sideQuest/commands/source.js.map +1 -0
  72. package/bundle/typescript/src/commands/game/sideQuest/factories/scene-chunks.js +6 -3
  73. package/bundle/typescript/src/commands/game/sideQuest/factories/scene-chunks.js.map +1 -1
  74. package/bundle/typescript/src/commands/game/sideQuest/game.d.ts +71 -1
  75. package/bundle/typescript/src/commands/game/sideQuest/game.js +424 -29
  76. package/bundle/typescript/src/commands/game/sideQuest/game.js.map +1 -1
  77. package/bundle/typescript/src/commands/game/sideQuest/models/item.d.ts +28 -0
  78. package/bundle/typescript/src/commands/game/sideQuest/models/item.js +83 -0
  79. package/bundle/typescript/src/commands/game/sideQuest/models/item.js.map +1 -1
  80. package/bundle/typescript/src/commands/game/sideQuest/models/npc.js +29 -7
  81. package/bundle/typescript/src/commands/game/sideQuest/models/npc.js.map +1 -1
  82. package/bundle/typescript/src/commands/game/sideQuest/models/player.d.ts +23 -3
  83. package/bundle/typescript/src/commands/game/sideQuest/models/player.js +78 -17
  84. package/bundle/typescript/src/commands/game/sideQuest/models/player.js.map +1 -1
  85. package/bundle/typescript/src/commands/game/sideQuest/models/scene.js +7 -1
  86. package/bundle/typescript/src/commands/game/sideQuest/models/scene.js.map +1 -1
  87. package/bundle/typescript/src/commands/game/sideQuest/scenes/scene2.json +299 -60
  88. package/bundle/typescript/src/commands/game/sideQuest/types/save-file.d.ts +25 -0
  89. package/bundle/typescript/src/commands/game/sideQuest/ui.js +73 -3
  90. package/bundle/typescript/src/commands/game/sideQuest/ui.js.map +1 -1
  91. package/bundle/typescript/src/commands/game/sideQuest/utilities/catalog-data.d.ts +32 -0
  92. package/bundle/typescript/src/commands/game/sideQuest/utilities/catalog-data.js +112 -0
  93. package/bundle/typescript/src/commands/game/sideQuest/utilities/catalog-data.js.map +1 -0
  94. package/bundle/typescript/src/commands/game/sideQuest/utilities/catalog.d.ts +28 -0
  95. package/bundle/typescript/src/commands/game/sideQuest/utilities/catalog.js +128 -0
  96. package/bundle/typescript/src/commands/game/sideQuest/utilities/catalog.js.map +1 -0
  97. package/bundle/typescript/src/commands/game/sideQuest/utilities/combat-exchange.d.ts +3 -0
  98. package/bundle/typescript/src/commands/game/sideQuest/utilities/combat-exchange.js +41 -9
  99. package/bundle/typescript/src/commands/game/sideQuest/utilities/combat-exchange.js.map +1 -1
  100. package/bundle/typescript/src/commands/game/sideQuest/utilities/comm-style.d.ts +19 -0
  101. package/bundle/typescript/src/commands/game/sideQuest/utilities/comm-style.js +13 -0
  102. package/bundle/typescript/src/commands/game/sideQuest/utilities/comm-style.js.map +1 -1
  103. package/bundle/typescript/src/commands/game/sideQuest/utilities/docwagon.d.ts +33 -0
  104. package/bundle/typescript/src/commands/game/sideQuest/utilities/docwagon.js +44 -0
  105. package/bundle/typescript/src/commands/game/sideQuest/utilities/docwagon.js.map +1 -0
  106. package/bundle/typescript/src/commands/game/sideQuest/utilities/persistence.js +8 -0
  107. package/bundle/typescript/src/commands/game/sideQuest/utilities/persistence.js.map +1 -1
  108. package/bundle/typescript/src/commands/game/sideQuest/utilities/planes.d.ts +4 -2
  109. package/bundle/typescript/src/commands/game/sideQuest/utilities/planes.js +35 -4
  110. package/bundle/typescript/src/commands/game/sideQuest/utilities/planes.js.map +1 -1
  111. package/bundle/typescript/src/commands/game/sideQuest/utilities/programs.d.ts +39 -0
  112. package/bundle/typescript/src/commands/game/sideQuest/utilities/programs.js +63 -0
  113. package/bundle/typescript/src/commands/game/sideQuest/utilities/programs.js.map +1 -0
  114. package/bundle/typescript/src/commands/game/sideQuest/utilities/session-lock.d.ts +18 -0
  115. package/bundle/typescript/src/commands/game/sideQuest/utilities/session-lock.js +91 -0
  116. package/bundle/typescript/src/commands/game/sideQuest/utilities/session-lock.js.map +1 -0
  117. package/bundle/typescript/src/commands/game/sideQuest.sub.cmd.js +25 -16
  118. package/bundle/typescript/src/commands/game/sideQuest.sub.cmd.js.map +1 -1
  119. package/package.json +1 -1
@@ -12,7 +12,9 @@
12
12
  ],
13
13
  "currency": {
14
14
  "type": "nuyen",
15
- "authorityRoomTags": ["Bank"]
15
+ "authorityRoomTags": [
16
+ "Bank"
17
+ ]
16
18
  },
17
19
  "rumors": [
18
20
  "The Haze Dragons doubled their watch on the Smuggler's Tunnel -- something's moving under the district that even Brick won't name.",
@@ -143,7 +145,7 @@
143
145
  "color": "Black",
144
146
  "texture": "Rugged",
145
147
  "rating": "Common",
146
- "weight": 2.0
148
+ "weight": 2
147
149
  },
148
150
  {
149
151
  "name": "Knockoff Smart Glasses",
@@ -158,22 +160,38 @@
158
160
  }
159
161
  ]
160
162
  },
161
-
162
163
  "rooms": [
163
164
  {
164
165
  "name": "Neon Strip",
165
166
  "description": "The spine of the Purple Haze district: rain-slick pavement under a canopy of violet neon, food smoke, and AR graffiti three layers deep. Everyone you need is a block away in some direction.",
166
167
  "roomType": "Street",
167
- "tags": ["residence"],
168
+ "tags": [
169
+ "residence"
170
+ ],
168
171
  "supportedLifestyles": {
169
- "residenceTypes": ["Street", "Squatter"]
172
+ "residenceTypes": [
173
+ "Street",
174
+ "Squatter"
175
+ ]
170
176
  },
171
177
  "isStartRoom": true,
172
178
  "exits": [
173
- { "direction": "north", "targetRoom": "Purple Haze Bar" },
174
- { "direction": "east", "targetRoom": "Night Market" },
175
- { "direction": "south", "targetRoom": "Rain-Chewed Alley" },
176
- { "direction": "west", "targetRoom": "Mama Wu's Noodles" }
179
+ {
180
+ "direction": "north",
181
+ "targetRoom": "Purple Haze Bar"
182
+ },
183
+ {
184
+ "direction": "east",
185
+ "targetRoom": "Night Market"
186
+ },
187
+ {
188
+ "direction": "south",
189
+ "targetRoom": "Rain-Chewed Alley"
190
+ },
191
+ {
192
+ "direction": "west",
193
+ "targetRoom": "Mama Wu's Noodles"
194
+ }
177
195
  ]
178
196
  },
179
197
  {
@@ -182,13 +200,32 @@
182
200
  "roomType": "Bar",
183
201
  "size": "large",
184
202
  "spots": [
185
- { "name": "door", "description": "The street door, where the neon bleeds in." },
186
- { "name": "bar", "description": "The long counter, sticky with decades." },
187
- { "name": "booths", "description": "High-backed booths built for quiet deals.", "tags": ["cover-partial"] },
188
- { "name": "back corner", "description": "The dim table nobody chooses by accident." }
203
+ {
204
+ "name": "door",
205
+ "description": "The street door, where the neon bleeds in."
206
+ },
207
+ {
208
+ "name": "bar",
209
+ "description": "The long counter, sticky with decades."
210
+ },
211
+ {
212
+ "name": "booths",
213
+ "description": "High-backed booths built for quiet deals.",
214
+ "tags": [
215
+ "cover-partial"
216
+ ]
217
+ },
218
+ {
219
+ "name": "back corner",
220
+ "description": "The dim table nobody chooses by accident."
221
+ }
189
222
  ],
190
223
  "exits": [
191
- { "direction": "north", "targetRoom": "Bar Backroom", "atSpot": "back corner" }
224
+ {
225
+ "direction": "north",
226
+ "targetRoom": "Bar Backroom",
227
+ "atSpot": "back corner"
228
+ }
192
229
  ]
193
230
  },
194
231
  {
@@ -197,9 +234,15 @@
197
234
  "roomType": "Bar",
198
235
  "size": "small",
199
236
  "spots": [
200
- { "name": "door" },
201
- { "name": "card table" },
202
- { "name": "crates" }
237
+ {
238
+ "name": "door"
239
+ },
240
+ {
241
+ "name": "card table"
242
+ },
243
+ {
244
+ "name": "crates"
245
+ }
203
246
  ]
204
247
  },
205
248
  {
@@ -208,8 +251,14 @@
208
251
  "roomType": "Restaurant",
209
252
  "size": "small",
210
253
  "spots": [
211
- { "name": "door", "description": "A bead curtain and a blast of chili-scented steam." },
212
- { "name": "counter", "description": "Six stools and the pot that never empties." }
254
+ {
255
+ "name": "door",
256
+ "description": "A bead curtain and a blast of chili-scented steam."
257
+ },
258
+ {
259
+ "name": "counter",
260
+ "description": "Six stools and the pot that never empties."
261
+ }
213
262
  ]
214
263
  },
215
264
  {
@@ -218,14 +267,35 @@
218
267
  "roomType": "Market",
219
268
  "size": "large",
220
269
  "spots": [
221
- { "name": "entrance" },
222
- { "name": "stalls" },
223
- { "name": "shadowed edge", "tags": ["cover-partial"] }
270
+ {
271
+ "name": "entrance"
272
+ },
273
+ {
274
+ "name": "stalls"
275
+ },
276
+ {
277
+ "name": "shadowed edge",
278
+ "tags": [
279
+ "cover-partial"
280
+ ]
281
+ }
224
282
  ],
225
283
  "exits": [
226
- { "direction": "north", "targetRoom": "Ironmonger's Arms", "atSpot": "stalls" },
227
- { "direction": "east", "targetRoom": "Circuit Bazaar", "atSpot": "stalls" },
228
- { "direction": "south", "targetRoom": "Doc Halloran's Clinic", "atSpot": "stalls" }
284
+ {
285
+ "direction": "north",
286
+ "targetRoom": "Ironmonger's Arms",
287
+ "atSpot": "stalls"
288
+ },
289
+ {
290
+ "direction": "east",
291
+ "targetRoom": "Circuit Bazaar",
292
+ "atSpot": "stalls"
293
+ },
294
+ {
295
+ "direction": "south",
296
+ "targetRoom": "Doc Halloran's Clinic",
297
+ "atSpot": "stalls"
298
+ }
229
299
  ]
230
300
  },
231
301
  {
@@ -235,9 +305,15 @@
235
305
  "owner": "Torque",
236
306
  "size": "small",
237
307
  "spots": [
238
- { "name": "door" },
239
- { "name": "counter" },
240
- { "name": "racks" }
308
+ {
309
+ "name": "door"
310
+ },
311
+ {
312
+ "name": "counter"
313
+ },
314
+ {
315
+ "name": "racks"
316
+ }
241
317
  ]
242
318
  },
243
319
  {
@@ -248,12 +324,21 @@
248
324
  "hasNode": true,
249
325
  "size": "small",
250
326
  "spots": [
251
- { "name": "door" },
252
- { "name": "counter" },
253
- { "name": "workbenches" }
327
+ {
328
+ "name": "door"
329
+ },
330
+ {
331
+ "name": "counter"
332
+ },
333
+ {
334
+ "name": "workbenches"
335
+ }
254
336
  ],
255
337
  "exits": [
256
- { "direction": "east", "targetRoom": "Talismonger's Hut" }
338
+ {
339
+ "direction": "east",
340
+ "targetRoom": "Talismonger's Hut"
341
+ }
257
342
  ]
258
343
  },
259
344
  {
@@ -264,8 +349,12 @@
264
349
  "warded": true,
265
350
  "size": "small",
266
351
  "spots": [
267
- { "name": "doorway" },
268
- { "name": "altar table" }
352
+ {
353
+ "name": "doorway"
354
+ },
355
+ {
356
+ "name": "altar table"
357
+ }
269
358
  ]
270
359
  },
271
360
  {
@@ -275,9 +364,15 @@
275
364
  "owner": "Doc Halloran",
276
365
  "size": "small",
277
366
  "spots": [
278
- { "name": "door" },
279
- { "name": "cots" },
280
- { "name": "supply shelf" }
367
+ {
368
+ "name": "door"
369
+ },
370
+ {
371
+ "name": "cots"
372
+ },
373
+ {
374
+ "name": "supply shelf"
375
+ }
281
376
  ]
282
377
  },
283
378
  {
@@ -285,8 +380,14 @@
285
380
  "description": "The way down: an alley chewed ragged by decades of acid rain, its storm drains breathing cold air up from the undermarket below.",
286
381
  "roomType": "Street",
287
382
  "exits": [
288
- { "direction": "south", "targetRoom": "Flooded Undermarket" },
289
- { "direction": "east", "targetRoom": "Union Pawnshop" }
383
+ {
384
+ "direction": "south",
385
+ "targetRoom": "Flooded Undermarket"
386
+ },
387
+ {
388
+ "direction": "east",
389
+ "targetRoom": "Union Pawnshop"
390
+ }
290
391
  ]
291
392
  },
292
393
  {
@@ -296,9 +397,15 @@
296
397
  "owner": "Whisper",
297
398
  "size": "small",
298
399
  "spots": [
299
- { "name": "door" },
300
- { "name": "counter" },
301
- { "name": "back shelves" }
400
+ {
401
+ "name": "door"
402
+ },
403
+ {
404
+ "name": "counter"
405
+ },
406
+ {
407
+ "name": "back shelves"
408
+ }
302
409
  ]
303
410
  },
304
411
  {
@@ -307,13 +414,27 @@
307
414
  "roomType": "Market",
308
415
  "size": "large",
309
416
  "spots": [
310
- { "name": "entrance stair" },
311
- { "name": "stilted stalls" },
312
- { "name": "dry platforms" }
417
+ {
418
+ "name": "entrance stair"
419
+ },
420
+ {
421
+ "name": "stilted stalls"
422
+ },
423
+ {
424
+ "name": "dry platforms"
425
+ }
313
426
  ],
314
427
  "exits": [
315
- { "direction": "south", "targetRoom": "Smuggler's Tunnel", "atSpot": "stilted stalls" },
316
- { "direction": "west", "targetRoom": "Condemned Chapel", "atSpot": "dry platforms" }
428
+ {
429
+ "direction": "south",
430
+ "targetRoom": "Smuggler's Tunnel",
431
+ "atSpot": "stilted stalls"
432
+ },
433
+ {
434
+ "direction": "west",
435
+ "targetRoom": "Condemned Chapel",
436
+ "atSpot": "dry platforms"
437
+ }
317
438
  ]
318
439
  },
319
440
  {
@@ -321,8 +442,14 @@
321
442
  "description": "A bore of cracked ferrocrete running under the district, lit by chemlights and lined with cargo that never saw customs.",
322
443
  "roomType": "Tunnel",
323
444
  "exits": [
324
- { "direction": "east", "targetRoom": "Haze Dragons Turf" },
325
- { "direction": "south", "targetRoom": "Sim Den" }
445
+ {
446
+ "direction": "east",
447
+ "targetRoom": "Haze Dragons Turf"
448
+ },
449
+ {
450
+ "direction": "south",
451
+ "targetRoom": "Sim Den"
452
+ }
326
453
  ]
327
454
  },
328
455
  {
@@ -332,9 +459,18 @@
332
459
  "owner": "Brick",
333
460
  "size": "medium",
334
461
  "spots": [
335
- { "name": "gate" },
336
- { "name": "fire barrel" },
337
- { "name": "stacked crates", "tags": ["cover-partial"] }
462
+ {
463
+ "name": "gate"
464
+ },
465
+ {
466
+ "name": "fire barrel"
467
+ },
468
+ {
469
+ "name": "stacked crates",
470
+ "tags": [
471
+ "cover-partial"
472
+ ]
473
+ }
338
474
  ]
339
475
  },
340
476
  {
@@ -343,12 +479,23 @@
343
479
  "roomType": "Chapel",
344
480
  "size": "medium",
345
481
  "spots": [
346
- { "name": "doorway" },
347
- { "name": "nave" },
348
- { "name": "altar" }
482
+ {
483
+ "name": "doorway"
484
+ },
485
+ {
486
+ "name": "nave"
487
+ },
488
+ {
489
+ "name": "altar"
490
+ }
349
491
  ],
350
492
  "exits": [
351
- { "direction": "down", "targetRoom": "Chapel Crypt", "puzzle": "Crypt Grate", "atSpot": "altar" }
493
+ {
494
+ "direction": "down",
495
+ "targetRoom": "Chapel Crypt",
496
+ "puzzle": "Crypt Grate",
497
+ "atSpot": "altar"
498
+ }
352
499
  ]
353
500
  },
354
501
  {
@@ -357,8 +504,12 @@
357
504
  "roomType": "Crypt",
358
505
  "size": "small",
359
506
  "spots": [
360
- { "name": "entry stairs" },
361
- { "name": "reliquary niches" }
507
+ {
508
+ "name": "entry stairs"
509
+ },
510
+ {
511
+ "name": "reliquary niches"
512
+ }
362
513
  ]
363
514
  },
364
515
  {
@@ -369,8 +520,12 @@
369
520
  "nodeAccess": "wired",
370
521
  "size": "small",
371
522
  "spots": [
372
- { "name": "door" },
373
- { "name": "couch rows" }
523
+ {
524
+ "name": "door"
525
+ },
526
+ {
527
+ "name": "couch rows"
528
+ }
374
529
  ]
375
530
  },
376
531
  {
@@ -1208,6 +1363,90 @@
1208
1363
  "currencyAmount": 300,
1209
1364
  "room": "Chapel Crypt",
1210
1365
  "atSpot": "reliquary niches"
1366
+ },
1367
+ {
1368
+ "name": "Torque's Commlink",
1369
+ "description": "A ruggedized shop commlink, speed-dial worn down to the metal -- Torque answers for paying customers.",
1370
+ "size": "Small",
1371
+ "category": "Commlink",
1372
+ "shape": "Slab",
1373
+ "color": "Gunmetal",
1374
+ "texture": "Scarred Polymer",
1375
+ "rating": "Standard",
1376
+ "weight": 0.2,
1377
+ "heldBy": "Torque",
1378
+ "owner": "Torque",
1379
+ "transferable": false
1380
+ },
1381
+ {
1382
+ "name": "Ratchet's Commlink",
1383
+ "description": "A franken-link of three generations of parts that somehow outperforms all of them.",
1384
+ "size": "Small",
1385
+ "category": "Commlink",
1386
+ "shape": "Slab",
1387
+ "color": "Circuit Green",
1388
+ "texture": "Taped Seams",
1389
+ "rating": "Rare",
1390
+ "weight": 0.2,
1391
+ "heldBy": "Ratchet",
1392
+ "owner": "Ratchet",
1393
+ "transferable": false
1394
+ },
1395
+ {
1396
+ "name": "Halloran's Commlink",
1397
+ "description": "A clinic-grade commlink with a triage tone nobody in the district ignores.",
1398
+ "size": "Small",
1399
+ "category": "Commlink",
1400
+ "shape": "Slab",
1401
+ "color": "Bone White",
1402
+ "texture": "Antiseptic Plastic",
1403
+ "rating": "Standard",
1404
+ "weight": 0.2,
1405
+ "heldBy": "Doc Halloran",
1406
+ "owner": "Doc Halloran",
1407
+ "transferable": false
1408
+ },
1409
+ {
1410
+ "name": "Cray's Commlink",
1411
+ "description": "An ancient rigger deck stripped down to a talk-box -- the dead datajack port still blinks.",
1412
+ "size": "Small",
1413
+ "category": "Commlink",
1414
+ "shape": "Slab",
1415
+ "color": "Faded Orange",
1416
+ "texture": "Worn Rubber",
1417
+ "rating": "Common",
1418
+ "weight": 0.2,
1419
+ "heldBy": "Old Cray",
1420
+ "owner": "Old Cray",
1421
+ "transferable": false
1422
+ },
1423
+ {
1424
+ "name": "Skitter's Commlink",
1425
+ "description": "A knockoff commlink under three cracked screen protectors, ringtone set to a jingle.",
1426
+ "size": "Small",
1427
+ "category": "Commlink",
1428
+ "shape": "Slab",
1429
+ "color": "Neon Pink",
1430
+ "texture": "Sticker-Covered",
1431
+ "rating": "Common",
1432
+ "weight": 0.2,
1433
+ "heldBy": "Skitter",
1434
+ "owner": "Skitter",
1435
+ "transferable": false
1436
+ },
1437
+ {
1438
+ "name": "Whisper's Commlink",
1439
+ "description": "A pawned-and-reclaimed executive commlink, call log encrypted twice.",
1440
+ "size": "Small",
1441
+ "category": "Commlink",
1442
+ "shape": "Slab",
1443
+ "color": "Silver",
1444
+ "texture": "Polished Glass",
1445
+ "rating": "Standard",
1446
+ "weight": 0.2,
1447
+ "heldBy": "Whisper",
1448
+ "owner": "Whisper",
1449
+ "transferable": false
1211
1450
  }
1212
1451
  ],
1213
1452
  "puzzles": [
@@ -25,6 +25,9 @@ export interface ISavedItem extends IItemSeedJson {
25
25
  jammed?: boolean;
26
26
  deckDamage?: number;
27
27
  droneDamage?: number;
28
+ /** Cyberdeck runtime (p.227): programs in running memory + array deal. */
29
+ loadedPrograms?: string[];
30
+ deckOrder?: number[];
28
31
  }
29
32
  /**
30
33
  * Equipment layout keyed "group.slot" ("rightHand.weapon") -> the FULL
@@ -155,7 +158,29 @@ export interface ISavedGameState {
155
158
  spent: number;
156
159
  gigs: number;
157
160
  asked: boolean;
161
+ role?: string;
158
162
  }][];
163
+ /** SWAG orders in flight (commands/source.ts): paid, awaiting the
164
+ * next homecoming. Optional -- absent in pre-swag v1 saves. */
165
+ procurements?: {
166
+ contact: string;
167
+ itemConfig: ISavedItem;
168
+ price: number;
169
+ }[];
170
+ /** DocWagon contract (utilities/docwagon.ts). Optional -- uninsured. */
171
+ docwagon?: {
172
+ tier: string;
173
+ resuscsLeft: number;
174
+ homecomingsLeft: number;
175
+ };
176
+ /** Leadership's Command action (commands/lead.ts): the recruit riding
177
+ * the next run, and who refused you at what loyalty. */
178
+ enlistedAlly?: {
179
+ name: string;
180
+ description: string;
181
+ combat: Record<string, unknown>;
182
+ };
183
+ commandRefusals?: Record<string, number>;
159
184
  fencedCategories: string[];
160
185
  /** Rumor pool stays seed-sourced; only the cursor + active persist. */
161
186
  rumorIndex: number;
@@ -8,7 +8,17 @@ import { STANCE_CYCLE } from './models/player.js';
8
8
  import { AutoFight } from './utilities/auto-fight.js';
9
9
  import { TERMINAL_RESET_SEQUENCE } from './utilities/terminal-reset.js';
10
10
  import { readSave } from './utilities/persistence.js';
11
+ import { acquireSessionLock, releaseSessionLock } from './utilities/session-lock.js';
11
12
  import { SAVE_VERSION } from './types/save-file.js';
13
+ // MENU verbs (player direction): pure-reference panels render in the
14
+ // Mechanics column instead of the world log, keeping the narrative
15
+ // clean. Hybrid read/act verbs whose output is mostly reference (deck,
16
+ // qualities) ride along; transactional verbs (docwagon, buy, install)
17
+ // stay in the world log where actions belong.
18
+ const MENU_VERBS = new Set([
19
+ 'contacts', 'sheet', 'stats', 'inv', 'inventory', 'equipment', 'eq',
20
+ 'map', 'exits', 'spells', 'catalog', 'qualities', 'quality', 'deck', 'help',
21
+ ]);
12
22
  // Windows Terminal draws astral-plane emoji (📞 call icon, 📍 HUD pin,
13
23
  // 👥 companions, 💀) TWO columns wide, but blessed's 2015-era unicode
14
24
  // tables predate emoji being classified wide and count them as ONE. The
@@ -40,6 +50,26 @@ import { SAVE_VERSION } from './types/save-file.js';
40
50
  uni.chars.all = new RegExp(`(${uni.chars.all.source}|${pictographs})`, 'g');
41
51
  }
42
52
  export async function main(playerName, sceneSeed, options) {
53
+ // ONE TERMINAL PER RUNNER (see utilities/session-lock.ts): claim the
54
+ // save slot BEFORE blessed takes the terminal, so a refusal prints as
55
+ // plain text instead of flashing through a dying screen. The launcher
56
+ // already warned politely; this is the authoritative claim that wins
57
+ // the race two simultaneous launches would otherwise share. Released
58
+ // on EVERY exit path via the hook below; a crash leaves it to go
59
+ // stale (~90s) instead.
60
+ if (options.saveFilePath) {
61
+ const claim = acquireSessionLock(options.saveFilePath);
62
+ if (!claim.ok) {
63
+ console.error(`This runner is already jacked in from another terminal${claim.pid ? ` (PID ${claim.pid})` : ''}. One life, one session -- quit that one first.`);
64
+ process.exit(1);
65
+ }
66
+ process.on('exit', () => {
67
+ try {
68
+ releaseSessionLock(options.saveFilePath);
69
+ }
70
+ catch { /* never block the way out */ }
71
+ });
72
+ }
43
73
  // Create a screen object
44
74
  const screen = blessed.screen({
45
75
  smartCSR: true,
@@ -220,7 +250,14 @@ export async function main(playerName, sceneSeed, options) {
220
250
  // already land as the yellow speech line, and "> say hoi"
221
251
  // above "hoi" read as a stutter (playtest note).
222
252
  const echoVerb = input.trim().split(' ')[0]?.toLowerCase();
223
- if (input.trim().length > 0 && echoVerb !== 'clear') {
253
+ // MENU commands (player direction): reference panels render in
254
+ // the Mechanics column, not the world log -- the narrative
255
+ // stays narrative, and "contacts" doesn't scroll the fight off
256
+ // the screen. These verbs echo into the panel (as its divider)
257
+ // instead of the log. Transactional verbs (docwagon, buy...)
258
+ // stay in the world log: their output is things HAPPENING.
259
+ const isMenuVerb = MENU_VERBS.has(echoVerb ?? '');
260
+ if (input.trim().length > 0 && echoVerb !== 'clear' && !isMenuVerb) {
224
261
  game.logBox.pushLine('');
225
262
  if (echoVerb !== 'say') {
226
263
  game.logBox.pushLine(`{cyan-fg}> ${input.trim()}{/cyan-fg}`);
@@ -263,8 +300,41 @@ export async function main(playerName, sceneSeed, options) {
263
300
  // Empty responses stop printing blank filler -- the turn-block
264
301
  // echo above is the separator now.
265
302
  if (response) {
266
- game.logBox.pushLine(response);
267
- game.followLog();
303
+ // Route on the verb the game actually RAN, not the typed
304
+ // word: a corrected typo ("sjeet" -> "sheet") must still
305
+ // land its menu in the panel. The correction receipt line
306
+ // stays in the world log (standing ruling: it's the only
307
+ // receipt for a command you didn't type).
308
+ const ranMenuVerb = MENU_VERBS.has(game.lastResolvedVerb || echoVerb || '');
309
+ let panelBody = response;
310
+ if (ranMenuVerb && !isMenuVerb && response.startsWith('(read ')) {
311
+ const nl = response.indexOf('\n');
312
+ const receipt = nl === -1 ? response : response.slice(0, nl);
313
+ panelBody = nl === -1 ? '' : response.slice(nl + 1);
314
+ game.logBox.pushLine(receipt);
315
+ game.followLog();
316
+ }
317
+ if (ranMenuVerb && panelBody) {
318
+ // pushLine, NOT insertBottom: insertBottom targets the
319
+ // bottom of the VISIBLE view, and in a no-render loop it
320
+ // reuses the same index -- every menu rendered bottom-up
321
+ // (player screenshot). pushLine appends to the content.
322
+ // Divider names the command as RUN: typed args survive, a
323
+ // corrected verb replaces the typo'd one.
324
+ const dividerLabel = isMenuVerb
325
+ ? input.trim()
326
+ : [game.lastResolvedVerb, ...input.trim().split(' ').slice(1)].join(' ').trim();
327
+ game.metaBox.pushLine(`{blue-fg}── ${dividerLabel} ──{/blue-fg}`);
328
+ for (const line of panelBody.split('\n')) {
329
+ game.metaBox.pushLine(line);
330
+ }
331
+ game.metaBox.scrollTo(game.metaBox.getScrollHeight());
332
+ screen.render();
333
+ }
334
+ else if (!ranMenuVerb) {
335
+ game.logBox.pushLine(response);
336
+ game.followLog();
337
+ }
268
338
  }
269
339
  }
270
340
  catch (error) {