@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
|
@@ -20,10 +20,11 @@
|
|
|
20
20
|
* gear -- these strings are what the player reads, and what an NPC's
|
|
21
21
|
* swag briefing quotes.
|
|
22
22
|
*/
|
|
23
|
-
import type {
|
|
24
|
-
import type {
|
|
25
|
-
|
|
26
|
-
export
|
|
23
|
+
import type { IQuality } from '../qualities.js';
|
|
24
|
+
import type { ICatalogChoice, ICatalogRestrictions } from './effects.js';
|
|
25
|
+
import type { ICatalogEffect } from './effects.js';
|
|
26
|
+
export declare const CATALOG_VERSION = 14;
|
|
27
|
+
export type CatalogKind = 'gear' | 'quality' | 'spell' | 'augmentation' | 'metatype' | 'adept-power' | 'metamagic';
|
|
27
28
|
/** The skill a weapon is fired or swung with. The last four have no engine
|
|
28
29
|
* skill yet (SkillName); the engine falls back per models/player.ts. */
|
|
29
30
|
export type WeaponSkill = 'pistols' | 'automatics' | 'longarms' | 'archery' | 'blades' | 'clubs' | 'unarmed' | 'heavy-weapons' | 'throwing-weapons' | 'exotic-melee' | 'exotic-ranged';
|
|
@@ -136,80 +137,7 @@ export interface ICatalogMod {
|
|
|
136
137
|
/** Weapon classes it refuses: a silencer fits no revolver or shotgun (p.432). */
|
|
137
138
|
excludes?: ('shotgun' | 'revolver')[];
|
|
138
139
|
}
|
|
139
|
-
export type EffectPool
|
|
140
|
-
export type EffectLimit = 'physical' | 'mental' | 'social' | 'accuracy';
|
|
141
|
-
export type EffectAttribute = 'body' | 'agility' | 'reaction' | 'strength' | 'willpower' | 'logic' | 'intuition' | 'charisma' | 'edge' | 'magic' | 'resonance' | 'reach' | 'armor-bonus';
|
|
142
|
-
export type EffectMatrixAttribute = 'attack' | 'sleaze' | 'dataProcessing' | 'firewall' | 'damage';
|
|
143
|
-
/** A capability is a flag the engine asks for by key (Player.hasCapability). */
|
|
144
|
-
export type EffectCapability = 'dni' | 'smartlink' | 'smartgun' | 'low-light' | 'thermographic' | 'no-fog' | 'silenced' | 'full-body' | 'autopicker' | 'maglock-opposed';
|
|
145
|
-
/**
|
|
146
|
-
* A modifier the row grants while it applies. `value` is a NUMBER, never a
|
|
147
|
-
* string: every reader adds it, and a string would need parsing at each
|
|
148
|
-
* one and would drift in the web's seed. `scaleBy` multiplies it by the
|
|
149
|
-
* row's `ratingValue` (rating), the cast Force (force) or the hits of a
|
|
150
|
-
* sustained spell (hits). `when` defaults by kind: a wearable's effects
|
|
151
|
-
* apply worn, a weapon's held, a program's running, a data soft's stored,
|
|
152
|
-
* a mod's fitted, an augmentation's installed, a quality's held.
|
|
153
|
-
*/
|
|
154
|
-
export type ICatalogEffect = {
|
|
155
|
-
type: 'dice';
|
|
156
|
-
category: 'skills';
|
|
157
|
-
property: SkillName;
|
|
158
|
-
value: number;
|
|
159
|
-
scaleBy?: EffectScale;
|
|
160
|
-
when?: EffectWhen;
|
|
161
|
-
only?: string;
|
|
162
|
-
} | {
|
|
163
|
-
type: 'dice';
|
|
164
|
-
category: 'pools';
|
|
165
|
-
property: EffectPool;
|
|
166
|
-
value: number;
|
|
167
|
-
scaleBy?: EffectScale;
|
|
168
|
-
when?: EffectWhen;
|
|
169
|
-
only?: string;
|
|
170
|
-
} | {
|
|
171
|
-
type: 'limit';
|
|
172
|
-
category: 'limits';
|
|
173
|
-
property: EffectLimit;
|
|
174
|
-
value: number;
|
|
175
|
-
scaleBy?: EffectScale;
|
|
176
|
-
when?: EffectWhen;
|
|
177
|
-
only?: string;
|
|
178
|
-
} | {
|
|
179
|
-
type: 'attribute';
|
|
180
|
-
category: 'attributes';
|
|
181
|
-
property: EffectAttribute;
|
|
182
|
-
value: number;
|
|
183
|
-
scaleBy?: EffectScale;
|
|
184
|
-
when?: EffectWhen;
|
|
185
|
-
only?: string;
|
|
186
|
-
} | {
|
|
187
|
-
type: 'attribute';
|
|
188
|
-
category: 'matrix';
|
|
189
|
-
property: EffectMatrixAttribute;
|
|
190
|
-
value: number;
|
|
191
|
-
scaleBy?: EffectScale;
|
|
192
|
-
when?: EffectWhen;
|
|
193
|
-
only?: string;
|
|
194
|
-
} | {
|
|
195
|
-
type: 'initiative';
|
|
196
|
-
category: 'pools';
|
|
197
|
-
property: 'dice' | 'score';
|
|
198
|
-
value: number;
|
|
199
|
-
scaleBy?: EffectScale;
|
|
200
|
-
when?: EffectWhen;
|
|
201
|
-
only?: string;
|
|
202
|
-
} | {
|
|
203
|
-
type: 'flag';
|
|
204
|
-
category: 'capability';
|
|
205
|
-
property: EffectCapability;
|
|
206
|
-
value: number;
|
|
207
|
-
scaleBy?: EffectScale;
|
|
208
|
-
when?: EffectWhen;
|
|
209
|
-
only?: string;
|
|
210
|
-
};
|
|
211
|
-
export type EffectScale = 'rating' | 'force' | 'hits';
|
|
212
|
-
export type EffectWhen = 'worn' | 'held' | 'carried' | 'running' | 'stored' | 'fitted' | 'installed' | 'held-quality' | 'sustained';
|
|
140
|
+
export type { EffectPool, EffectLimit, EffectAttribute, EffectMatrixAttribute, EffectCapability, ICatalogEffect, EffectScale, EffectWhen, } from './effects.js';
|
|
213
141
|
/** Every kind shares this. */
|
|
214
142
|
export interface ICatalogBase {
|
|
215
143
|
/** Absent = 'gear'. */
|
|
@@ -222,6 +150,34 @@ export interface ICatalogBase {
|
|
|
222
150
|
page?: string;
|
|
223
151
|
approx?: boolean;
|
|
224
152
|
effects?: ICatalogEffect[];
|
|
153
|
+
/**
|
|
154
|
+
* THE SPELL A FORMULA TEACHES, by spells.ts key.
|
|
155
|
+
*
|
|
156
|
+
* A spell formula is written for ONE spell (p.461, p.299: "the spell
|
|
157
|
+
* you want"), and its PRICE is set by that spell's category. The
|
|
158
|
+
* five rows here used to be the categories themselves -- "Combat
|
|
159
|
+
* Spell Formula" -- and Player.knowsSpell matched them by looking
|
|
160
|
+
* for the spell's name inside the item's name. No category name
|
|
161
|
+
* ever contains a spell name, so the match could never fire: every
|
|
162
|
+
* one of them was 500 to 2,000 nuyen for a scroll that taught
|
|
163
|
+
* nothing.
|
|
164
|
+
*/
|
|
165
|
+
teaches?: string;
|
|
166
|
+
/**
|
|
167
|
+
* A pick this row cannot work without (ICatalogChoice). ON THE BASE,
|
|
168
|
+
* so a quality, an augmentation, a spell or an adept power all declare
|
|
169
|
+
* one the same way -- a Hardwire naming a skill is the same question
|
|
170
|
+
* Aptitude asks, and asking it twice in two shapes is how the picker
|
|
171
|
+
* ends up rebuilt per kind.
|
|
172
|
+
*/
|
|
173
|
+
choice?: ICatalogChoice;
|
|
174
|
+
/**
|
|
175
|
+
* What this row refuses to be held with (ICatalogRestrictions), in the
|
|
176
|
+
* same one shape for every kind. Assembled from each source's own
|
|
177
|
+
* per-kind fields, so one enforcement pass covers all 69 rather than
|
|
178
|
+
* one hand-written gate covering one.
|
|
179
|
+
*/
|
|
180
|
+
restrictions?: ICatalogRestrictions;
|
|
225
181
|
}
|
|
226
182
|
export interface ICatalogItem extends ICatalogBase {
|
|
227
183
|
kind?: 'gear';
|
|
@@ -266,11 +222,41 @@ export interface ICatalogQuality extends ICatalogBase {
|
|
|
266
222
|
requires?: 'awakened' | 'mundane' | 'caster-or-technomancer';
|
|
267
223
|
requiresQuality?: string;
|
|
268
224
|
requiresMetatype?: Metatype[];
|
|
225
|
+
/**
|
|
226
|
+
* THE FOUR FIELDS qualityRows() writes and this interface did not
|
|
227
|
+
* declare (found by maka-cli-com-c3 reading the commit, 2026-09-04).
|
|
228
|
+
*
|
|
229
|
+
* They were invisible to the compiler because the object literal
|
|
230
|
+
* carrying them contains conditional spreads, and a literal with a
|
|
231
|
+
* spread is no longer FRESH -- excess-property checking does not
|
|
232
|
+
* apply to it. So the row shipped four fields the published .d.ts
|
|
233
|
+
* denied existed, and the web's mirror would have needed a cast to
|
|
234
|
+
* read `row.quality.choice` -- the sort of cast that later gets
|
|
235
|
+
* tidied away by someone who trusts the type.
|
|
236
|
+
*
|
|
237
|
+
* DERIVED FROM IQuality, not retyped. `family`'s union and the shape
|
|
238
|
+
* of a choice live in qualities.ts, and indexing them here means the
|
|
239
|
+
* catalog cannot fall behind the source the way it just did. It also
|
|
240
|
+
* answers the question c3 asked -- "tell me if the names or the
|
|
241
|
+
* family union move" -- with "they cannot, if you index them too".
|
|
242
|
+
*/
|
|
243
|
+
family: IQuality['family'];
|
|
244
|
+
inert?: string;
|
|
245
|
+
choice?: ICatalogChoice;
|
|
246
|
+
excludesQuality?: string;
|
|
269
247
|
};
|
|
270
248
|
}
|
|
271
249
|
export interface ICatalogSpell extends ICatalogBase {
|
|
272
250
|
kind: 'spell';
|
|
273
251
|
spell: {
|
|
252
|
+
/**
|
|
253
|
+
* WHICH ROUTINE CASTS IT. The one field a row could not supply,
|
|
254
|
+
* and so the one thing stopping a spell from being sourced from
|
|
255
|
+
* the catalog rather than compiled in -- which is where the
|
|
256
|
+
* rules are headed (mjmcee, 2026-09-04: "the engine rule comes
|
|
257
|
+
* from the catalog. We shouldn't be hard coding the rules").
|
|
258
|
+
*/
|
|
259
|
+
cast: 'combat' | 'heal' | 'armor' | 'sustained-utility' | 'barrier';
|
|
274
260
|
category: 'Combat' | 'Detection' | 'Health' | 'Illusion' | 'Manipulation';
|
|
275
261
|
type: 'mana' | 'physical';
|
|
276
262
|
range: 'LOS' | 'LOS(A)' | 'touch';
|
|
@@ -296,6 +282,31 @@ export interface ICatalogAugmentation extends ICatalogBase {
|
|
|
296
282
|
canonEssence?: number;
|
|
297
283
|
};
|
|
298
284
|
}
|
|
285
|
+
/**
|
|
286
|
+
* AN ADEPT POWER (p.308-310). Bought with Power Points rather than nuyen
|
|
287
|
+
* or karma, which is why it carries no price: `levelCosts` is the PP to
|
|
288
|
+
* HOLD it at each level, and a magic-capped power extends linearly to the
|
|
289
|
+
* character's Magic.
|
|
290
|
+
*/
|
|
291
|
+
export interface ICatalogAdeptPower extends ICatalogBase {
|
|
292
|
+
kind: 'adept-power';
|
|
293
|
+
adeptPower: {
|
|
294
|
+
levelCosts: number[];
|
|
295
|
+
magicCapped: boolean;
|
|
296
|
+
costPerLevel?: number;
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* A METAMAGIC (p.325-326) or a technomancer's echo (p.258). Bought with an
|
|
301
|
+
* initiation or submersion grade, so it has no price either; `path` is who
|
|
302
|
+
* may take it.
|
|
303
|
+
*/
|
|
304
|
+
export interface ICatalogMetamagic extends ICatalogBase {
|
|
305
|
+
kind: 'metamagic';
|
|
306
|
+
metamagic: {
|
|
307
|
+
path: 'caster' | 'adept' | 'techno';
|
|
308
|
+
};
|
|
309
|
+
}
|
|
299
310
|
export interface ICatalogMetatype extends ICatalogBase {
|
|
300
311
|
kind: 'metatype';
|
|
301
312
|
metatype: {
|
|
@@ -307,11 +318,8 @@ export interface ICatalogMetatype extends ICatalogBase {
|
|
|
307
318
|
lifestyleCostMult?: number;
|
|
308
319
|
};
|
|
309
320
|
}
|
|
310
|
-
export type ICatalogRow = ICatalogItem | ICatalogQuality | ICatalogSpell | ICatalogAugmentation | ICatalogMetatype;
|
|
321
|
+
export type ICatalogRow = ICatalogItem | ICatalogQuality | ICatalogSpell | ICatalogAugmentation | ICatalogMetatype | ICatalogAdeptPower | ICatalogMetamagic;
|
|
311
322
|
/** Gear or not -- the discriminator every consumer of the gear list uses. */
|
|
312
323
|
export declare function isGearRow(r: ICatalogRow): r is ICatalogItem;
|
|
313
324
|
export declare const CATALOG_ITEMS: ICatalogItem[];
|
|
314
|
-
/** THE WHOLE SEED, every kind. Gear today; qualities, spells, augmentations
|
|
315
|
-
* and metatypes join it in v14. The loader (utilities/catalog.ts) weighs
|
|
316
|
-
* THIS against the server and the cache. */
|
|
317
325
|
export declare const CATALOG_ROWS: ICatalogRow[];
|
|
@@ -20,7 +20,13 @@
|
|
|
20
20
|
* gear -- these strings are what the player reads, and what an NPC's
|
|
21
21
|
* swag briefing quotes.
|
|
22
22
|
*/
|
|
23
|
-
|
|
23
|
+
import { AUGMENTATIONS } from '../augmentations.js';
|
|
24
|
+
import { QUALITIES } from '../qualities.js';
|
|
25
|
+
import { ADEPT_POWER_CATALOG } from '../adept-powers.js';
|
|
26
|
+
import { SPELL_CATALOG } from '../spells.js';
|
|
27
|
+
import { METATYPES } from '../metatypes.js';
|
|
28
|
+
import { METAMAGICS } from '../commands/initiate.js';
|
|
29
|
+
export const CATALOG_VERSION = 14;
|
|
24
30
|
/** Gear or not -- the discriminator every consumer of the gear list uses. */
|
|
25
31
|
export function isGearRow(r) {
|
|
26
32
|
return r.kind === undefined || r.kind === 'gear';
|
|
@@ -279,11 +285,12 @@ export const CATALOG_ITEMS = [
|
|
|
279
285
|
row('spirit-focus-1', 'Spirit Focus (Force 1)', 'Focus', 4000, 3, 'Where a summoner keeps the leash.', { page: 'p.461', shape: 'talisman', size: 'Tiny', weight: 0.1, rating: 'Standard', legality: 'R', stats: 'Force 1: force x 4,000 nuyen, avail (force x 3)R', ratingValue: 1, effects: [{ type: 'dice', category: 'skills', property: 'summoning', value: 1, when: 'carried', scaleBy: 'rating' }] }),
|
|
280
286
|
row('weapon-focus-1', 'Weapon Focus (Force 1)', 'Focus', 7000, 4, 'A blade that cuts things that have never had a body.', { page: 'p.461', shape: 'blade', size: 'Medium', weight: 1.2, rating: 'Rare', legality: 'R', stats: 'Force 1: force x 7,000 nuyen, avail (force x 4)R', ratingValue: 1 }),
|
|
281
287
|
row('power-focus-1', 'Power Focus (Force 1)', 'Focus', 18000, 4, 'A bound anchor for living mana. The real investment.', { page: 'p.461', shape: 'amulet', size: 'Tiny', weight: 0.2, rating: 'Rare', legality: 'R', stats: 'Force 1: force x 18,000 nuyen, avail (force x 4)R', ratingValue: 1, effects: [{ type: 'dice', category: 'skills', property: 'spellcasting', value: 1, when: 'carried', scaleBy: 'rating' }] }),
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
288
|
+
// SPELL FORMULAE ARE GENERATED, one per spell, by formulaRows() below
|
|
289
|
+
// -- a formula is written for ONE spell and priced by that spell's
|
|
290
|
+
// category (p.461). The five category-named rows that used to sit
|
|
291
|
+
// here could never teach anything: knowsSpell looks for the spell
|
|
292
|
+
// name inside the item name, and "Combat Spell Formula" contains no
|
|
293
|
+
// spell's name.
|
|
287
294
|
// ---- Drones (p.466) ----
|
|
288
295
|
// ANTHROPOMORPHIC DRONES (Rigger 5.0 p.145-148) -- the FIRST rows in
|
|
289
296
|
// this catalog cited to a book other than the core rulebook, so the
|
|
@@ -393,8 +400,268 @@ export const CATALOG_ITEMS = [
|
|
|
393
400
|
row('credstick-platinum', 'Certified Credstick (Platinum)', 'Credstick', 500, 10, 'Half a million, certified. People have died for the empty ones.', { page: 'p.443', shape: 'stick', size: 'Tiny', weight: 0.1, color: 'platinum', rating: 'Standard', stats: 'Max 500,000 nuyen' }),
|
|
394
401
|
row('credstick-ebony', 'Certified Credstick (Ebony)', 'Credstick', 1000, 20, 'A million nuyen and a very short list of people who own one.', { page: 'p.443', shape: 'stick', size: 'Tiny', weight: 0.1, color: 'ebony', rating: 'Rare', stats: 'Max 1,000,000 nuyen' }),
|
|
395
402
|
];
|
|
396
|
-
/**
|
|
397
|
-
*
|
|
398
|
-
*
|
|
399
|
-
|
|
403
|
+
/**
|
|
404
|
+
* THE NON-GEAR ROWS (catalog v14, user 2026-09-04: "I don't see any
|
|
405
|
+
* spells, or qualities there. The catalog should cover ALL things that
|
|
406
|
+
* can be obtained in the game, backed by canon").
|
|
407
|
+
*
|
|
408
|
+
* DERIVED, NEVER RETYPED. qualities.ts and augmentations.ts are the
|
|
409
|
+
* engine's own sources of truth -- the clinic charges from them, the
|
|
410
|
+
* creation ledger prices from them, the sheet prints from them -- so the
|
|
411
|
+
* catalog reads THOSE rather than carrying a second copy. A hand-copied
|
|
412
|
+
* list of something that already exists cannot stay right: that is
|
|
413
|
+
* exactly how the Conjurer shipped broken this morning, when a duplicate
|
|
414
|
+
* of MAGICAL_GROUP_SKILLS went stale the day the original moved.
|
|
415
|
+
*
|
|
416
|
+
* Every field here already existed on the source rows. Nothing is
|
|
417
|
+
* invented to fill the shape: `requiresMetatype` stays absent because
|
|
418
|
+
* this engine models no metatype and a gate it cannot check is a rule it
|
|
419
|
+
* cannot keep (qualities.ts says so in its own words), and `legality` /
|
|
420
|
+
* `canonEssence` stay absent on augmentations for the same reason --
|
|
421
|
+
* the source does not carry them.
|
|
422
|
+
*/
|
|
423
|
+
/**
|
|
424
|
+
* The restrictions a row declares, assembled from whichever per-kind
|
|
425
|
+
* fields its source happens to use. One shape out, so the server can
|
|
426
|
+
* enforce every kind in one pass; the sources keep the field names that
|
|
427
|
+
* read well where they live.
|
|
428
|
+
*
|
|
429
|
+
* Returns undefined rather than an empty object when a row restricts
|
|
430
|
+
* nothing, so "has restrictions" stays a truthiness check and 400 rows
|
|
431
|
+
* do not each grow an empty object.
|
|
432
|
+
*/
|
|
433
|
+
function restrictionsOf(src) {
|
|
434
|
+
const excludes = [
|
|
435
|
+
...(src.excludes ?? []),
|
|
436
|
+
...(src.excludesQuality !== undefined ? [src.excludesQuality] : []),
|
|
437
|
+
];
|
|
438
|
+
const out = {
|
|
439
|
+
...(excludes.length > 0 ? { excludes } : {}),
|
|
440
|
+
...(src.requiresQuality !== undefined ? { needs: [src.requiresQuality] } : {}),
|
|
441
|
+
...(src.requires !== undefined ? { path: src.requires } : {}),
|
|
442
|
+
};
|
|
443
|
+
return Object.keys(out).length > 0 ? out : undefined;
|
|
444
|
+
}
|
|
445
|
+
function qualityRows() {
|
|
446
|
+
return QUALITIES.map(q => ({
|
|
447
|
+
kind: 'quality',
|
|
448
|
+
slug: q.key,
|
|
449
|
+
name: q.name,
|
|
450
|
+
description: q.effect,
|
|
451
|
+
page: q.page,
|
|
452
|
+
// The mechanics, in the same vocabulary a weapon states its DV in,
|
|
453
|
+
// so a reader of the catalog gets a quality's NUMBERS and not just
|
|
454
|
+
// its sentence. Absent where SR5's effect is not a flat modifier
|
|
455
|
+
// (or where the engine implements it as its own rule) -- see the
|
|
456
|
+
// `effects` comment in qualities.ts, which says why that is the
|
|
457
|
+
// honest answer rather than a gap to be filled in.
|
|
458
|
+
...(q.effects !== undefined ? { effects: q.effects } : {}),
|
|
459
|
+
// On the ROW, not in the quality block -- ICatalogBase carries both,
|
|
460
|
+
// so chrome and spells declare them in the same place.
|
|
461
|
+
...(q.choice !== undefined ? { choice: q.choice } : {}),
|
|
462
|
+
...(restrictionsOf(q) !== undefined ? { restrictions: restrictionsOf(q) } : {}),
|
|
463
|
+
quality: {
|
|
464
|
+
polarity: q.kind,
|
|
465
|
+
karma: q.karma,
|
|
466
|
+
...(q.maxRating !== undefined ? { maxRating: q.maxRating } : {}),
|
|
467
|
+
...(q.retired !== undefined ? { retired: q.retired } : {}),
|
|
468
|
+
...(q.requires !== undefined ? { requires: q.requires } : {}),
|
|
469
|
+
...(q.requiresQuality !== undefined ? { requiresQuality: q.requiresQuality } : {}),
|
|
470
|
+
// WHAT KIND OF RULE this is, and whether the engine runs it yet.
|
|
471
|
+
// `family` is always present (qualities.ts requires it); `inert`
|
|
472
|
+
// is present only when the quality currently delivers nothing,
|
|
473
|
+
// and names the missing seat -- so a reader of the catalog can
|
|
474
|
+
// tell a finished rule from one that is still only priced.
|
|
475
|
+
family: q.family,
|
|
476
|
+
...(q.inert !== undefined ? { inert: q.inert } : {}),
|
|
477
|
+
// The pick chargen has to collect before the quality can work,
|
|
478
|
+
// and the quality it may not be held alongside (p.65-66).
|
|
479
|
+
...(q.excludesQuality !== undefined ? { excludesQuality: q.excludesQuality } : {}),
|
|
480
|
+
},
|
|
481
|
+
}));
|
|
482
|
+
}
|
|
483
|
+
function augmentationRows() {
|
|
484
|
+
return AUGMENTATIONS.map(a => ({
|
|
485
|
+
kind: 'augmentation',
|
|
486
|
+
slug: a.key,
|
|
487
|
+
name: a.name,
|
|
488
|
+
description: a.effect,
|
|
489
|
+
page: a.page,
|
|
490
|
+
// The dice, in the same vocabulary a weapon states its DV in. Chrome
|
|
491
|
+
// declared a `bonuses` map of its own until 2026-09-04, which is why
|
|
492
|
+
// this column read empty in the catalog while every piece of 'ware in
|
|
493
|
+
// the game was moving real dice.
|
|
494
|
+
...(a.effects !== undefined ? { effects: a.effects } : {}),
|
|
495
|
+
// 62 of the 69 restrictions in the catalog are these: the exclusions
|
|
496
|
+
// that stop Wired Reflexes I riding alongside a synaptic booster, or
|
|
497
|
+
// three vision enhancements stacking. Declared for a long time,
|
|
498
|
+
// enforced by nothing.
|
|
499
|
+
...(restrictionsOf(a) !== undefined ? { restrictions: restrictionsOf(a) } : {}),
|
|
500
|
+
augmentation: {
|
|
501
|
+
ware: a.kind,
|
|
502
|
+
essence: a.essence,
|
|
503
|
+
cost: a.cost,
|
|
504
|
+
wakeLine: a.wakeLine,
|
|
505
|
+
...(a.excludes !== undefined ? { excludes: a.excludes } : {}),
|
|
506
|
+
...(a.avail !== undefined ? { avail: a.avail } : {}),
|
|
507
|
+
...(a.canonCost !== undefined ? { canonCost: a.canonCost } : {}),
|
|
508
|
+
},
|
|
509
|
+
}));
|
|
510
|
+
}
|
|
511
|
+
/** THE WHOLE SEED, every kind: gear, qualities and augmentations. Spells
|
|
512
|
+
* and metatypes are still outstanding -- see the note above qualityRows.
|
|
513
|
+
* The loader (utilities/catalog.ts) weighs THIS against the server and
|
|
514
|
+
* the cache. */
|
|
515
|
+
/**
|
|
516
|
+
* THE SPELLS (SR5 p.283-295). Held out of the catalog until now because
|
|
517
|
+
* ICatalogSpell wants Type, Range and Duration and the engine stored none
|
|
518
|
+
* of them -- recorded at the time as a deliberate omission rather than an
|
|
519
|
+
* oversight. spells.ts carries all three since 2026-09-04, each read off
|
|
520
|
+
* the printed stat block, so the shape is satisfied by canon rather than
|
|
521
|
+
* by inference and the rows can ship.
|
|
522
|
+
*
|
|
523
|
+
* A spell has no PRICE: it is learned, not bought, which is why the row
|
|
524
|
+
* carries no availability or nuyen and the spell block carries the drain
|
|
525
|
+
* instead. What a formula costs on the street is a GEAR row, and there
|
|
526
|
+
* are five of those already (Category 'SpellFormula').
|
|
527
|
+
*/
|
|
528
|
+
/**
|
|
529
|
+
* A spell's line, composed from its own stat block.
|
|
530
|
+
*
|
|
531
|
+
* spells.ts carries no prose -- it never needed any, because cast.ts
|
|
532
|
+
* names the spell and rolls it -- and inventing twenty-one descriptions
|
|
533
|
+
* to fill a `description` field would be putting words in the book's
|
|
534
|
+
* mouth. So the line is DERIVED: the printed Type, Range, Duration and
|
|
535
|
+
* Drain, in a sentence, plus what resists it. Every word of it is data
|
|
536
|
+
* the row already carries.
|
|
537
|
+
*/
|
|
538
|
+
function spellLine(sp) {
|
|
539
|
+
const range = sp.range === 'touch' ? 'Touch' : sp.range === 'LOS(A)' ? 'line of sight, area' : 'line of sight';
|
|
540
|
+
const duration = sp.duration === 'I' ? 'instantaneous' : sp.duration === 'S' ? 'sustained' : 'permanent';
|
|
541
|
+
const drain = `Drain F${sp.drainOffset === 0 ? '' : sp.drainOffset > 0 ? ` + ${sp.drainOffset}` : ` - ${-sp.drainOffset}`}`;
|
|
542
|
+
const resist = sp.soak === 'willpower' ? '; resisted with Willpower'
|
|
543
|
+
: sp.soak === 'body' ? '; resisted with Body'
|
|
544
|
+
: sp.soak === 'armor' ? '; soaked in full, less AP' : '';
|
|
545
|
+
return `${sp.category} spell, ${sp.type}, ${range}, ${duration}. ${drain}${resist}.`;
|
|
546
|
+
}
|
|
547
|
+
/**
|
|
548
|
+
* WHAT A FORMULA COSTS, by the category of the spell it teaches (p.461,
|
|
549
|
+
* priced from the Magical Goods table). The formula is for ONE spell;
|
|
550
|
+
* the CATEGORY is only what sets the price, which is why these rows are
|
|
551
|
+
* generated per spell rather than per category.
|
|
552
|
+
*/
|
|
553
|
+
const FORMULA_PRICE = {
|
|
554
|
+
Detection: { price: 500, avail: 4 },
|
|
555
|
+
Health: { price: 500, avail: 4 },
|
|
556
|
+
Illusion: { price: 1000, avail: 8 },
|
|
557
|
+
Manipulation: { price: 1500, avail: 8 },
|
|
558
|
+
Combat: { price: 2000, avail: 8 },
|
|
559
|
+
};
|
|
560
|
+
/**
|
|
561
|
+
* ONE FORMULA PER SPELL, derived from SPELL_CATALOG.
|
|
562
|
+
*
|
|
563
|
+
* These are GEAR rows -- a scroll you buy from a talismonger and carry --
|
|
564
|
+
* and they are the first gear the engine reads for something other than
|
|
565
|
+
* a dice modifier: `teaches` names the spell, and Player.knowsSpell reads
|
|
566
|
+
* it. Generated rather than authored so a spell added tomorrow is
|
|
567
|
+
* purchasable the same day, with no second edit to forget.
|
|
568
|
+
*
|
|
569
|
+
* The Detection price sits in the table above and produces no rows,
|
|
570
|
+
* because this engine has no Detection spell yet. That is deliberate: a
|
|
571
|
+
* "Detection Spell Formula" WAS on sale here for 500 nuyen, for a
|
|
572
|
+
* category with nothing in it.
|
|
573
|
+
*/
|
|
574
|
+
function formulaRows() {
|
|
575
|
+
return SPELL_CATALOG.map(sp => {
|
|
576
|
+
const { price, avail } = FORMULA_PRICE[sp.category];
|
|
577
|
+
return row(`spell-formula-${sp.key}`, `Spell Formula (${sp.name})`, 'SpellFormula', price, avail, `${sp.name}, notated for study in somebody else's hand. Bring talent.`, {
|
|
578
|
+
page: 'p.461', shape: 'scroll', size: 'Tiny', weight: 0.1, legality: 'R',
|
|
579
|
+
teaches: sp.key,
|
|
580
|
+
stats: `${sp.category} formula: ${price} nuyen, avail ${avail}R`,
|
|
581
|
+
});
|
|
582
|
+
});
|
|
583
|
+
}
|
|
584
|
+
function spellRows() {
|
|
585
|
+
return SPELL_CATALOG.map(sp => ({
|
|
586
|
+
kind: 'spell',
|
|
587
|
+
slug: sp.key,
|
|
588
|
+
name: sp.name,
|
|
589
|
+
description: spellLine(sp),
|
|
590
|
+
page: sp.page,
|
|
591
|
+
// What it does to whoever it is held on, in the shared vocabulary.
|
|
592
|
+
// Absent on every Instantaneous spell -- a combat spell resolves at
|
|
593
|
+
// cast time -- and on the two barriers, whose effect is a wall in a
|
|
594
|
+
// room rather than a modifier on anybody.
|
|
595
|
+
...(sp.effects !== undefined ? { effects: sp.effects } : {}),
|
|
596
|
+
spell: {
|
|
597
|
+
cast: sp.cast,
|
|
598
|
+
category: sp.category,
|
|
599
|
+
type: sp.type,
|
|
600
|
+
range: sp.range,
|
|
601
|
+
duration: sp.duration,
|
|
602
|
+
drainOffset: sp.drainOffset,
|
|
603
|
+
...(sp.soak !== undefined ? { soak: sp.soak } : {}),
|
|
604
|
+
...(sp.stun !== undefined ? { stun: sp.stun } : {}),
|
|
605
|
+
...(sp.area !== undefined ? { area: sp.area } : {}),
|
|
606
|
+
...(sp.touch !== undefined ? { touch: sp.touch } : {}),
|
|
607
|
+
},
|
|
608
|
+
}));
|
|
609
|
+
}
|
|
610
|
+
function adeptPowerRows() {
|
|
611
|
+
return ADEPT_POWER_CATALOG.map(a => ({
|
|
612
|
+
kind: 'adept-power',
|
|
613
|
+
slug: a.key,
|
|
614
|
+
name: a.name,
|
|
615
|
+
description: a.effect,
|
|
616
|
+
page: a.page,
|
|
617
|
+
...(a.effects !== undefined ? { effects: a.effects } : {}),
|
|
618
|
+
adeptPower: {
|
|
619
|
+
levelCosts: a.levelCosts,
|
|
620
|
+
magicCapped: a.magicCapped,
|
|
621
|
+
...(a.costPerLevel !== undefined ? { costPerLevel: a.costPerLevel } : {}),
|
|
622
|
+
},
|
|
623
|
+
}));
|
|
624
|
+
}
|
|
625
|
+
function metamagicRows() {
|
|
626
|
+
return METAMAGICS.map(m => ({
|
|
627
|
+
kind: 'metamagic',
|
|
628
|
+
slug: m.key,
|
|
629
|
+
name: m.name,
|
|
630
|
+
description: m.effect,
|
|
631
|
+
page: m.page,
|
|
632
|
+
...(m.effects !== undefined ? { effects: m.effects } : {}),
|
|
633
|
+
metamagic: { path: m.path },
|
|
634
|
+
}));
|
|
635
|
+
}
|
|
636
|
+
/**
|
|
637
|
+
* THE METATYPES (p.66). Rows only: this engine models no metatype on a
|
|
638
|
+
* character and this pass does not change that -- what it does is put the
|
|
639
|
+
* table where it can be read, cited and priced, so the shape stops being
|
|
640
|
+
* an empty promise in the schema.
|
|
641
|
+
*/
|
|
642
|
+
function metatypeRows() {
|
|
643
|
+
return METATYPES.map(m => ({
|
|
644
|
+
kind: 'metatype',
|
|
645
|
+
slug: m.key,
|
|
646
|
+
name: m.name,
|
|
647
|
+
description: m.description,
|
|
648
|
+
page: m.page,
|
|
649
|
+
...(m.effects !== undefined ? { effects: m.effects } : {}),
|
|
650
|
+
metatype: {
|
|
651
|
+
attributes: m.attributes,
|
|
652
|
+
sprintMetersPerHit: m.sprintMetersPerHit,
|
|
653
|
+
...(m.lifestyleCostMult !== undefined ? { lifestyleCostMult: m.lifestyleCostMult } : {}),
|
|
654
|
+
},
|
|
655
|
+
}));
|
|
656
|
+
}
|
|
657
|
+
export const CATALOG_ROWS = [
|
|
658
|
+
...CATALOG_ITEMS,
|
|
659
|
+
...formulaRows(),
|
|
660
|
+
...qualityRows(),
|
|
661
|
+
...augmentationRows(),
|
|
662
|
+
...adeptPowerRows(),
|
|
663
|
+
...metamagicRows(),
|
|
664
|
+
...spellRows(),
|
|
665
|
+
...metatypeRows(),
|
|
666
|
+
];
|
|
400
667
|
//# sourceMappingURL=catalog-data.js.map
|