@maka/maka-cli 5.83.0 → 5.84.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 (49) hide show
  1. package/bundle/typescript/package.json +1 -1
  2. package/bundle/typescript/src/commands/game/sideQuest/commands/cast.js +7 -0
  3. package/bundle/typescript/src/commands/game/sideQuest/commands/cast.js.map +1 -1
  4. package/bundle/typescript/src/commands/game/sideQuest/commands/go.d.ts +3 -0
  5. package/bundle/typescript/src/commands/game/sideQuest/commands/go.js +23 -4
  6. package/bundle/typescript/src/commands/game/sideQuest/commands/go.js.map +1 -1
  7. package/bundle/typescript/src/commands/game/sideQuest/commands/heal.d.ts +53 -0
  8. package/bundle/typescript/src/commands/game/sideQuest/commands/heal.js +158 -0
  9. package/bundle/typescript/src/commands/game/sideQuest/commands/heal.js.map +1 -0
  10. package/bundle/typescript/src/commands/game/sideQuest/commands/sustain.d.ts +12 -0
  11. package/bundle/typescript/src/commands/game/sideQuest/commands/sustain.js +52 -2
  12. package/bundle/typescript/src/commands/game/sideQuest/commands/sustain.js.map +1 -1
  13. package/bundle/typescript/src/commands/game/sideQuest/commands/use.d.ts +17 -11
  14. package/bundle/typescript/src/commands/game/sideQuest/commands/use.js +45 -32
  15. package/bundle/typescript/src/commands/game/sideQuest/commands/use.js.map +1 -1
  16. package/bundle/typescript/src/commands/game/sideQuest/factories/scene-chunks.d.ts +34 -1
  17. package/bundle/typescript/src/commands/game/sideQuest/factories/scene-chunks.js +84 -6
  18. package/bundle/typescript/src/commands/game/sideQuest/factories/scene-chunks.js.map +1 -1
  19. package/bundle/typescript/src/commands/game/sideQuest/factories/scene-seed-generator.d.ts +9 -2
  20. package/bundle/typescript/src/commands/game/sideQuest/factories/scene-seed-generator.js +12 -5
  21. package/bundle/typescript/src/commands/game/sideQuest/factories/scene-seed-generator.js.map +1 -1
  22. package/bundle/typescript/src/commands/game/sideQuest/game.d.ts +8 -0
  23. package/bundle/typescript/src/commands/game/sideQuest/game.js +120 -3
  24. package/bundle/typescript/src/commands/game/sideQuest/game.js.map +1 -1
  25. package/bundle/typescript/src/commands/game/sideQuest/models/player.d.ts +16 -0
  26. package/bundle/typescript/src/commands/game/sideQuest/models/player.js +23 -0
  27. package/bundle/typescript/src/commands/game/sideQuest/models/player.js.map +1 -1
  28. package/bundle/typescript/src/commands/game/sideQuest/types/save-file.d.ts +8 -0
  29. package/bundle/typescript/src/commands/game/sideQuest/utilities/backlog-vocab.js +6 -0
  30. package/bundle/typescript/src/commands/game/sideQuest/utilities/backlog-vocab.js.map +1 -1
  31. package/bundle/typescript/src/commands/game/sideQuest/utilities/first-aid.d.ts +124 -0
  32. package/bundle/typescript/src/commands/game/sideQuest/utilities/first-aid.js +209 -0
  33. package/bundle/typescript/src/commands/game/sideQuest/utilities/first-aid.js.map +1 -0
  34. package/bundle/typescript/src/commands/game/sideQuest/utilities/persistence.js +9 -0
  35. package/bundle/typescript/src/commands/game/sideQuest/utilities/persistence.js.map +1 -1
  36. package/bundle/typescript/src/commands/game/sideQuest/utilities/planes.d.ts +57 -0
  37. package/bundle/typescript/src/commands/game/sideQuest/utilities/planes.js +121 -16
  38. package/bundle/typescript/src/commands/game/sideQuest/utilities/planes.js.map +1 -1
  39. package/bundle/typescript/src/commands/game/sideQuest/utilities/presence-gate.d.ts +21 -0
  40. package/bundle/typescript/src/commands/game/sideQuest/utilities/presence-gate.js +28 -0
  41. package/bundle/typescript/src/commands/game/sideQuest/utilities/presence-gate.js.map +1 -0
  42. package/bundle/typescript/src/commands/game/sideQuest/utilities/shared-run.d.ts +5 -0
  43. package/bundle/typescript/src/commands/game/sideQuest/utilities/shared-run.js +33 -0
  44. package/bundle/typescript/src/commands/game/sideQuest/utilities/shared-run.js.map +1 -1
  45. package/bundle/typescript/src/commands/game/sideQuest/utilities/web-character-generator.js +9 -1
  46. package/bundle/typescript/src/commands/game/sideQuest/utilities/web-character-generator.js.map +1 -1
  47. package/bundle/typescript/src/commands/game/sideQuest.sub.cmd.js +3 -1
  48. package/bundle/typescript/src/commands/game/sideQuest.sub.cmd.js.map +1 -1
  49. package/package.json +1 -1
