@maka/maka-cli 5.170.0 → 5.171.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.170.0",
3
+ "version": "5.171.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.",
@@ -157,6 +157,10 @@ Tailoring rules:
157
157
  - Never gate FINISHING the run behind a capability they lack: no matrix-plane winCondition
158
158
  item unless they can already jack in (deck or resonance) or a findable Cyberdeck is placed
159
159
  in a reachable room; no ward/"spell"-bypass-only route for someone who can't cast.
160
+ - The mirror of that rule: if they CAN jack in and the winCondition item is a Datachip or
161
+ Document, it is PAYDATA -- "plane": "matrix", in a hasNode room, with an ice NPC stationed
162
+ there. A hacker's file is never lying on a desk in the meat world; the host IS the job.
163
+ (A physical objective -- a person, a prototype, a briefcase -- stays physical.)
160
164
  - Don't hand them loot they can't use as a puzzle rewardItem or the winCondition rewardItem
161
165
  (spellcasting gear for an adept, a second cyberdeck or drone for someone who already has
162
166
  one). Useless-to-them gear may still exist as ordinary world dressing or valuables.
@@ -500,7 +504,9 @@ Hard structural rules (validated mechanically -- a violation is rejected):
500
504
  skill can still take the shortcut -- pick the lock, hack the panel -- but the found way
501
505
  must exist for a runner who has neither.
502
506
  - The winCondition item must not be heldBy winCondition.toNpc. If a matrix-plane item is the
503
- winCondition item, its room has hasNode true AND a "matrix"-plane NPC stationed there.
507
+ winCondition item, its room has hasNode true AND a "matrix"-plane NPC stationed there. If
508
+ the runner can jack in, a Datachip/Document winCondition item MUST be that matrix-plane
509
+ item -- data for a hacker lives on a host, never on a desk.
504
510
  - ${isContinuation
505
511
  ? 'ZERO "starting"-role items -- the runner arrives with everything they own. 4-6'
506
512
  : '3-5 "starting"-role items (basics the runner doesn\'t already own -- see the dossier), 4-6'}
@@ -763,6 +769,14 @@ export function partyCanDispel(player) {
763
769
  export function partyCanDeck(player) {
764
770
  return !!player && (player.isTechnomancer() || !!player.getCyberdeck());
765
771
  }
772
+ /** The item categories that ARE data: the only shapes paydata takes
773
+ * (schema: "matrix" = paydata, category Datachip/Document). A win item
774
+ * in one of these, for a runner who can deck, belongs on a host --
775
+ * see the rule in validateSkeleton (jfjjTmJ7NYwDaFiyB). */
776
+ export const DATA_ITEM_CATEGORIES = ['datachip', 'document'];
777
+ export function isDataShaped(category) {
778
+ return !!category && DATA_ITEM_CATEGORIES.includes(category.trim().toLowerCase());
779
+ }
766
780
  /**
767
781
  * WHAT KIND OF JOB IS ON THE TABLE.
768
782
  *
@@ -990,6 +1004,44 @@ export function validateSkeleton(skeleton, player, crew) {
990
1004
  fail(`winCondition.item "${skeleton.winCondition.item}" is not in items.`);
991
1005
  if (!npcNames.has(skeleton.winCondition.toNpc))
992
1006
  fail(`winCondition.toNpc "${skeleton.winCondition.toNpc}" is not in npcs.`);
1007
+ // A HACKER'S DATA LIVES ON A HOST (jfjjTmJ7NYwDaFiyB, Ted: "the
1008
+ // encrypted data chip was just laying there in the meat world...
1009
+ // hardly a fun run for a decker that never needs to attack a host,
1010
+ // get the data, download it, and get out"). The data-run brief only
1011
+ // fires on the DATA_RUN_SHARE roll; the other seven jobs in ten are
1012
+ // standard runs, and a standard run was free to make its objective a
1013
+ // Datachip on a desk -- for a runner whose whole toolkit is the
1014
+ // Matrix. So: whenever the runner CAN jack in and the objective is
1015
+ // data-shaped, it is paydata, and paydata sits inside a host with ice
1016
+ // on it. A runner who cannot deck keeps the chip on the desk (the
1017
+ // "never gate finishing" rule outranks this one), and a physical
1018
+ // objective -- a person, a prototype, a briefcase -- is untouched.
1019
+ //
1020
+ // Checked HERE, at the skeleton, and not left to validateMatrixDefense
1021
+ // (scene-seed-generator.ts): that one runs after the detail passes and
1022
+ // its wording routes to the items chunk through classifyRepair, which
1023
+ // cannot add a hasNode flag or an ice NPC -- the skeleton owns both.
1024
+ // Worded to route to 'skeleton' (no "items[", no "Win condition item").
1025
+ const winItem = skeleton.items.find(i => i.name === skeleton.winCondition.item);
1026
+ if (winItem && isDataShaped(winItem.category) && winItem.plane !== 'matrix' && partyCanDeck(player)) {
1027
+ fail(`the winCondition item "${winItem.name}" is a ${winItem.category} on the meat plane, and this runner can jack in -- for a decker or technomancer, data is PAYDATA: give it "plane": "matrix", place it in a hasNode room (not heldBy anyone), and station a "matrix"-plane NPC (ice) there. A chip lying on a desk is no job for a hacker.`);
1028
+ }
1029
+ // The other half of the same rule, for ANY matrix-plane objective: the
1030
+ // schema says its room has hasNode and an ice NPC stationed there, and
1031
+ // until now nothing at the skeleton checked it.
1032
+ if (winItem?.plane === 'matrix') {
1033
+ if (!winItem.room) {
1034
+ fail(`the winCondition item "${winItem.name}" is matrix-plane paydata but has no "room" -- data lives on a host, never in a pocket. Place it in a hasNode room.`);
1035
+ }
1036
+ const vault = skeleton.rooms.find(r => r.name === winItem.room);
1037
+ if (!vault?.hasNode) {
1038
+ fail(`the winCondition item "${winItem.name}" is matrix-plane paydata in "${winItem.room}", which has no "hasNode": true -- a matrix file can only exist on a host. Mark that room hasNode.`);
1039
+ }
1040
+ const ice = skeleton.npcs.some(n => n.plane === 'matrix' && n.startLocation === winItem.room);
1041
+ if (!ice) {
1042
+ fail(`the winCondition item "${winItem.name}" is matrix-plane paydata in hasNode room "${winItem.room}" with no ice guarding it -- station a "matrix"-plane NPC there. An undefended vault is a free win.`);
1043
+ }
1044
+ }
993
1045
  // Lock-and-key reachability. CRITICAL: edges are BIDIRECTIONAL -- the
994
1046
  // engine mirrors every declared exit into a shared two-way Door
995
1047
  // (room.addExit writes both sides), so a one-sided skeleton exit still
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@maka/maka-cli",
3
- "version": "5.170.0",
3
+ "version": "5.171.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.",