@maka/maka-cli 5.150.0 → 5.152.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.
- package/bundle/typescript/package.json +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/look.js +27 -8
- package/bundle/typescript/src/commands/game/sideQuest/commands/take.js +22 -0
- package/bundle/typescript/src/commands/game/sideQuest/game.js +27 -0
- package/bundle/typescript/src/commands/game/sideQuest/models/npc.js +10 -0
- package/bundle/typescript/src/commands/game/sideQuest/models/player.js +31 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/ar.js +11 -4
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@maka/maka-cli",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.152.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.",
|
|
@@ -66,6 +66,30 @@ export class LookCommand extends Command {
|
|
|
66
66
|
return this.inspectItem(carried.name, this.actor.inventory);
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
|
+
// AN EXACT NAME BEATS A FUZZY ITEM SUBSTRING (Sjjy52mjSqSdjFGdg:
|
|
70
|
+
// "look Jo" resolved to "Certified Credstick (job payments)" --
|
|
71
|
+
// Inventory.resolveKey does deliberately generous substring
|
|
72
|
+
// matching for item-name typos ("jo" sits inside "job payments"),
|
|
73
|
+
// and that ran before the room's actor list was ever consulted.
|
|
74
|
+
// A present person's EXACT name is a far stronger signal than an
|
|
75
|
+
// incidental item substring, so it wins first; an inexact query
|
|
76
|
+
// still falls through to the item/direction ladder below exactly
|
|
77
|
+
// as before.
|
|
78
|
+
// AN EXACT NAME BEATS A FUZZY ITEM SUBSTRING (Sjjy52mjSqSdjFGdg:
|
|
79
|
+
// "look Jo" resolved to "Certified Credstick (job payments)" --
|
|
80
|
+
// Inventory.resolveKey does deliberately generous substring
|
|
81
|
+
// matching for item-name typos ("jo" sits inside "job payments"),
|
|
82
|
+
// and that ran before the room's actor list was ever consulted.
|
|
83
|
+
// A present person's EXACT name is a far stronger signal than an
|
|
84
|
+
// incidental item substring, so it wins first; an inexact query
|
|
85
|
+
// still falls through to the item/direction ladder below exactly
|
|
86
|
+
// as before.
|
|
87
|
+
const exactActorMatch = this.scene
|
|
88
|
+
.getActorsInRoom(this.actor.currentLocation)
|
|
89
|
+
.find(a => a.name.toLowerCase() === target.toLowerCase() && this.actor.canPerceive(a));
|
|
90
|
+
if (exactActorMatch) {
|
|
91
|
+
return this.inspectActor(exactActorMatch.name);
|
|
92
|
+
}
|
|
69
93
|
if (this.actor.inventory.hasItem(target)) {
|
|
70
94
|
this.logger.write(`Looking at item '${target}' in ${this.actor.name} inventory.`);
|
|
71
95
|
return this.inspectItem(target, this.actor.inventory);
|
|
@@ -79,14 +103,9 @@ export class LookCommand extends Command {
|
|
|
79
103
|
return this.lookOutside(target);
|
|
80
104
|
}
|
|
81
105
|
else {
|
|
82
|
-
//
|
|
83
|
-
//
|
|
84
|
-
|
|
85
|
-
.getActorsInRoom(this.actor.currentLocation)
|
|
86
|
-
.find(a => a.name.toLowerCase() === target.toLowerCase() && this.actor.canPerceive(a));
|
|
87
|
-
if (actorMatch) {
|
|
88
|
-
return this.inspectActor(actorMatch.name);
|
|
89
|
-
}
|
|
106
|
+
// The exact-name actor check above already covers a present
|
|
107
|
+
// person; reaching here means the target is neither an item,
|
|
108
|
+
// a direction, nor anyone in the room by that exact name.
|
|
90
109
|
return `You cannot see ${target}`;
|
|
91
110
|
}
|
|
92
111
|
}
|
|
@@ -88,6 +88,10 @@ export class TakeCommand extends Command {
|
|
|
88
88
|
taken.push(item.name);
|
|
89
89
|
}
|
|
90
90
|
}
|
|
91
|
+
// Same durable-change rule as the loose-floor pickups below
|
|
92
|
+
// (RKLbzxQQRJk8eD8Az) -- only when something actually moved.
|
|
93
|
+
if (taken.length > 0)
|
|
94
|
+
this.game?.requestSave('take');
|
|
91
95
|
const lines = [taken.length > 0 ? `${prefix}You take ${taken.join(', ')} from the ${container.name}.` : `${prefix}You take nothing from the ${container.name}.`, ...left];
|
|
92
96
|
return lines.join('\n');
|
|
93
97
|
}
|
|
@@ -100,6 +104,7 @@ export class TakeCommand extends Command {
|
|
|
100
104
|
if (!container.inventory.transferItemTo(item.name.toLowerCase(), this.actor.inventory)) {
|
|
101
105
|
return `${prefix}You can't lift the ${item.name} right now.`;
|
|
102
106
|
}
|
|
107
|
+
this.game?.requestSave('take');
|
|
103
108
|
this.actor.performAction('takes', `${item.name} from the ${container.name}`);
|
|
104
109
|
return `${prefix}You take the ${item.name} from the ${container.name}.`;
|
|
105
110
|
}
|
|
@@ -223,6 +228,14 @@ export class TakeCommand extends Command {
|
|
|
223
228
|
}
|
|
224
229
|
if (tookAnything) {
|
|
225
230
|
this.scene.updateInventory(this.scene.getPlayer().inventory);
|
|
231
|
+
// A PICKUP IS A DURABLE CHANGE (RKLbzxQQRJk8eD8Az: "I picked up
|
|
232
|
+
// the 'Ferret's ledger Service Log', but I don't see it reflected
|
|
233
|
+
// in the character sheet"). buy.ts's own fix comment named this
|
|
234
|
+
// file as a sibling that never learned the lesson (vR8ajvm3wXdexxdF2)
|
|
235
|
+
// -- the web sheet reads the last SAVED snapshot, and nothing here
|
|
236
|
+
// ever asked for one, so a swept haul sat invisible until the next
|
|
237
|
+
// unrelated save beat (homecoming, rest, a trade).
|
|
238
|
+
this.game?.requestSave('take');
|
|
226
239
|
}
|
|
227
240
|
// Win-condition checks run AFTER the sweep summary renders: the check
|
|
228
241
|
// logs the JOB COMPLETE banner itself, and running it per-item used to
|
|
@@ -363,6 +376,15 @@ export class TakeCommand extends Command {
|
|
|
363
376
|
room.inventory.removeItem(itemName);
|
|
364
377
|
room.plainSightItems.delete(item.name.toLowerCase());
|
|
365
378
|
this.logger.write(`Successfully removed "${itemName}" from ${room.name} room's inventory during 'Take' command.`);
|
|
379
|
+
// A PICKUP IS A DURABLE CHANGE (RKLbzxQQRJk8eD8Az: "I picked up
|
|
380
|
+
// the 'Ferret's ledger Service Log', but I don't see it reflected
|
|
381
|
+
// in the character sheet"). buy.ts's own fix comment named this
|
|
382
|
+
// file as a sibling that never learned the lesson (vR8ajvm3wXdexxdF2)
|
|
383
|
+
// -- the web sheet reads the last SAVED snapshot, and nothing here
|
|
384
|
+
// ever asked for one. Placed after the item has actually changed
|
|
385
|
+
// hands (the try's own catch below handles a too-heavy rollback
|
|
386
|
+
// before this line is ever reached), same rule as buy.ts/unequip.ts.
|
|
387
|
+
this.game?.requestSave('take');
|
|
366
388
|
// Possession-based win condition: if some OTHER actor ends up with
|
|
367
389
|
// the item the win condition's target NPC wants, that counts just as
|
|
368
390
|
// much as the player handing it over directly (emergent delivery).
|
|
@@ -552,6 +552,33 @@ export default class Game {
|
|
|
552
552
|
return `{yellow-fg}🔥 Heat: ears up all over the block{/yellow-fg}`;
|
|
553
553
|
return `{yellow-fg}🔥 Heat: somebody heard something{/yellow-fg}`;
|
|
554
554
|
}
|
|
555
|
+
/**
|
|
556
|
+
* THE SAME BAND, FOR AN NPC'S MOUTH (YE9G3Q5P85y5xcP7n: "Mr. Ibis said
|
|
557
|
+
* 'Quiet as promised' however, there's a status of: 🔥 Heat: sirens
|
|
558
|
+
* circling closer"). heatBand() paints the player's own HUD; nothing
|
|
559
|
+
* fed the run's actual heat into NPC.respondTo's prompt at all, so an
|
|
560
|
+
* NPC narrating "the coast is clear" had no way to know it wasn't --
|
|
561
|
+
* the same shape as payoutSummary's fix for an invented payout, here
|
|
562
|
+
* for an invented all-clear.
|
|
563
|
+
*
|
|
564
|
+
* DELIBERATELY NOT ITS OWN THRESHOLDS. heat-band-honesty.test.ts pins
|
|
565
|
+
* the top band's heat check to the ONE line inside heatBand(), on
|
|
566
|
+
* purpose: the HUD's promise and checkpointOnRideHome's verifierDice
|
|
567
|
+
* escalation share that number so they cannot drift apart. A second
|
|
568
|
+
* copy of the same comparison here for the AI prompt would be exactly
|
|
569
|
+
* the drift that guard exists to catch. So this reads heatBand()'s OWN
|
|
570
|
+
* text -- strip the color codes and the HUD's "🔥 Heat: " lede, and
|
|
571
|
+
* what is left is plain enough for a prompt -- rather than re-deriving
|
|
572
|
+
* the bands.
|
|
573
|
+
*/
|
|
574
|
+
heatSummaryForDialogue() {
|
|
575
|
+
if (!this.onRun)
|
|
576
|
+
return undefined;
|
|
577
|
+
const band = this.heatBand();
|
|
578
|
+
if (!band)
|
|
579
|
+
return undefined;
|
|
580
|
+
return band.replace(/\{[^}]*\}/g, '').replace(/^🔥\s*Heat:\s*/, '');
|
|
581
|
+
}
|
|
555
582
|
// THE FOR-HIRE BOARD: archetype-built candidates, fresh faces each
|
|
556
583
|
// homecoming (the gig-pool rotation school). Not saved -- the street's
|
|
557
584
|
// talent pool churns; whoever you HIRED is the persistent part.
|
|
@@ -1660,6 +1660,15 @@ ${worldEventsSummary}
|
|
|
1660
1660
|
const payoutSummary = payout
|
|
1661
1661
|
? `The agreed payout for the current job is EXACTLY ${payout} nuyen, paid as ONE LUMP SUM on delivery -- there is no advance and no half up front; never speak as if part has already been paid. Any time you mention payment, reward, or what the job is worth, use exactly this figure -- never invent a different one. Payment transfers automatically when the job completes; you never need to hand it over.`
|
|
1662
1662
|
: '';
|
|
1663
|
+
// HEAT IS MECHANICALLY REAL TOO (YE9G3Q5P85y5xcP7n: an NPC said
|
|
1664
|
+
// "Quiet as promised" while the player's own HUD read "Heat: sirens
|
|
1665
|
+
// circling closer"). Same shape as payoutSummary above -- nothing
|
|
1666
|
+
// told the model the run's actual heat, so a reassuring line had
|
|
1667
|
+
// nothing to check itself against.
|
|
1668
|
+
const heat = this._scene?.ownerGame?.heatSummaryForDialogue?.();
|
|
1669
|
+
const heatSummary = heat
|
|
1670
|
+
? `The district's current HEAT on this run is ${heat}. If you would naturally reassure them that things are quiet, clean, or under control, that claim has to be TRUE against this -- never tell them the coast is clear, that nobody noticed, or that things went quiet if heat says otherwise. Speak honestly about how hot it actually is instead.`
|
|
1671
|
+
: '';
|
|
1663
1672
|
// If nothing else has happened to/around this NPC yet this scene, this
|
|
1664
1673
|
// is the first time anyone's reached out -- nudge toward volunteering
|
|
1665
1674
|
// the job rather than waiting to be asked, which real playtesting
|
|
@@ -2103,6 +2112,7 @@ Your objective is to drive the story line.`}
|
|
|
2103
2112
|
${eph ? '' : objectiveSummary}
|
|
2104
2113
|
${dialogueSummary}
|
|
2105
2114
|
${eph ? '' : payoutSummary}
|
|
2115
|
+
${eph ? '' : heatSummary}
|
|
2106
2116
|
|
|
2107
2117
|
${roomDesc}${spotBlock}${combatSpatialBlock}
|
|
2108
2118
|
${formattedExitsStr}
|
|
@@ -652,7 +652,37 @@ export class Player extends AbstractPlayer {
|
|
|
652
652
|
return true;
|
|
653
653
|
if (this.arOffline)
|
|
654
654
|
return false;
|
|
655
|
-
|
|
655
|
+
if (!this.getPanMaster())
|
|
656
|
+
return false;
|
|
657
|
+
return this.hasARDisplay();
|
|
658
|
+
}
|
|
659
|
+
/**
|
|
660
|
+
* THE MISSING HALF OF AR (canon p.53-54/221-222, RAG-checked
|
|
661
|
+
* 2026-09-10, acBi46ZKKJCPyBKXb: "it looks like I'm able to see AR
|
|
662
|
+
* with the Hermes Ikon, however, I don't have a method to interface
|
|
663
|
+
* to it -- no trode, or commlink jack. I think this is a gap"). It
|
|
664
|
+
* was: "a commlink alone does not automatically give you AR -- the
|
|
665
|
+
* commlink processes and sends the information, but you still need a
|
|
666
|
+
* display device to receive it." hasMatrixEyes gated ONLY on a
|
|
667
|
+
* PAN master existing, never on having any way to actually SEE what
|
|
668
|
+
* it sends -- so a runner with a commlink in their pocket and nothing
|
|
669
|
+
* on their face or in their skull got the full overlay regardless.
|
|
670
|
+
*
|
|
671
|
+
* Two independent roads in, matching what the rulebook actually lists:
|
|
672
|
+
* a DNI (trodes/datajack/technomancer -- Player.hasDirectNeuralInterface,
|
|
673
|
+
* "you can use all your senses to view AR without any extra devices"),
|
|
674
|
+
* or a worn visual display (cybereyes, glasses, goggles, contacts --
|
|
675
|
+
* same head.eyes slot and same two categories smartlink detection
|
|
676
|
+
* already reads, Category.Glasses / Category.EyeCyberwere). Audio-only
|
|
677
|
+
* and haptic-only AROs have their own separate gear (earbuds/cyberear,
|
|
678
|
+
* AR gloves, p.222/439) and are not modelled here -- this predicate is
|
|
679
|
+
* specifically the VISUAL overlay hasMatrixEyes has always been about.
|
|
680
|
+
*/
|
|
681
|
+
hasARDisplay() {
|
|
682
|
+
if (this.hasDirectNeuralInterface())
|
|
683
|
+
return true;
|
|
684
|
+
const onFace = this._equipment.head?.eyes;
|
|
685
|
+
return !!onFace && (onFace.category === Category.Glasses || onFace.category === Category.EyeCyberwere);
|
|
656
686
|
}
|
|
657
687
|
/**
|
|
658
688
|
* A DIRECT NEURAL INTERFACE -- what VR needs and AR does not (SR5 core
|
|
@@ -225,10 +225,17 @@ export function arStatusSlots(actor) {
|
|
|
225
225
|
? `{white-fg}◌ AR OFF{/white-fg}`
|
|
226
226
|
: !actor.getPanMaster() && !actor.isTechnomancer()
|
|
227
227
|
? `{white-fg}◌ no AR rig{/white-fg}`
|
|
228
|
-
//
|
|
229
|
-
//
|
|
230
|
-
//
|
|
231
|
-
|
|
228
|
+
// A processor with nothing to paint it on (acBi46ZKKJCPyBKXb):
|
|
229
|
+
// a commlink sends the overlay, but nothing here receives it
|
|
230
|
+
// (Player.hasARDisplay -- no DNI, no worn glasses/goggles/
|
|
231
|
+
// cybereyes). Distinct from "no AR rig" -- the player HAS a
|
|
232
|
+
// rig, it just has nowhere to show up.
|
|
233
|
+
: !actor.hasARDisplay()
|
|
234
|
+
? `{white-fg}◌ no display -- trodes or eyewear{/white-fg}`
|
|
235
|
+
// Off-plane, or any future state that puts the overlay down
|
|
236
|
+
// without being one of the above. game.ts drops the slot
|
|
237
|
+
// entirely while off-plane -- a persona has its own HUD line.
|
|
238
|
+
: `{white-fg}◌ AR dark{/white-fg}`;
|
|
232
239
|
// The link slot asks for the LIVE LINK -- worn commlink or working
|
|
233
240
|
// deck -- because that is what call.ts now asks for (p.223: a deck
|
|
234
241
|
// performs all commlink functions). The old "AR ON | Link offline"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@maka/maka-cli",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.152.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.",
|