@maka/maka-cli 5.122.0 → 5.123.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/deploy/ubuntu.sub.cmd.js +12 -8
- package/bundle/typescript/src/commands/deploy/ubuntu.sub.cmd.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/adept-powers.d.ts +15 -0
- package/bundle/typescript/src/commands/game/sideQuest/adept-powers.js +12 -0
- package/bundle/typescript/src/commands/game/sideQuest/adept-powers.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/archetypes.d.ts +10 -0
- package/bundle/typescript/src/commands/game/sideQuest/archetypes.js +40 -14
- package/bundle/typescript/src/commands/game/sideQuest/archetypes.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/augmentations.d.ts +33 -10
- package/bundle/typescript/src/commands/game/sideQuest/augmentations.js +155 -72
- package/bundle/typescript/src/commands/game/sideQuest/augmentations.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/advance.js +15 -6
- package/bundle/typescript/src/commands/game/sideQuest/commands/advance.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/ask.js +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/ask.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/bluff.js +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/bluff.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/cast.js +33 -33
- package/bundle/typescript/src/commands/game/sideQuest/commands/cast.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/drone.js +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/drone.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/go.js +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/go.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/grapple.js +5 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/grapple.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/hack.js +6 -6
- package/bundle/typescript/src/commands/game/sideQuest/commands/hack.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/haggle.js +4 -4
- package/bundle/typescript/src/commands/game/sideQuest/commands/haggle.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/hop.js +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/hop.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/initiate.d.ts +20 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/initiate.js +9 -0
- package/bundle/typescript/src/commands/game/sideQuest/commands/initiate.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/lead.js +7 -3
- package/bundle/typescript/src/commands/game/sideQuest/commands/lead.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/move.js +3 -3
- package/bundle/typescript/src/commands/game/sideQuest/commands/move.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/persuade.js +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/persuade.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/rest.js +3 -3
- package/bundle/typescript/src/commands/game/sideQuest/commands/rest.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/sheet.js +10 -10
- package/bundle/typescript/src/commands/game/sideQuest/commands/sheet.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/tap.js +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/commands/tap.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/factories/chargen-factory.d.ts +24 -0
- package/bundle/typescript/src/commands/game/sideQuest/factories/chargen-factory.js +95 -0
- package/bundle/typescript/src/commands/game/sideQuest/factories/chargen-factory.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/game.d.ts +45 -1
- package/bundle/typescript/src/commands/game/sideQuest/game.js +119 -8
- package/bundle/typescript/src/commands/game/sideQuest/game.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/metatypes.d.ts +53 -0
- package/bundle/typescript/src/commands/game/sideQuest/metatypes.js +86 -0
- package/bundle/typescript/src/commands/game/sideQuest/metatypes.js.map +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/models/npc.js +8 -2
- package/bundle/typescript/src/commands/game/sideQuest/models/npc.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/models/player.d.ts +215 -18
- package/bundle/typescript/src/commands/game/sideQuest/models/player.js +548 -117
- package/bundle/typescript/src/commands/game/sideQuest/models/player.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/models/scene.d.ts +2 -1
- package/bundle/typescript/src/commands/game/sideQuest/models/scene.js +3 -2
- package/bundle/typescript/src/commands/game/sideQuest/models/scene.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/qualities.d.ts +96 -4
- package/bundle/typescript/src/commands/game/sideQuest/qualities.js +290 -11
- package/bundle/typescript/src/commands/game/sideQuest/qualities.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/skill-groups.d.ts +11 -1
- package/bundle/typescript/src/commands/game/sideQuest/skill-groups.js +13 -1
- package/bundle/typescript/src/commands/game/sideQuest/skill-groups.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/skills.d.ts +17 -0
- package/bundle/typescript/src/commands/game/sideQuest/skills.js +23 -0
- package/bundle/typescript/src/commands/game/sideQuest/skills.js.map +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/spells.d.ts +76 -3
- package/bundle/typescript/src/commands/game/sideQuest/spells.js +48 -21
- package/bundle/typescript/src/commands/game/sideQuest/spells.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/catalog-data.d.ts +90 -82
- package/bundle/typescript/src/commands/game/sideQuest/utilities/catalog-data.js +277 -10
- package/bundle/typescript/src/commands/game/sideQuest/utilities/catalog-data.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/catalog.d.ts +121 -2
- package/bundle/typescript/src/commands/game/sideQuest/utilities/catalog.js +342 -18
- 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 +65 -2
- package/bundle/typescript/src/commands/game/sideQuest/utilities/cloud-saves.js +74 -7
- 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 +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/combat-exchange.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/effects.d.ts +248 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/effects.js +38 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/effects.js.map +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/first-aid.js +1 -2
- package/bundle/typescript/src/commands/game/sideQuest/utilities/first-aid.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/perception.js +1 -2
- package/bundle/typescript/src/commands/game/sideQuest/utilities/perception.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/persistence.js +5 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/persistence.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/planes.js +5 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/planes.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/pregen-worksheet.js +22 -12
- package/bundle/typescript/src/commands/game/sideQuest/utilities/pregen-worksheet.js.map +1 -1
- package/bundle/typescript/src/commands/game/sideQuest/utilities/spots.js +1 -2
- 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 +1 -0
- package/bundle/typescript/src/commands/game/sideQuest/utilities/web-character-generator.js +20 -0
- 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 +31 -0
- package/bundle/typescript/src/commands/game/sideQuest.sub.cmd.js.map +1 -1
- package/bundle/typescript/src/commands/login.js +19 -1
- package/bundle/typescript/src/commands/login.js.map +1 -1
- package/bundle/typescript/src/commands/logout.js +16 -1
- package/bundle/typescript/src/commands/logout.js.map +1 -1
- package/bundle/typescript/src/tools/guarded-file/guarded-file.class.d.ts +59 -0
- package/bundle/typescript/src/tools/guarded-file/guarded-file.class.js +120 -0
- package/bundle/typescript/src/tools/guarded-file/guarded-file.class.js.map +1 -0
- package/bundle/typescript/src/tools/mpi/mpi.class.d.ts +16 -0
- package/bundle/typescript/src/tools/mpi/mpi.class.js +25 -7
- package/bundle/typescript/src/tools/mpi/mpi.class.js.map +1 -1
- package/package.json +1 -1
|
@@ -19,17 +19,22 @@ export const QUALITIES = [
|
|
|
19
19
|
// ------------------------------ Positive ------------------------------
|
|
20
20
|
{
|
|
21
21
|
key: 'toughness', name: 'Toughness', kind: 'positive', karma: 9, page: 'p.77',
|
|
22
|
+
family: 'pool',
|
|
22
23
|
effect: '+1 die on every damage soak roll',
|
|
24
|
+
effects: [{ type: 'dice', category: 'pools', property: 'soak', value: 1 }],
|
|
23
25
|
},
|
|
24
26
|
{
|
|
25
27
|
// RAW: ignore one box per rating when counting wound modifiers, and it
|
|
26
28
|
// cannot combine with a pain editor (woundModifier enforces that).
|
|
27
29
|
key: 'high-pain-tolerance', name: 'High Pain Tolerance', kind: 'positive', karma: 7, page: 'p.74',
|
|
30
|
+
family: 'engine-rule',
|
|
28
31
|
effect: 'ignore 1 box of damage when counting wound modifiers',
|
|
29
32
|
},
|
|
30
33
|
{
|
|
31
34
|
key: 'catlike', name: 'Catlike', kind: 'positive', karma: 7, page: 'p.72',
|
|
35
|
+
family: 'pool',
|
|
32
36
|
effect: '+2 dice on sneaking tests',
|
|
37
|
+
effects: [{ type: 'dice', category: 'pools', property: 'sneak', value: 2 }],
|
|
33
38
|
},
|
|
34
39
|
{
|
|
35
40
|
// THE INVITE (Data Trails p.45-46, Prime Datahaven Membership). You
|
|
@@ -46,6 +51,7 @@ export const QUALITIES = [
|
|
|
46
51
|
// named people you call, and inventing a group entry to carry two
|
|
47
52
|
// numbers nothing reads would be a worse lie than the omission.
|
|
48
53
|
key: 'prime-datahaven-membership', name: 'Prime Datahaven Membership',
|
|
54
|
+
family: 'engine-rule',
|
|
49
55
|
kind: 'positive', karma: 7, page: 'Data Trails p.45-46',
|
|
50
56
|
effect: 'JackPoint knows your handle -- the haven answers when you call it',
|
|
51
57
|
},
|
|
@@ -53,38 +59,71 @@ export const QUALITIES = [
|
|
|
53
59
|
// RAW: +2 on Running/Gymnastics -- here, the athletics sprint that
|
|
54
60
|
// breaks off a fight (go.ts) is where that muscle shows.
|
|
55
61
|
key: 'natural-athlete', name: 'Natural Athlete', kind: 'positive', karma: 7, page: 'p.76',
|
|
62
|
+
family: 'pool',
|
|
56
63
|
effect: '+2 dice on athletics tests (including the sprint out of a fight)',
|
|
64
|
+
effects: [{ type: 'dice', category: 'pools', property: 'athletics', value: 2 }],
|
|
57
65
|
},
|
|
58
66
|
{
|
|
59
|
-
//
|
|
60
|
-
//
|
|
67
|
+
// A CEILING, NOT A POINT -- RAG-checked p.76, which is explicit
|
|
68
|
+
// about the difference: "Lucky allows a character to possess an Edge
|
|
69
|
+
// attribute one point higher than his metatype maximum ... Note that
|
|
70
|
+
// taking this quality does not actually increase the character's
|
|
71
|
+
// current Edge rating, it just allows her the opportunity to do so;
|
|
72
|
+
// the Karma cost for gaining the extra point must still be paid."
|
|
73
|
+
// A human's Edge maximum goes 7 -> 8, and the eighth point is bought
|
|
74
|
+
// at "advance" like any other.
|
|
75
|
+
//
|
|
76
|
+
// THE COMMENT THAT USED TO SIT HERE said "RAW raises the Edge CEILING
|
|
77
|
+
// without granting the point; with no point-buy attributes here, the
|
|
78
|
+
// adaptation grants it outright" -- an honest approximation from the
|
|
79
|
+
// days when nothing in this file could express a ceiling. That excuse
|
|
80
|
+
// expired when `cap` effects arrived, and by then the approximation
|
|
81
|
+
// was costing something real: the web chargen applies the book's
|
|
82
|
+
// rule, so the same archetype built in the wizard and in the CLI
|
|
83
|
+
// disagreed about Edge by one. Reported by the user on 2026-09-04 --
|
|
84
|
+
// "I'm adding Lucky ... I don't see this updating in the chargen".
|
|
85
|
+
// The wizard was right.
|
|
86
|
+
//
|
|
87
|
+
// It is also WHY this quality and Exceptional Attribute exclude each
|
|
88
|
+
// other (p.65-66): they are the same mechanic, and Edge is the one
|
|
89
|
+
// attribute Exceptional Attribute may not name.
|
|
61
90
|
key: 'lucky', name: 'Lucky', kind: 'positive', karma: 12, page: 'p.76',
|
|
62
|
-
|
|
91
|
+
family: 'ceiling',
|
|
92
|
+
excludesQuality: 'exceptional-attribute',
|
|
93
|
+
effect: 'your Edge may run 1 past its natural maximum -- buy the point at "advance"',
|
|
94
|
+
effects: [{ type: 'cap', category: 'attributes', property: 'edge', value: 1 }],
|
|
63
95
|
},
|
|
64
96
|
{
|
|
65
97
|
// RAW: +2 social dice on a first meeting. Meetings aren't tracked
|
|
66
98
|
// per-NPC, so the adaptation is per JOB: the first social play of
|
|
67
99
|
// every job (persuade, bluff, haggle) gets the bonus.
|
|
68
100
|
key: 'first-impression', name: 'First Impression', kind: 'positive', karma: 11, page: 'p.74',
|
|
101
|
+
family: 'engine-rule',
|
|
69
102
|
effect: '+2 dice on the first social play of every job',
|
|
70
103
|
},
|
|
71
104
|
{
|
|
72
105
|
// RAW: +2 on all Healing Tests -- exactly the first-aid roll (use.ts)
|
|
73
106
|
// and the rest recovery roll (rest.ts).
|
|
74
107
|
key: 'quick-healer', name: 'Quick Healer', kind: 'positive', karma: 3, page: 'p.77',
|
|
108
|
+
family: 'pool',
|
|
75
109
|
effect: '+2 dice on every healing test made on or by you (first aid, rest)',
|
|
110
|
+
effects: [{ type: 'dice', category: 'pools', property: 'healing', value: 2 }],
|
|
76
111
|
},
|
|
77
112
|
{
|
|
78
113
|
// RAW: +2 on Logic tests for pattern analysis / puzzle-cracking --
|
|
79
114
|
// mapped to the hacking rolls, the game's logic-puzzle work.
|
|
80
115
|
key: 'analytical-mind', name: 'Analytical Mind', kind: 'positive', karma: 5, page: 'p.72',
|
|
116
|
+
family: 'pool',
|
|
81
117
|
effect: '+2 dice on hacking tests -- code is just a puzzle with rent',
|
|
118
|
+
effects: [{ type: 'dice', category: 'skills', property: 'hacking', value: 2 }],
|
|
82
119
|
},
|
|
83
120
|
{
|
|
84
121
|
// RAW: +2 juryrigging mechanical/electronic gear -- mapped to the
|
|
85
122
|
// piloting roll (drone work IS field rigging) and bench deck repair.
|
|
86
123
|
key: 'juryrigger', name: 'Juryrigger', kind: 'positive', karma: 10, page: 'p.75',
|
|
124
|
+
family: 'pool',
|
|
87
125
|
effect: '+2 dice on piloting and on bench-repairing a damaged deck',
|
|
126
|
+
effects: [{ type: 'dice', category: 'pools', property: 'piloting', value: 2 }],
|
|
88
127
|
},
|
|
89
128
|
{
|
|
90
129
|
// RAW: +1 on ALL Perception Tests, and the book says "including
|
|
@@ -95,7 +134,9 @@ export const QUALITIES = [
|
|
|
95
134
|
// and its shape is co-owned with the web chargen, so a second entry
|
|
96
135
|
// would be inventing a rating system in the key names.
|
|
97
136
|
key: 'perceptive', name: 'Perceptive', kind: 'positive', karma: 5, page: 'Run Faster p.148',
|
|
137
|
+
family: 'pool',
|
|
98
138
|
effect: '+1 die on every perception test -- meat, astral or grid',
|
|
139
|
+
effects: [{ type: 'dice', category: 'pools', property: 'perception', value: 1 }],
|
|
99
140
|
},
|
|
100
141
|
{
|
|
101
142
|
// RAW: +1 to every skill in the INFLUENCE group (Etiquette,
|
|
@@ -110,7 +151,9 @@ export const QUALITIES = [
|
|
|
110
151
|
// social chrome does too -- a bigger change than this entry, made
|
|
111
152
|
// sideways. The verbs named below are the ones that actually move.
|
|
112
153
|
key: 'trustworthy', name: 'Trustworthy', kind: 'positive', karma: 15, page: 'Run Faster p.151',
|
|
154
|
+
family: 'pool',
|
|
113
155
|
effect: '+1 die when you ask, bluff, haggle or persuade -- people believe you',
|
|
156
|
+
effects: [{ type: 'dice', category: 'pools', property: 'social', value: 1 }],
|
|
114
157
|
},
|
|
115
158
|
{
|
|
116
159
|
// RAW: +2 to ONE Matrix action you choose when you take it (p.237's
|
|
@@ -123,9 +166,16 @@ export const QUALITIES = [
|
|
|
123
166
|
// shipped because it is one the engine actually names: hack.ts logs
|
|
124
167
|
// the sleaze route as "Hack on the Fly (sleaze)" per p.240, and
|
|
125
168
|
// mark.ts states that placing a mark IS that same action.
|
|
126
|
-
key: 'codeslinger
|
|
169
|
+
key: 'codeslinger', name: 'Codeslinger',
|
|
170
|
+
family: 'pool',
|
|
127
171
|
kind: 'positive', karma: 10, page: 'p.72',
|
|
128
|
-
effect: '+2 dice on
|
|
172
|
+
effect: '+2 dice on ONE Matrix action you choose -- the route you made your own',
|
|
173
|
+
choice: {
|
|
174
|
+
of: 'matrix-action',
|
|
175
|
+
prompt: 'Which way in did you make your own -- the quiet one or the loud one?',
|
|
176
|
+
from: ['matrix-sleaze', 'matrix-attack'],
|
|
177
|
+
},
|
|
178
|
+
effects: [{ type: 'dice', category: 'pools', property: 'chosen', value: 2 }],
|
|
129
179
|
},
|
|
130
180
|
{
|
|
131
181
|
// GOING FOR ALL THREE AT ONCE (Data Trails p.44, cited on
|
|
@@ -136,59 +186,94 @@ export const QUALITIES = [
|
|
|
136
186
|
// pool bonus -- a -4 handed to every intrusion would be a different,
|
|
137
187
|
// much stronger quality than the book's.
|
|
138
188
|
key: 'go-big-or-go-home', name: 'Go Big or Go Home',
|
|
189
|
+
family: 'engine-rule',
|
|
139
190
|
kind: 'positive', karma: 6, page: 'Data Trails p.44',
|
|
140
191
|
effect: 'reaching for all three marks in one action costs -6 dice instead of -10',
|
|
141
192
|
},
|
|
142
193
|
// ------------------------------ Negative ------------------------------
|
|
143
194
|
{
|
|
144
195
|
key: 'sinner-national', name: 'SINner (National)', kind: 'negative', karma: 5, page: 'p.84',
|
|
196
|
+
family: 'engine-rule',
|
|
145
197
|
effect: 'a legal SIN with taxes attached: 15% of every job and gig payout withheld',
|
|
146
198
|
},
|
|
147
199
|
{
|
|
148
200
|
key: 'sinner-criminal', name: 'SINner (Criminal)', kind: 'negative', karma: 10, page: 'p.84',
|
|
201
|
+
family: 'engine-rule',
|
|
149
202
|
effect: 'a felon\'s SIN, broadcast always: 15% of every payout withheld, and the law knows your face',
|
|
150
203
|
},
|
|
151
204
|
{
|
|
152
205
|
key: 'sinner-corp', name: 'SINner (Corporate Limited)', kind: 'negative', karma: 15, page: 'p.84-85',
|
|
206
|
+
family: 'engine-rule',
|
|
153
207
|
effect: 'a megacorp owns your file: 20% of every payout goes home to the company',
|
|
154
208
|
},
|
|
155
209
|
{
|
|
156
210
|
key: 'low-pain-tolerance', name: 'Low Pain Tolerance', kind: 'negative', karma: 9, page: 'p.82',
|
|
211
|
+
family: 'engine-rule',
|
|
157
212
|
effect: 'wound modifiers bite every 2 boxes instead of every 3',
|
|
158
213
|
},
|
|
159
214
|
{
|
|
160
215
|
// RAW: first Initiative Score of a combat halved. Mapped to the
|
|
161
216
|
// opening exchange of any fresh fight (combat-exchange.ts).
|
|
162
217
|
key: 'combat-paralysis', name: 'Combat Paralysis', kind: 'negative', karma: 12, page: 'p.80',
|
|
218
|
+
family: 'engine-rule',
|
|
163
219
|
effect: 'you freeze when it starts: initiative halved in a fight\'s opening exchange',
|
|
164
220
|
},
|
|
165
221
|
{
|
|
166
222
|
// RAW: spent Edge can turn on you. Adaptation: burning edge rolls a
|
|
167
223
|
// die -- on a 1 the point is gone and the boost never arms (edge.ts).
|
|
168
224
|
key: 'bad-luck', name: 'Bad Luck', kind: 'negative', karma: 12, page: 'p.79',
|
|
225
|
+
family: 'engine-rule',
|
|
169
226
|
effect: '1 in 6 edge burns curdle: the point is spent, the boost never comes',
|
|
170
227
|
},
|
|
171
228
|
{
|
|
172
229
|
// RAW: a look people remember, easy to describe, easy to identify.
|
|
173
230
|
// Adaptation: -2 on sneaking tests -- witnesses clock you.
|
|
174
231
|
key: 'distinctive-style', name: 'Distinctive Style', kind: 'negative', karma: 5, page: 'p.80',
|
|
232
|
+
family: 'pool',
|
|
175
233
|
effect: 'people remember you: -2 dice on sneaking tests',
|
|
234
|
+
effects: [{ type: 'dice', category: 'pools', property: 'sneak', value: -2 }],
|
|
176
235
|
},
|
|
177
236
|
{
|
|
178
237
|
// RAW: rest may not restore you fully. Adaptation: rest recovery
|
|
179
238
|
// halved (rest.ts) -- sleep never comes easy.
|
|
180
239
|
key: 'insomnia', name: 'Insomnia', kind: 'negative', karma: 10, page: 'p.81',
|
|
240
|
+
family: 'engine-rule',
|
|
181
241
|
effect: 'rest recovers half the stun it should -- sleep never comes easy',
|
|
182
242
|
},
|
|
183
243
|
{
|
|
184
244
|
key: 'simsense-vertigo', name: 'Simsense Vertigo', kind: 'negative', karma: 5, page: 'p.83',
|
|
245
|
+
family: 'pool',
|
|
185
246
|
effect: '-2 dice on Matrix actions -- the sim makes your inner ear lie',
|
|
247
|
+
effects: [{ type: 'dice', category: 'pools', property: 'matrix', value: -2 }],
|
|
186
248
|
},
|
|
187
249
|
{
|
|
188
250
|
// RAW: an Active skill group you simply cannot have. skillRating
|
|
189
251
|
// pins it to 0 and advance.ts refuses to train it.
|
|
190
|
-
|
|
191
|
-
|
|
252
|
+
// PER SKILL GROUP, NOT PER SKILL, and RAG-checked after this entry
|
|
253
|
+
// first shipped as a single-skill pick: p.81 applies the quality to
|
|
254
|
+
// "a certain Active skill group" and treats the holder as unaware
|
|
255
|
+
// "for all skills in the skill group". Naming one skill was a
|
|
256
|
+
// deviation I introduced while retiring the old slug -- the slug
|
|
257
|
+
// said hacking, and I carried its narrowness across instead of
|
|
258
|
+
// reading the quality.
|
|
259
|
+
//
|
|
260
|
+
// FORBIDDEN, NOT ZEROED. Unaware (p.131) is "You cannot default the
|
|
261
|
+
// skill" -- so this is a `forbid` effect and not a ceiling, because
|
|
262
|
+
// no number says "absent". A -6 would read as 0 at creation and 6
|
|
263
|
+
// against the career ceiling, and even an absolute 0 would still
|
|
264
|
+
// default at -1 in this engine.
|
|
265
|
+
key: 'incompetent', name: 'Incompetent', kind: 'negative', karma: 5, page: 'p.81',
|
|
266
|
+
choice: {
|
|
267
|
+
of: 'skill-group',
|
|
268
|
+
prompt: 'Which whole set of skills has never taken, however hard anyone tried?',
|
|
269
|
+
},
|
|
270
|
+
effects: [{ type: 'forbid', category: 'skills', property: 'chosen' }],
|
|
271
|
+
// Half-live, and deliberately not tagged inert: advance.ts refuses
|
|
272
|
+
// to train the skill at any price (the "never trained" half of the
|
|
273
|
+
// rule). What is missing is the other half -- nothing forces the
|
|
274
|
+
// rating to 0 at creation, so an archetype could still hand one out.
|
|
275
|
+
family: 'engine-rule',
|
|
276
|
+
effect: 'one whole skill group is closed to you -- you cannot use it, train it, or even default on it',
|
|
192
277
|
},
|
|
193
278
|
{
|
|
194
279
|
// RAW: you start play with 3 points of Notoriety. Read straight by
|
|
@@ -196,6 +281,7 @@ export const QUALITIES = [
|
|
|
196
281
|
// awareness exactly as earned notoriety does -- the quality does not
|
|
197
282
|
// need its own arithmetic, it needs the number the book gives it.
|
|
198
283
|
key: 'bad-rep', name: 'Bad Rep', kind: 'negative', karma: 7, page: 'p.79',
|
|
284
|
+
family: 'engine-rule',
|
|
199
285
|
effect: 'the street tells stories about you: 3 points of notoriety, before you have earned any',
|
|
200
286
|
},
|
|
201
287
|
{
|
|
@@ -206,16 +292,25 @@ export const QUALITIES = [
|
|
|
206
292
|
// (skillRating already floors at 0 with an unskilled -1 default, so
|
|
207
293
|
// there is no lower rung to drop to).
|
|
208
294
|
key: 'uncouth', name: 'Uncouth', kind: 'negative', karma: 14, page: 'p.85-86',
|
|
295
|
+
family: 'pool',
|
|
209
296
|
effect: '-2 dice when you ask, bluff, haggle or persuade -- you rub people wrong',
|
|
297
|
+
effects: [{ type: 'dice', category: 'pools', property: 'social', value: -2 }],
|
|
210
298
|
},
|
|
211
299
|
{
|
|
212
300
|
// RAW: -2 on ONE Matrix action you choose. Same key-encoded choice
|
|
213
301
|
// as Codeslinger above, and the same reason. Brute Force is the
|
|
214
302
|
// action shipped: hack.ts logs the loud route as "Brute Force
|
|
215
303
|
// (attack)" per p.238, so the engine names it.
|
|
216
|
-
key: 'codeblock
|
|
304
|
+
key: 'codeblock', name: 'Codeblock',
|
|
305
|
+
family: 'pool',
|
|
217
306
|
kind: 'negative', karma: 10, page: 'p.80',
|
|
218
|
-
effect: '-2 dice on
|
|
307
|
+
effect: '-2 dice on ONE Matrix action you choose -- the one that never sits right',
|
|
308
|
+
choice: {
|
|
309
|
+
of: 'matrix-action',
|
|
310
|
+
prompt: 'Which way in never sits right -- the quiet one or the loud one?',
|
|
311
|
+
from: ['matrix-sleaze', 'matrix-attack'],
|
|
312
|
+
},
|
|
313
|
+
effects: [{ type: 'dice', category: 'pools', property: 'chosen', value: -2 }],
|
|
219
314
|
},
|
|
220
315
|
// ================= THE FULL-CATALOG PASS (2026-09-01) =================
|
|
221
316
|
// The user's report: "the qualities list is severely lacking" -- and it
|
|
@@ -230,145 +325,237 @@ export const QUALITIES = [
|
|
|
230
325
|
// ------------------------------ Positive ------------------------------
|
|
231
326
|
{
|
|
232
327
|
key: 'ambidextrous', name: 'Ambidextrous', kind: 'positive', karma: 4, page: 'p.71',
|
|
328
|
+
inert: 'the engine applies no off-hand penalty (p.178), so there is none to waive',
|
|
329
|
+
family: 'engine-rule',
|
|
233
330
|
effect: 'either hand works equally well -- no off-hand penalty (p.178)',
|
|
234
331
|
},
|
|
235
332
|
{
|
|
333
|
+
// RAG-checked p.72: the chosen skill may be rated 7 at creation
|
|
334
|
+
// (against the usual 6) and may eventually reach 13 (against 12).
|
|
335
|
+
// Both ends are the SAME delta -- one step further than anyone else
|
|
336
|
+
// gets -- so the engine applies +1 to its own ceiling at both ends
|
|
337
|
+
// rather than writing the book's absolute numbers over house ones.
|
|
338
|
+
// Taken once only.
|
|
236
339
|
key: 'aptitude', name: 'Aptitude', kind: 'positive', karma: 14, page: 'p.72',
|
|
340
|
+
inert: 'the engine path is complete -- the web chargen does not yet ask which skill, and without an answer the ceiling lifts nothing',
|
|
341
|
+
family: 'ceiling',
|
|
237
342
|
effect: 'one chosen skill may start at 7 and one day reach 13 -- past every limit',
|
|
343
|
+
choice: { of: 'skill', prompt: 'Which skill is the one you were born for?' },
|
|
344
|
+
effects: [{ type: 'cap', category: 'skills', property: 'chosen', value: 1 }],
|
|
238
345
|
},
|
|
239
346
|
{
|
|
240
347
|
key: 'astral-chameleon', name: 'Astral Chameleon', kind: 'positive', karma: 10, page: 'p.72',
|
|
348
|
+
inert: 'no astral signature is recorded, so nothing can fade faster or read fainter',
|
|
349
|
+
family: 'engine-rule',
|
|
241
350
|
requires: 'awakened',
|
|
242
351
|
effect: 'your astral signature fades in half the time and reads at -2 to assensing',
|
|
243
352
|
},
|
|
244
353
|
{
|
|
245
354
|
key: 'bilingual', name: 'Bilingual', kind: 'positive', karma: 5, page: 'p.72',
|
|
355
|
+
inert: 'the engine models no languages',
|
|
356
|
+
family: 'narrative',
|
|
246
357
|
effect: 'a second language as a native tongue, free, from birth',
|
|
247
358
|
},
|
|
248
359
|
{
|
|
249
360
|
key: 'blandness', name: 'Blandness', kind: 'positive', karma: 8, page: 'p.72',
|
|
361
|
+
inert: 'no test carries a threshold this could raise; recall and shadowing are not rolled',
|
|
362
|
+
family: 'threshold',
|
|
250
363
|
effect: 'forgettable on purpose: +1 threshold to recall or shadow you (not vs magic or Matrix)',
|
|
251
364
|
},
|
|
252
365
|
{
|
|
253
366
|
key: 'double-jointed', name: 'Double-Jointed', kind: 'positive', karma: 6, page: 'p.72',
|
|
367
|
+
family: 'pool',
|
|
254
368
|
effect: '+2 dice on escape-artist work; squeeze where others cannot',
|
|
369
|
+
effects: [{ type: 'dice', category: 'skills', property: 'escape-artist', value: 2 }],
|
|
255
370
|
},
|
|
256
371
|
{
|
|
372
|
+
// RAG-checked p.73-74: +1 to the NATURAL MAXIMUM of one attribute,
|
|
373
|
+
// never Edge (p.65-66 -- Edge is Lucky's job, and the book says you
|
|
374
|
+
// may buy either quality, not both). It does not raise the
|
|
375
|
+
// attribute itself: it moves the ceiling and you still pay to climb.
|
|
257
376
|
key: 'exceptional-attribute', name: 'Exceptional Attribute', kind: 'positive', karma: 14, page: 'p.72',
|
|
377
|
+
inert: 'the engine path is complete -- the web chargen does not yet ask which attribute, and without an answer the ceiling lifts nothing',
|
|
378
|
+
family: 'ceiling',
|
|
258
379
|
effect: 'one attribute may run 1 above its natural maximum (never Edge -- that is Lucky)',
|
|
380
|
+
choice: {
|
|
381
|
+
of: 'attribute',
|
|
382
|
+
prompt: 'Which attribute runs past the human ceiling?',
|
|
383
|
+
excludes: ['edge'],
|
|
384
|
+
},
|
|
385
|
+
excludesQuality: 'lucky',
|
|
386
|
+
effects: [{ type: 'cap', category: 'attributes', property: 'chosen', value: 1 }],
|
|
259
387
|
},
|
|
260
388
|
{
|
|
261
389
|
key: 'focused-concentration', name: 'Focused Concentration',
|
|
390
|
+
family: 'engine-rule',
|
|
262
391
|
kind: 'positive', karma: 4, maxRating: 6, page: 'p.74', requires: 'caster-or-technomancer',
|
|
263
392
|
effect: 'sustain one spell of Force up to your rating with no sustaining penalty',
|
|
264
393
|
},
|
|
265
394
|
{
|
|
266
395
|
key: 'gearhead', name: 'Gearhead', kind: 'positive', karma: 11, page: 'p.74',
|
|
396
|
+
inert: 'the piloting roll has no notion of a hard maneuver, and no speed or Handling to boost',
|
|
397
|
+
family: 'pool',
|
|
267
398
|
effect: 'behind any wheel or stick: +2 dice on hard maneuvers, +20% speed or +1 Handling for 1D6 minutes',
|
|
268
399
|
},
|
|
269
400
|
{
|
|
270
401
|
key: 'guts', name: 'Guts', kind: 'positive', karma: 10, page: 'p.74',
|
|
402
|
+
inert: 'nothing rolls to resist fear -- brandish menaces, but the target never tests',
|
|
403
|
+
family: 'pool',
|
|
271
404
|
effect: '+2 dice to resist fear and intimidation, mundane or magical',
|
|
272
405
|
},
|
|
273
406
|
{
|
|
274
407
|
key: 'home-ground', name: 'Home Ground', kind: 'positive', karma: 10, page: 'p.74',
|
|
408
|
+
inert: 'needs a chosen domain (IQualityChoice) and a per-domain bonus seat',
|
|
409
|
+
family: 'pool',
|
|
275
410
|
effect: 'your turf, one chosen edge on it: the streets, the people, the host, or the bolt-holes',
|
|
276
411
|
},
|
|
277
412
|
{
|
|
278
413
|
key: 'magic-resistance', name: 'Magic Resistance',
|
|
414
|
+
family: 'engine-rule',
|
|
279
415
|
kind: 'positive', karma: 6, maxRating: 4, page: 'p.76', requires: 'mundane',
|
|
280
416
|
effect: '+1 die per rating when you resist a spell -- always on: friendly spells (Heal included) fail on you too',
|
|
281
417
|
},
|
|
282
418
|
{
|
|
283
419
|
key: 'mentor-spirit', name: 'Mentor Spirit', kind: 'positive', karma: 5, page: 'p.76',
|
|
420
|
+
inert: 'needs a chosen patron and its per-mentor bonuses and demands (p.320)',
|
|
421
|
+
family: 'engine-rule',
|
|
284
422
|
requires: 'awakened',
|
|
285
423
|
effect: 'a patron spirit guides your magic -- its blessings and its demands (p.320)',
|
|
286
424
|
},
|
|
287
425
|
{
|
|
288
426
|
key: 'natural-hardening', name: 'Natural Hardening', kind: 'positive', karma: 10, page: 'p.76',
|
|
427
|
+
family: 'pool',
|
|
289
428
|
effect: '1 point of natural biofeedback filtering, cumulative with a filter or living firewall',
|
|
429
|
+
effects: [{ type: 'dice', category: 'pools', property: 'biofeedback', value: 1 }],
|
|
290
430
|
},
|
|
291
431
|
{
|
|
292
|
-
key: 'natural-immunity
|
|
432
|
+
key: 'natural-immunity', name: 'Natural Immunity',
|
|
433
|
+
choice: {
|
|
434
|
+
of: 'hazard-class',
|
|
435
|
+
prompt: 'Which does your body simply refuse -- something natural, or something built?',
|
|
436
|
+
from: ['natural', 'synthetic'],
|
|
437
|
+
},
|
|
438
|
+
inert: 'no disease or toxin track exists to be immune to',
|
|
439
|
+
family: 'engine-rule',
|
|
293
440
|
kind: 'positive', karma: 4, page: 'p.77',
|
|
294
441
|
effect: 'immune to ONE chosen natural disease or toxin (never magical ones)',
|
|
295
442
|
},
|
|
296
443
|
{
|
|
297
444
|
key: 'natural-immunity-synthetic', name: 'Natural Immunity (Synthetic)',
|
|
445
|
+
inert: 'no disease or toxin track exists to be immune to',
|
|
446
|
+
family: 'engine-rule',
|
|
298
447
|
kind: 'positive', karma: 10, page: 'p.77',
|
|
299
448
|
effect: 'immune to ONE chosen synthetic disease or toxin (never magical ones)',
|
|
300
449
|
},
|
|
301
450
|
{
|
|
302
451
|
key: 'photographic-memory', name: 'Photographic Memory', kind: 'positive', karma: 6, page: 'p.77',
|
|
452
|
+
inert: 'nothing rolls a Memory Test',
|
|
453
|
+
family: 'pool',
|
|
303
454
|
effect: '+2 dice on every Memory Test -- what you saw stays seen',
|
|
304
455
|
},
|
|
305
456
|
{
|
|
306
|
-
key: 'resistance-
|
|
457
|
+
key: 'resistance-one', name: 'Resistance (One Class)',
|
|
458
|
+
choice: {
|
|
459
|
+
of: 'hazard-class',
|
|
460
|
+
prompt: 'Which do you shrug off -- pathogens, or toxins?',
|
|
461
|
+
from: ['pathogens', 'toxins'],
|
|
462
|
+
},
|
|
463
|
+
inert: 'nothing rolls to resist a pathogen or a toxin',
|
|
464
|
+
family: 'pool',
|
|
307
465
|
kind: 'positive', karma: 4, page: 'p.77',
|
|
308
466
|
effect: '+1 die to resist one chosen class: pathogens, or toxins',
|
|
309
467
|
},
|
|
310
468
|
{
|
|
311
469
|
key: 'resistance-pathogens-and-toxins', name: 'Resistance to Pathogens AND Toxins',
|
|
470
|
+
inert: 'nothing rolls to resist a pathogen or a toxin',
|
|
471
|
+
family: 'pool',
|
|
312
472
|
kind: 'positive', karma: 8, page: 'p.77',
|
|
313
473
|
effect: '+1 die to resist both pathogens and toxins',
|
|
314
474
|
},
|
|
315
475
|
{
|
|
316
476
|
key: 'spirit-affinity', name: 'Spirit Affinity', kind: 'positive', karma: 7, page: 'p.77',
|
|
477
|
+
inert: 'needs a chosen spirit type; binding and services are not rolled per type',
|
|
478
|
+
family: 'engine-rule',
|
|
317
479
|
requires: 'awakened',
|
|
318
480
|
effect: 'one spirit type favors you: +1 service from them, +1 die to bind them',
|
|
319
481
|
},
|
|
320
482
|
// ------------------------------ Negative ------------------------------
|
|
321
483
|
{
|
|
322
484
|
key: 'addiction-mild', name: 'Addiction (Mild)', kind: 'negative', karma: 4, page: 'p.77-78',
|
|
485
|
+
inert: 'no craving clock and no withdrawal state',
|
|
486
|
+
family: 'condition',
|
|
323
487
|
effect: 'hooked, mildly: cravings monthly; withdrawal bites your tests until fed',
|
|
324
488
|
},
|
|
325
489
|
{
|
|
326
490
|
key: 'addiction-moderate', name: 'Addiction (Moderate)', kind: 'negative', karma: 9, page: 'p.77-78',
|
|
491
|
+
inert: 'no craving clock and no withdrawal state',
|
|
492
|
+
family: 'condition',
|
|
327
493
|
effect: 'hooked: cravings every two weeks; withdrawal bites your tests until fed',
|
|
328
494
|
},
|
|
329
495
|
{
|
|
330
496
|
key: 'allergy-common-mild', name: 'Allergy (Common, Mild)', kind: 'negative', karma: 10, page: 'p.78',
|
|
497
|
+
inert: 'no exposure state -- nothing knows you are standing in the sun',
|
|
498
|
+
family: 'condition',
|
|
331
499
|
effect: 'allergic to something everywhere (sunlight, soy, pollutants): -1 die while exposed, -1 to resist it as a weapon',
|
|
332
500
|
},
|
|
333
501
|
{
|
|
334
502
|
key: 'astral-beacon', name: 'Astral Beacon', kind: 'negative', karma: 10, page: 'p.78-79',
|
|
503
|
+
inert: 'no astral signature is recorded',
|
|
504
|
+
family: 'engine-rule',
|
|
335
505
|
requires: 'awakened',
|
|
336
506
|
effect: 'your astral signature burns bright and lasts twice as long -- easier to read, easier to trace',
|
|
337
507
|
},
|
|
338
508
|
{
|
|
339
509
|
key: 'code-of-honor', name: 'Code of Honor', kind: 'negative', karma: 15, page: 'p.80',
|
|
510
|
+
inert: 'canon leaves this to the table; the engine adjudicates no vow',
|
|
511
|
+
family: 'narrative',
|
|
340
512
|
effect: 'a group you will not kill, ever -- non-lethal only, whatever it costs the run',
|
|
341
513
|
},
|
|
342
514
|
{
|
|
343
515
|
key: 'gremlins', name: 'Gremlins', kind: 'negative', karma: 4, maxRating: 4, page: 'p.81',
|
|
516
|
+
family: 'threshold',
|
|
344
517
|
effect: 'machines hate you: on the deck, a glitch needs one fewer 1 per rating',
|
|
345
518
|
},
|
|
346
519
|
{
|
|
347
520
|
key: 'loss-of-confidence', name: 'Loss of Confidence', kind: 'negative', karma: 10, page: 'p.82',
|
|
521
|
+
inert: 'specializations are not modelled, so none can be suspended',
|
|
522
|
+
family: 'condition',
|
|
348
523
|
effect: 'one skill you were proud of, now doubted -- its specializations unusable while the doubt holds',
|
|
349
524
|
},
|
|
350
525
|
{
|
|
351
526
|
key: 'scorched', name: 'Scorched', kind: 'negative', karma: 10, page: 'p.83',
|
|
527
|
+
inert: 'no neurological scar state, and nothing triggers on entering VR',
|
|
528
|
+
family: 'condition',
|
|
352
529
|
effect: 'black IC or BTL left a mark: one chosen neurological scar that flares in VR',
|
|
353
530
|
},
|
|
354
531
|
{
|
|
355
532
|
key: 'sensitive-system', name: 'Sensitive System', kind: 'negative', karma: 12, page: 'p.83',
|
|
533
|
+
inert: 'the clinic charges canon Essence; there is no doubling hook, and bioware is not rejected',
|
|
534
|
+
family: 'engine-rule',
|
|
356
535
|
effect: 'implants hate you: DOUBLE Essence loss from cyberware; bioware is rejected outright',
|
|
357
536
|
},
|
|
358
537
|
{
|
|
359
538
|
key: 'social-stress', name: 'Social Stress', kind: 'negative', karma: 8, page: 'p.85',
|
|
539
|
+
inert: 'no pressure state to read',
|
|
540
|
+
family: 'condition',
|
|
360
541
|
effect: 'crowds and confrontation wear on you -- emotions interfere when the pressure is social',
|
|
361
542
|
},
|
|
362
543
|
{
|
|
363
544
|
key: 'uneducated', name: 'Uneducated', kind: 'negative', karma: 8, page: 'p.87',
|
|
545
|
+
inert: 'knowledge skills are not modelled, and learning costs are flat',
|
|
546
|
+
family: 'engine-rule',
|
|
364
547
|
effect: 'no schooling: unaware in Technical/Academic/Professional knowledge you do not hold; learning them costs double',
|
|
365
548
|
},
|
|
366
549
|
{
|
|
367
550
|
key: 'unsteady-hands', name: 'Unsteady Hands', kind: 'negative', karma: 7, page: 'p.87',
|
|
551
|
+
inert: 'no symptom state, and no fine-handwork test to penalise',
|
|
552
|
+
family: 'condition',
|
|
368
553
|
effect: 'the shakes: -2 dice on fine handwork when the symptoms surface',
|
|
369
554
|
},
|
|
370
555
|
{
|
|
371
556
|
key: 'weak-immune-system', name: 'Weak Immune System', kind: 'negative', karma: 10, page: 'p.87',
|
|
557
|
+
inert: 'no disease track, so no Power to raise',
|
|
558
|
+
family: 'engine-rule',
|
|
372
559
|
effect: 'disease hits harder: +2 Power on every disease you resist (excludes the immunity qualities)',
|
|
373
560
|
},
|
|
374
561
|
// ------------------------- Cutting Aces (2026-09-02) -------------------------
|
|
@@ -383,85 +570,133 @@ export const QUALITIES = [
|
|
|
383
570
|
// ------------------------------ Positive ------------------------------
|
|
384
571
|
{
|
|
385
572
|
key: 'alibi', name: 'Alibi', kind: 'positive', karma: 4, page: 'Cutting Aces p.150',
|
|
573
|
+
inert: 'canon narrows it to plausible evidence, which nothing tracks',
|
|
574
|
+
family: 'pool',
|
|
386
575
|
effect: 'always the +2 on Con tests for plausible-seeming evidence -- your excuses are pre-made',
|
|
387
576
|
},
|
|
388
577
|
{
|
|
389
578
|
key: 'closer', name: 'Closer', kind: 'positive', karma: 4, page: 'Cutting Aces p.150',
|
|
579
|
+
inert: 'canon narrows it to life-or-death stakes, which nothing tracks',
|
|
580
|
+
family: 'pool',
|
|
390
581
|
effect: '+2 dice on Negotiation when it is a matter of life or death',
|
|
391
582
|
},
|
|
392
583
|
{
|
|
393
584
|
key: 'cynic', name: 'Cynic', kind: 'positive', karma: 6, page: 'Cutting Aces p.150',
|
|
585
|
+
inert: 'the engine rolls no opposed pool for an NPC acting socially ON you',
|
|
586
|
+
family: 'pool',
|
|
394
587
|
effect: 'anyone making a Social test against you rolls at -1',
|
|
395
588
|
},
|
|
396
589
|
{
|
|
397
590
|
key: 'empathic-listener', name: 'Empathic Listener', kind: 'positive', karma: 10, page: 'Cutting Aces p.150',
|
|
591
|
+
inert: 'no substitution seat: a pool is assembled from fixed attributes',
|
|
592
|
+
family: 'substitution',
|
|
398
593
|
effect: 'Intuition stands in for Charisma on Etiquette tests',
|
|
399
594
|
},
|
|
400
595
|
{
|
|
401
596
|
key: 'good-looking-and-knows-it', name: 'Good Looking and Knows It', kind: 'positive', karma: 10, page: 'Cutting Aces p.150',
|
|
597
|
+
inert: 'no modifier ledger to ignore two points of',
|
|
598
|
+
family: 'threshold',
|
|
402
599
|
effect: 'ignore 2 points of negative modifiers on any Social test; +1 Notoriety, and people remember your face (+2 to recall you)',
|
|
403
600
|
},
|
|
404
601
|
{
|
|
405
602
|
key: 'groupthink', name: 'Groupthink', kind: 'positive', karma: 5, page: 'Cutting Aces p.150-151',
|
|
603
|
+
inert: 'no social teamwork test, and the assistant/leader roles do not exist',
|
|
604
|
+
family: 'pool',
|
|
406
605
|
effect: 'social teamwork: as an assistant +1 die and +1 Social limit; as the leader, take -2 to soften an assistant\'s glitch',
|
|
407
606
|
},
|
|
408
607
|
{
|
|
409
608
|
key: 'honest-face', name: 'Honest Face', kind: 'positive', karma: 5, page: 'Cutting Aces p.151',
|
|
609
|
+
inert: 'nothing rolls Judge Intentions against you',
|
|
610
|
+
family: 'pool',
|
|
410
611
|
effect: '+2 dice on your Charisma + Willpower when someone Judges your Intentions',
|
|
411
612
|
},
|
|
412
613
|
{
|
|
413
614
|
key: 'innocuous', name: 'Innocuous', kind: 'positive', karma: 5, page: 'Cutting Aces p.151',
|
|
615
|
+
inert: 'canon narrows it to hiding in a crowd, which the room does not model',
|
|
616
|
+
family: 'pool',
|
|
414
617
|
effect: '+2 on Sneaking tests to hide in a crowd',
|
|
415
618
|
},
|
|
416
619
|
{
|
|
417
620
|
key: 'master-debater', name: 'Master Debater', kind: 'positive', karma: 10, page: 'Cutting Aces p.151',
|
|
621
|
+
inert: 'no substitution seat: a pool is assembled from fixed attributes',
|
|
622
|
+
family: 'substitution',
|
|
418
623
|
effect: 'Logic stands in for Charisma on Diplomacy tests -- you win by crushing their logic',
|
|
419
624
|
},
|
|
420
625
|
{
|
|
421
626
|
key: 'memory-palace', name: 'Memory Palace', kind: 'positive', karma: 6, page: 'Cutting Aces p.151',
|
|
627
|
+
inert: 'nothing rolls a Memory Test, and interrogation is not a test',
|
|
628
|
+
family: 'pool',
|
|
422
629
|
effect: '+1 die on Memory tests and to resist Intimidation (Interrogation)',
|
|
423
630
|
},
|
|
424
631
|
{
|
|
425
632
|
key: 'method-actor', name: 'Method Actor', kind: 'positive', karma: 7, page: 'Cutting Aces p.151',
|
|
633
|
+
inert: 'no immersion clock, and Impersonation is not rolled',
|
|
634
|
+
family: 'pool',
|
|
426
635
|
effect: 'each full day immersed in a role: +1 die and +1 Social limit on Impersonation as that role, up to your Willpower',
|
|
427
636
|
},
|
|
428
637
|
{
|
|
429
638
|
key: 'mnemonic-vault', name: 'Mnemonic Vault', kind: 'positive', karma: 8, page: 'Cutting Aces p.151',
|
|
639
|
+
inert: 'interrogation is not a test',
|
|
640
|
+
family: 'pool',
|
|
430
641
|
requiresQuality: 'memory-palace',
|
|
431
642
|
effect: 'lock memories away: +2 dice to resist Interrogation and anything that would compel you to talk; resist, and they believe that was all you knew',
|
|
432
643
|
},
|
|
433
644
|
{
|
|
434
645
|
key: 'watch-the-suit', name: 'Watch the Suit', kind: 'positive', karma: 3, page: 'Cutting Aces p.151',
|
|
646
|
+
inert: 'appearance carries no Etiquette penalty to be spared',
|
|
647
|
+
family: 'engine-rule',
|
|
435
648
|
effect: 'Stun never marks your appearance: no Etiquette penalty for looking roughed up after a fight you took no Physical damage in',
|
|
436
649
|
},
|
|
437
650
|
// ------------------------------ Negative ------------------------------
|
|
438
651
|
{
|
|
439
652
|
key: 'alpha-junkie', name: 'Alpha Junkie', kind: 'negative', karma: 12, page: 'Cutting Aces p.151-152',
|
|
653
|
+
inert: 'no leadership-over-you state to trigger the Composure test',
|
|
654
|
+
family: 'condition',
|
|
440
655
|
effect: 'when someone takes charge over you (or wins a Leadership test against you): Charisma + Willpower (3) or you fight for control -- argue, intimidate, or attack',
|
|
441
656
|
},
|
|
442
657
|
{
|
|
443
658
|
key: 'designated-omega', name: 'Designated Omega', kind: 'negative', karma: 5, page: 'Cutting Aces p.152',
|
|
659
|
+
family: 'pool',
|
|
444
660
|
effect: '-2 dice on every Leadership test, initiating or resisting',
|
|
661
|
+
effects: [{ type: 'dice', category: 'skills', property: 'leadership', value: -2 }],
|
|
445
662
|
},
|
|
446
663
|
{
|
|
447
664
|
key: 'disheveled', name: 'Disheveled', kind: 'negative', karma: 5, page: 'Cutting Aces p.152',
|
|
665
|
+
inert: 'no positive social modifier ledger to cap',
|
|
666
|
+
family: 'threshold',
|
|
448
667
|
effect: 'clothing never gives you a positive Social dice pool or limit modifier',
|
|
449
668
|
},
|
|
450
669
|
{
|
|
451
670
|
key: 'favored', name: 'Favored', kind: 'negative', karma: 5, page: 'Cutting Aces p.152',
|
|
671
|
+
family: 'pool',
|
|
452
672
|
effect: 'a group you cannot see straight (common group, biased): -2 dice on Social tests with them, and they negotiate against you at +2',
|
|
673
|
+
effects: [{ type: 'dice', category: 'pools', property: 'social', value: -2 }],
|
|
453
674
|
},
|
|
454
675
|
{
|
|
455
676
|
key: 'one-born-every-minute', name: 'One Born Every Minute', kind: 'negative', karma: 5, page: 'Cutting Aces p.152',
|
|
677
|
+
inert: 'nothing rolls for you to resist a Con made against you',
|
|
678
|
+
family: 'pool',
|
|
456
679
|
effect: '-2 dice to resist every Con test made against you',
|
|
457
680
|
},
|
|
458
681
|
{
|
|
459
682
|
key: 'the-goat', name: 'The Goat', kind: 'negative', karma: 8, page: 'Cutting Aces p.152',
|
|
683
|
+
family: 'pool',
|
|
460
684
|
effect: 'you just look guilty: everyone meeting you for the first time is suspicious (-1 Social), and security watches you first',
|
|
685
|
+
effects: [{ type: 'dice', category: 'pools', property: 'social', value: -1 }],
|
|
461
686
|
},
|
|
462
687
|
{
|
|
463
688
|
key: 'ugly-and-doesnt-care', name: "Ugly and Doesn't Care", kind: 'negative', karma: 10, page: 'Cutting Aces p.152-153',
|
|
689
|
+
family: 'attribute',
|
|
464
690
|
effect: 'Charisma maximum -1 and starting Charisma -1 (minimum 1)',
|
|
691
|
+
effects: [
|
|
692
|
+
// BOTH HALVES of the printed line. The attribute effect is the
|
|
693
|
+
// "starting Charisma -1"; the cap is the "Charisma maximum -1",
|
|
694
|
+
// which nothing enforced until ceilings existed -- the same gap
|
|
695
|
+
// Lucky had, found by sweeping the family rather than by a second
|
|
696
|
+
// report.
|
|
697
|
+
{ type: 'attribute', category: 'attributes', property: 'charisma', value: -1 },
|
|
698
|
+
{ type: 'cap', category: 'attributes', property: 'charisma', value: -1 },
|
|
699
|
+
],
|
|
465
700
|
},
|
|
466
701
|
];
|
|
467
702
|
/**
|
|
@@ -472,16 +707,22 @@ export const QUALITIES = [
|
|
|
472
707
|
export const RETIRED_QUALITIES = [
|
|
473
708
|
{
|
|
474
709
|
key: 'indomitable', name: 'Indomitable', kind: 'positive', karma: 8, maxRating: 3, page: 'p.75',
|
|
710
|
+
inert: 'the engine models only the Social limit, and no limit may be chosen',
|
|
711
|
+
family: 'limit',
|
|
475
712
|
effect: '+1 to one Inherent limit of your choice per rating',
|
|
476
713
|
retired: 'the engine models only the Social limit, and the choice of limit has no seat yet',
|
|
477
714
|
},
|
|
478
715
|
{
|
|
479
716
|
key: 'will-to-live', name: 'Will to Live', kind: 'positive', karma: 3, maxRating: 3, page: 'p.77',
|
|
717
|
+
inert: 'there is no overflow track',
|
|
718
|
+
family: 'engine-rule',
|
|
480
719
|
effect: '+1 Damage Overflow box per rating -- more room between down and dead, no easier to knock out',
|
|
481
720
|
retired: 'the engine has no overflow track: a full Physical track is death',
|
|
482
721
|
},
|
|
483
722
|
{
|
|
484
723
|
key: 'social-appearance-anxiety', name: 'Social Appearance Anxiety', kind: 'negative', karma: 3, maxRating: 3, page: 'Cutting Aces p.152',
|
|
724
|
+
inert: 'there is no grooming state',
|
|
725
|
+
family: 'condition',
|
|
485
726
|
effect: '-1 die per rating on all Social rolls whenever you are not clean, coiffed, and cutting',
|
|
486
727
|
retired: 'the engine has no grooming state to judge "clean, coiffed, and cutting"',
|
|
487
728
|
},
|
|
@@ -490,7 +731,43 @@ export const RETIRED_QUALITIES = [
|
|
|
490
731
|
* A saved or offered key, resolved: the old fixed "<key>-1" entries
|
|
491
732
|
* (every rated quality shipped as Rating 1 only) read as key + rating 1.
|
|
492
733
|
*/
|
|
734
|
+
/**
|
|
735
|
+
* THE KEYS THAT BAKED A PLAYER-S CHOICE INTO THE SLUG, and what each
|
|
736
|
+
* one resolves to now.
|
|
737
|
+
*
|
|
738
|
+
* Before the shared choice lane existed, a quality whose effect named
|
|
739
|
+
* something the player picked had nowhere to put the answer, so the
|
|
740
|
+
* answer went into the key: incompetent-hacking, codeslinger-hack-on-
|
|
741
|
+
* the-fly, and five more. Seven slugs for what is really two qualities
|
|
742
|
+
* and a pick.
|
|
743
|
+
*
|
|
744
|
+
* These keys are written into every save that holds one, so they are
|
|
745
|
+
* not renamed -- they are RESOLVED, here, into the key plus the pick
|
|
746
|
+
* they always meant. An old save loads, the pick lands in Player.picks,
|
|
747
|
+
* and the character plays identically. Nothing has to be migrated and
|
|
748
|
+
* nothing can be missed, which is the same shape as the legacy
|
|
749
|
+
* "<key>-1" rated form below.
|
|
750
|
+
*
|
|
751
|
+
* A pick's VALUE is the engine's own word, never a label: Codeslinger's
|
|
752
|
+
* is the POOL it modifies (matrix-sleaze), so `property: 'chosen'`
|
|
753
|
+
* resolves with no translation table in between.
|
|
754
|
+
*/
|
|
755
|
+
const LEGACY_CHOICE_KEYS = {
|
|
756
|
+
// The old slug named a SKILL; the quality is per GROUP (p.81), so it
|
|
757
|
+
// resolves to the group hacking belongs to. A character who held
|
|
758
|
+
// incompetent-hacking was, in canon terms, always Incompetent
|
|
759
|
+
// (Cracking) -- the slug simply could not say so.
|
|
760
|
+
'incompetent-hacking': { key: 'incompetent', pick: 'cracking' },
|
|
761
|
+
'codeslinger-hack-on-the-fly': { key: 'codeslinger', pick: 'matrix-sleaze' },
|
|
762
|
+
'codeblock-brute-force': { key: 'codeblock', pick: 'matrix-attack' },
|
|
763
|
+
'natural-immunity-natural': { key: 'natural-immunity', pick: 'natural' },
|
|
764
|
+
'natural-immunity-synthetic': { key: 'natural-immunity', pick: 'synthetic' },
|
|
765
|
+
'resistance-pathogens-or-toxins': { key: 'resistance-one', pick: 'toxins' },
|
|
766
|
+
};
|
|
493
767
|
export function resolveQualityKey(key) {
|
|
768
|
+
const legacy = LEGACY_CHOICE_KEYS[key];
|
|
769
|
+
if (legacy)
|
|
770
|
+
return { key: legacy.key, rating: 1, pick: legacy.pick };
|
|
494
771
|
const m = /^(.*)-1$/.exec(key);
|
|
495
772
|
if (m) {
|
|
496
773
|
const base = m[1];
|
|
@@ -499,6 +776,8 @@ export function resolveQualityKey(key) {
|
|
|
499
776
|
}
|
|
500
777
|
return { key, rating: 1 };
|
|
501
778
|
}
|
|
779
|
+
/** Every legacy slug that resolves to a key plus a pick, for tests and tooling. */
|
|
780
|
+
export const LEGACY_CHOICE_SLUGS = Object.keys(LEGACY_CHOICE_KEYS);
|
|
502
781
|
export function getQuality(key) {
|
|
503
782
|
if (!key)
|
|
504
783
|
return undefined;
|