@craftrpgs/cli 0.2.0-alpha.0 → 0.2.0-alpha.1
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/dist/bin.js +623 -19
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -26899,6 +26899,7 @@ End each reply on something concrete in front of the player's character that the
|
|
|
26899
26899
|
];
|
|
26900
26900
|
var RESPONSE_LENGTH = "Response length";
|
|
26901
26901
|
var ROLL_NUMBERS = "Roll numbers in narration";
|
|
26902
|
+
var LONG_TRAVEL = "Long-distance travel";
|
|
26902
26903
|
var PLATFORM_OPTIONS = [
|
|
26903
26904
|
{
|
|
26904
26905
|
revision: 3,
|
|
@@ -26984,6 +26985,46 @@ var PLATFORM_OPTIONS = [
|
|
|
26984
26985
|
}
|
|
26985
26986
|
]
|
|
26986
26987
|
}
|
|
26988
|
+
},
|
|
26989
|
+
{
|
|
26990
|
+
revision: 1,
|
|
26991
|
+
option: {
|
|
26992
|
+
key: "platform-long-distance-travel",
|
|
26993
|
+
label: LONG_TRAVEL,
|
|
26994
|
+
description: "What happens when the party travels somewhere far away.",
|
|
26995
|
+
kind: "one",
|
|
26996
|
+
default: ["up-to-gm"],
|
|
26997
|
+
choices: [
|
|
26998
|
+
{
|
|
26999
|
+
key: "up-to-gm",
|
|
27000
|
+
label: "Up to the GM",
|
|
27001
|
+
description: "The Game Master decides when the road is worth playing.",
|
|
27002
|
+
instructions: []
|
|
27003
|
+
},
|
|
27004
|
+
{
|
|
27005
|
+
key: "fast-travel",
|
|
27006
|
+
label: "Fast travel",
|
|
27007
|
+
description: "Skip ahead to the destination, with the trip summed up.",
|
|
27008
|
+
instructions: [
|
|
27009
|
+
{
|
|
27010
|
+
when: "always",
|
|
27011
|
+
body: `When the party travels somewhere far (a trip of hours or more), take them straight there in the same reply: record it as arriving ("Move Kael and Mira to Harrowmere"), never "set out for", sum up the trip in a sentence or two (how long it took, how the way went), and go on from the arrival. When the player set out from the map, tell the arrival the same way.`
|
|
27012
|
+
}
|
|
27013
|
+
]
|
|
27014
|
+
},
|
|
27015
|
+
{
|
|
27016
|
+
key: "journey",
|
|
27017
|
+
label: "Journey",
|
|
27018
|
+
description: "Travel there step by step, with the road played out.",
|
|
27019
|
+
instructions: [
|
|
27020
|
+
{
|
|
27021
|
+
when: "always",
|
|
27022
|
+
body: `When the party travels somewhere far (a trip of hours or more), play it as a journey to where the player said they are going. Set out first ("Kael and Mira set out for Harrowmere by the coast road; it takes about three days"), then tell the way in stages over several replies, for as long as the distance really takes: the road and the weather, rests and camps, people and trouble met on the way, with time passing as it would ("It is now dusk"). The party stays on the way the whole time: a camp or a rest is told with the time it takes, never a move to a camp or a stretch of road. Someone met stops the journey where they meet; when the party goes on from there, record it as "Kael and Mira set out again for Harrowmere", never as a move farther along the road. Keep heading for the place the player named unless they change course, and record the arrival ("Move Kael and Mira to Harrowmere") only once the way has been travelled. When the player set out from the map, they are already on the way: go on with the journey.`
|
|
27023
|
+
}
|
|
27024
|
+
]
|
|
27025
|
+
}
|
|
27026
|
+
]
|
|
27027
|
+
}
|
|
26987
27028
|
}
|
|
26988
27029
|
];
|
|
26989
27030
|
|
|
@@ -41012,6 +41053,8 @@ var FILE_DESIGNATION_METADATA_SCHEMA_VERSION_V6 = "file-designation-metadata:v6"
|
|
|
41012
41053
|
var FILE_DESIGNATION_METADATA_SCHEMA_VERSION_V7 = "file-designation-metadata:v7";
|
|
41013
41054
|
var FILE_DESIGNATION_METADATA_SCHEMA_VERSION_V8 = "file-designation-metadata:v8";
|
|
41014
41055
|
var FILE_DESIGNATION_METADATA_SCHEMA_VERSION_V9 = "file-designation-metadata:v9";
|
|
41056
|
+
var FILE_DESIGNATION_METADATA_SCHEMA_VERSION_V10 = "file-designation-metadata:v10";
|
|
41057
|
+
var FILE_DESIGNATION_METADATA_SCHEMA_VERSION_V11 = "file-designation-metadata:v11";
|
|
41015
41058
|
var GAME_START_OPENING_MAX_LENGTH = 1e4;
|
|
41016
41059
|
var GAME_START_MAX_OPENING_BEATS = 50;
|
|
41017
41060
|
var GAME_START_MAX_CHARACTER_OPENINGS = 100;
|
|
@@ -41212,6 +41255,142 @@ var MapDataV6Schema = MapDataV5Schema.extend({
|
|
|
41212
41255
|
var MapDataV8Schema = MapDataV6Schema.extend({
|
|
41213
41256
|
grid: MapGridSchema.nullable().default(null)
|
|
41214
41257
|
});
|
|
41258
|
+
var MAP_EXIT_KINDS = [
|
|
41259
|
+
"door",
|
|
41260
|
+
"gate",
|
|
41261
|
+
"stairs",
|
|
41262
|
+
"ladder",
|
|
41263
|
+
"hatch",
|
|
41264
|
+
"path",
|
|
41265
|
+
"road",
|
|
41266
|
+
"dock",
|
|
41267
|
+
"portal",
|
|
41268
|
+
"other"
|
|
41269
|
+
];
|
|
41270
|
+
var MAP_EXIT_DIRECTIONS = [
|
|
41271
|
+
"up",
|
|
41272
|
+
"down",
|
|
41273
|
+
"in",
|
|
41274
|
+
"out",
|
|
41275
|
+
"through"
|
|
41276
|
+
];
|
|
41277
|
+
var MapExitSchema = exports_external.object({
|
|
41278
|
+
kind: exports_external.enum(MAP_EXIT_KINDS).default("door"),
|
|
41279
|
+
to: exports_external.string().uuid().nullable().default(null),
|
|
41280
|
+
direction: exports_external.enum(MAP_EXIT_DIRECTIONS).optional(),
|
|
41281
|
+
arriveAt: exports_external.string().uuid().nullable().optional(),
|
|
41282
|
+
main: exports_external.boolean().optional(),
|
|
41283
|
+
locked: exports_external.boolean().optional(),
|
|
41284
|
+
hidden: exports_external.boolean().optional()
|
|
41285
|
+
});
|
|
41286
|
+
var MapAreaV10Schema = MapAreaSchema.extend({
|
|
41287
|
+
exit: MapExitSchema.optional()
|
|
41288
|
+
});
|
|
41289
|
+
var MapPointV10Schema = MapPointSchema.extend({
|
|
41290
|
+
exit: MapExitSchema.optional()
|
|
41291
|
+
});
|
|
41292
|
+
var MapDataV10Schema = MapDataV8Schema.extend({
|
|
41293
|
+
areas: exports_external.array(MapAreaV10Schema),
|
|
41294
|
+
points: exports_external.array(MapPointV10Schema)
|
|
41295
|
+
});
|
|
41296
|
+
var COMPASS_DIRECTIONS = [
|
|
41297
|
+
"north",
|
|
41298
|
+
"northeast",
|
|
41299
|
+
"east",
|
|
41300
|
+
"southeast",
|
|
41301
|
+
"south",
|
|
41302
|
+
"southwest",
|
|
41303
|
+
"west",
|
|
41304
|
+
"northwest"
|
|
41305
|
+
];
|
|
41306
|
+
var PLACE_WAY_KINDS = [
|
|
41307
|
+
...MAP_EXIT_KINDS,
|
|
41308
|
+
"bridge",
|
|
41309
|
+
"ferry",
|
|
41310
|
+
"tunnel",
|
|
41311
|
+
"ritual"
|
|
41312
|
+
];
|
|
41313
|
+
var PLACE_WAY_DIRECTIONS = [
|
|
41314
|
+
...MAP_EXIT_DIRECTIONS,
|
|
41315
|
+
...COMPASS_DIRECTIONS
|
|
41316
|
+
];
|
|
41317
|
+
var relationWords = (max) => exports_external.string().trim().min(1).max(max);
|
|
41318
|
+
var PlaceWaySchema = MapExitSchema.extend({
|
|
41319
|
+
kind: exports_external.enum(PLACE_WAY_KINDS).default("door"),
|
|
41320
|
+
direction: exports_external.enum(PLACE_WAY_DIRECTIONS).optional(),
|
|
41321
|
+
oneWay: exports_external.boolean().optional(),
|
|
41322
|
+
when: relationWords(200).optional(),
|
|
41323
|
+
requires: relationWords(200).optional(),
|
|
41324
|
+
by: exports_external.string().uuid().optional(),
|
|
41325
|
+
label: relationWords(120).optional(),
|
|
41326
|
+
distance: relationWords(60).optional(),
|
|
41327
|
+
time: relationWords(60).optional()
|
|
41328
|
+
});
|
|
41329
|
+
var MapAreaV11Schema = MapAreaSchema.extend({
|
|
41330
|
+
exit: PlaceWaySchema.optional()
|
|
41331
|
+
});
|
|
41332
|
+
var MapPointV11Schema = MapPointSchema.extend({
|
|
41333
|
+
exit: PlaceWaySchema.optional()
|
|
41334
|
+
});
|
|
41335
|
+
var MapDataV11Schema = MapDataV8Schema.extend({
|
|
41336
|
+
areas: exports_external.array(MapAreaV11Schema),
|
|
41337
|
+
points: exports_external.array(MapPointV11Schema)
|
|
41338
|
+
});
|
|
41339
|
+
var RelationIdSchema = exports_external.string().uuid();
|
|
41340
|
+
var RelationTargetSchema = exports_external.string().uuid();
|
|
41341
|
+
var InsideRelationSchema = exports_external.object({
|
|
41342
|
+
id: RelationIdSchema,
|
|
41343
|
+
type: exports_external.literal("inside"),
|
|
41344
|
+
to: RelationTargetSchema,
|
|
41345
|
+
level: exports_external.number().int().min(-100).max(500).optional()
|
|
41346
|
+
});
|
|
41347
|
+
var ConnectsRelationSchema = PlaceWaySchema.extend({
|
|
41348
|
+
id: RelationIdSchema,
|
|
41349
|
+
type: exports_external.literal("connects")
|
|
41350
|
+
});
|
|
41351
|
+
var OtherRelationSchema = exports_external.object({
|
|
41352
|
+
id: RelationIdSchema,
|
|
41353
|
+
type: exports_external.literal("other"),
|
|
41354
|
+
to: RelationTargetSchema,
|
|
41355
|
+
label: relationWords(120)
|
|
41356
|
+
});
|
|
41357
|
+
var PlaceRelationSchema = exports_external.discriminatedUnion("type", [
|
|
41358
|
+
InsideRelationSchema,
|
|
41359
|
+
ConnectsRelationSchema,
|
|
41360
|
+
OtherRelationSchema
|
|
41361
|
+
]);
|
|
41362
|
+
var MAX_PLACE_RELATIONS = 100;
|
|
41363
|
+
var TRANSPORT_KINDS = [
|
|
41364
|
+
"ship",
|
|
41365
|
+
"boat",
|
|
41366
|
+
"airship",
|
|
41367
|
+
"wagon",
|
|
41368
|
+
"caravan",
|
|
41369
|
+
"carriage",
|
|
41370
|
+
"train",
|
|
41371
|
+
"car",
|
|
41372
|
+
"bus",
|
|
41373
|
+
"plane",
|
|
41374
|
+
"mount",
|
|
41375
|
+
"other"
|
|
41376
|
+
];
|
|
41377
|
+
var TRANSPORT_MEDIUMS = [
|
|
41378
|
+
"water",
|
|
41379
|
+
"land",
|
|
41380
|
+
"air",
|
|
41381
|
+
"rail",
|
|
41382
|
+
"underground",
|
|
41383
|
+
"space"
|
|
41384
|
+
];
|
|
41385
|
+
var TransportMetadataSchema = exports_external.object({
|
|
41386
|
+
kind: exports_external.enum(TRANSPORT_KINDS),
|
|
41387
|
+
travels: exports_external.enum(TRANSPORT_MEDIUMS).optional(),
|
|
41388
|
+
speed: exports_external.object({
|
|
41389
|
+
value: exports_external.number().positive(),
|
|
41390
|
+
unit: exports_external.enum(["mph", "km/h", "knots"])
|
|
41391
|
+
}).optional(),
|
|
41392
|
+
capacity: exports_external.number().int().positive().optional()
|
|
41393
|
+
});
|
|
41215
41394
|
var GmInstructionTriggerPhaseSchema = exports_external.enum(GM_INSTRUCTION_TRIGGER_PHASES);
|
|
41216
41395
|
var GmInstructionToolEventSchema = exports_external.enum(GM_INSTRUCTION_TOOL_EVENTS);
|
|
41217
41396
|
var GmInstructionNarrativeMetadataSchema = exports_external.object({
|
|
@@ -41403,24 +41582,36 @@ var FileDesignationMetadataV9Schema = FileDesignationMetadataV8Schema.extend({
|
|
|
41403
41582
|
schemaVersionId: exports_external.literal(FILE_DESIGNATION_METADATA_SCHEMA_VERSION_V9).default(FILE_DESIGNATION_METADATA_SCHEMA_VERSION_V9),
|
|
41404
41583
|
script: ScriptMetadataSchema.optional()
|
|
41405
41584
|
});
|
|
41406
|
-
var
|
|
41407
|
-
|
|
41585
|
+
var FileDesignationMetadataV10Schema = FileDesignationMetadataV9Schema.extend({
|
|
41586
|
+
schemaVersionId: exports_external.literal(FILE_DESIGNATION_METADATA_SCHEMA_VERSION_V10).default(FILE_DESIGNATION_METADATA_SCHEMA_VERSION_V10),
|
|
41587
|
+
map: MapDataV10Schema.optional(),
|
|
41588
|
+
transport: TransportMetadataSchema.optional()
|
|
41589
|
+
});
|
|
41590
|
+
var FileDesignationMetadataV11Schema = FileDesignationMetadataV10Schema.extend({
|
|
41591
|
+
schemaVersionId: exports_external.literal(FILE_DESIGNATION_METADATA_SCHEMA_VERSION_V11).default(FILE_DESIGNATION_METADATA_SCHEMA_VERSION_V11),
|
|
41592
|
+
map: MapDataV11Schema.optional(),
|
|
41593
|
+
relations: exports_external.array(PlaceRelationSchema).max(MAX_PLACE_RELATIONS).optional()
|
|
41594
|
+
});
|
|
41595
|
+
var MapSchema = FileDesignationMetadataV11Schema.shape.map.unwrap();
|
|
41596
|
+
var LocationDesignationMetadataSchema = FileDesignationMetadataV11Schema.pick({
|
|
41408
41597
|
schemaVersionId: true,
|
|
41409
|
-
map: true
|
|
41598
|
+
map: true,
|
|
41599
|
+
transport: true,
|
|
41600
|
+
relations: true
|
|
41410
41601
|
});
|
|
41411
|
-
var CharacterDesignationMetadataSchema =
|
|
41602
|
+
var CharacterDesignationMetadataSchema = FileDesignationMetadataV11Schema.pick({
|
|
41412
41603
|
schemaVersionId: true,
|
|
41413
41604
|
playable: true
|
|
41414
41605
|
});
|
|
41415
|
-
var GmInstructionDesignationMetadataSchema =
|
|
41606
|
+
var GmInstructionDesignationMetadataSchema = FileDesignationMetadataV11Schema.pick({
|
|
41416
41607
|
schemaVersionId: true,
|
|
41417
41608
|
gmInstruction: true
|
|
41418
41609
|
});
|
|
41419
|
-
var GameStartDesignationMetadataSchema =
|
|
41610
|
+
var GameStartDesignationMetadataSchema = FileDesignationMetadataV11Schema.pick({
|
|
41420
41611
|
schemaVersionId: true,
|
|
41421
41612
|
gameStart: true
|
|
41422
41613
|
});
|
|
41423
|
-
var ScriptDesignationMetadataSchema =
|
|
41614
|
+
var ScriptDesignationMetadataSchema = FileDesignationMetadataV11Schema.pick({
|
|
41424
41615
|
schemaVersionId: true,
|
|
41425
41616
|
script: true
|
|
41426
41617
|
});
|
|
@@ -41428,10 +41619,17 @@ function upgradeFileDesignationMetadata(input) {
|
|
|
41428
41619
|
if (input === null || input === undefined) {
|
|
41429
41620
|
return null;
|
|
41430
41621
|
}
|
|
41431
|
-
|
|
41432
|
-
|
|
41622
|
+
const schemaVersionId = readSchemaVersionId(input);
|
|
41623
|
+
if (schemaVersionId === FILE_DESIGNATION_METADATA_SCHEMA_VERSION_V11) {
|
|
41624
|
+
return FileDesignationMetadataV11Schema.parse(input);
|
|
41433
41625
|
}
|
|
41434
|
-
|
|
41626
|
+
if (schemaVersionId === FILE_DESIGNATION_METADATA_SCHEMA_VERSION_V10) {
|
|
41627
|
+
return upgradeV10MetadataToV11(FileDesignationMetadataV10Schema.parse(input));
|
|
41628
|
+
}
|
|
41629
|
+
if (schemaVersionId === FILE_DESIGNATION_METADATA_SCHEMA_VERSION_V9) {
|
|
41630
|
+
return upgradeV10MetadataToV11(upgradeV9MetadataToV10(FileDesignationMetadataV9Schema.parse(input)));
|
|
41631
|
+
}
|
|
41632
|
+
return upgradeV10MetadataToV11(upgradeV9MetadataToV10(upgradeV8MetadataToV9(upgradeMetadataToV8(input))));
|
|
41435
41633
|
}
|
|
41436
41634
|
function upgradeMetadataToV8(input) {
|
|
41437
41635
|
const schemaVersionId = readSchemaVersionId(input);
|
|
@@ -41518,6 +41716,18 @@ function upgradeV8MetadataToV9(metadata) {
|
|
|
41518
41716
|
schemaVersionId: FILE_DESIGNATION_METADATA_SCHEMA_VERSION_V9
|
|
41519
41717
|
});
|
|
41520
41718
|
}
|
|
41719
|
+
function upgradeV9MetadataToV10(metadata) {
|
|
41720
|
+
return FileDesignationMetadataV10Schema.parse({
|
|
41721
|
+
...metadata,
|
|
41722
|
+
schemaVersionId: FILE_DESIGNATION_METADATA_SCHEMA_VERSION_V10
|
|
41723
|
+
});
|
|
41724
|
+
}
|
|
41725
|
+
function upgradeV10MetadataToV11(metadata) {
|
|
41726
|
+
return FileDesignationMetadataV11Schema.parse({
|
|
41727
|
+
...metadata,
|
|
41728
|
+
schemaVersionId: FILE_DESIGNATION_METADATA_SCHEMA_VERSION_V11
|
|
41729
|
+
});
|
|
41730
|
+
}
|
|
41521
41731
|
function normalizeLegacyDefaultGrid(map2) {
|
|
41522
41732
|
if (map2.grid?.mode !== "default") {
|
|
41523
41733
|
return map2;
|
|
@@ -45379,7 +45589,7 @@ async function refreshWorkspaceScriptTypes({
|
|
|
45379
45589
|
// package.json
|
|
45380
45590
|
var package_default = {
|
|
45381
45591
|
name: "@craftrpgs/cli",
|
|
45382
|
-
version: "0.2.0-alpha.
|
|
45592
|
+
version: "0.2.0-alpha.1",
|
|
45383
45593
|
description: "Sync Craft projects with a local folder — clone, edit with any coding agent, push back.",
|
|
45384
45594
|
license: "UNLICENSED",
|
|
45385
45595
|
homepage: "https://craftrpgs.com",
|
|
@@ -45439,6 +45649,17 @@ var cliMetaWriteResponseSchema = exports_external.object({
|
|
|
45439
45649
|
version: exports_external.object({ id: exports_external.string().min(1) }),
|
|
45440
45650
|
linkStateChanged: exports_external.boolean().optional()
|
|
45441
45651
|
});
|
|
45652
|
+
var cliPlacePairWriteResponseSchema = exports_external.object({
|
|
45653
|
+
changedFileIds: exports_external.array(exports_external.string().min(1))
|
|
45654
|
+
});
|
|
45655
|
+
var cliLinkedLocationsResponseSchema = exports_external.object({
|
|
45656
|
+
parent: exports_external.object({ referenceId: exports_external.string() }).nullable(),
|
|
45657
|
+
places: exports_external.array(exports_external.object({
|
|
45658
|
+
referenceId: exports_external.string(),
|
|
45659
|
+
name: exports_external.string(),
|
|
45660
|
+
pair: exports_external.record(exports_external.string(), exports_external.unknown())
|
|
45661
|
+
}))
|
|
45662
|
+
});
|
|
45442
45663
|
var cliFileMetaResponseSchema = exports_external.object({
|
|
45443
45664
|
currentVersion: exports_external.object({
|
|
45444
45665
|
id: exports_external.string().min(1),
|
|
@@ -45829,6 +46050,40 @@ function createCliClient({
|
|
|
45829
46050
|
async putGmInstruction({ fileId, gmInstruction }) {
|
|
45830
46051
|
return await putMetadata(`/api/files/${fileId}/gm-instruction`, { gmInstruction }, "GM instruction trigger save");
|
|
45831
46052
|
},
|
|
46053
|
+
async fetchLinkedLocations({ fileId }) {
|
|
46054
|
+
const response = await request(`/api/files/${fileId}/relations`);
|
|
46055
|
+
if (response.status === 404) {
|
|
46056
|
+
return null;
|
|
46057
|
+
}
|
|
46058
|
+
if (!response.ok) {
|
|
46059
|
+
const { code, message, details } = await readErrorBody(response);
|
|
46060
|
+
throw new CliApiError({
|
|
46061
|
+
message,
|
|
46062
|
+
code,
|
|
46063
|
+
status: response.status,
|
|
46064
|
+
exitCode: 1,
|
|
46065
|
+
details
|
|
46066
|
+
});
|
|
46067
|
+
}
|
|
46068
|
+
return await parseJson(response, cliLinkedLocationsResponseSchema, "linked locations");
|
|
46069
|
+
},
|
|
46070
|
+
async putFileTransport({ fileId, transport }) {
|
|
46071
|
+
return await putMetadata(`/api/files/${fileId}/transport`, { transport }, "transport save");
|
|
46072
|
+
},
|
|
46073
|
+
async putPlacePair({ fileId, otherFileId, pair }) {
|
|
46074
|
+
const response = await request(`/api/files/${fileId}/relations/${otherFileId}`, pair === null ? { method: "DELETE" } : { method: "PUT", body: JSON.stringify(pair) });
|
|
46075
|
+
if (!response.ok) {
|
|
46076
|
+
const { code, message, details } = await readErrorBody(response);
|
|
46077
|
+
throw new CliApiError({
|
|
46078
|
+
message,
|
|
46079
|
+
code,
|
|
46080
|
+
status: response.status,
|
|
46081
|
+
exitCode: response.status === 400 || response.status === 422 ? 2 : 1,
|
|
46082
|
+
details
|
|
46083
|
+
});
|
|
46084
|
+
}
|
|
46085
|
+
return await parseJson(response, cliPlacePairWriteResponseSchema, "linked location save");
|
|
46086
|
+
},
|
|
45832
46087
|
async putDesignationFlag({ fileId, flag, value }) {
|
|
45833
46088
|
return await putMetadata(`/api/files/${fileId}/designation`, { flag, value }, "designation flag save");
|
|
45834
46089
|
},
|
|
@@ -48549,11 +48804,66 @@ async function runLogout(argv) {
|
|
|
48549
48804
|
|
|
48550
48805
|
// src/commands/map.ts
|
|
48551
48806
|
import { readFile as readFile11 } from "node:fs/promises";
|
|
48807
|
+
|
|
48808
|
+
// src/commands/place-metadata.ts
|
|
48809
|
+
function pathOrId(ledger, referenceId) {
|
|
48810
|
+
return referenceIdToPath({ ledger, referenceId }) ?? referenceId;
|
|
48811
|
+
}
|
|
48812
|
+
function exitForOutput(ledger, exit) {
|
|
48813
|
+
return {
|
|
48814
|
+
...exit,
|
|
48815
|
+
...typeof exit.to === "string" ? { to: pathOrId(ledger, exit.to) } : {},
|
|
48816
|
+
...typeof exit.by === "string" ? { by: pathOrId(ledger, exit.by) } : {}
|
|
48817
|
+
};
|
|
48818
|
+
}
|
|
48819
|
+
function relationsForOutput(ledger, relations) {
|
|
48820
|
+
return relations.map((relation) => exitForOutput(ledger, relation));
|
|
48821
|
+
}
|
|
48822
|
+
function listMapExitsForOutput(ledger, map2) {
|
|
48823
|
+
return [...map2.areas, ...map2.points].flatMap((element) => element.exit ? [
|
|
48824
|
+
{
|
|
48825
|
+
element: element.label ?? element.id,
|
|
48826
|
+
...exitForOutput(ledger, element.exit)
|
|
48827
|
+
}
|
|
48828
|
+
] : []);
|
|
48829
|
+
}
|
|
48830
|
+
function resolveExitInput({
|
|
48831
|
+
ledger,
|
|
48832
|
+
exit,
|
|
48833
|
+
where,
|
|
48834
|
+
failures
|
|
48835
|
+
}) {
|
|
48836
|
+
if (typeof exit !== "object" || exit === null || Array.isArray(exit)) {
|
|
48837
|
+
return exit;
|
|
48838
|
+
}
|
|
48839
|
+
const record2 = { ...exit };
|
|
48840
|
+
for (const key of ["to", "by"]) {
|
|
48841
|
+
const value = record2[key];
|
|
48842
|
+
if (typeof value !== "string") {
|
|
48843
|
+
continue;
|
|
48844
|
+
}
|
|
48845
|
+
const resolution = resolveLink({ ledger, link: value });
|
|
48846
|
+
if (resolution.status === "resolved") {
|
|
48847
|
+
record2[key] = resolution.referenceId;
|
|
48848
|
+
} else {
|
|
48849
|
+
failures.push({
|
|
48850
|
+
where: `${where}.${key}`,
|
|
48851
|
+
link: value,
|
|
48852
|
+
reason: resolution.status
|
|
48853
|
+
});
|
|
48854
|
+
}
|
|
48855
|
+
}
|
|
48856
|
+
return record2;
|
|
48857
|
+
}
|
|
48858
|
+
|
|
48859
|
+
// src/commands/map.ts
|
|
48552
48860
|
var MAP_USAGE = `Usage: craft map get <location-path> [--json]
|
|
48553
48861
|
` + ` craft map set <location-path> --file <map.json>
|
|
48554
48862
|
` + `
|
|
48555
|
-
` + "The map JSON is the stored MapData shape; in `set` input, areas/points may\n" + 'use `"link": "<workspace path | slug.type | referenceId>"` instead of\n' + `fileReferenceId, and element ids are minted when omitted.
|
|
48556
|
-
` + "
|
|
48863
|
+
` + "The map JSON is the stored MapData shape; in `set` input, areas/points may\n" + 'use `"link": "<workspace path | slug.type | referenceId>"` instead of\n' + `fileReferenceId, and element ids are minted when omitted. An element's
|
|
48864
|
+
` + '`exit` (a door, stairs, a road to another location) takes `"to"` as a\n' + "workspace path too; no `to` is the way out to the parent map. `get` prints\n" + `links and exit targets as workspace paths. Read
|
|
48865
|
+
` + `.craft/instructions/authoring-maps.md for the format and
|
|
48866
|
+
` + ".craft/instructions/linking-locations.md for exits.";
|
|
48557
48867
|
async function runMap(argv) {
|
|
48558
48868
|
const [subcommand, ...rest] = argv;
|
|
48559
48869
|
if (subcommand === "get") {
|
|
@@ -48575,16 +48885,22 @@ function hydrateMapForOutput(workspace, map2) {
|
|
|
48575
48885
|
if (typeof element !== "object" || element === null) {
|
|
48576
48886
|
return element;
|
|
48577
48887
|
}
|
|
48578
|
-
|
|
48888
|
+
let record2 = element;
|
|
48889
|
+
if (typeof record2.exit === "object" && record2.exit !== null) {
|
|
48890
|
+
record2 = {
|
|
48891
|
+
...record2,
|
|
48892
|
+
exit: exitForOutput(workspace.ledger, record2.exit)
|
|
48893
|
+
};
|
|
48894
|
+
}
|
|
48579
48895
|
if (typeof record2.fileReferenceId !== "string") {
|
|
48580
|
-
return
|
|
48896
|
+
return record2;
|
|
48581
48897
|
}
|
|
48582
48898
|
const path = referenceIdToPath({
|
|
48583
48899
|
ledger: workspace.ledger,
|
|
48584
48900
|
referenceId: record2.fileReferenceId
|
|
48585
48901
|
});
|
|
48586
48902
|
if (!path) {
|
|
48587
|
-
return
|
|
48903
|
+
return record2;
|
|
48588
48904
|
}
|
|
48589
48905
|
const { fileReferenceId: _dropped, ...rest } = record2;
|
|
48590
48906
|
return { ...rest, link: path };
|
|
@@ -48677,6 +48993,14 @@ function normalizeMapInput(workspace, raw) {
|
|
|
48677
48993
|
if (record2.fileReferenceId === undefined) {
|
|
48678
48994
|
record2.fileReferenceId = null;
|
|
48679
48995
|
}
|
|
48996
|
+
if (record2.exit !== undefined) {
|
|
48997
|
+
record2.exit = resolveExitInput({
|
|
48998
|
+
ledger: workspace.ledger,
|
|
48999
|
+
exit: record2.exit,
|
|
49000
|
+
where: `${kindLabel2}[${index}].exit`,
|
|
49001
|
+
failures
|
|
49002
|
+
});
|
|
49003
|
+
}
|
|
48680
49004
|
for (const [key, value] of Object.entries(defaults)) {
|
|
48681
49005
|
if (record2[key] === undefined) {
|
|
48682
49006
|
record2[key] = value;
|
|
@@ -48945,13 +49269,75 @@ function translateGameStartAuthoringInput({
|
|
|
48945
49269
|
return input;
|
|
48946
49270
|
}
|
|
48947
49271
|
|
|
49272
|
+
// ../shared/src/place-pairs.ts
|
|
49273
|
+
var PLACE_PAIR_KINDS = [
|
|
49274
|
+
"same_place",
|
|
49275
|
+
"contains",
|
|
49276
|
+
"part_of",
|
|
49277
|
+
"separate",
|
|
49278
|
+
"other"
|
|
49279
|
+
];
|
|
49280
|
+
var PairWaySchema = PlaceWaySchema.omit({
|
|
49281
|
+
to: true,
|
|
49282
|
+
arriveAt: true,
|
|
49283
|
+
main: true,
|
|
49284
|
+
oneWay: true
|
|
49285
|
+
}).extend({
|
|
49286
|
+
oneWay: exports_external.enum(["there", "back"]).optional()
|
|
49287
|
+
});
|
|
49288
|
+
var PairWordsSchema = exports_external.object({
|
|
49289
|
+
text: exports_external.string().trim().min(1).max(120),
|
|
49290
|
+
first: exports_external.enum(["a", "b"])
|
|
49291
|
+
});
|
|
49292
|
+
var PlacePairSchema = exports_external.object({
|
|
49293
|
+
kind: exports_external.enum(PLACE_PAIR_KINDS),
|
|
49294
|
+
parentRef: exports_external.string().uuid().optional(),
|
|
49295
|
+
way: PairWaySchema.nullable(),
|
|
49296
|
+
words: PairWordsSchema.nullable()
|
|
49297
|
+
});
|
|
49298
|
+
function placePairProblem({
|
|
49299
|
+
pair,
|
|
49300
|
+
aRef,
|
|
49301
|
+
bRef
|
|
49302
|
+
}) {
|
|
49303
|
+
if (aRef === bRef) {
|
|
49304
|
+
return "A location can't be linked to itself.";
|
|
49305
|
+
}
|
|
49306
|
+
if (pair.kind === "same_place") {
|
|
49307
|
+
if (!pair.parentRef) {
|
|
49308
|
+
return "Pick the location they're both in.";
|
|
49309
|
+
}
|
|
49310
|
+
if (pair.parentRef === aRef || pair.parentRef === bRef) {
|
|
49311
|
+
return "A location can't be inside itself.";
|
|
49312
|
+
}
|
|
49313
|
+
} else if (pair.parentRef) {
|
|
49314
|
+
return "Only locations in one location name the location they're in.";
|
|
49315
|
+
}
|
|
49316
|
+
if (pair.kind === "separate" && !pair.way) {
|
|
49317
|
+
return "Separate locations need a way between them.";
|
|
49318
|
+
}
|
|
49319
|
+
if (pair.kind === "other" && !pair.words) {
|
|
49320
|
+
return "Say how they relate.";
|
|
49321
|
+
}
|
|
49322
|
+
if (pair.kind !== "other" && pair.words) {
|
|
49323
|
+
return "Only something else has words of its own.";
|
|
49324
|
+
}
|
|
49325
|
+
return null;
|
|
49326
|
+
}
|
|
49327
|
+
|
|
48948
49328
|
// src/commands/meta.ts
|
|
49329
|
+
var PAIR_KIND_FIELD_RE = /^kind/;
|
|
48949
49330
|
var META_USAGE = `Usage: craft meta get <path> [--json]
|
|
48950
49331
|
` + ` craft meta set-game-start <game-start-path> --file <json>
|
|
48951
49332
|
` + ` craft meta set-gm-trigger <gm-instruction-path> (--file <json> | --clear)
|
|
48952
49333
|
` + ` craft meta set-playable <character-path> <true|false>
|
|
49334
|
+
` + ` craft meta set-transport <location-path> (--file <json> | --clear)
|
|
49335
|
+
` + ` craft meta link <location-path> <other-location-path> --file <json>
|
|
49336
|
+
` + ` craft meta unlink <location-path> <other-location-path>
|
|
48953
49337
|
` + `
|
|
48954
|
-
` +
|
|
49338
|
+
` + `See .craft/instructions/making-it-playable.md for game starts, triggers and
|
|
49339
|
+
` + `playable, and .craft/instructions/linking-locations.md for transports and
|
|
49340
|
+
` + "linked locations. `get` on a location shows its transport, its linked\n" + "locations (read from both ends) and its map's exits, with workspace paths.";
|
|
48955
49341
|
async function runMeta(argv) {
|
|
48956
49342
|
const [subcommand, ...rest] = argv;
|
|
48957
49343
|
if (subcommand === "get") {
|
|
@@ -48966,6 +49352,15 @@ async function runMeta(argv) {
|
|
|
48966
49352
|
if (subcommand === "set-playable") {
|
|
48967
49353
|
return await runSetPlayable(rest);
|
|
48968
49354
|
}
|
|
49355
|
+
if (subcommand === "set-transport") {
|
|
49356
|
+
return await runSetTransport(rest);
|
|
49357
|
+
}
|
|
49358
|
+
if (subcommand === "link") {
|
|
49359
|
+
return await runLink(rest, "link");
|
|
49360
|
+
}
|
|
49361
|
+
if (subcommand === "unlink") {
|
|
49362
|
+
return await runLink(rest, "unlink");
|
|
49363
|
+
}
|
|
48969
49364
|
throw new CliError(META_USAGE, 2);
|
|
48970
49365
|
}
|
|
48971
49366
|
async function readJsonFile2(inputPath) {
|
|
@@ -49028,6 +49423,8 @@ async function runMetaGet(argv) {
|
|
|
49028
49423
|
if (gameStart) {
|
|
49029
49424
|
gameStart.startingLocationFileReferenceId = undefined;
|
|
49030
49425
|
}
|
|
49426
|
+
const isLocation = meta3.fileType?.designation === "location" || Boolean(parsed?.map || parsed?.transport || parsed?.relations);
|
|
49427
|
+
const linkedLocations = isLocation ? await linkedLocationsForOutput(workspace, client, entry.fileId) : undefined;
|
|
49031
49428
|
printJson({
|
|
49032
49429
|
path,
|
|
49033
49430
|
fileType: entry.fileType,
|
|
@@ -49039,11 +49436,38 @@ async function runMetaGet(argv) {
|
|
|
49039
49436
|
areas: parsed.map.areas.length,
|
|
49040
49437
|
points: parsed.map.points.length,
|
|
49041
49438
|
useParentMap: parsed.map.useParentMap ?? false,
|
|
49439
|
+
exits: listMapExitsForOutput(workspace.ledger, parsed.map),
|
|
49042
49440
|
hint: "Full map via `craft map get`."
|
|
49043
|
-
} : null
|
|
49441
|
+
} : null,
|
|
49442
|
+
...isLocation ? {
|
|
49443
|
+
transport: parsed?.transport ?? null,
|
|
49444
|
+
relations: relationsForOutput(workspace.ledger, parsed?.relations ?? []),
|
|
49445
|
+
...linkedLocations === undefined ? {} : { linkedLocations }
|
|
49446
|
+
} : {}
|
|
49044
49447
|
});
|
|
49045
49448
|
return 0;
|
|
49046
49449
|
}
|
|
49450
|
+
async function linkedLocationsForOutput(workspace, client, fileId) {
|
|
49451
|
+
const linked = await client.fetchLinkedLocations({ fileId });
|
|
49452
|
+
if (!linked) {
|
|
49453
|
+
return;
|
|
49454
|
+
}
|
|
49455
|
+
return linked.places.map((place) => {
|
|
49456
|
+
const pair = place.pair;
|
|
49457
|
+
return {
|
|
49458
|
+
location: pathForReference(workspace, place.referenceId) ?? place.name,
|
|
49459
|
+
relation: pair.kind,
|
|
49460
|
+
...pair.parentRef ? { in: pathForReference(workspace, pair.parentRef) } : {},
|
|
49461
|
+
...pair.way ? {
|
|
49462
|
+
way: exitForOutput(workspace.ledger, pair.way)
|
|
49463
|
+
} : {},
|
|
49464
|
+
...pair.words ? {
|
|
49465
|
+
words: pair.words.text,
|
|
49466
|
+
wordsFirst: pair.words.first === "a" ? "location" : "other"
|
|
49467
|
+
} : {}
|
|
49468
|
+
};
|
|
49469
|
+
});
|
|
49470
|
+
}
|
|
49047
49471
|
function projectOpeningForOutput(workspace, opening) {
|
|
49048
49472
|
if (opening.kind !== "static" || !opening.beats?.length) {
|
|
49049
49473
|
return opening;
|
|
@@ -49220,6 +49644,159 @@ async function runSetPlayable(argv) {
|
|
|
49220
49644
|
printLines([`Set playable: ${value} on ${path}.`]);
|
|
49221
49645
|
return 0;
|
|
49222
49646
|
}
|
|
49647
|
+
async function runSetTransport(argv) {
|
|
49648
|
+
const args = parseCommandArgs({
|
|
49649
|
+
argv,
|
|
49650
|
+
flags: {
|
|
49651
|
+
file: { type: "string" },
|
|
49652
|
+
clear: { type: "boolean" },
|
|
49653
|
+
json: { type: "boolean" }
|
|
49654
|
+
},
|
|
49655
|
+
maxPositionals: 1
|
|
49656
|
+
});
|
|
49657
|
+
const path = args.positionals[0];
|
|
49658
|
+
const inputPath = stringFlag(args, "file");
|
|
49659
|
+
const clear = args.booleans.has("clear");
|
|
49660
|
+
const exactlyOneMode = clear ? !inputPath : Boolean(inputPath);
|
|
49661
|
+
if (!(path && exactlyOneMode)) {
|
|
49662
|
+
throw new CliError(META_USAGE, 2);
|
|
49663
|
+
}
|
|
49664
|
+
let transport = null;
|
|
49665
|
+
if (inputPath) {
|
|
49666
|
+
const parsed = LocationDesignationMetadataSchema.shape.transport.unwrap().safeParse(await readJsonFile2(inputPath));
|
|
49667
|
+
if (!parsed.success) {
|
|
49668
|
+
throw new CliError(`The transport JSON failed validation:
|
|
49669
|
+
` + parsed.error.issues.map((issue3) => ` ${issue3.path.join(".") || "(root)"}: ${issue3.message}`).join(`
|
|
49670
|
+
`), 2);
|
|
49671
|
+
}
|
|
49672
|
+
transport = parsed.data;
|
|
49673
|
+
}
|
|
49674
|
+
const workspace = await loadWorkspaceContext();
|
|
49675
|
+
const entry = resolveTrackedEntry({ ledger: workspace.ledger, input: path });
|
|
49676
|
+
const client = await workspaceClient(workspace);
|
|
49677
|
+
const result = await client.putFileTransport({
|
|
49678
|
+
fileId: entry.fileId,
|
|
49679
|
+
transport
|
|
49680
|
+
});
|
|
49681
|
+
await freshenLedgerAfterMetaWrite({
|
|
49682
|
+
root: workspace.root,
|
|
49683
|
+
ledger: workspace.ledger,
|
|
49684
|
+
fileId: entry.fileId,
|
|
49685
|
+
versionId: result.version.id
|
|
49686
|
+
});
|
|
49687
|
+
if (args.booleans.has("json")) {
|
|
49688
|
+
printJson({ path, saved: true, transport });
|
|
49689
|
+
return 0;
|
|
49690
|
+
}
|
|
49691
|
+
printLines([
|
|
49692
|
+
transport ? `Saved transport on ${path}: ${transport.kind}${transport.travels ? ` (${transport.travels})` : ""}.` : `Cleared transport on ${path}.`
|
|
49693
|
+
]);
|
|
49694
|
+
return 0;
|
|
49695
|
+
}
|
|
49696
|
+
function translatePlacePairInput({
|
|
49697
|
+
workspace,
|
|
49698
|
+
raw,
|
|
49699
|
+
aRef,
|
|
49700
|
+
bRef
|
|
49701
|
+
}) {
|
|
49702
|
+
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
|
|
49703
|
+
throw new CliError("The link JSON must be a single object.", 2);
|
|
49704
|
+
}
|
|
49705
|
+
const input = raw;
|
|
49706
|
+
const failures = [];
|
|
49707
|
+
let parentRef;
|
|
49708
|
+
if (typeof input.in === "string") {
|
|
49709
|
+
const resolution = resolveLink({
|
|
49710
|
+
ledger: workspace.ledger,
|
|
49711
|
+
link: input.in
|
|
49712
|
+
});
|
|
49713
|
+
if (resolution.status === "resolved") {
|
|
49714
|
+
parentRef = resolution.referenceId;
|
|
49715
|
+
} else {
|
|
49716
|
+
failures.push({ where: "in", link: input.in, reason: resolution.status });
|
|
49717
|
+
}
|
|
49718
|
+
}
|
|
49719
|
+
const way = input.way === undefined || input.way === null ? null : resolveExitInput({
|
|
49720
|
+
ledger: workspace.ledger,
|
|
49721
|
+
exit: input.way,
|
|
49722
|
+
where: "way",
|
|
49723
|
+
failures
|
|
49724
|
+
});
|
|
49725
|
+
if (failures.length > 0) {
|
|
49726
|
+
throw new CliError(`Nothing was saved — some links do not resolve to pushed files:
|
|
49727
|
+
` + failures.map((failure2) => ` ${failure2.where}: "${failure2.link}"` + `${failure2.reason === "unpushed" ? " (tracked but not pushed yet)" : " (no tracked file matches)"}`).join(`
|
|
49728
|
+
`), 2);
|
|
49729
|
+
}
|
|
49730
|
+
const parsedWay = way === null ? null : PairWaySchema.safeParse(way);
|
|
49731
|
+
const parsed = PlacePairSchema.safeParse({
|
|
49732
|
+
kind: input.relation,
|
|
49733
|
+
...parentRef ? { parentRef } : {},
|
|
49734
|
+
way: parsedWay?.success ? parsedWay.data : way,
|
|
49735
|
+
words: typeof input.words === "string" ? { text: input.words, first: input.wordsFirst === "other" ? "b" : "a" } : null
|
|
49736
|
+
});
|
|
49737
|
+
if (!parsed.success) {
|
|
49738
|
+
throw new CliError(`The link JSON failed validation:
|
|
49739
|
+
` + parsed.error.issues.map((issue3) => {
|
|
49740
|
+
const field = issue3.path.join(".").replace(PAIR_KIND_FIELD_RE, "relation");
|
|
49741
|
+
return ` ${field || "(root)"}: ${issue3.message}`;
|
|
49742
|
+
}).join(`
|
|
49743
|
+
`), 2);
|
|
49744
|
+
}
|
|
49745
|
+
const problem = placePairProblem({ pair: parsed.data, aRef, bRef });
|
|
49746
|
+
if (problem) {
|
|
49747
|
+
throw new CliError(problem, 2);
|
|
49748
|
+
}
|
|
49749
|
+
return parsed.data;
|
|
49750
|
+
}
|
|
49751
|
+
async function runLink(argv, mode) {
|
|
49752
|
+
const args = parseCommandArgs({
|
|
49753
|
+
argv,
|
|
49754
|
+
flags: { file: { type: "string" }, json: { type: "boolean" } },
|
|
49755
|
+
maxPositionals: 2
|
|
49756
|
+
});
|
|
49757
|
+
const [path, otherPath] = args.positionals;
|
|
49758
|
+
const inputPath = stringFlag(args, "file");
|
|
49759
|
+
if (!(path && otherPath) || mode === "link" !== Boolean(inputPath)) {
|
|
49760
|
+
throw new CliError(META_USAGE, 2);
|
|
49761
|
+
}
|
|
49762
|
+
const workspace = await loadWorkspaceContext();
|
|
49763
|
+
const entry = resolveTrackedEntry({ ledger: workspace.ledger, input: path });
|
|
49764
|
+
const other = resolveTrackedEntry({
|
|
49765
|
+
ledger: workspace.ledger,
|
|
49766
|
+
input: otherPath
|
|
49767
|
+
});
|
|
49768
|
+
const pair = inputPath ? translatePlacePairInput({
|
|
49769
|
+
workspace,
|
|
49770
|
+
raw: await readJsonFile2(inputPath),
|
|
49771
|
+
aRef: entry.referenceId,
|
|
49772
|
+
bRef: other.referenceId
|
|
49773
|
+
}) : null;
|
|
49774
|
+
const client = await workspaceClient(workspace);
|
|
49775
|
+
const { changedFileIds } = await client.putPlacePair({
|
|
49776
|
+
fileId: entry.fileId,
|
|
49777
|
+
otherFileId: other.fileId,
|
|
49778
|
+
pair
|
|
49779
|
+
});
|
|
49780
|
+
for (const fileId of changedFileIds) {
|
|
49781
|
+
const meta3 = await client.fetchFileMeta({ fileId });
|
|
49782
|
+
await freshenLedgerAfterMetaWrite({
|
|
49783
|
+
root: workspace.root,
|
|
49784
|
+
ledger: workspace.ledger,
|
|
49785
|
+
fileId,
|
|
49786
|
+
versionId: meta3.currentVersion.id
|
|
49787
|
+
});
|
|
49788
|
+
}
|
|
49789
|
+
if (args.booleans.has("json")) {
|
|
49790
|
+
printJson({ path, other: otherPath, saved: true, pair, changedFileIds });
|
|
49791
|
+
return 0;
|
|
49792
|
+
}
|
|
49793
|
+
const changed = changedFileIds.length === 0 ? "nothing changed" : `${changedFileIds.length} location${changedFileIds.length === 1 ? "" : "s"} changed`;
|
|
49794
|
+
printLines([
|
|
49795
|
+
mode === "link" ? `Linked ${path} and ${otherPath} (${pair?.kind}): ${changed}.` : `Unlinked ${path} and ${otherPath}: ${changed}.`,
|
|
49796
|
+
"See where each location now sits with `craft meta get`."
|
|
49797
|
+
]);
|
|
49798
|
+
return 0;
|
|
49799
|
+
}
|
|
49223
49800
|
|
|
49224
49801
|
// src/commands/mv.ts
|
|
49225
49802
|
import { existsSync as existsSync8 } from "node:fs";
|
|
@@ -56055,9 +56632,12 @@ var HELP_COMMAND_LINES = ` clone <projectIdOrUrl> [dir] Download a project as
|
|
|
56055
56632
|
map get|set <location-path> Read/author the interactive map stored on a
|
|
56056
56633
|
location file (see "craft help map")
|
|
56057
56634
|
meta get <path> Show a file's designation metadata (game start
|
|
56058
|
-
config, GM triggers, playable flag, map summary
|
|
56635
|
+
config, GM triggers, playable flag, map summary,
|
|
56636
|
+
a location's transport and linked locations)
|
|
56059
56637
|
meta set-game-start|set-gm-trigger|set-playable
|
|
56060
56638
|
Configure playability metadata (see "craft help meta")
|
|
56639
|
+
meta set-transport|link|unlink Make a location a ship/caravan, or link two
|
|
56640
|
+
locations (see "craft help meta")
|
|
56061
56641
|
vn list|create|pull|check|push|publish|assets
|
|
56062
56642
|
Write visual novels: pull a story to a JSON
|
|
56063
56643
|
file, edit it, push it back, publish it
|
|
@@ -56389,6 +56969,10 @@ Authoring format = the stored MapData shape with conveniences:
|
|
|
56389
56969
|
- element "id"s are minted when omitted; point style defaults are applied.
|
|
56390
56970
|
- required: "aspectRatio" matching the background image (4:3 for a default
|
|
56391
56971
|
landscape-4-3 generation). background/scale/grid default to null.
|
|
56972
|
+
- an area/point may carry "exit": a way to another location, e.g.
|
|
56973
|
+
{"kind":"stairs","to":"Places/The Inn Upstairs.location.json","direction":"up"}.
|
|
56974
|
+
"to" takes a workspace path (or slug.type / referenceId); leave it out for
|
|
56975
|
+
the way out to the parent map. \`get\` prints links and exit "to"s as paths.
|
|
56392
56976
|
|
|
56393
56977
|
The background image URL must be Craft-hosted \u2014 generate one with
|
|
56394
56978
|
\`craft image generate\` (or upload with \`craft image upload\`) and paste
|
|
@@ -56440,6 +57024,9 @@ chapters, where cutouts stand (desktop and phone), and pictures on pages.
|
|
|
56440
57024
|
craft meta set-game-start <game-start-path> --file <json>
|
|
56441
57025
|
craft meta set-gm-trigger <gm-instruction-path> (--file <json> | --clear)
|
|
56442
57026
|
craft meta set-playable <character-path> <true|false>
|
|
57027
|
+
craft meta set-transport <location-path> (--file <json> | --clear)
|
|
57028
|
+
craft meta link <location-path> <other-location-path> --file <json>
|
|
57029
|
+
craft meta unlink <location-path> <other-location-path>
|
|
56443
57030
|
|
|
56444
57031
|
Designation metadata is app-managed and lives outside the working tree;
|
|
56445
57032
|
these commands write the server directly (the target file must be pushed).
|
|
@@ -56461,6 +57048,23 @@ set-gm-trigger JSON (triggered GM rules; name \u2264120 / body \u2264500 chars):
|
|
|
56461
57048
|
|
|
56462
57049
|
Read .craft/instructions/making-it-playable.md for how these fit together.
|
|
56463
57050
|
|
|
57051
|
+
set-transport JSON (a location that carries people; its deck plan is its map):
|
|
57052
|
+
{"kind":"ship","travels":"water","speed":{"value":6,"unit":"knots"},"capacity":40}
|
|
57053
|
+
kind: ship|boat|airship|wagon|caravan|carriage|train|car|bus|plane|mount|other
|
|
57054
|
+
|
|
57055
|
+
link JSON \u2014 how <location> relates to <other>, the shape \`meta get\` prints
|
|
57056
|
+
under linkedLocations (it replaces whatever lay between the two):
|
|
57057
|
+
{"relation":"part_of","way":{"kind":"stairs","direction":"up"}}
|
|
57058
|
+
relation: same_place (both parts of "in": "<path>") | contains (other is part
|
|
57059
|
+
of location) | part_of (location is part of other) | separate (needs "way") |
|
|
57060
|
+
other (needs "words": "is the Shadowfell reflection of", "wordsFirst":
|
|
57061
|
+
"location"|"other"). way: {kind, direction from location, oneWay:
|
|
57062
|
+
"there"|"back", locked, hidden, when, requires, label, distance, time}.
|
|
57063
|
+
A location is inside at most one place and never inside itself; linking can
|
|
57064
|
+
move a place in or out of another. unlink removes everything between them.
|
|
57065
|
+
Read .craft/instructions/linking-locations.md for exits, transports and
|
|
57066
|
+
linked locations.
|
|
57067
|
+
|
|
56464
57068
|
upload: send a local image file (max 10MB; 50 per 24h, 1,000 per 24h for
|
|
56465
57069
|
subscribers) to the project's media
|
|
56466
57070
|
storage; the server re-encodes it to webp and returns the same pasteable
|
package/package.json
CHANGED