@maka/maka-cli 5.133.0 → 5.134.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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@maka/maka-cli",
3
- "version": "5.133.0",
3
+ "version": "5.134.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.",
@@ -14,6 +14,7 @@ import { spotsActive, resolveSpot, spotOf, describeSpotRoster, OPEN_FLOOR, pathB
14
14
  // do fall a level.
15
15
  import { fallDamageDVMeters, climbHitsFor, climbMetersFrom, climbSurfaceModifier, METERS_PER_CELL, METERS_PER_LEVEL, key, distanceMeters } from '../utilities/room-grid.js';
16
16
  import { rollPool, formatRoll } from '../utilities/dice.js';
17
+ import { trailMaster } from '../utilities/companion-heel.js';
17
18
  /**
18
19
  * "walk to <spot>" / "run to <spot>" / "sprint to <spot>" -- crossing
19
20
  * the CURRENT room to one of its "at" spots (see utilities/spots.ts;
@@ -101,6 +102,15 @@ export class MoveCommand extends Command {
101
102
  }
102
103
  return `Spots are a meat-world concern -- on the grid there is no distance at all, so "go <room>" puts your persona anywhere by name.`;
103
104
  }
105
+ /** Your shells trail you across the room (companion-heel.ts
106
+ * trailMaster): after every in-room move they re-place themselves
107
+ * beside you. An NPC mover has no Game in its context and drags
108
+ * nobody. */
109
+ trailCompanions() {
110
+ if (!this.game)
111
+ return;
112
+ trailMaster(this.actor, this.game.companions);
113
+ }
104
114
  async execute(args = []) {
105
115
  const actor = this.actor;
106
116
  const room = actor.currentLocation;
@@ -633,6 +643,7 @@ export class MoveCommand extends Command {
633
643
  // an NPC's own spot is a social event for them (the bartender greets
634
644
  // you when you reach the bar).
635
645
  actor.performAction('moves to', `the ${spot.name}`);
646
+ this.trailCompanions();
636
647
  this.logger.write(`MoveCommand: ${actor.name} ${this.mode()}s to ${spot.name} in ${room.name}.`);
637
648
  // Companions drift along with their master (go.ts follow precedent).
638
649
  if (actor === this.scene.getPlayer() && this.game) {
@@ -762,6 +773,7 @@ export class MoveCommand extends Command {
762
773
  // A shell of yours on that square steps aside (spots.ts heelsTo).
763
774
  yieldSquareToMaster(room, actor);
764
775
  actor.performAction('steps', `${taken} ${taken === 1 ? 'pace' : 'paces'} ${direction}`);
776
+ this.trailCompanions();
765
777
  this.scene.updateStatus();
766
778
  this.scene.updateExits(room);
767
779
  // QUIET STEPS (user, 2026-09-01: "You step 1 pace east" is spammy now
@@ -867,6 +879,7 @@ export class MoveCommand extends Command {
867
879
  actor.atCell = cell;
868
880
  actor.atSpot = spotForCell(room, cell);
869
881
  actor.performAction('steps up beside', target.name);
882
+ this.trailCompanions();
870
883
  this.scene.updateStatus();
871
884
  this.scene.updateExits(room);
872
885
  const pace = actor.isRunningThisTurn ? ` You're running now -- everything else this turn is at -2.` : '';
@@ -1016,6 +1029,7 @@ export class MoveCommand extends Command {
1016
1029
  actor.atCell = cell;
1017
1030
  actor.atSpot = spotForCell(room, cell);
1018
1031
  actor.performAction('moves to', `the ${direction} doorway`);
1032
+ this.trailCompanions();
1019
1033
  this.scene.updateStatus();
1020
1034
  this.scene.updateExits(room);
1021
1035
  return `You cross to the ${direction} way out.${hint(` ("go ${direction}" to step through.)`)}`;
@@ -353,5 +353,11 @@
353
353
  // garage-born or not (it used to answer "no drone in your pack" away from
354
354
  // the hideout). An NPC with no dialogue and no AI no longer greets you
355
355
  // with "<name>: undefined".
356
- export const ENGINE_VERSION = '1.38.0';
356
+ // 1.39.0 (2026-09-06): COMPANIONS TRAIL YOU ACROSS THE ROOM. COMMAND SEMANTICS
357
+ // in shared scenes: every in-room move ("move <direction>", "move to
358
+ // <spot>", the doorway) re-places your shells on the nearest free square
359
+ // beside you (companion-heel.ts trailMaster) -- they used to heel only on
360
+ // a room change and sat in the doorway while you paced. "recall" judges
361
+ // "already at your side" by cells, not spot names.
362
+ export const ENGINE_VERSION = '1.39.0';
357
363
  //# sourceMappingURL=engine-version.js.map
@@ -1,22 +1,80 @@
1
+ import { actorCell, standingRoomNear, onTheFloor, heelsTo } from './spots.js';
2
+ /** Chebyshev distance in cells, or undefined when either has no cell. */
3
+ function cellGap(room, a, b) {
4
+ const ca = actorCell(room, a);
5
+ const cb = actorCell(room, b);
6
+ if (!ca || !cb)
7
+ return undefined;
8
+ return Math.max(Math.abs(ca.x - cb.x), Math.abs(ca.y - cb.y), Math.abs(ca.z - cb.z));
9
+ }
10
+ /** Is the shell beside its master -- same room, same spot, and at most
11
+ * one square away (or on a room with no grid to measure)? */
12
+ export function atMastersSide(entry, master) {
13
+ const room = master.currentLocation;
14
+ if (entry.npc.currentLocation !== room || entry.npc.atSpot !== master.atSpot)
15
+ return false;
16
+ const gap = cellGap(room, entry.npc, master);
17
+ return gap === undefined || gap <= 1;
18
+ }
19
+ /** Put the shell on the nearest free square beside its master, at the
20
+ * master's spot. */
21
+ export function placeBeside(entry, master) {
22
+ const room = master.currentLocation;
23
+ if (entry.npc.currentLocation !== room)
24
+ entry.npc.currentLocation = room;
25
+ entry.npc.atSpot = master.atSpot;
26
+ const here = actorCell(room, master);
27
+ entry.npc.atCell = here ? standingRoomNear(room, here, entry.npc) : undefined;
28
+ }
1
29
  /**
2
30
  * BRING A COMPANION TO HEEL (player ruling 2026-09-06: "recall" is
3
31
  * "return to me" -- the frame comes to your side and follows again;
4
32
  * putting it away is "stow"). The shell crosses to the master's room
5
- * and spot, its cell is released so seating finds it a place beside
6
- * them, and any HOLDING flag clears so the next "go" drags it along
7
- * like any companion. Returns whether it had anywhere to come from.
33
+ * and spot, takes the nearest free square beside them, and any HOLDING
34
+ * flag clears so the next move drags it along like any companion.
35
+ * Returns whether it had anywhere to come from -- judged by CELLS, not
36
+ * spot names: a frame eight squares off on the same open floor shares
37
+ * the spot name and is not "at your side" (transcript 2026-09-06).
8
38
  *
9
39
  * One function, used by Game.heelCompanion and by the tests that pin
10
40
  * recall, so a mock Game and the real one cannot disagree about it.
11
41
  */
12
42
  export function bringToHeel(entry, master) {
13
- const here = master.currentLocation;
14
- const moved = entry.npc.currentLocation !== here || entry.npc.atSpot !== master.atSpot || !!entry.holding;
15
- if (entry.npc.currentLocation !== here)
16
- entry.npc.currentLocation = here;
17
- entry.npc.atSpot = master.atSpot;
18
- entry.npc.atCell = undefined;
43
+ const moved = !!entry.holding || !atMastersSide(entry, master);
44
+ placeBeside(entry, master);
19
45
  entry.holding = false;
20
46
  return { moved };
21
47
  }
48
+ /**
49
+ * COMPANIONS TRAIL THEIR MASTER ACROSS THE ROOM (playtest 2026-09-06:
50
+ * "It will follow to another room, but then just sit at the door").
51
+ * go.ts heels every shell on a ROOM change; nothing did on an in-room
52
+ * move, so a rigger who paced eight squares across the Neon Strip left
53
+ * the frame parked in the doorway. Called after every successful
54
+ * in-room move (move.ts): each shell of the mover's that is on the
55
+ * floor here, not HOLDING and not hired crew, is re-placed beside them.
56
+ * The frame answers to the meat body only (go.ts HEELS_ON): a rigger
57
+ * flying one frame does not drag the others around.
58
+ */
59
+ export function trailMaster(master, entries) {
60
+ if (master.plane !== 'meat')
61
+ return [];
62
+ const room = master.currentLocation;
63
+ const moved = [];
64
+ for (const entry of entries) {
65
+ if (entry.holding || entry.kind === 'ally')
66
+ continue;
67
+ if (!heelsTo(entry.npc, master))
68
+ continue;
69
+ if (entry.npc.currentLocation !== room || !onTheFloor(entry.npc))
70
+ continue;
71
+ if (entry.npc.isIncapacitated() || entry.npc.inExchange)
72
+ continue;
73
+ if (atMastersSide(entry, master))
74
+ continue;
75
+ placeBeside(entry, master);
76
+ moved.push(entry.npc);
77
+ }
78
+ return moved;
79
+ }
22
80
  //# sourceMappingURL=companion-heel.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@maka/maka-cli",
3
- "version": "5.133.0",
3
+ "version": "5.134.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.",