@maka/maka-cli 5.388.0 → 5.389.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/go.js +15 -3
- package/bundle/typescript/src/commands/game/sideQuest/commands/rest.js +10 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/travel.js +26 -0
- package/bundle/typescript/src/commands/game/sideQuest/engine-version.js +8 -1
- package/bundle/typescript/src/commands/game/sideQuest/game.js +49 -0
- package/bundle/typescript/src/commands/game/sideQuest/models/door.js +4 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/spots.js +4 -0
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@maka/maka-cli",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.389.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.",
|
|
@@ -43,6 +43,18 @@ const DRIFT_WAYS = new Set([
|
|
|
43
43
|
Direction.NORTH, Direction.SOUTH, Direction.EAST, Direction.WEST,
|
|
44
44
|
Direction.UP, Direction.DOWN,
|
|
45
45
|
]);
|
|
46
|
+
/**
|
|
47
|
+
* IS THIS DOOR LOCKED TO SOMEONE LEAVING `from`. A tenant lock
|
|
48
|
+
* (Game.lockForeignResidences) is a flat's deadbolt: it keeps the street
|
|
49
|
+
* out and opens from inside, so nobody standing in the flat -- a save
|
|
50
|
+
* made there before the lock existed, a runner who breached in -- is
|
|
51
|
+
* shut in by it.
|
|
52
|
+
*/
|
|
53
|
+
function lockedFrom(door, from) {
|
|
54
|
+
if (!door.checkIfLocked())
|
|
55
|
+
return false;
|
|
56
|
+
return !(door.tenantLocked && from.residenceTier !== undefined);
|
|
57
|
+
}
|
|
46
58
|
export class GoCommand extends Command {
|
|
47
59
|
/**
|
|
48
60
|
* WHICH PLANE A COMPANION CAN HEEL ON, one rule per kind.
|
|
@@ -738,7 +750,7 @@ export class GoCommand extends Command {
|
|
|
738
750
|
const way = wayOut(currentRoom, direction, here);
|
|
739
751
|
const plane = way?.kind === 'seam' ? this.scene?.ensurePlane?.() : undefined;
|
|
740
752
|
const at = plane?.placements.get(roomKey(currentRoom.name));
|
|
741
|
-
const gated = exit instanceof Door && exit
|
|
753
|
+
const gated = exit instanceof Door && lockedFrom(exit, currentRoom);
|
|
742
754
|
if (way?.kind === 'seam' && at && here && !gated) {
|
|
743
755
|
const world = { x: at.origin.x + way.door.x, y: at.origin.y + way.door.y, z: at.origin.z + way.door.z };
|
|
744
756
|
const there = plane.placements.get(roomKey(way.target.name));
|
|
@@ -772,7 +784,7 @@ export class GoCommand extends Command {
|
|
|
772
784
|
// crossExit). Asked BEFORE the walk: the bolt is visible from
|
|
773
785
|
// across the room, and a runner told about it here is not made to
|
|
774
786
|
// cross the floor to hear it.
|
|
775
|
-
if (exit instanceof Door && exit
|
|
787
|
+
if (exit instanceof Door && lockedFrom(exit, currentRoom) && this.actor.plane === 'meat') {
|
|
776
788
|
this.actor.performAction('is prevented by locked door', currentRoom.name);
|
|
777
789
|
// NAME THE ROUTE (blocker 2026-08-27). This is FIRST CONTACT --
|
|
778
790
|
// what a player types before they know a barrier is even there
|
|
@@ -815,7 +827,7 @@ export class GoCommand extends Command {
|
|
|
815
827
|
*/
|
|
816
828
|
async crossExit(exit, direction, currentRoom, crossNote) {
|
|
817
829
|
if (exit instanceof Door) {
|
|
818
|
-
if (exit
|
|
830
|
+
if (lockedFrom(exit, currentRoom) && this.actor.plane === 'meat') {
|
|
819
831
|
this.actor.performAction('is prevented by locked door', currentRoom.name);
|
|
820
832
|
return `${crossNote}The door in the direction "${direction}" is locked.${lockedRouteHint(currentRoom, direction, exit)}`;
|
|
821
833
|
}
|
|
@@ -109,7 +109,16 @@ export class RestCommand extends Command {
|
|
|
109
109
|
// lifestyleChoices residence against the rooms the seed provides.
|
|
110
110
|
// It answers "may someone of this tier live in this scene", never
|
|
111
111
|
// "is this particular room your bedroom".
|
|
112
|
-
|
|
112
|
+
//
|
|
113
|
+
// AND A BED IS YOURS OR IT IS NOT A BED (kL23W3ufgsF5MZ2bt). "The
|
|
114
|
+
// roomType of _homeRoom and of nothing else" stopped being true when
|
|
115
|
+
// every district above Tacoma authored its own residence: a Street
|
|
116
|
+
// runner visiting Everett slept in Mill Court Flats on somebody
|
|
117
|
+
// else's lease. A residence a district authors FOR A TIER is the
|
|
118
|
+
// tenant's and nobody else's; any other Residence room (the runtime
|
|
119
|
+
// hole, a bench's `home` fixture) keeps the room-type answer.
|
|
120
|
+
const foreignFlat = room.residenceTier !== undefined && room !== this.game?.homeRoom;
|
|
121
|
+
const isResidence = room.roomType?.toLowerCase() === 'residence' && !foreignFlat;
|
|
113
122
|
if (actor.stunTaken === 0 && actor.damageTaken === 0 && damagedDevices.length === 0 && damagedDrones.length === 0 && damagedImplants.length === 0) {
|
|
114
123
|
// Nothing to heal -- but sleeping is its own point now (needs
|
|
115
124
|
// system: edge refills only fed-and-slept, see Game.
|
|
@@ -83,6 +83,23 @@ export class TravelCommand extends Command {
|
|
|
83
83
|
return `The driver takes the ${charge.paid} you have and doesn't ask twice.`;
|
|
84
84
|
return `The fare takes its ${fare}.`;
|
|
85
85
|
}
|
|
86
|
+
/**
|
|
87
|
+
* A CAB TAKES BODIES (6pdp3ELhsT8ihgtwH: "when using travel while
|
|
88
|
+
* projecting, my body is moved to the district, and am no longer
|
|
89
|
+
* projecting -- and when I return there is a duplicate body"). The
|
|
90
|
+
* ride moved the whole runner while the form was out, and bodyRoom
|
|
91
|
+
* kept a flesh in the room it had just left. call.ts's taxi has always
|
|
92
|
+
* refused off the meat plane; the ride across the sprawl is the same
|
|
93
|
+
* cab, so it asks the same question.
|
|
94
|
+
*/
|
|
95
|
+
offPlaneRefusal() {
|
|
96
|
+
switch (this.actor.plane) {
|
|
97
|
+
case 'astral': return `Cabs take bodies, not ghosts -- "return" first.`;
|
|
98
|
+
case 'matrix': return `Cabs take bodies, not personas -- "jack out" first.`;
|
|
99
|
+
case 'drone': return `Your body is slumped where you left it and the frame can't hail a cab -- "jump out" first.`;
|
|
100
|
+
default: return undefined;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
86
103
|
async execute(args = []) {
|
|
87
104
|
const game = this.game;
|
|
88
105
|
// "travel to the safehouse" is "travel safehouse" (player 2026-09-25:
|
|
@@ -113,6 +130,9 @@ export class TravelCommand extends Command {
|
|
|
113
130
|
if (!goingHome && destination === undefined) {
|
|
114
131
|
return `Nowhere called "${wanted}" that a cab will take you.${hint(' ("travel" on its own lists the districts; "travel home" leaves.)')}`;
|
|
115
132
|
}
|
|
133
|
+
const offPlane = this.offPlaneRefusal();
|
|
134
|
+
if (offPlane)
|
|
135
|
+
return offPlane;
|
|
116
136
|
if (!game.onLeaveSpaceRequested)
|
|
117
137
|
return `The door sticks -- the way home is not answering. Try again in a moment.`;
|
|
118
138
|
if (inLiveCombat(this.scene, this.actor))
|
|
@@ -173,6 +193,9 @@ export class TravelCommand extends Command {
|
|
|
173
193
|
return `No crew, no table -- seat a table or take a seat first.${hint(' ("crew invite <runner>", or accept an invite.)')}`;
|
|
174
194
|
if (!this.scene.isHumanControlled(this.actor))
|
|
175
195
|
return `The crew's table is for the crew, not the help.`;
|
|
196
|
+
const offPlane = this.offPlaneRefusal();
|
|
197
|
+
if (offPlane)
|
|
198
|
+
return offPlane;
|
|
176
199
|
if (game.hasOpenRun)
|
|
177
200
|
return `Not with a job left open -- finish it or walk out first.`;
|
|
178
201
|
if (inLiveCombat(this.scene, this.actor))
|
|
@@ -251,6 +274,9 @@ export class TravelCommand extends Command {
|
|
|
251
274
|
? `You are home.`
|
|
252
275
|
: `You are already in ${districts.find(d => d.id === targetId)?.label ?? targetId}.`;
|
|
253
276
|
}
|
|
277
|
+
const offPlane = this.offPlaneRefusal();
|
|
278
|
+
if (offPlane)
|
|
279
|
+
return offPlane;
|
|
254
280
|
// THE FARE IS READ OFF BOTH ENDS, so it has to be computed before the move
|
|
255
281
|
// -- afterwards `districtId` is the destination and the origin is gone.
|
|
256
282
|
const hereRating = game.districtPressure?.neighborhood;
|
|
@@ -3389,5 +3389,12 @@
|
|
|
3389
3389
|
// or ranged attack whose line crosses a standing face is at -1, the
|
|
3390
3390
|
// Light Fog row of the Environmental Modifiers table (p.175; confirmed
|
|
3391
3391
|
// against the rules index and SR5 references online). Melee is exempt.
|
|
3392
|
-
|
|
3392
|
+
// 1.201.0 (2026-10-05): A CAB TAKES BODIES (6pdp3ELhsT8ihgtwH): `travel`
|
|
3393
|
+
// refuses a runner who is projecting, jacked in or jumped in, as `call
|
|
3394
|
+
// taxi` always has -- the ride moved the form and left a body behind.
|
|
3395
|
+
// SOMEBODY ELSE'S FLAT IS LOCKED (kL23W3ufgsF5MZ2bt): an authored
|
|
3396
|
+
// residence that is not the runner's home has its street door locked
|
|
3397
|
+
// (Game.lockForeignResidences; opens from inside), and `rest` counts
|
|
3398
|
+
// only the runner's own home as a bed.
|
|
3399
|
+
export const ENGINE_VERSION = '1.201.0';
|
|
3393
3400
|
//# sourceMappingURL=engine-version.js.map
|
|
@@ -3522,6 +3522,7 @@ export default class Game {
|
|
|
3522
3522
|
// cosmetics below, ask whether this district authors a building for
|
|
3523
3523
|
// the tier now being paid for, and move house if it does.
|
|
3524
3524
|
this.rebindHomeForTier();
|
|
3525
|
+
this.lockForeignResidences();
|
|
3525
3526
|
/**
|
|
3526
3527
|
* AN AUTHORED RESIDENCE IS THE SEED'S, NOT THE TIER TABLE'S.
|
|
3527
3528
|
*
|
|
@@ -3634,6 +3635,50 @@ export default class Game {
|
|
|
3634
3635
|
return Object.values(this.scene?.getRooms?.() ?? {})
|
|
3635
3636
|
.find(r => r.residenceTier === this.lifestyle.name);
|
|
3636
3637
|
}
|
|
3638
|
+
/**
|
|
3639
|
+
* SOMEBODY ELSE'S FLAT IS LOCKED (kL23W3ufgsF5MZ2bt: "I'm able to enter
|
|
3640
|
+
* and use an apartment for a lifestyle I don't pay for").
|
|
3641
|
+
*
|
|
3642
|
+
* Every district above Tacoma authors one residence, for its own tier,
|
|
3643
|
+
* and that room used to stand open to anyone on the street: a Street
|
|
3644
|
+
* runner visiting Everett walked into Mill Court Flats and slept in its
|
|
3645
|
+
* bed. The address is the lease's, so the door is locked to everyone
|
|
3646
|
+
* but its tenant -- and unlocked again the day the lease is theirs.
|
|
3647
|
+
* Only the locks this put on are ever lifted: a door a seed or a device
|
|
3648
|
+
* locked keeps its own reasons.
|
|
3649
|
+
*
|
|
3650
|
+
* Breaking in is still a way in (breach); this is a lock, not a wall.
|
|
3651
|
+
*/
|
|
3652
|
+
lockForeignResidences() {
|
|
3653
|
+
const rooms = Object.values(this.scene?.getRooms?.() ?? {});
|
|
3654
|
+
for (const room of rooms) {
|
|
3655
|
+
if (room.residenceTier === undefined)
|
|
3656
|
+
continue;
|
|
3657
|
+
const ours = room === this._homeRoom;
|
|
3658
|
+
const doors = new Set();
|
|
3659
|
+
for (const r of rooms) {
|
|
3660
|
+
for (const ex of r.exits.values()) {
|
|
3661
|
+
if (ex instanceof Door && (ex.roomA === room || ex.roomB === room))
|
|
3662
|
+
doors.add(ex);
|
|
3663
|
+
}
|
|
3664
|
+
}
|
|
3665
|
+
for (const door of doors) {
|
|
3666
|
+
// YOUR OWN DOOR: lifted whether or not this session put the lock
|
|
3667
|
+
// on -- a hub overlay restores isLocked but not the flag, so a
|
|
3668
|
+
// flat locked on a visit and moved into later would otherwise
|
|
3669
|
+
// come back shut on its tenant. Keyed and device-held locks are
|
|
3670
|
+
// the seed's, and stay.
|
|
3671
|
+
if (ours && door.isLocked && !door.heldBy && (door.tenantLocked || !door.unlockItemOrSolution)) {
|
|
3672
|
+
door.isLocked = false;
|
|
3673
|
+
door.tenantLocked = false;
|
|
3674
|
+
}
|
|
3675
|
+
else if (!ours && !door.isLocked && !door.heldBy) {
|
|
3676
|
+
door.isLocked = true;
|
|
3677
|
+
door.tenantLocked = true;
|
|
3678
|
+
}
|
|
3679
|
+
}
|
|
3680
|
+
}
|
|
3681
|
+
}
|
|
3637
3682
|
rebindHomeForTier() {
|
|
3638
3683
|
const current = this._homeRoom;
|
|
3639
3684
|
if (current === undefined)
|
|
@@ -5750,6 +5795,8 @@ ${client.name} won't be remembering anything. Dead Johnsons pay nothing -- and t
|
|
|
5750
5795
|
this.gangedRooms.clear();
|
|
5751
5796
|
this.peopledRooms.clear();
|
|
5752
5797
|
this.patrolledRooms.clear();
|
|
5798
|
+
// Arrived in a district with somebody else's flat on it (or your own).
|
|
5799
|
+
this.lockForeignResidences();
|
|
5753
5800
|
const arrivalLines = this.unfoldCompanionsOnArrival();
|
|
5754
5801
|
this.repaintForScene();
|
|
5755
5802
|
this.refreshLogLabel();
|
|
@@ -6450,6 +6497,8 @@ ${client.name} won't be remembering anything. Dead Johnsons pay nothing -- and t
|
|
|
6450
6497
|
// everything stored since.
|
|
6451
6498
|
const world = elsewhere ? this._hubArchive[here] : save.hub;
|
|
6452
6499
|
applyHubOverlay(this.scene, world ? { ...world, home: save.hub.home } : save.hub, this.player, this._homeRoom, here);
|
|
6500
|
+
// The overlay restores door locks; whose flat is whose is decided now.
|
|
6501
|
+
this.lockForeignResidences();
|
|
6453
6502
|
this._homeDistrictId = save.game.homeDistrictId;
|
|
6454
6503
|
this._birthDistrictId = save.game.birthDistrictId;
|
|
6455
6504
|
this._tier = save.game.tier;
|
|
@@ -8,6 +8,10 @@ export class Door extends AbstractDoor {
|
|
|
8
8
|
unlockItemOrSolution;
|
|
9
9
|
/** Set when a Device holds this door shut -- see IDoorHolder. */
|
|
10
10
|
heldBy;
|
|
11
|
+
/** Locked because it is the street door of a residence that is not the
|
|
12
|
+
* runner's own (Game.lockForeignResidences) -- the lock that lifts the
|
|
13
|
+
* day the lease is theirs. */
|
|
14
|
+
tenantLocked;
|
|
11
15
|
logger;
|
|
12
16
|
isLockable;
|
|
13
17
|
constructor(config) {
|
|
@@ -1643,6 +1643,10 @@ export function lockSeenFromOutside(building, side, door) {
|
|
|
1643
1643
|
return ` ${device.name} holds it, and it is worked from inside.`;
|
|
1644
1644
|
if (door.heldBy)
|
|
1645
1645
|
return ` It's barred from ${door.heldBy.room} -- ${door.heldBy.device} is in there.`;
|
|
1646
|
+
// SOMEBODY'S FLAT (kL23W3ufgsF5MZ2bt): a residence that is not yours
|
|
1647
|
+
// is locked to you; Game.lockForeignResidences put the lock on.
|
|
1648
|
+
if (door.tenantLocked)
|
|
1649
|
+
return ` Somebody's flat -- the lease on it isn't yours, and neither is the key.`;
|
|
1646
1650
|
if (door.unlockItemOrSolution)
|
|
1647
1651
|
return ` It's keyed -- it takes ${door.unlockItemOrSolution}, from inside.`;
|
|
1648
1652
|
return ` Bolted from the inside -- nothing on this side of it to work.`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@maka/maka-cli",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.389.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.",
|