@maka/maka-cli 5.121.0 → 5.122.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/archetypes.d.ts +72 -0
- package/bundle/typescript/src/commands/game/sideQuest/archetypes.js +300 -61
- package/bundle/typescript/src/commands/game/sideQuest/archetypes.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/aspects.js +11 -1
- package/bundle/typescript/src/commands/game/sideQuest/aspects.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/augmentations.d.ts +33 -0
- package/bundle/typescript/src/commands/game/sideQuest/augmentations.js +85 -0
- package/bundle/typescript/src/commands/game/sideQuest/augmentations.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/buy.js +8 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/buy.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/equipment.js +4 -2
- package/bundle/typescript/src/commands/game/sideQuest/commands/equipment.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/hack.d.ts +16 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/hack.js +273 -28
- package/bundle/typescript/src/commands/game/sideQuest/commands/hack.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/mark.d.ts +19 -10
- package/bundle/typescript/src/commands/game/sideQuest/commands/mark.js +43 -227
- package/bundle/typescript/src/commands/game/sideQuest/commands/mark.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/move.js +31 -3
- package/bundle/typescript/src/commands/game/sideQuest/commands/move.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/rest.js +5 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/rest.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/sell.js +4 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/sell.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/silent.js +4 -6
- package/bundle/typescript/src/commands/game/sideQuest/commands/silent.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/stance.d.ts +10 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/stance.js +50 -2
- package/bundle/typescript/src/commands/game/sideQuest/commands/stance.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/unequip.js +27 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/unequip.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 +3 -2
- package/bundle/typescript/src/commands/game/sideQuest/factories/chargen-factory.js +34 -41
- package/bundle/typescript/src/commands/game/sideQuest/factories/chargen-factory.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/factories/scene-factory.js +37 -1
- package/bundle/typescript/src/commands/game/sideQuest/factories/scene-factory.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/game.d.ts +47 -0
- package/bundle/typescript/src/commands/game/sideQuest/game.js +103 -4
- package/bundle/typescript/src/commands/game/sideQuest/game.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/headless-harness.d.ts +17 -0
- package/bundle/typescript/src/commands/game/sideQuest/headless-harness.js +30 -2
- package/bundle/typescript/src/commands/game/sideQuest/headless-harness.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/models/device.d.ts +14 -0
- package/bundle/typescript/src/commands/game/sideQuest/models/device.js +14 -0
- package/bundle/typescript/src/commands/game/sideQuest/models/device.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/models/item.d.ts +6 -0
- package/bundle/typescript/src/commands/game/sideQuest/models/item.js +8 -0
- package/bundle/typescript/src/commands/game/sideQuest/models/item.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/models/player.d.ts +82 -1
- package/bundle/typescript/src/commands/game/sideQuest/models/player.js +118 -0
- package/bundle/typescript/src/commands/game/sideQuest/models/player.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/qualities.d.ts +4 -0
- package/bundle/typescript/src/commands/game/sideQuest/qualities.js +16 -0
- package/bundle/typescript/src/commands/game/sideQuest/qualities.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/scenes/scene1.json +9 -9
- package/bundle/typescript/src/commands/game/sideQuest/scenes/scene2.json +6 -6
- package/bundle/typescript/src/commands/game/sideQuest/types/save-file.d.ts +5 -1
- package/bundle/typescript/src/commands/game/sideQuest/ui.js +23 -26
- package/bundle/typescript/src/commands/game/sideQuest/ui.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/catalog.d.ts +24 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/catalog.js +34 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/catalog.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/cloud-saves.d.ts +9 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/cloud-saves.js +8 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/cloud-saves.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/combat-exchange.js +25 -2
- package/bundle/typescript/src/commands/game/sideQuest/utilities/combat-exchange.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/comm-style.d.ts +32 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/comm-style.js +33 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/comm-style.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/dice.d.ts +5 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/dice.js +35 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/dice.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/matrix-intrusion.d.ts +121 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/matrix-intrusion.js +141 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/matrix-intrusion.js.map +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/persistence.js +5 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/persistence.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/pregen-worksheet.d.ts +93 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/pregen-worksheet.js +201 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/pregen-worksheet.js.map +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/room-view.js +91 -9
- package/bundle/typescript/src/commands/game/sideQuest/utilities/room-view.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/spots.d.ts +16 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/spots.js +50 -3
- package/bundle/typescript/src/commands/game/sideQuest/utilities/spots.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/web-character-generator.d.ts +7 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/web-character-generator.js +7 -2
- package/bundle/typescript/src/commands/game/sideQuest/utilities/web-character-generator.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest.sub.cmd.js +43 -3
- package/bundle/typescript/src/commands/game/sideQuest.sub.cmd.js.map +1 -1
- package/package.json +1 -1
|
@@ -2,35 +2,55 @@ import { Player } from './models/player.js';
|
|
|
2
2
|
import { Item } from './models/item.js';
|
|
3
3
|
import { Size, Category, Rating } from './types/shared/item-enum.js';
|
|
4
4
|
import { getAug } from './augmentations.js';
|
|
5
|
-
import { creationSplit } from './qualities.js';
|
|
6
|
-
|
|
7
|
-
size: Size.Small,
|
|
8
|
-
weight: 1,
|
|
9
|
-
shape: 'Gear',
|
|
10
|
-
color: 'Black',
|
|
11
|
-
texture: 'Matte',
|
|
12
|
-
...partial,
|
|
13
|
-
});
|
|
5
|
+
import { creationSplit, getQuality, CREATION_KARMA, KARMA_CARRYOVER_MAX, KARMA_TO_NUYEN_MAX, KARMA_NUYEN_RATE, HELD_NUYEN_MAX } from './qualities.js';
|
|
6
|
+
import { catalogGearDef, catalogRowFor } from './utilities/catalog.js';
|
|
14
7
|
export const ARCHETYPES = [
|
|
15
8
|
{
|
|
16
9
|
// No qualities at all IS the identity: nothing bought, nothing owed --
|
|
17
10
|
// the untouched 25 ledger splits per RAW into 7 karma + 20,000 nuyen.
|
|
18
11
|
name: 'Runner',
|
|
12
|
+
priorities: { metatype: 'C', attributes: 'A', magic: 'E', skills: 'B', resources: 'D' },
|
|
19
13
|
description: 'The balanced default: decent at everything, spectacular at nothing.',
|
|
20
|
-
combat: { body: 4, agility: 4, reaction: 4, combatSkill: 3, strength:
|
|
21
|
-
skills: { automatics: 3, pistols: 3, longarms: 3, blades: 2, unarmed: 3, sneaking:
|
|
14
|
+
combat: { body: 4, agility: 4, reaction: 4, combatSkill: 3, strength: 4, willpower: 4, logic: 4, intuition: 4, charisma: 4, edge: 3, magic: 0,
|
|
15
|
+
skills: { automatics: 3, pistols: 3, longarms: 3, blades: 2, unarmed: 3, sneaking: 3, perception: 4, gymnastics: 2, running: 2, swimming: 2, hacking: 1, locksmith: 1, negotiation: 3, con: 1, etiquette: 1, 'first-aid': 2 } },
|
|
16
|
+
// Nothing owed and nothing exotic -- the generalist spends the ledger
|
|
17
|
+
// on noticing things and shrugging off wounds.
|
|
18
|
+
qualities: ['perceptive', 'quick-healer'],
|
|
19
|
+
augs: [
|
|
20
|
+
'datajack', 'smartlink', 'reaction-enhancers-1', 'synaptic-booster'
|
|
21
|
+
],
|
|
22
|
+
gearSlugs: [
|
|
23
|
+
'ares-predator-v', 'quick-draw-holster', 'spare-clip', 'regular-ammo',
|
|
24
|
+
'gel-rounds', 'defiance-t-250', 'armor-jacket', 'combat-boots',
|
|
25
|
+
'erika-elite', 'fake-sin-4', 'fake-license-4', 'medkit-3', 'trauma-patch',
|
|
26
|
+
'stim-patch', 'ear-buds', 'glasses', 'microtransceiver', 'lockpick-set',
|
|
27
|
+
'tool-kit', 'climbing-gear', 'stealth-rope', 'survival-kit',
|
|
28
|
+
'respirator-4', 'smoke-grenade', 'flash-bang', 'tag-eraser',
|
|
29
|
+
'white-noise-generator', 'mapsoft', 'credstick-silver'
|
|
30
|
+
],
|
|
22
31
|
},
|
|
23
32
|
{
|
|
24
33
|
name: 'Street Samurai',
|
|
34
|
+
priorities: { metatype: 'C', attributes: 'B', magic: 'E', skills: 'A', resources: 'D' },
|
|
25
35
|
description: 'Chrome and trigger discipline. Hits hard, soaks harder, thinks later.',
|
|
26
36
|
combat: { body: 5, agility: 5, reaction: 4, combatSkill: 5, strength: 4, willpower: 3, logic: 2, intuition: 3, charisma: 2, edge: 2, magic: 0,
|
|
27
|
-
skills: { automatics: 6, pistols: 6, longarms: 6, blades: 4, unarmed: 5, gymnastics: 4, running:
|
|
28
|
-
augs: ['wired-reflexes-1', 'smartlink'],
|
|
37
|
+
skills: { automatics: 6, pistols: 6, longarms: 6, blades: 4, unarmed: 5, gymnastics: 4, running: 3, swimming: 3, perception: 3, intimidation: 4, sneaking: 2 } },
|
|
29
38
|
// Built to take a beating; the record says the beatings went both
|
|
30
39
|
// ways. Ledger 25 - 16 + 10 = 19 -> 7 karma + 20,000 nuyen.
|
|
31
|
-
qualities: ['toughness', 'high-pain-tolerance', 'sinner-criminal'],
|
|
32
|
-
|
|
33
|
-
|
|
40
|
+
qualities: ['toughness', 'high-pain-tolerance', 'quick-healer', 'sinner-criminal'],
|
|
41
|
+
// The book's own sam (p.112): the Predator with its smartgun, and a
|
|
42
|
+
// lined coat -- Armor 9 under the street jacket.
|
|
43
|
+
augs: [
|
|
44
|
+
'wired-reflexes-1', 'smartlink', 'bone-lacing', 'dermal-plating-2',
|
|
45
|
+
'platelet-factories', 'cybereyes', 'vision-enhancement-2'
|
|
46
|
+
],
|
|
47
|
+
gearSlugs: [
|
|
48
|
+
'ares-predator-v', 'quick-draw-holster', 'spare-clip', 'regular-ammo',
|
|
49
|
+
'apds', 'ares-alpha', 'combat-knife', 'lined-coat', 'armored-pants',
|
|
50
|
+
'combat-boots', 'helmet', 'hermes-ikon', 'fake-sin-4', 'fake-license-4',
|
|
51
|
+
'medkit-6', 'trauma-patch', 'stim-patch', 'ear-buds', 'glasses',
|
|
52
|
+
'microtransceiver', 'white-noise-generator', 'survival-kit',
|
|
53
|
+
'credstick-silver'
|
|
34
54
|
],
|
|
35
55
|
},
|
|
36
56
|
{
|
|
@@ -38,6 +58,7 @@ export const ARCHETYPES = [
|
|
|
38
58
|
// nothing and cannot project -- half their magic rides every meat
|
|
39
59
|
// attack and defense pool instead (see Player.adept).
|
|
40
60
|
name: 'Adept',
|
|
61
|
+
priorities: { metatype: 'D', attributes: 'B', magic: 'C', skills: 'A', resources: 'E' },
|
|
41
62
|
description: 'Magic as muscle: faster than chrome, no spells, no projection -- the body IS the focus.',
|
|
42
63
|
// CHOSEN POWERS (regen 2026-09-01): Magic 5 = 5 free Power Points
|
|
43
64
|
// (p.69), spent to the last half-point -- Improved Reflexes 2 (2.5) +
|
|
@@ -45,14 +66,19 @@ export const ARCHETYPES = [
|
|
|
45
66
|
// Sense 1 (0.5) + Mystic Armor 1 (0.5). Richer than the compressed
|
|
46
67
|
// floor(5/2) bonus this replaces: real initiative, physical fists,
|
|
47
68
|
// armor that was never worn.
|
|
48
|
-
combat: { body: 4, agility: 4, reaction: 4, combatSkill: 4, strength: 4, willpower: 4, logic: 2, intuition: 3, charisma:
|
|
69
|
+
combat: { body: 4, agility: 4, reaction: 4, combatSkill: 4, strength: 4, willpower: 4, logic: 2, intuition: 3, charisma: 3, edge: 2, magic: 5, adept: true,
|
|
49
70
|
adeptPowers: { 'improved-reflexes': 2, 'improved-ability-combat': 2, 'killing-hands': 1, 'combat-sense': 1, 'mystic-armor': 1 },
|
|
50
71
|
skills: { blades: 6, unarmed: 5, gymnastics: 5, running: 5, swimming: 5, sneaking: 4, perception: 3, assensing: 3, intimidation: 2, automatics: 2, pistols: 2, longarms: 2 } },
|
|
51
72
|
// The body IS the focus -- and it rejects the sim the way it rejects
|
|
52
73
|
// chrome. Ledger 25 - 14 + 5 = 16 -> 7 karma + 18,000 nuyen.
|
|
53
74
|
qualities: ['catlike', 'natural-athlete', 'simsense-vertigo'],
|
|
54
|
-
|
|
55
|
-
|
|
75
|
+
// The katana is the p.423 row (Acc 7, STR+3, AP -3); the bonded weapon
|
|
76
|
+
// focus rides beside it as the Force 1 row.
|
|
77
|
+
gearSlugs: [
|
|
78
|
+
'katana', 'weapon-focus-1', 'qi-focus-1', 'combat-knife', 'armor-jacket',
|
|
79
|
+
'combat-boots', 'fake-sin-2', 'meta-link', 'medkit-3', 'trauma-patch',
|
|
80
|
+
'stim-patch', 'ear-buds', 'glasses', 'climbing-gear', 'stealth-rope',
|
|
81
|
+
'gecko-tape-gloves', 'survival-kit', 'credstick-silver'
|
|
56
82
|
],
|
|
57
83
|
},
|
|
58
84
|
{
|
|
@@ -63,6 +89,7 @@ export const ARCHETYPES = [
|
|
|
63
89
|
// body, and NEVER astrally projects -- the one place the path sides
|
|
64
90
|
// with the adept.
|
|
65
91
|
name: 'Mystic Adept',
|
|
92
|
+
priorities: { metatype: 'D', attributes: 'C', magic: 'A', skills: 'B', resources: 'E' },
|
|
66
93
|
description: 'Spell in one hand, killing hands on the other -- both worlds, and the astral door stays shut.',
|
|
67
94
|
// Ledger: 25 - 10 (2 Power Points) + 10 (Astral Beacon) = 25 -> 7
|
|
68
95
|
// karma + 20,000 nuyen. The beacon is the price of burning on both
|
|
@@ -70,34 +97,48 @@ export const ARCHETYPES = [
|
|
|
70
97
|
// Powers: Improved Reflexes 1 (1.5) + Killing Hands (0.5) = 2.0 --
|
|
71
98
|
// the bought points, spent whole. Spells: Magic 6 allows 12; eight
|
|
72
99
|
// chosen, breadth over artillery.
|
|
73
|
-
combat: { body: 3, agility: 3, reaction: 3, combatSkill: 3, strength:
|
|
100
|
+
combat: { body: 3, agility: 3, reaction: 3, combatSkill: 3, strength: 2, willpower: 4, logic: 3, intuition: 4, charisma: 2, edge: 2, magic: 6, adept: false, powerPoints: 2,
|
|
74
101
|
knownSpells: ['manabolt', 'stunbolt', 'fireball', 'heal', 'armor', 'invisibility', 'reflexes', 'barrier'],
|
|
75
102
|
adeptPowers: { 'improved-reflexes': 1, 'killing-hands': 1 },
|
|
76
103
|
skills: { spellcasting: 5, counterspelling: 3, assensing: 3, unarmed: 4, blades: 3, gymnastics: 3, running: 3, swimming: 2, perception: 3, sneaking: 3, pistols: 2 } },
|
|
77
|
-
qualities: ['astral-beacon'],
|
|
78
|
-
|
|
79
|
-
|
|
104
|
+
qualities: ['focused-concentration', 'mentor-spirit', 'astral-beacon'],
|
|
105
|
+
gearSlugs: [
|
|
106
|
+
'power-focus-1', 'reagents', 'armor-jacket', 'combat-boots', 'meta-link',
|
|
107
|
+
'medkit-3', 'trauma-patch', 'stim-patch', 'ear-buds', 'glasses',
|
|
108
|
+
'survival-kit', 'credstick-silver'
|
|
80
109
|
],
|
|
81
110
|
},
|
|
82
111
|
{
|
|
83
112
|
name: 'Covert Ops',
|
|
113
|
+
priorities: { metatype: 'C', attributes: 'B', magic: 'E', skills: 'A', resources: 'D' },
|
|
84
114
|
description: 'In through the vents, out before the alarm. Locks are suggestions.',
|
|
85
|
-
combat: { body: 3, agility: 5, reaction: 4, combatSkill: 3, strength: 3, willpower:
|
|
115
|
+
combat: { body: 3, agility: 5, reaction: 4, combatSkill: 3, strength: 3, willpower: 2, logic: 3, intuition: 5, charisma: 3, edge: 3, magic: 0,
|
|
86
116
|
skills: { sneaking: 6, locksmith: 5, perception: 4, gymnastics: 4, running: 4, swimming: 4, automatics: 3, pistols: 3, longarms: 3, unarmed: 3, con: 3, hacking: 2 } },
|
|
87
|
-
augs: ['cybereyes'],
|
|
88
117
|
// Quiet, charmed, and never quite off duty -- the paranoia that keeps
|
|
89
118
|
// you alive doesn't sleep either. Ledger 25 - 19 + 15 = 21 -> 7 karma
|
|
90
119
|
// + 20,000 nuyen.
|
|
91
|
-
qualities: ['catlike', 'lucky', 'sinner-national', 'insomnia'],
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
120
|
+
qualities: ['catlike', 'lucky', 'innocuous', 'sinner-national', 'insomnia'],
|
|
121
|
+
// The picks, and a Sequencer that now rolls its rating against the
|
|
122
|
+
// lock's (pick.ts). "Locks are suggestions" has teeth.
|
|
123
|
+
augs: [
|
|
124
|
+
'cybereyes', 'vision-enhancement-2', 'datajack', 'muscle-toner-1'
|
|
125
|
+
],
|
|
126
|
+
gearSlugs: [
|
|
127
|
+
'chameleon-suit', 'lockpick-set', 'sequencer-4', 'autopicker-3',
|
|
128
|
+
'keycard-copier-4', 'grapple-gun', 'stealth-rope', 'climbing-gear',
|
|
129
|
+
'rappelling-gloves', 'gecko-tape-gloves', 'tag-eraser', 'stealth-tags',
|
|
130
|
+
'micro-camera', 'data-tap', 'white-noise-generator', 'erika-elite',
|
|
131
|
+
'fake-sin-4', 'fake-license-4', 'ares-light-fire-70', 'silencer',
|
|
132
|
+
'spare-clip', 'regular-ammo', 'medkit-3', 'trauma-patch', 'stim-patch',
|
|
133
|
+
'ear-buds', 'glasses', 'respirator-4', 'chisel-crowbar', 'survival-kit',
|
|
134
|
+
'combat-boots', 'credstick-silver'
|
|
95
135
|
],
|
|
96
136
|
},
|
|
97
137
|
{
|
|
98
138
|
name: 'Face',
|
|
139
|
+
priorities: { metatype: 'C', attributes: 'B', magic: 'E', skills: 'A', resources: 'D' },
|
|
99
140
|
description: 'Talks the job open before anyone draws. Charm, luck, and just enough gun.',
|
|
100
|
-
combat: { body: 3, agility: 3, reaction: 3, combatSkill: 3, strength:
|
|
141
|
+
combat: { body: 3, agility: 3, reaction: 3, combatSkill: 3, strength: 2, willpower: 4, logic: 3, intuition: 4, charisma: 6, edge: 3, magic: 0,
|
|
101
142
|
// Etiquette in for sneaking: the Face blends SOCIALLY (RAW p.138:
|
|
102
143
|
// "a social version of Sneak") -- vents are someone else's job.
|
|
103
144
|
// Leadership in for intimidation (same Cha-social slot, ledger
|
|
@@ -107,44 +148,69 @@ export const ARCHETYPES = [
|
|
|
107
148
|
// opens doors is exactly what witnesses describe to Knight Errant.
|
|
108
149
|
// Ledger 25 - 23 + 10 = 12 -> 7 karma + 10,000 nuyen.
|
|
109
150
|
qualities: ['first-impression', 'lucky', 'distinctive-style', 'sinner-national'],
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
151
|
+
// The book's Face (p.119): the Avalon, Actioneer Business Clothes
|
|
152
|
+
// (Armor 8), and a Shopsoft on the link for the haggle.
|
|
153
|
+
augs: [
|
|
154
|
+
'tailored-pheromones-2', 'cybereyes', 'vision-enhancement-1', 'datajack'
|
|
155
|
+
],
|
|
156
|
+
gearSlugs: [
|
|
157
|
+
'transys-avalon', 'actioneer-business-clothes', 'shopsoft',
|
|
158
|
+
'electrochromic-clothing', 'fake-sin-4', 'fake-license-4',
|
|
159
|
+
'ares-light-fire-70', 'quick-draw-holster', 'spare-clip', 'regular-ammo',
|
|
160
|
+
'micro-camera', 'data-tap', 'tag-eraser', 'white-noise-generator',
|
|
161
|
+
'microtransceiver', 'ear-buds', 'glasses', 'medkit-3', 'stim-patch',
|
|
162
|
+
'mapsoft', 'combat-boots', 'credstick-gold'
|
|
113
163
|
],
|
|
114
164
|
},
|
|
115
165
|
{
|
|
116
166
|
name: 'Street Doc',
|
|
167
|
+
priorities: { metatype: 'B', attributes: 'A', magic: 'E', skills: 'C', resources: 'D' },
|
|
117
168
|
description: 'Keeps the team breathing: brains, steady hands, and a bag full of trauma kits.',
|
|
118
|
-
combat: { body:
|
|
169
|
+
combat: { body: 4, agility: 4, reaction: 4, combatSkill: 2, strength: 3, willpower: 4, logic: 6, intuition: 4, charisma: 3, edge: 4, magic: 0,
|
|
119
170
|
skills: { 'first-aid': 6, perception: 4, negotiation: 3, automatics: 2, pistols: 2, longarms: 2, unarmed: 2, hacking: 2, con: 2 } },
|
|
120
171
|
// Brilliant hands that freeze when the shooting starts -- which is
|
|
121
172
|
// why they became the one who patches, not the one who charges.
|
|
122
173
|
// Ledger 25 - 8 + 12 = 29 -> 7 karma + 20,000 nuyen.
|
|
123
|
-
qualities: ['quick-healer', 'analytical-mind', 'combat-paralysis'],
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
174
|
+
qualities: ['quick-healer', 'analytical-mind', 'photographic-memory', 'resistance-pathogens-and-toxins', 'combat-paralysis'],
|
|
175
|
+
// The Rating 6 medkit is the kit that thinks (first-aid.ts).
|
|
176
|
+
augs: [
|
|
177
|
+
'cybereyes', 'vision-enhancement-1', 'datajack', 'cerebral-booster-1',
|
|
178
|
+
'symbiotes-1'
|
|
179
|
+
],
|
|
180
|
+
gearSlugs: [
|
|
181
|
+
'medkit-6', 'medkit-supplies', 'disposable-syringe', 'antidote-patch-4',
|
|
182
|
+
'tranq-patch-6', 'biomonitor', 'trauma-patch', 'stim-patch',
|
|
183
|
+
'armor-jacket', 'combat-boots', 'renraku-sensei', 'fake-sin-4',
|
|
184
|
+
'fake-license-4', 'ares-light-fire-70', 'quick-draw-holster', 'spare-clip',
|
|
185
|
+
'regular-ammo', 'ear-buds', 'glasses', 'tool-kit', 'gas-mask',
|
|
186
|
+
'respirator-4', 'survival-kit', 'credstick-silver'
|
|
127
187
|
],
|
|
128
188
|
},
|
|
129
189
|
{
|
|
130
190
|
name: 'Combat Mage',
|
|
191
|
+
priorities: { metatype: 'D', attributes: 'B', magic: 'A', skills: 'C', resources: 'E' },
|
|
131
192
|
description: 'Awakened artillery: manabolts through milspec armor, if the drain doesn\'t eat you first.',
|
|
132
193
|
// CHOSEN SPELLBOOK (regen 2026-09-01): Magic 6 knows up to 12 (p.300)
|
|
133
194
|
// and the artillery build takes all 12 -- every combat spell in the
|
|
134
195
|
// catalog plus the sustains that keep the caster standing.
|
|
135
|
-
combat: { body:
|
|
196
|
+
combat: { body: 4, agility: 3, reaction: 3, combatSkill: 2, strength: 2, willpower: 5, logic: 4, intuition: 4, charisma: 3, edge: 2, magic: 6,
|
|
136
197
|
knownSpells: ['manabolt', 'stunbolt', 'powerbolt', 'fireball', 'lightning-bolt', 'ball-lightning', 'manaball', 'stunball', 'armor', 'heal', 'reflexes', 'barrier'],
|
|
137
198
|
skills: { spellcasting: 6, counterspelling: 4, assensing: 4, conjuring: 3, perception: 3, unarmed: 2, automatics: 2, pistols: 2, longarms: 2 } },
|
|
138
199
|
// Drain taught them what pain is worth ignoring; the astral bleeds
|
|
139
200
|
// into their dreams and calls it rent. Ledger 25 - 7 + 10 = 28 -> 7
|
|
140
201
|
// karma + 20,000 nuyen.
|
|
141
|
-
qualities: ['high-pain-tolerance', 'insomnia'],
|
|
142
|
-
|
|
143
|
-
|
|
202
|
+
qualities: ['high-pain-tolerance', 'focused-concentration', 'mentor-spirit', 'quick-healer', 'insomnia'],
|
|
203
|
+
gearSlugs: [
|
|
204
|
+
'spell-focus-1', 'combat-spell-formula', 'reagents', 'lodge-materials-3',
|
|
205
|
+
'armor-jacket', 'combat-boots', 'fake-sin-2', 'fake-license-4',
|
|
206
|
+
'meta-link', 'ares-light-fire-70', 'spare-clip', 'regular-ammo',
|
|
207
|
+
'medkit-3', 'trauma-patch', 'stim-patch', 'ear-buds', 'glasses',
|
|
208
|
+
'credstick-silver'
|
|
144
209
|
],
|
|
145
210
|
},
|
|
146
211
|
{
|
|
147
212
|
name: 'Street Shaman',
|
|
213
|
+
priorities: { metatype: 'D', attributes: 'B', magic: 'C', skills: 'A', resources: 'E' },
|
|
148
214
|
description: 'Awakened the hard way: iron will, sharp instincts, spirits on speed dial.',
|
|
149
215
|
// CHOSEN SPELLBOOK (regen 2026-09-01): Magic 5 knows up to 10 (p.300)
|
|
150
216
|
// -- the mender's list: mercy settings, wards, and the heal that is
|
|
@@ -156,8 +222,71 @@ export const ARCHETYPES = [
|
|
|
156
222
|
// but nobody forgets the one draped in bones and braided wire.
|
|
157
223
|
// Ledger 25 - 15 + 5 = 15 -> 7 karma + 16,000 nuyen.
|
|
158
224
|
qualities: ['lucky', 'quick-healer', 'distinctive-style'],
|
|
159
|
-
|
|
160
|
-
|
|
225
|
+
gearSlugs: [
|
|
226
|
+
'spirit-focus-1', 'lodge-materials-3', 'reagents', 'armor-jacket',
|
|
227
|
+
'combat-boots', 'fake-sin-2', 'meta-link', 'ares-light-fire-70',
|
|
228
|
+
'spare-clip', 'regular-ammo', 'medkit-3', 'trauma-patch', 'stim-patch',
|
|
229
|
+
'ear-buds', 'glasses', 'survival-kit', 'credstick-silver'
|
|
230
|
+
],
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
// THE ASPECTED MAGICIAN, FINALLY PLAYABLE FROM THE MENU (user ask,
|
|
234
|
+
// 2026-09-03: "how about the aspected magician?"). aspects.ts, the
|
|
235
|
+
// Player.aspect field, the chargen path and the verb gates in
|
|
236
|
+
// summon.ts / cast.ts / dispel.ts have all been here since
|
|
237
|
+
// 2026-09-02 -- there was simply no pregen carrying `aspect`, so the
|
|
238
|
+
// fifth magical path existed everywhere except where a player picks
|
|
239
|
+
// a character. Two of them, because the engine honours exactly two
|
|
240
|
+
// aspects: Enchanter waits on alchemy (UNAVAILABLE_ASPECTS).
|
|
241
|
+
//
|
|
242
|
+
// Magic B on the Aspected row is Magic 5 (p.65, ASPECTED_PRIORITY) --
|
|
243
|
+
// the same rating the full magician gets at B, which is the trade:
|
|
244
|
+
// half the art, none of the discount.
|
|
245
|
+
name: 'Sorcerer',
|
|
246
|
+
priorities: { metatype: 'C', attributes: 'A', magic: 'B', skills: 'E', resources: 'D' },
|
|
247
|
+
description: 'Spells and nothing else: no spirits will ever answer you, and the astral is a window you cannot climb through.',
|
|
248
|
+
combat: { body: 3, agility: 3, reaction: 3, combatSkill: 2, strength: 2, willpower: 6, logic: 5, intuition: 5, charisma: 5, edge: 3, magic: 5, aspect: 'sorcerer',
|
|
249
|
+
// Magic x 2 at creation (p.69), the same cap a full magician's
|
|
250
|
+
// spellbook uses -- an aspected caster is not a smaller caster.
|
|
251
|
+
knownSpells: ['manabolt', 'stunbolt', 'powerbolt', 'manaball', 'stunball', 'lightning-bolt', 'armor', 'heal', 'reflexes', 'barrier'],
|
|
252
|
+
// Sorcery only. `conjuring` is absent on purpose and enforced twice
|
|
253
|
+
// over: the chargen payload check (forbiddenSkillsFor) and
|
|
254
|
+
// summon.ts's aspect gate.
|
|
255
|
+
skills: { spellcasting: 4, counterspelling: 4, 'ritual-spellcasting': 4, assensing: 4, perception: 4, negotiation: 3, unarmed: 3, gymnastics: 2, sneaking: 2 } },
|
|
256
|
+
// One art, held deeper than a generalist holds two -- and a mentor
|
|
257
|
+
// who never let them look at the other half.
|
|
258
|
+
// Ledger 25 - 9 = 16 -> 7 karma + 18,000 nuyen.
|
|
259
|
+
qualities: ['focused-concentration', 'mentor-spirit'],
|
|
260
|
+
gearSlugs: [
|
|
261
|
+
'spell-focus-1', 'power-focus-1', 'combat-spell-formula', 'reagents',
|
|
262
|
+
'lodge-materials-3', 'armor-jacket', 'combat-boots', 'fake-sin-4',
|
|
263
|
+
'fake-license-4', 'renraku-sensei', 'mage-sight-goggles', 'medkit-3',
|
|
264
|
+
'trauma-patch', 'stim-patch', 'ear-buds', 'glasses', 'microtransceiver',
|
|
265
|
+
'white-noise-generator', 'survival-kit', 'ares-light-fire-70',
|
|
266
|
+
'spare-clip', 'regular-ammo', 'credstick-silver'
|
|
267
|
+
],
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
// The other half of the same coin. Charisma is the maxed attribute
|
|
271
|
+
// here rather than Willpower: summoning is a negotiation with
|
|
272
|
+
// something that does not want to be there.
|
|
273
|
+
name: 'Conjurer',
|
|
274
|
+
priorities: { metatype: 'C', attributes: 'A', magic: 'B', skills: 'E', resources: 'D' },
|
|
275
|
+
description: 'Spirits answer you and nothing else does -- no spells, no counterspelling, and the astral stays a window.',
|
|
276
|
+
combat: { body: 3, agility: 3, reaction: 3, combatSkill: 2, strength: 2, willpower: 5, logic: 5, intuition: 5, charisma: 6, edge: 3, magic: 5, aspect: 'conjurer',
|
|
277
|
+
// No spellbook at all: "they cannot perform any of the magical
|
|
278
|
+
// skills associated with the two groups they did not select"
|
|
279
|
+
// (p.69), and cast.ts refuses them by aspect, not by empty list.
|
|
280
|
+
skills: { conjuring: 6, summoning: 4, binding: 4, banishing: 4, assensing: 4, perception: 4, negotiation: 2, unarmed: 2 } },
|
|
281
|
+
// The spirits like them, which is not the same as the spirits being
|
|
282
|
+
// safe. Ledger 25 - 11 = 14 -> 7 karma + 14,000 nuyen.
|
|
283
|
+
qualities: ['spirit-affinity', 'focused-concentration'],
|
|
284
|
+
gearSlugs: [
|
|
285
|
+
'spirit-focus-1', 'power-focus-1', 'lodge-materials-3', 'reagents',
|
|
286
|
+
'armor-jacket', 'combat-boots', 'fake-sin-4', 'fake-license-4',
|
|
287
|
+
'renraku-sensei', 'medkit-3', 'trauma-patch', 'stim-patch', 'ear-buds',
|
|
288
|
+
'glasses', 'microtransceiver', 'survival-kit', 'ares-light-fire-70',
|
|
289
|
+
'spare-clip', 'regular-ammo', 'credstick-silver'
|
|
161
290
|
],
|
|
162
291
|
},
|
|
163
292
|
{
|
|
@@ -166,24 +295,40 @@ export const ARCHETYPES = [
|
|
|
166
295
|
// deck is the requisite: its quality feeds program damage and
|
|
167
296
|
// firewall, and its hardware track is what the ice chews on.
|
|
168
297
|
name: 'Decker',
|
|
298
|
+
priorities: { metatype: 'D', attributes: 'B', magic: 'E', skills: 'C', resources: 'A' },
|
|
169
299
|
description: 'A ghost in the grid: hosts crack, ice burns, maglocks open. Just don\'t get caught in meatspace.',
|
|
170
|
-
combat: { body:
|
|
300
|
+
combat: { body: 4, agility: 2, reaction: 3, combatSkill: 2, strength: 2, willpower: 4, logic: 6, intuition: 5, charisma: 2, edge: 3, magic: 0,
|
|
171
301
|
skills: { hacking: 6, perception: 4, locksmith: 3, sneaking: 3, automatics: 2, pistols: 2, longarms: 2, unarmed: 2, con: 2 } },
|
|
172
|
-
augs: ['datajack'],
|
|
173
302
|
// Hosts are puzzles and hardware is clay -- meatspace gunfire is
|
|
174
303
|
// neither, and the freeze proves it. Ledger 25 - 15 + 12 = 22 -> 7
|
|
175
304
|
// karma + 20,000 nuyen.
|
|
176
|
-
qualities: ['analytical-mind', 'juryrigger', 'combat-paralysis'],
|
|
177
|
-
|
|
178
|
-
|
|
305
|
+
qualities: ['analytical-mind', 'juryrigger', 'codeslinger-hack-on-the-fly', 'combat-paralysis'],
|
|
306
|
+
// The Navigator (DR 3, three programs running) and the book's own
|
|
307
|
+
// decker kit (p.121) trimmed to what the deck can run: the chips file
|
|
308
|
+
// into its storage on pickup (Player.addInventory).
|
|
309
|
+
augs: [
|
|
310
|
+
'datajack', 'cerebral-booster-1', 'headware-cyberdeck', 'cybereyes',
|
|
311
|
+
'vision-enhancement-1', 'sleep-regulator', 'reaction-enhancers-1'
|
|
312
|
+
],
|
|
313
|
+
gearSlugs: [
|
|
314
|
+
'novatech-navigator', 'exploit-program', 'armor-program',
|
|
315
|
+
'biofeedback-filter-program', 'encryption-program', 'toolbox-program',
|
|
316
|
+
'signal-scrub-program', 'browse-program', 'sneak-program',
|
|
317
|
+
'hammer-program', 'decryption-program', 'agent-rating-4', 'trodes',
|
|
318
|
+
'sim-module', 'hermes-ikon', 'armor-jacket', 'combat-boots', 'fake-sin-4',
|
|
319
|
+
'fake-license-4', 'lockpick-set', 'sequencer-4', 'data-tap', 'tag-eraser',
|
|
320
|
+
'white-noise-generator', 'microtransceiver', 'medkit-6', 'trauma-patch',
|
|
321
|
+
'stim-patch', 'ear-buds', 'glasses', 'ares-light-fire-70', 'spare-clip',
|
|
322
|
+
'regular-ammo', 'mapsoft', 'shopsoft', 'credstick-silver'
|
|
179
323
|
],
|
|
180
324
|
},
|
|
181
325
|
{
|
|
182
326
|
// The living persona (see ICombatAttributes.resonance): no deck, no
|
|
183
327
|
// commlink -- and no hardware between their stun track and the ice.
|
|
184
328
|
name: 'Technomancer',
|
|
329
|
+
priorities: { metatype: 'D', attributes: 'C', magic: 'A', skills: 'B', resources: 'E' },
|
|
185
330
|
description: 'The Matrix answers when they think at it. No deck to brick -- only a mind to burn.',
|
|
186
|
-
combat: { body: 2, agility: 2, reaction: 3, combatSkill: 2, strength: 2, willpower: 5, logic: 5, intuition:
|
|
331
|
+
combat: { body: 2, agility: 2, reaction: 3, combatSkill: 2, strength: 2, willpower: 5, logic: 5, intuition: 3, charisma: 2, edge: 3, magic: 0, resonance: 6,
|
|
187
332
|
// The Resonance trio are three skills and the books test each by
|
|
188
333
|
// name (SR5 p.250). A Technomancer who could compile and register
|
|
189
334
|
// at 4 but decompile at the unskilled -1 would be an odd graduate;
|
|
@@ -194,26 +339,87 @@ export const ARCHETYPES = [
|
|
|
194
339
|
// its 20% cut of everything) followed them into the shadows, and the
|
|
195
340
|
// taxman never stops collecting. Ledger 25 - 5 + 15 = 35 -> 7 karma
|
|
196
341
|
// + 20,000 nuyen (the rest went into that resonance).
|
|
197
|
-
qualities: ['analytical-mind', 'sinner-corp'],
|
|
342
|
+
qualities: ['analytical-mind', 'natural-hardening', 'prime-datahaven-membership', 'focused-concentration', 'sinner-corp'],
|
|
343
|
+
gearSlugs: [
|
|
344
|
+
'armor-jacket', 'combat-boots', 'fake-sin-4', 'meta-link',
|
|
345
|
+
'microtransceiver', 'data-tap', 'micro-camera', 'stealth-tags',
|
|
346
|
+
'tag-eraser', 'white-noise-generator', 'medkit-3', 'trauma-patch',
|
|
347
|
+
'stim-patch', 'ear-buds', 'glasses', 'tool-kit', 'survival-kit', 'mapsoft',
|
|
348
|
+
'credstick-silver'
|
|
349
|
+
],
|
|
198
350
|
},
|
|
199
351
|
{
|
|
200
352
|
// The drone is the mechanic: "drone" launches the Fly-Spy for live
|
|
201
353
|
// recon of every adjacent room (see commands/drone.ts). Jumped-in
|
|
202
354
|
// drone rigging can build on this later.
|
|
203
355
|
name: 'Rigger',
|
|
356
|
+
priorities: { metatype: 'C', attributes: 'B', magic: 'E', skills: 'A', resources: 'D' },
|
|
204
357
|
description: 'Eyes everywhere: the Fly-Spy scouts the next room so your body never has to.',
|
|
205
358
|
combat: { body: 3, agility: 3, reaction: 5, combatSkill: 3, strength: 3, willpower: 3, logic: 5, intuition: 4, charisma: 2, edge: 2, magic: 0,
|
|
206
359
|
skills: { piloting: 6, hacking: 4, perception: 4, automatics: 3, pistols: 3, longarms: 3, locksmith: 3, unarmed: 2, 'first-aid': 2 } },
|
|
207
|
-
augs: ['control-rig'],
|
|
208
360
|
// Anything with a motor runs better under their hands; the drone
|
|
209
361
|
// feeds run all night, and so do they. Ledger 25 - 10 + 10 = 25 -> 7
|
|
210
362
|
// karma + 20,000 nuyen.
|
|
211
|
-
qualities: ['juryrigger', 'insomnia'],
|
|
212
|
-
|
|
213
|
-
|
|
363
|
+
qualities: ['juryrigger', 'gearhead', 'insomnia'],
|
|
364
|
+
// The p.466 row: Pilot 3, Body 1, a real hull.
|
|
365
|
+
augs: [
|
|
366
|
+
'control-rig', 'datajack', 'reaction-enhancers-1', 'cybereyes',
|
|
367
|
+
'vision-enhancement-1'
|
|
368
|
+
],
|
|
369
|
+
gearSlugs: [
|
|
370
|
+
'fly-spy', 'mct-nissan-roto-drone', 'ferret-rpd-5x', 'autosoft-3',
|
|
371
|
+
'tool-kit', 'miniwelder', 'erika-elite', 'fake-sin-4', 'fake-license-4',
|
|
372
|
+
'armor-jacket', 'combat-boots', 'ares-light-fire-70', 'quick-draw-holster',
|
|
373
|
+
'spare-clip', 'regular-ammo', 'medkit-3', 'trauma-patch', 'stim-patch',
|
|
374
|
+
'ear-buds', 'glasses', 'microtransceiver', 'mapsoft', 'credstick-silver'
|
|
214
375
|
],
|
|
215
376
|
},
|
|
216
377
|
];
|
|
378
|
+
/** The p.65 Resources column, lowest to highest. */
|
|
379
|
+
export const RESOURCES_PRIORITY = { E: 6_000, D: 50_000, C: 140_000, B: 275_000, A: 450_000 };
|
|
380
|
+
/**
|
|
381
|
+
* THE CREATION LEDGER, THE WAY THE CHARGEN VALIDATOR RUNS IT (user,
|
|
382
|
+
* 2026-09-03: "ensure the starting nuyen is appropriate for the archetype
|
|
383
|
+
* -- use the chargen api to validate"). maka-cli.com's validateWorksheet
|
|
384
|
+
* prices a build as: budget = the Resources column + converted karma x
|
|
385
|
+
* 2,000 (at most 10 karma, after 7 carry over, p.98); spent = gear at
|
|
386
|
+
* catalog price + 'ware at its cost x grade + the first month's
|
|
387
|
+
* lifestyle; and the factory caps what a runner may HOLD out of the
|
|
388
|
+
* remainder at 5,000 (p.95) -- the rest is gone into the build. Same
|
|
389
|
+
* constants, same prices, same rows; mirrored here because a pregen has
|
|
390
|
+
* no worksheet to POST (its skill spread is a spread, not a priority
|
|
391
|
+
* column, and the validator would refuse it on that before it priced
|
|
392
|
+
* it). The column is the archetype's own (IArchetype.priorities): the book's
|
|
393
|
+
* pregens are priority builds, and now so are these.
|
|
394
|
+
*
|
|
395
|
+
* Before this, outfitArchetype handed the converted karma over as CASH
|
|
396
|
+
* (up to 20,000): a pregen started with four times what a web-built
|
|
397
|
+
* runner may hold. Street lifestyle (the scenes' tier) costs nothing.
|
|
398
|
+
*/
|
|
399
|
+
export function archetypeLedger(archetype) {
|
|
400
|
+
const gearNuyen = (archetype.gearSlugs ?? []).reduce((n, slug) => {
|
|
401
|
+
const row = catalogRowFor(slug);
|
|
402
|
+
if (!row)
|
|
403
|
+
throw new Error(`Archetype "${archetype.name}" names catalog slug "${slug}", which has no row.`);
|
|
404
|
+
return n + row.price;
|
|
405
|
+
}, 0);
|
|
406
|
+
const augNuyen = (archetype.augs ?? []).reduce((n, key) => n + (getAug(key)?.cost ?? 0), 0);
|
|
407
|
+
const spent = (archetype.qualities ?? []).reduce((n, key) => {
|
|
408
|
+
const q = getQuality(key);
|
|
409
|
+
return n + (q ? (q.kind === 'positive' ? q.karma : -q.karma) : 0);
|
|
410
|
+
}, 0) + (archetype.combat.powerPoints ?? 0) * 5;
|
|
411
|
+
const karmaRemainder = CREATION_KARMA - spent;
|
|
412
|
+
const karmaConverted = Math.min(Math.max(0, karmaRemainder - KARMA_CARRYOVER_MAX), KARMA_TO_NUYEN_MAX);
|
|
413
|
+
const karmaCarry = Math.min(Math.max(0, karmaRemainder), KARMA_CARRYOVER_MAX);
|
|
414
|
+
const kit = gearNuyen + augNuyen;
|
|
415
|
+
// The DECLARED column (IArchetype.priorities) -- the build's own row, the
|
|
416
|
+
// one the wizard validates against. archetype-priorities.test.ts proves
|
|
417
|
+
// it affords the kit.
|
|
418
|
+
const resources = archetype.priorities.resources;
|
|
419
|
+
const nuyenBudget = RESOURCES_PRIORITY[resources] + karmaConverted * KARMA_NUYEN_RATE;
|
|
420
|
+
const nuyenRemaining = nuyenBudget - kit;
|
|
421
|
+
return { gearNuyen, augNuyen, karmaRemainder, karmaCarry, karmaConverted, resources, nuyenBudget, nuyenRemaining, held: Math.max(0, Math.min(nuyenRemaining, HELD_NUYEN_MAX)) };
|
|
422
|
+
}
|
|
217
423
|
export function getArchetype(name) {
|
|
218
424
|
return ARCHETYPES.find(a => a.name === name) ?? ARCHETYPES[0];
|
|
219
425
|
}
|
|
@@ -223,7 +429,24 @@ export function getArchetype(name) {
|
|
|
223
429
|
* ones -- a samurai starts with the Predator IN HAND, not in a duffel.
|
|
224
430
|
*/
|
|
225
431
|
export function createArchetypeGear(archetype) {
|
|
226
|
-
return instantiateGear(archetype
|
|
432
|
+
return instantiateGear(archetypeGearDefs(archetype));
|
|
433
|
+
}
|
|
434
|
+
/**
|
|
435
|
+
* Every piece an archetype starts with, as constructor configs: the
|
|
436
|
+
* catalog rows first (by slug, converted once in utilities/catalog.ts),
|
|
437
|
+
* then any custom pieces. The harness serializes these into a save; the
|
|
438
|
+
* game instantiates them. A slug with no row throws -- at build time, in
|
|
439
|
+
* the tests that walk every archetype -- rather than shipping a runner
|
|
440
|
+
* without her gun.
|
|
441
|
+
*/
|
|
442
|
+
export function archetypeGearDefs(archetype) {
|
|
443
|
+
const fromRows = (archetype.gearSlugs ?? []).map(slug => {
|
|
444
|
+
const def = catalogGearDef(slug);
|
|
445
|
+
if (!def)
|
|
446
|
+
throw new Error(`Archetype "${archetype.name}" names catalog slug "${slug}", which has no row.`);
|
|
447
|
+
return def;
|
|
448
|
+
});
|
|
449
|
+
return [...fromRows, ...(archetype.gear ?? [])];
|
|
227
450
|
}
|
|
228
451
|
function instantiateGear(defs) {
|
|
229
452
|
return defs.map(def => new Item({
|
|
@@ -285,18 +508,23 @@ export function outfitArchetype(player, archetype) {
|
|
|
285
508
|
powerPoints: archetype.combat.powerPoints ?? 0,
|
|
286
509
|
});
|
|
287
510
|
player.karma += split.karma;
|
|
288
|
-
//
|
|
511
|
+
// WHAT IS HELD arrives as a CREDSTICK, not a floating number --
|
|
289
512
|
// currency only counts when a carrier in the pack holds it (see
|
|
290
513
|
// Player.currency), same pattern as the job-payment stick (scene.ts).
|
|
291
|
-
|
|
514
|
+
// The amount is the chargen ledger's (archetypeLedger): what remains of
|
|
515
|
+
// the Resources column after the kit, capped at the 5,000 a runner may
|
|
516
|
+
// hold (p.95) -- not the converted karma as cash, which was four times
|
|
517
|
+
// what a web-built runner walks in with.
|
|
518
|
+
const ledger = archetypeLedger(archetype);
|
|
519
|
+
if (ledger.held > 0) {
|
|
292
520
|
const gearStick = new Item({
|
|
293
521
|
name: 'Certified Credstick (gear money)',
|
|
294
|
-
description:
|
|
522
|
+
description: `What was left when the outfitting was done -- certified, anonymous, and spending fast. (Resources ${ledger.resources}: ${ledger.nuyenRemaining.toLocaleString()} left after the kit, ${HELD_NUYEN_MAX.toLocaleString()} the most anyone walks out holding.)`,
|
|
295
523
|
size: Size.Tiny, category: Category.Credstick,
|
|
296
524
|
shape: 'Rectangle', color: 'Gunmetal', texture: 'Smooth',
|
|
297
525
|
rating: Rating.Standard, weight: 0.05, transferable: true,
|
|
298
526
|
});
|
|
299
|
-
gearStick.addCurrency(
|
|
527
|
+
gearStick.addCurrency(ledger.held);
|
|
300
528
|
player.addInventory(gearStick);
|
|
301
529
|
gearStick.owner = player.name;
|
|
302
530
|
}
|
|
@@ -313,10 +541,21 @@ export function outfitArchetype(player, archetype) {
|
|
|
313
541
|
player.addInventory(item);
|
|
314
542
|
item.owner = player.name;
|
|
315
543
|
if (EQUIP_ON_START.has(item.category)) {
|
|
544
|
+
// THE FIRST WEAPON LISTED IS THE SIGNATURE ONE, and a later one
|
|
545
|
+
// does not take its place (2026-09-03, found the moment loadouts
|
|
546
|
+
// grew past a single gun: a Street Samurai walked out holding a
|
|
547
|
+
// combat knife because it came after the Predator and the Alpha).
|
|
548
|
+
// The catch below already SAID "a second weapon just stays
|
|
549
|
+
// holstered" -- equip swaps, so it never did. Armor still layers
|
|
550
|
+
// over the baseline wardrobe on purpose, so only weapons are
|
|
551
|
+
// guarded here.
|
|
552
|
+
const isWeapon = item.category === Category.Weapon || item.category === Category.MeleeWeapon || item.category === Category.RangedWeapon;
|
|
553
|
+
if (isWeapon && player.getCarriedWeapon())
|
|
554
|
+
continue;
|
|
316
555
|
try {
|
|
317
556
|
player.equip(item);
|
|
318
557
|
}
|
|
319
|
-
catch { /*
|
|
558
|
+
catch { /* nothing to slot it into */ }
|
|
320
559
|
}
|
|
321
560
|
}
|
|
322
561
|
}
|