@maka/maka-cli 5.229.0 → 5.231.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.229.0",
3
+ "version": "5.231.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.",
@@ -35,17 +35,36 @@ export class PanCommand extends Command {
35
35
  }
36
36
  return this.dashboard();
37
37
  }
38
- /** One device on or off the network (p.233 -- slaving is a choice). */
39
- switchDevice(name, on) {
38
+ /**
39
+ * Everything on this runner the switch can reach, held and worn gear
40
+ * INCLUDED. Equipping moves an item out of `inventory.getAllItems()`,
41
+ * so a list built from inventory alone loses the gun in your hand --
42
+ * which is the one device a player is most likely to mute. Both the
43
+ * lookup and the "switched off" list read this, so a device you can
44
+ * turn off is always a device you can see is off.
45
+ */
46
+ reachableDevices() {
40
47
  const a = this.actor;
41
- if (!name)
42
- return `${on ? 'Link' : 'Unlink'} what? Try "pan ${on ? 'on' : 'off'} <device>".`;
43
- const candidates = [
48
+ const seen = new Set();
49
+ return [
44
50
  a.equipment.head?.commlink,
51
+ a.equipment.head?.eyes,
45
52
  a.equipment.rightHand?.weapon,
46
53
  a.equipment.leftHand?.weapon,
47
54
  ...a.inventory.getAllItems(),
48
- ].filter((i) => i != null);
55
+ ].filter((i) => {
56
+ if (i == null || seen.has(i))
57
+ return false;
58
+ seen.add(i);
59
+ return true;
60
+ });
61
+ }
62
+ /** One device on or off the network (p.233 -- slaving is a choice). */
63
+ switchDevice(name, on) {
64
+ const a = this.actor;
65
+ if (!name)
66
+ return `${on ? 'Link' : 'Unlink'} what? Try "pan ${on ? 'on' : 'off'} <device>".`;
67
+ const candidates = this.reachableDevices();
49
68
  const needle = name.toLowerCase();
50
69
  const item = candidates.find(i => i.name.toLowerCase() === needle)
51
70
  ?? candidates.find(i => i.name.toLowerCase().includes(needle));
@@ -85,7 +104,7 @@ export class PanCommand extends Command {
85
104
  const a = this.actor;
86
105
  const master = a.getPanMaster();
87
106
  if (!master) {
88
- const off = a.inventory.getAllItems().filter(i => !i.wirelessOn && Player.canJoinPan(i));
107
+ const off = this.reachableDevices().filter(i => !i.wirelessOn && Player.canJoinPan(i));
89
108
  if (off.length > 0) {
90
109
  // The honest reason, because "no PAN" reads like a bug when you
91
110
  // are holding a commlink you switched off yourself.
@@ -136,7 +155,7 @@ export class PanCommand extends Command {
136
155
  }
137
156
  // Anything deliberately switched off is listed too: a device you
138
157
  // cannot see on this screen is a device you will forget you muted.
139
- const off = [...a.inventory.getAllItems()].filter(i => !i.wirelessOn && Player.canJoinPan(i));
158
+ const off = this.reachableDevices().filter(i => !i.wirelessOn && Player.canJoinPan(i));
140
159
  if (off.length > 0) {
141
160
  lines.push('');
142
161
  lines.push('Switched off:');
@@ -997,10 +997,25 @@ export class Player extends AbstractPlayer {
997
997
  * not here and a smartgun is: the smartlink is the device.
998
998
  */
999
999
  panSlaves() {
1000
+ // Over capacity is the master's problem, not a silent truncation --
1001
+ // panOverflow() reports the excess so `pan` can say so out loud.
1002
+ return this.panCandidates().slice(0, this.panCapacity());
1003
+ }
1004
+ /** Slaves that do not fit under the master's (DR x 3) ceiling. */
1005
+ panOverflow() {
1006
+ return Math.max(0, this.panCandidates().length - this.panCapacity());
1007
+ }
1008
+ /**
1009
+ * Everything eligible to be a slave right now, master excluded. ONE
1010
+ * assembly for both readers above -- they disagreed in the first cut
1011
+ * (slaves counted worn gear, overflow counted only inventory), which
1012
+ * would have reported "0 over capacity" while quietly dropping the gun
1013
+ * in your hand off the end of the list.
1014
+ */
1015
+ panCandidates() {
1000
1016
  const master = this.getPanMaster();
1001
1017
  if (!master)
1002
1018
  return [];
1003
- const carried = this._inventory.getAllItems();
1004
1019
  const worn = [
1005
1020
  this._equipment.head?.commlink,
1006
1021
  this._equipment.rightHand?.weapon,
@@ -1008,7 +1023,7 @@ export class Player extends AbstractPlayer {
1008
1023
  ].filter((i) => i !== undefined && i !== null);
1009
1024
  const seen = new Set([master]);
1010
1025
  const out = [];
1011
- for (const item of [...worn, ...carried]) {
1026
+ for (const item of [...worn, ...this._inventory.getAllItems()]) {
1012
1027
  if (seen.has(item) || !item.wirelessOn)
1013
1028
  continue;
1014
1029
  if (!Player.canJoinPan(item))
@@ -1016,17 +1031,7 @@ export class Player extends AbstractPlayer {
1016
1031
  seen.add(item);
1017
1032
  out.push(item);
1018
1033
  }
1019
- // Over capacity is the master's problem, not a silent truncation --
1020
- // panOverflow() reports the excess so `pan` can say so out loud.
1021
- return out.slice(0, this.panCapacity());
1022
- }
1023
- /** Slaves that do not fit under the master's (DR x 3) ceiling. */
1024
- panOverflow() {
1025
- const master = this.getPanMaster();
1026
- if (!master)
1027
- return 0;
1028
- const wanted = this._inventory.getAllItems().filter(i => i !== master && i.wirelessOn && Player.canJoinPan(i)).length;
1029
- return Math.max(0, wanted - this.panCapacity());
1034
+ return out;
1030
1035
  }
1031
1036
  /** Whether an item is the kind of thing a PAN can hold at all (p.233:
1032
1037
  * "only devices can be slaves, masters, or part of a PAN"). */
@@ -1035,7 +1040,16 @@ export class Player extends AbstractPlayer {
1035
1040
  return true;
1036
1041
  if (item.isFirearm())
1037
1042
  return item.isSmartgun;
1038
- return item.category === Category.Drone || item.category === Category.Electronics;
1043
+ if (item.category === Category.Drone)
1044
+ return true;
1045
+ // ELECTRONICS ONLY IF IT IS ACTUALLY A DEVICE. p.233 is narrow --
1046
+ // "only devices can be slaves, masters, or part of a PAN" -- and
1047
+ // Category.Electronics is not: it is also where the survival kit,
1048
+ // the binoculars and a thermographic vision MOD live. A catalog row
1049
+ // that declares a `device` block is the engine's own record of
1050
+ // having a Device Rating, so that is the test. Without it the
1051
+ // dashboard listed a first-aid tin as hackable gear.
1052
+ return item.category === Category.Electronics && item.row?.device !== undefined;
1039
1053
  }
1040
1054
  /**
1041
1055
  * Defense against a PAN intrusion, itemised: the book's attribute plus
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@maka/maka-cli",
3
- "version": "5.229.0",
3
+ "version": "5.231.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.",