@@ -9,6 +9,7 @@ import { Door } from './models/door.js';
9
9
  import { SAVE_VERSION } from './types/save-file.js';
10
10
  import { serializePlayer, restorePlayer, captureHubOverlay, applyHubOverlay, writeSaveAtomic, deleteSave, restoreItem, readSave, serializeItem, saveSlug, } from './utilities/persistence.js';
11
11
  import { heartbeatPresence, heartbeatPresenceNow } from './utilities/social.js';
12
+ import { presenceBeatAllowed } from './utilities/presence-gate.js';
12
13
  import { pushSave, burnCloudSaveFor } from './utilities/cloud-saves.js';
13
14
  import { DOCWAGON_TIERS, RESUSC_FEE, DEATH_COMP } from './utilities/docwagon.js';
14
15
  import { isFence, LIFESTYLE_TIERS } from './utilities/commerce.js';
@@ -127,6 +128,7 @@ import { JournalCommand } from './commands/journal.js';
127
128
  import { CoverCommand } from './commands/cover.js';
128
129
  import { PostureCommand, LieDownCommand, StandCommand } from './commands/posture.js';
129
130
  import { TreatCommand } from './commands/treat.js';
131
+ import { HealCommand } from './commands/heal.js';
130
132
  import { WorkCommand } from './commands/work.js';
131
133
  import { EatCommand } from './commands/eat.js';
132
134
  import { DrinkCommand } from './commands/drink.js';
@@ -529,8 +531,36 @@ export default class Game {
529
531
  }, 500);
530
532
  this._presenceEquipTimer.unref?.();
531
533
  }
