@maka/maka-cli 5.124.0 → 5.126.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/companions.js +13 -5
- package/bundle/typescript/src/commands/game/sideQuest/commands/companions.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/drone.js +5 -2
- package/bundle/typescript/src/commands/game/sideQuest/commands/drone.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/garage.d.ts +15 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/garage.js +55 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/garage.js.map +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/jack.js +9 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/jack.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/jump.js +10 -4
- package/bundle/typescript/src/commands/game/sideQuest/commands/jump.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/lifestyle.d.ts +7 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/lifestyle.js +58 -9
- package/bundle/typescript/src/commands/game/sideQuest/commands/lifestyle.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/project.js +7 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/project.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/rest.js +7 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/rest.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/sheet.js +7 -2
- package/bundle/typescript/src/commands/game/sideQuest/commands/sheet.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/take.js +22 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/take.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/engine-version.d.ts +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/engine-version.js +17 -1
- package/bundle/typescript/src/commands/game/sideQuest/engine-version.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/factories/chargen-factory.d.ts +39 -1
- package/bundle/typescript/src/commands/game/sideQuest/factories/chargen-factory.js +99 -23
- package/bundle/typescript/src/commands/game/sideQuest/factories/chargen-factory.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/game.d.ts +42 -1
- package/bundle/typescript/src/commands/game/sideQuest/game.js +115 -34
- package/bundle/typescript/src/commands/game/sideQuest/game.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/models/home-containers.d.ts +36 -0
- package/bundle/typescript/src/commands/game/sideQuest/models/home-containers.js +62 -0
- package/bundle/typescript/src/commands/game/sideQuest/models/home-containers.js.map +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/models/room.js +15 -1
- package/bundle/typescript/src/commands/game/sideQuest/models/room.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/types/save-file.d.ts +8 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/commerce.d.ts +32 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/commerce.js +45 -5
- package/bundle/typescript/src/commands/game/sideQuest/utilities/commerce.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/owned-drones.d.ts +39 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/owned-drones.js +37 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/owned-drones.js.map +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/persistence.d.ts +34 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/persistence.js +63 -27
- package/bundle/typescript/src/commands/game/sideQuest/utilities/persistence.js.map +1 -1
- package/package.json +1 -1
|
@@ -655,18 +655,39 @@ export default class Game {
|
|
|
655
655
|
haggled: boolean;
|
|
656
656
|
};
|
|
657
657
|
lifestyleTier: string;
|
|
658
|
+
/**
|
|
659
|
+
* LIFESTYLE OPTIONS (SR5 p.370, 2026-09-05): riders on the tier, by
|
|
660
|
+
* canonical key -- today only 'garage', the Special Work Area that
|
|
661
|
+
* parks a rigger's frames (utilities/commerce.ts LIFESTYLE_OPTIONS).
|
|
662
|
+
* Barred on Street; a slide to Street drops them (returnToHub).
|
|
663
|
+
*/
|
|
664
|
+
lifestyleOptions: string[];
|
|
658
665
|
/** The Big Ten grid a High lifestyle rides (SR5 p.222). A placeholder default until chargen offers the pick (grids.ts). */
|
|
659
666
|
gridProvider: string;
|
|
660
667
|
rentDebt: number;
|
|
661
668
|
/** The active lifestyle tier's row (falls back to Squatter). */
|
|
662
669
|
get lifestyle(): ILifestyleTier;
|
|
670
|
+
hasLifestyleOption(key: string): boolean;
|
|
671
|
+
/** What the homecoming collects: the tier's share plus every option's. */
|
|
672
|
+
get lifestyleUpkeep(): number;
|
|
673
|
+
/**
|
|
674
|
+
* Drop every option the current tier bars (p.370: none on Street).
|
|
675
|
+
* Returns the keys dropped, so the caller can say the lease lapsed.
|
|
676
|
+
*/
|
|
677
|
+
dropBarredLifestyleOptions(): string[];
|
|
663
678
|
/**
|
|
664
679
|
* Makes the hideout LOOK like what the rent buys: the room's description
|
|
665
680
|
* follows the active tier (player request -- an upgraded lifestyle read
|
|
666
681
|
* as the same windowless squat). Called wherever the tier moves: the
|
|
667
682
|
* lifestyle command, and the shortfall slide in returnToHub.
|
|
683
|
+
*
|
|
684
|
+
* THE GARAGE FOLLOWS THE OPTION (2026-09-05): the bay exists exactly
|
|
685
|
+
* while the lifestyle carries 'garage'. Reconciling here, on the same
|
|
686
|
+
* call every tier move already makes, is what keeps the furniture and
|
|
687
|
+
* the lease from disagreeing. Returns the names of any frames a lapsed
|
|
688
|
+
* lease spilled onto the floor, for the caller to mention.
|
|
668
689
|
*/
|
|
669
|
-
syncHomeToLifestyle():
|
|
690
|
+
syncHomeToLifestyle(): string[];
|
|
670
691
|
private static readonly RESTOCK_CATEGORIES;
|
|
671
692
|
private _restockSnapshot;
|
|
672
693
|
/** Captures every restockable shelf item's blueprint (hub capture time). */
|
|
@@ -1006,6 +1027,26 @@ export default class Game {
|
|
|
1006
1027
|
* matters less than its POSITION in init(): after seedHomeTurfContacts
|
|
1007
1028
|
* and snapshotVendorStock (both deliberately pre-overlay).
|
|
1008
1029
|
*/
|
|
1030
|
+
/**
|
|
1031
|
+
* THE LIFESTYLE THE SAVE PAID FOR, applied -- for EVERY save, a birth
|
|
1032
|
+
* certificate included (2026-09-05). This used to sit below the
|
|
1033
|
+
* `creation` early return in applyResumeState, so a web-born runner who
|
|
1034
|
+
* had paid a first month of High booted at the Squatter default, and
|
|
1035
|
+
* the first hub-arrival save then serialised that Squatter and buried
|
|
1036
|
+
* the tier for good. The lifestyle is Game-owned, not seed-owned; there
|
|
1037
|
+
* is no "world" it waits on.
|
|
1038
|
+
*
|
|
1039
|
+
* CANONICAL ON RESTORE (2026-09-01): the web factory once wrote a
|
|
1040
|
+
* lowercase 'street' that matched no LIFESTYLE_TIERS name, and this
|
|
1041
|
+
* line handed it to a getter that fell through to Squatter -- then
|
|
1042
|
+
* the next save SERIALIZED that Squatter, local and cloud, burying
|
|
1043
|
+
* any server-side repair. Canonicalizing here closes the fall-through
|
|
1044
|
+
* for every save that still carries the old spelling: 'street' means
|
|
1045
|
+
* Street, the factory's intent. (It cannot restore a PAID tier the
|
|
1046
|
+
* local file never knew -- that is the cloud repair's job, and the
|
|
1047
|
+
* sync protocol's, see the repair-visibility ruling in cloud-saves.)
|
|
1048
|
+
*/
|
|
1049
|
+
private applyLifestyleFromSave;
|
|
1009
1050
|
private applyResumeState;
|
|
1010
1051
|
/**
|
|
1011
1052
|
* IS THIS RUNNER'S LIFE THE SERVER'S? (server-only storage.)
|
|
@@ -18,12 +18,14 @@ import { Item } from './models/item.js';
|
|
|
18
18
|
import { Room, Container } from './models/_index.js';
|
|
19
19
|
import { Door } from './models/door.js';
|
|
20
20
|
import { SAVE_VERSION } from './types/save-file.js';
|
|
21
|
-
import { serializePlayer, restorePlayer, captureHubOverlay, applyHubOverlay, writeSaveAtomic, deleteSave, restoreItem, readSave, serializeItem, saveSlug, spillPathFor, } from './utilities/persistence.js';
|
|
21
|
+
import { serializePlayer, restorePlayer, captureHubOverlay, applyHubOverlay, applyHomeBlock, writeSaveAtomic, deleteSave, restoreItem, readSave, serializeItem, saveSlug, spillPathFor, } from './utilities/persistence.js';
|
|
22
22
|
import { heartbeatPresence, heartbeatPresenceNow } from './utilities/social.js';
|
|
23
23
|
import { presenceBeatAllowed } from './utilities/presence-gate.js';
|
|
24
24
|
import { pushSave, burnCloudSaveFor, enqueueBoundPush, flushPushQueue, writeSpill, takeLastMemorial, authToken, clearSpill, hasPendingPush, } from './utilities/cloud-saves.js';
|
|
25
25
|
import { DOCWAGON_TIERS, RESUSC_FEE, DEATH_COMP } from './utilities/docwagon.js';
|
|
26
|
-
import { isFence, LIFESTYLE_TIERS, canonicalLifestyleTier } from './utilities/commerce.js';
|
|
26
|
+
import { isFence, LIFESTYLE_TIERS, LIFESTYLE_OPTIONS, canonicalLifestyleTier, canonicalLifestyleOption, lifestyleOptionAllowed } from './utilities/commerce.js';
|
|
27
|
+
import { reconcileGarage } from './models/home-containers.js';
|
|
28
|
+
import { ownedDrones } from './utilities/owned-drones.js';
|
|
27
29
|
import { attachBrandMark, attachBrandMarkBottomRight } from './utilities/brand-mark.js';
|
|
28
30
|
import { logoPanelLines } from './utilities/logo-mark.js';
|
|
29
31
|
import { bestFakeSin, wandRead, processArrest } from './utilities/sin.js';
|
|
@@ -142,6 +144,7 @@ import { BuyCommand } from './commands/buy.js';
|
|
|
142
144
|
import { SellCommand } from './commands/sell.js';
|
|
143
145
|
import { PayCommand } from './commands/pay.js';
|
|
144
146
|
import { LifestyleCommand } from './commands/lifestyle.js';
|
|
147
|
+
import { GarageCommand } from './commands/garage.js';
|
|
145
148
|
import { JobsCommand } from './commands/jobs.js';
|
|
146
149
|
import { JournalCommand } from './commands/journal.js';
|
|
147
150
|
import { CoverCommand } from './commands/cover.js';
|
|
@@ -1362,10 +1365,17 @@ export default class Game {
|
|
|
1362
1365
|
// roster the runner OWNS and has not sent out -- drones in the bag, the
|
|
1363
1366
|
// deck's agent, registered sprites waiting in the Resonance. Spirits
|
|
1364
1367
|
// exist only while summoned, so none is ever stowed.
|
|
1365
|
-
|
|
1368
|
+
// ...and the frames parked in the Garage (2026-09-05): owned, not
|
|
1369
|
+
// deployed, and tagged so the sheet says where.
|
|
1370
|
+
for (const { item: d, where } of ownedDrones(player, this._homeRoom, { reach: 'owned' })) {
|
|
1366
1371
|
if (out.some(o => o.name === d.name))
|
|
1367
1372
|
continue;
|
|
1368
|
-
out.push({
|
|
1373
|
+
out.push({
|
|
1374
|
+
name: d.name, kind: 'drone', deployed: false,
|
|
1375
|
+
...(where === 'garage' ? { where: 'garage' } : {}),
|
|
1376
|
+
line: `Pilot ${d.pilotRating}, hull ${d.droneSummary()}${d.isWrecked ? ' -- WRECKED' : ''}`,
|
|
1377
|
+
damage: { taken: d.droneDamage, max: d.maxDroneBoxes },
|
|
1378
|
+
});
|
|
1369
1379
|
}
|
|
1370
1380
|
const deck = player.getAnyCyberdeck();
|
|
1371
1381
|
if (deck && !this.companions.some(c => c.kind === 'agent')) {
|
|
@@ -1747,6 +1757,13 @@ export default class Game {
|
|
|
1747
1757
|
// and while the tab stands, rest at the hideout recovers half (rest.ts;
|
|
1748
1758
|
// "pay" squares it, pay.ts; "lifestyle" views and moves tiers).
|
|
1749
1759
|
lifestyleTier = 'Squatter';
|
|
1760
|
+
/**
|
|
1761
|
+
* LIFESTYLE OPTIONS (SR5 p.370, 2026-09-05): riders on the tier, by
|
|
1762
|
+
* canonical key -- today only 'garage', the Special Work Area that
|
|
1763
|
+
* parks a rigger's frames (utilities/commerce.ts LIFESTYLE_OPTIONS).
|
|
1764
|
+
* Barred on Street; a slide to Street drops them (returnToHub).
|
|
1765
|
+
*/
|
|
1766
|
+
lifestyleOptions = [];
|
|
1750
1767
|
/** The Big Ten grid a High lifestyle rides (SR5 p.222). A placeholder default until chargen offers the pick (grids.ts). */
|
|
1751
1768
|
gridProvider = DEFAULT_GRID_PROVIDER;
|
|
1752
1769
|
rentDebt = 0;
|
|
@@ -1754,15 +1771,41 @@ export default class Game {
|
|
|
1754
1771
|
get lifestyle() {
|
|
1755
1772
|
return LIFESTYLE_TIERS.find(t => t.name === this.lifestyleTier) ?? LIFESTYLE_TIERS[1];
|
|
1756
1773
|
}
|
|
1774
|
+
hasLifestyleOption(key) {
|
|
1775
|
+
return this.lifestyleOptions.includes(key);
|
|
1776
|
+
}
|
|
1777
|
+
/** What the homecoming collects: the tier's share plus every option's. */
|
|
1778
|
+
get lifestyleUpkeep() {
|
|
1779
|
+
return this.lifestyle.upkeep
|
|
1780
|
+
+ LIFESTYLE_OPTIONS.filter(o => this.lifestyleOptions.includes(o.key)).reduce((n, o) => n + o.upkeep, 0);
|
|
1781
|
+
}
|
|
1782
|
+
/**
|
|
1783
|
+
* Drop every option the current tier bars (p.370: none on Street).
|
|
1784
|
+
* Returns the keys dropped, so the caller can say the lease lapsed.
|
|
1785
|
+
*/
|
|
1786
|
+
dropBarredLifestyleOptions() {
|
|
1787
|
+
const dropped = this.lifestyleOptions.filter(o => !lifestyleOptionAllowed(o, this.lifestyleTier));
|
|
1788
|
+
if (dropped.length > 0)
|
|
1789
|
+
this.lifestyleOptions = this.lifestyleOptions.filter(o => !dropped.includes(o));
|
|
1790
|
+
return dropped;
|
|
1791
|
+
}
|
|
1757
1792
|
/**
|
|
1758
1793
|
* Makes the hideout LOOK like what the rent buys: the room's description
|
|
1759
1794
|
* follows the active tier (player request -- an upgraded lifestyle read
|
|
1760
1795
|
* as the same windowless squat). Called wherever the tier moves: the
|
|
1761
1796
|
* lifestyle command, and the shortfall slide in returnToHub.
|
|
1797
|
+
*
|
|
1798
|
+
* THE GARAGE FOLLOWS THE OPTION (2026-09-05): the bay exists exactly
|
|
1799
|
+
* while the lifestyle carries 'garage'. Reconciling here, on the same
|
|
1800
|
+
* call every tier move already makes, is what keeps the furniture and
|
|
1801
|
+
* the lease from disagreeing. Returns the names of any frames a lapsed
|
|
1802
|
+
* lease spilled onto the floor, for the caller to mention.
|
|
1762
1803
|
*/
|
|
1763
1804
|
syncHomeToLifestyle() {
|
|
1764
|
-
if (this._homeRoom)
|
|
1765
|
-
|
|
1805
|
+
if (!this._homeRoom)
|
|
1806
|
+
return [];
|
|
1807
|
+
this._homeRoom.description = this.lifestyle.homeDescription;
|
|
1808
|
+
return reconcileGarage(this._homeRoom, this.player.name, this.hasLifestyleOption('garage'), this.lifestyle.garageDescription ?? 'A bay with a roll-down door. Your frames park here.');
|
|
1766
1809
|
}
|
|
1767
1810
|
// RESTOCK (see returnToHub): consumable shop stock -- food, drink,
|
|
1768
1811
|
// ammo, patches -- snapshotted at hub capture and restored to any shelf
|
|
@@ -2519,6 +2562,7 @@ ${client.name} won't be remembering anything. Dead Johnsons pay nothing -- and t
|
|
|
2519
2562
|
CommandFactory.registerCommand('eat', EatCommand);
|
|
2520
2563
|
CommandFactory.registerCommand('drink', DrinkCommand);
|
|
2521
2564
|
CommandFactory.registerCommand('lifestyle', LifestyleCommand);
|
|
2565
|
+
CommandFactory.registerCommand('garage', GarageCommand);
|
|
2522
2566
|
CommandFactory.registerCommand('jobs', JobsCommand);
|
|
2523
2567
|
CommandFactory.registerCommand('journal', JournalCommand);
|
|
2524
2568
|
CommandFactory.registerCommand('cover', CoverCommand);
|
|
@@ -2993,35 +3037,61 @@ ${client.name} won't be remembering anything. Dead Johnsons pay nothing -- and t
|
|
|
2993
3037
|
* matters less than its POSITION in init(): after seedHomeTurfContacts
|
|
2994
3038
|
* and snapshotVendorStock (both deliberately pre-overlay).
|
|
2995
3039
|
*/
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
// Street, the factory's intent. (It cannot restore a PAID tier the
|
|
3017
|
-
// local file never knew -- that is the cloud repair's job, and the
|
|
3018
|
-
// sync protocol's, see the repair-visibility ruling in cloud-saves.)
|
|
3040
|
+
/**
|
|
3041
|
+
* THE LIFESTYLE THE SAVE PAID FOR, applied -- for EVERY save, a birth
|
|
3042
|
+
* certificate included (2026-09-05). This used to sit below the
|
|
3043
|
+
* `creation` early return in applyResumeState, so a web-born runner who
|
|
3044
|
+
* had paid a first month of High booted at the Squatter default, and
|
|
3045
|
+
* the first hub-arrival save then serialised that Squatter and buried
|
|
3046
|
+
* the tier for good. The lifestyle is Game-owned, not seed-owned; there
|
|
3047
|
+
* is no "world" it waits on.
|
|
3048
|
+
*
|
|
3049
|
+
* CANONICAL ON RESTORE (2026-09-01): the web factory once wrote a
|
|
3050
|
+
* lowercase 'street' that matched no LIFESTYLE_TIERS name, and this
|
|
3051
|
+
* line handed it to a getter that fell through to Squatter -- then
|
|
3052
|
+
* the next save SERIALIZED that Squatter, local and cloud, burying
|
|
3053
|
+
* any server-side repair. Canonicalizing here closes the fall-through
|
|
3054
|
+
* for every save that still carries the old spelling: 'street' means
|
|
3055
|
+
* Street, the factory's intent. (It cannot restore a PAID tier the
|
|
3056
|
+
* local file never knew -- that is the cloud repair's job, and the
|
|
3057
|
+
* sync protocol's, see the repair-visibility ruling in cloud-saves.)
|
|
3058
|
+
*/
|
|
3059
|
+
applyLifestyleFromSave(save) {
|
|
3019
3060
|
this.lifestyleTier = canonicalLifestyleTier(save.game.lifestyleTier) ?? 'Street';
|
|
3061
|
+
// Options: canonical, known, and allowed on the tier -- a 'garage' a
|
|
3062
|
+
// Street save somehow carries is dropped here rather than built.
|
|
3063
|
+
this.lifestyleOptions = (save.game.lifestyleOptions ?? [])
|
|
3064
|
+
.map(canonicalLifestyleOption)
|
|
3065
|
+
.filter((o) => o !== undefined && lifestyleOptionAllowed(o, this.lifestyleTier));
|
|
3020
3066
|
if (typeof save.game.gridProvider === 'string' && save.game.gridProvider.trim())
|
|
3021
3067
|
this.gridProvider = save.game.gridProvider;
|
|
3022
3068
|
this.rentDebt = save.game.rentDebt;
|
|
3023
3069
|
this.syncHomeToLifestyle();
|
|
3024
3070
|
this.player.lifestyleEdgeBonus = this.lifestyle.edgeBonus;
|
|
3071
|
+
}
|
|
3072
|
+
applyResumeState(save) {
|
|
3073
|
+
restorePlayer(this.player, save.player);
|
|
3074
|
+
this.applyLifestyleFromSave(save);
|
|
3075
|
+
// A BIRTH CERTIFICATE IS NOT A RESUME. A `reason: 'creation'` save
|
|
3076
|
+
// (the web chargen factory) carries a player and a hub seed and NO
|
|
3077
|
+
// WORLD -- nothing has happened to overlay. Applying its empty hub as
|
|
3078
|
+
// if a session had produced it crashed the very first web-born runner
|
|
3079
|
+
// at boot (`saved.deadActors is not iterable`, 2026-09-01) and would
|
|
3080
|
+
// have zeroed the gig pool besides. The world boots fresh from the
|
|
3081
|
+
// embedded seed, exactly as a CLI-born character's does; the first
|
|
3082
|
+
// real requestSave writes the full state and every later resume
|
|
3083
|
+
// takes the branch below.
|
|
3084
|
+
//
|
|
3085
|
+
// WHAT A BIRTH CERTIFICATE DOES CARRY (2026-09-05): its lifestyle
|
|
3086
|
+
// (applied above) and its HOME block -- the Game-owned hideout's
|
|
3087
|
+
// furniture, which the factory fills when a rigger is born with a
|
|
3088
|
+
// garage full of frames. Both are the runner's, not the world's, so
|
|
3089
|
+
// both are applied; the seed-derived overlay stays skipped.
|
|
3090
|
+
if (save.reason === 'creation') {
|
|
3091
|
+
applyHomeBlock(this._homeRoom, save.hub?.home, this.player);
|
|
3092
|
+
return;
|
|
3093
|
+
}
|
|
3094
|
+
applyHubOverlay(this.scene, save.hub, this.player, this._homeRoom);
|
|
3025
3095
|
this._tier = save.game.tier;
|
|
3026
3096
|
this.contacts = new Map(save.game.contacts);
|
|
3027
3097
|
// Roles are DERIVED, not earned -- re-derive them all on every
|
|
@@ -3287,6 +3357,7 @@ ${client.name} won't be remembering anything. Dead Johnsons pay nothing -- and t
|
|
|
3287
3357
|
location: this.hubLocationSnapshot(),
|
|
3288
3358
|
gridProvider: this.gridProvider,
|
|
3289
3359
|
lifestyleTier: this.lifestyleTier,
|
|
3360
|
+
lifestyleOptions: [...this.lifestyleOptions],
|
|
3290
3361
|
rentDebt: this.rentDebt,
|
|
3291
3362
|
tier: this._tier,
|
|
3292
3363
|
contacts: [...this.contacts.entries()],
|
|
@@ -3685,7 +3756,9 @@ ${client.name} won't be remembering anything. Dead Johnsons pay nothing -- and t
|
|
|
3685
3756
|
// the shortfall becomes the tab -- rest.ts halves recovery while you
|
|
3686
3757
|
// owe; "pay" squares it; "lifestyle" climbs back up.
|
|
3687
3758
|
const tier = this.lifestyle;
|
|
3688
|
-
|
|
3759
|
+
// The tier's share plus every option's (the garage, p.370).
|
|
3760
|
+
const upkeep = this.lifestyleUpkeep;
|
|
3761
|
+
const due = upkeep + this.rentDebt;
|
|
3689
3762
|
const paid = Math.min(this.player.currency, due);
|
|
3690
3763
|
if (paid > 0)
|
|
3691
3764
|
this.player.adjustCurrency(-paid);
|
|
@@ -3695,16 +3768,24 @@ ${client.name} won't be remembering anything. Dead Johnsons pay nothing -- and t
|
|
|
3695
3768
|
const tierIndex = LIFESTYLE_TIERS.findIndex(t => t.name === tier.name);
|
|
3696
3769
|
if (tierIndex > 0) {
|
|
3697
3770
|
this.lifestyleTier = LIFESTYLE_TIERS[tierIndex - 1].name;
|
|
3771
|
+
// A lease the new tier cannot carry lapses with it (Street bars
|
|
3772
|
+
// every option), and the garage's frames land on the floor --
|
|
3773
|
+
// still yours, still here, just not parked.
|
|
3774
|
+
const dropped = this.dropBarredLifestyleOptions();
|
|
3698
3775
|
// The downgrade is visible the moment you look around.
|
|
3699
|
-
this.syncHomeToLifestyle();
|
|
3700
|
-
|
|
3776
|
+
const spilled = this.syncHomeToLifestyle();
|
|
3777
|
+
const lapse = dropped.length > 0
|
|
3778
|
+
? ` The garage lease goes with it${spilled.length > 0 ? `; ${spilled.join(', ')} sit${spilled.length === 1 ? 's' : ''} in the alley now` : ''}.`
|
|
3779
|
+
: '';
|
|
3780
|
+
rentLine = `The landlord's drone pings before the door even shuts: ${paid > 0 ? `${paid} paid, ` : ''}${this.rentDebt} nuyen still owed. Your ${tier.name} arrangement lapses -- you're living ${this.lifestyleTier} now.${lapse}${hint(` ("pay" the tab, "lifestyle" to climb back.)`)}`;
|
|
3701
3781
|
}
|
|
3702
3782
|
else {
|
|
3703
3783
|
rentLine = `Even the doorway costs something: ${this.rentDebt} nuyen on the tab.${hint(` ("pay" when you're flush.)`)}`;
|
|
3704
3784
|
}
|
|
3705
3785
|
}
|
|
3706
3786
|
else {
|
|
3707
|
-
|
|
3787
|
+
const share = upkeep > tier.upkeep ? ` (${tier.name} upkeep plus the garage)` : ` (${tier.name} upkeep)`;
|
|
3788
|
+
rentLine = `The landlord's drone takes its ${paid} nuyen${share} at the door and buzzes off satisfied.`;
|
|
3708
3789
|
}
|
|
3709
3790
|
this.player.lifestyleEdgeBonus = this.lifestyle.edgeBonus;
|
|
3710
3791
|
// A High lifestyle erases the run: hot shower, real bed, full reset.
|
|
@@ -5867,7 +5948,7 @@ ${client.name} won't be remembering anything. Dead Johnsons pay nothing -- and t
|
|
|
5867
5948
|
// else, so the Emerged shelf is where its audience looks.
|
|
5868
5949
|
{ title: 'resonance', entries: [['compile'], ['decompile'], ['thread'], ['unravel'], ['register'], ['standby'], ['sustain'], ['sprites']] },
|
|
5869
5950
|
{ title: 'social', entries: [['say'], ['emote', 'me'], ['talk-to'], ['call'], ['message'], ['end-call', 'end', 'hangup'], ['accept'], ['decline', 'deny', 'refuse'], ['haggle', 'negotiate'], ['persuade', 'convince'], ['ask'], ['contacts']] },
|
|
5870
|
-
{ title: 'street', entries: [['abandon'], ['browse', 'buy'], ['sell'], ['catalog'], ['source', 'procure'], ['work', 'gig'], ['jobs'], ['journal'], ['perform'], ['palm'], ['docwagon'], ['treat'], ['eat'], ['drink'], ['lifestyle'], ['pay']] },
|
|
5951
|
+
{ title: 'street', entries: [['abandon'], ['browse', 'buy'], ['sell'], ['catalog'], ['source', 'procure'], ['work', 'gig'], ['jobs'], ['journal'], ['perform'], ['palm'], ['docwagon'], ['treat'], ['eat'], ['drink'], ['lifestyle'], ['garage'], ['pay']] },
|
|
5871
5952
|
{ title: 'barriers', entries: [['pick'], ['breach'], ['dispel', 'dispell'], ['bluff'], ['unlock'], ['lock']] },
|
|
5872
5953
|
{ title: 'character', entries: [['sheet', 'stats'], ['advance'], ['qualities', 'quality'], ['sin', 'sins', 'papers'], ['initiate', 'submerge'], ['install', 'chrome']] },
|
|
5873
5954
|
{ title: 'session', entries: [['help'], ['hints'], ['time', 'clock'], ['note'], ['backlog'], ['review'], ['roles'], ['clear'], ['quit', 'exit']] },
|