534
+ /**
535
+ * Does this runner hold a LIVE SEAT right now -- riding at someone's
536
+ * table, or leading one that a real player sits at? Both sides are
537
+ * already tracked synchronously (HubLink.syncRiding fills ridingWith;
538
+ * the leader's live seats are liveOnly crew), so this needs no new
539
+ * state and no await.
540
+ */
541
+ holdsLiveSeat() {
542
+ return this.ridingWith.length > 0 || this.crew.some(m => m.ghost?.liveOnly);
543
+ }
532
544
  beatPresence() {
533
- if (!this.hasHub || this.scene !== this._hubScene)
545
+ if (!this.hasHub)
546
+ return;
547
+ // THE SEATED RUNNER DEFENDS ITS OWN PRESENCE DOC.
548
+ //
549
+ // This used to be `scene !== hubScene -> return`, on the reasonable
550
+ // ground that the run is nobody's business. But presence is not only
551
+ // the street's player list: the server reads the doc's SLUG to
552
+ // decide whose seats are still real, and a beat carrying a different
553
+ // slug dissolves an account's seats. So the one process that most
554
+ // needs to hold the doc -- a runner sitting in a live shared run --
555
+ // was the only one not beating, for the whole run. Any other beat on
556
+ // that account (a stale second terminal at its own hub, an older
557
+ // character) won the doc uncontested, and the seat was cut at
558
+ // heartbeat cadence with nothing printed on either side. Four
559
+ // reports, both sides of one table, twice in ten minutes.
560
+ //
561
+ // The rule itself lives in utilities/presence-gate.ts so it can be
562
+ // tested without a Game, a hub, or a socket.
563
+ if (!presenceBeatAllowed(this.scene === this._hubScene, this.holdsLiveSeat()))
534
564
  return;
535
565
  void heartbeatPresence(this.presencePayload());
536
566
  // The hub link rides the same pulse: a failed connect at boot must
@@ -2280,6 +2310,15 @@ ${client.name} won't be remembering anything. Dead Johnsons pay nothing -- and t
2280
2310
  CommandFactory.registerCommand('prone', LieDownCommand);
2281
2311
  CommandFactory.registerCommand('stand', StandCommand);
2282
2312
  CommandFactory.registerCommand('treat', TreatCommand);
2313
+ // FIRST AID, and the words a player actually reaches for. Every one
2314
+ // of these died at the parser before (see heal.ts): the mechanic was
2315
+ // real but only `use <medkit>` could reach it.
2316
+ CommandFactory.registerCommand('heal', HealCommand);
2317
+ CommandFactory.registerCommand('firstaid', HealCommand);
2318
+ CommandFactory.registerCommand('first', HealCommand); // "first aid"
2319
+ CommandFactory.registerCommand('bandage', HealCommand);
2320
+ CommandFactory.registerCommand('patch', HealCommand); // "patch up"
2321
+ CommandFactory.registerCommand('apply', HealCommand); // "apply first aid"
2283
2322
  CommandFactory.registerCommand('work', WorkCommand);
2284
2323
  CommandFactory.registerCommand('gig', WorkCommand);
2285
2324
  CommandFactory.registerCommand('haggle', HaggleCommand);
@@ -4471,6 +4510,80 @@ ${client.name} won't be remembering anything. Dead Johnsons pay nothing -- and t
4471
4510
  if (player.sustainedArmor > 0) {
4472
4511
  lines.push(`{magenta-fg}Sustained: armor +${player.sustainedArmor} soak (-2 dice to everything else){/magenta-fg}`);
4473
4512
  }
4513
+ // THE MAGE'S HALF OF THE SAME QUESTION (TNf9WrZGxCmCzqA4L, scope
4514
+ // completed by ruling).
4515
+ //
4516
+ // The item asked for threads, and threads got a line -- but
4517
+ // invisibility, increased reflexes and both barrier spells bill the
4518
+ // IDENTICAL -2 through the identical sustainingPenalty, and none of
4519
+ // them appeared anywhere. Only the armor spell had a line. So the
4520
+ // fix for one tradition left the other exactly where the report
4521
+ // found it, and the mage filing the same report later was a bill
4522
+ // already in the post.
4523
+ //
4524
+ // Armor and open astral senses keep their OWN lines, immediately
4525
+ // below: each carries something this one cannot (the soak value it
4526
+ // is buying, the verb that closes it). They are therefore excluded
4527
+ // here rather than duplicated -- no line ever counts the same -2
4528
+ // twice, which is the property that makes these totals readable at
4529
+ // all.
4530
+ //
4531
+ // DUMPSHOCK IS DELIBERATELY NOT HERE. It bills the same -2, but it
4532
+ // is damage done TO you, not a working you are holding up, and
4533
+ // "Sustained: dumpshock" would tell the player they can drop it.
4534
+ // Naming it belongs with the condition monitors if it belongs
4535
+ // anywhere; that is a separate call and not this item's.
4536
+ const heldSpells = [];
4537
+ if (player.sustainedInvisibility)
4538
+ heldSpells.push('invisibility');
4539
+ if (player.sustainedReflexes)
4540
+ heldSpells.push('increased reflexes');
4541
+ // The barriers say WHERE, because a wall you forgot you put up is
4542
+ // the one that strands the team -- and both of them seal an exit
4543
+ // that the caster cannot pass either.
4544
+ if (player.sustainedBarrier) {
4545
+ heldSpells.push(`physical barrier (${player.sustainedBarrier.roomName} ${player.sustainedBarrier.direction})`);
4546
+ }
4547
+ if (player.sustainedManaBarrier) {
4548
+ heldSpells.push(`mana barrier (${player.sustainedManaBarrier.roomName} ${player.sustainedManaBarrier.direction})`);
4549
+ }
4550
+ if (heldSpells.length > 0) {
4551
+ lines.push(`{magenta-fg}✴ Sustained: ${heldSpells.join(', ')} (-${heldSpells.length * 2} dice){/magenta-fg}`);
4552
+ }
4553
+ // ACTIVE THREADS, WITHOUT ASKING (TNf9WrZGxCmCzqA4L: "instead of
4554
+ // saying 'sustain' to see the active threads, list the threads in
4555
+ // the status area").
4556
+ //
4557
+ // A sustained form is a standing -2 on every pool the technomancer
4558
+ // rolls, which makes it exactly the kind of state the HUD exists for
4559
+ // -- the player was paying that price and had to type a command to
4560
+ // remember why. It sits with the other transient states rather than
4561
+ // on a line of its own, and only when something is actually woven.
4562
+ //
4563
+ // SPRITE-HELD FORMS RIDE ALONG, because they are half the answer the
4564
+ // `sustain` ledger gives and leaving them out would send the player
4565
+ // back to the command this replaces. They are listed apart from
4566
+ // yours on purpose: a form a sprite carries costs YOU nothing (p.256
4567
+ // -- it takes the -2 instead), so folding both into one dice total
4568
+ // would be a lie about the number that matters.
4569
+ //
4570
+ // The sprite keeps its full name, level suffix and all. It is longer
4571
+ // than the HUD would like, but it is what `sustain` prints and what
4572
+ // the player must type to take the form back -- and two sprites of
4573
+ // the same type are told apart by nothing else.
4574
+ const ownThreads = player.sustainedForms;
4575
+ const spriteHeld = player === this.player
4576
+ ? this.companions
4577
+ .filter(c => c.kind === 'sprite' && (c.npc.sustainedForms?.length ?? 0) > 0)
4578
+ .map(c => `${c.npc.name} holds ${c.npc.sustainedForms.map(f => f.key).join(', ')}`)
4579
+ : [];
4580
+ if (ownThreads.length > 0 || spriteHeld.length > 0) {
4581
+ const mine = ownThreads.length > 0
4582
+ ? `${ownThreads.map(f => f.key).join(', ')} (-${ownThreads.length * 2} dice)`
4583
+ : `none yourself`;
4584
+ const carried = spriteHeld.length > 0 ? ` | ${spriteHeld.join('; ')}` : '';
4585
+ lines.push(`{magenta-fg}✴ Threads: ${mine}${carried}{/magenta-fg}`);
4586
+ }
4474
4587
  if (player.astralPerceiving) {
4475
4588
  lines.push(`{magenta-fg}✧ ASTRAL SENSES OPEN (-2 dice sustained)${hint(' -- "assense" to close')}{/magenta-fg}`);
4476
4589
  }
@@ -4912,7 +5025,7 @@ ${client.name} won't be remembering anything. Dead Johnsons pay nothing -- and t
4912
5025
  static HELP_CATEGORIES = [
4913
5026
  { title: 'moving', entries: [['look'], ['go'], ['move', 'walk', 'approach'], ['run'], ['sprint'], ['climb', 'mantle', 'scale', 'clamber'], ['descend'], ['sit', 'kneel'], ['lie', 'prone'], ['stand'], ['follow'], ['unfollow'], ['map', 'exits'], ['search'], ['sneak']] },
4914
5027
  { title: 'gear', entries: [['inv', 'inventory'], ['equipment', 'eq'], ['take'], ['loot'], ['drop'], ['give'], ['store'], ['equip'], ['unequip'], ['brandish', 'draw'], ['holster', 'stow'], ['reload'], ['use'], ['read']] },
4915
- { title: 'combat', entries: [['attack'], ['kill'], ['subdue'], ['grapple', 'restrain', 'clinch'], ['struggle'], ['release'], ['cover'], ['stance'], ['surrender'], ['edge'], ['rest']] },
5028
+ { title: 'combat', entries: [['attack'], ['kill'], ['subdue'], ['grapple', 'restrain', 'clinch'], ['struggle'], ['release'], ['cover'], ['stance'], ['surrender'], ['edge'], ['rest'], ['heal', 'firstaid', 'bandage', 'patch']] },
4916
5029
  // The party layer: everyone who walks (or flies, or manifests) at
4917
5030
  // your side answers to these.
4918
5031
  // "players" folded back under crew after playtesting ("crew
@@ -4937,7 +5050,11 @@ ${client.name} won't be remembering anything. Dead Johnsons pay nothing -- and t
4937
5050
  * -- "crew players" is the advertised path; the bare verb still
4938
5051
  * answers). Without this, the uncategorized sweep resurrects them
4939
5052
  * in an "other" bucket. */
4940
- static HIDDEN_VERBS = ['players'];
5053
+ // 'first' and 'apply' exist ONLY to catch the two-word phrasings
5054
+ // ("first aid", "apply first aid") that used to die at the parser. As
5055
+ // bare words they mean nothing, so they are claimed but not advertised
5056
+ // -- `heal` is the verb the help screen teaches.
5057
+ static HIDDEN_VERBS = ['players', 'first', 'apply'];
4941
5058
  /** Session verbs that only a play-tester (or admin) can actually use
4942
5059
  * -- the server role-gates both and 403s everyone else. Listed in
4943
5060
  * help ONLY for a confirmed play-tester; see helpCategories. `roles`