@scm-js/plugin-api 1.3.0 → 1.5.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.
Files changed (2) hide show
  1. package/index.d.ts +445 -4
  2. package/package.json +1 -1
package/index.d.ts CHANGED
@@ -271,6 +271,225 @@ export interface TriggerRecord {
271
271
  /** The game's bookkeeping byte (offset 2399); StarEdit writes 0. */
272
272
  currentAction: number;
273
273
  }
274
+ declare const ConditionType: {
275
+ readonly None: 0;
276
+ readonly CountdownTimer: 1;
277
+ readonly Command: 2;
278
+ readonly Bring: 3;
279
+ readonly Accumulate: 4;
280
+ readonly Kill: 5;
281
+ readonly CommandTheMost: 6;
282
+ readonly CommandTheMostAt: 7;
283
+ readonly MostKills: 8;
284
+ readonly HighestScore: 9;
285
+ readonly MostResources: 10;
286
+ readonly Switch: 11;
287
+ readonly ElapsedTime: 12;
288
+ readonly Briefing: 13;
289
+ readonly Opponents: 14;
290
+ readonly Deaths: 15;
291
+ readonly CommandTheLeast: 16;
292
+ readonly CommandTheLeastAt: 17;
293
+ readonly LeastKills: 18;
294
+ readonly LowestScore: 19;
295
+ readonly LeastResources: 20;
296
+ readonly Score: 21;
297
+ readonly Always: 22;
298
+ readonly Never: 23;
299
+ };
300
+ declare const ActionType: {
301
+ readonly None: 0;
302
+ readonly Victory: 1;
303
+ readonly Defeat: 2;
304
+ readonly PreserveTrigger: 3;
305
+ readonly Wait: 4;
306
+ readonly PauseGame: 5;
307
+ readonly UnpauseGame: 6;
308
+ readonly Transmission: 7;
309
+ readonly PlayWav: 8;
310
+ readonly DisplayText: 9;
311
+ readonly CenterView: 10;
312
+ readonly CreateUnitWithProperties: 11;
313
+ readonly SetMissionObjectives: 12;
314
+ readonly SetSwitch: 13;
315
+ readonly SetCountdownTimer: 14;
316
+ readonly RunAiScript: 15;
317
+ readonly RunAiScriptAt: 16;
318
+ readonly LeaderboardControl: 17;
319
+ readonly LeaderboardControlAt: 18;
320
+ readonly LeaderboardResources: 19;
321
+ readonly LeaderboardKills: 20;
322
+ readonly LeaderboardPoints: 21;
323
+ readonly KillUnit: 22;
324
+ readonly KillUnitAt: 23;
325
+ readonly RemoveUnit: 24;
326
+ readonly RemoveUnitAt: 25;
327
+ readonly SetResources: 26;
328
+ readonly SetScore: 27;
329
+ readonly MinimapPing: 28;
330
+ readonly TalkingPortrait: 29;
331
+ readonly MuteUnitSpeech: 30;
332
+ readonly UnmuteUnitSpeech: 31;
333
+ readonly LeaderboardComputerPlayers: 32;
334
+ readonly LeaderboardGoalControl: 33;
335
+ readonly LeaderboardGoalControlAt: 34;
336
+ readonly LeaderboardGoalResources: 35;
337
+ readonly LeaderboardGoalKills: 36;
338
+ readonly LeaderboardGoalPoints: 37;
339
+ readonly MoveLocation: 38;
340
+ readonly MoveUnit: 39;
341
+ readonly LeaderboardGreed: 40;
342
+ readonly SetNextScenario: 41;
343
+ readonly SetDoodadState: 42;
344
+ readonly SetInvincibility: 43;
345
+ readonly CreateUnit: 44;
346
+ readonly SetDeaths: 45;
347
+ readonly Order: 46;
348
+ readonly Comment: 47;
349
+ readonly GiveUnits: 48;
350
+ readonly ModifyHitPoints: 49;
351
+ readonly ModifyEnergy: 50;
352
+ readonly ModifyShields: 51;
353
+ readonly ModifyResourceAmount: 52;
354
+ readonly ModifyHangarCount: 53;
355
+ readonly PauseTimer: 54;
356
+ readonly UnpauseTimer: 55;
357
+ readonly Draw: 56;
358
+ readonly SetAllianceStatus: 57;
359
+ readonly DisableDebugMode: 58;
360
+ readonly EnableDebugMode: 59;
361
+ };
362
+ declare const BriefingActionType: {
363
+ readonly None: 0;
364
+ readonly Wait: 1;
365
+ readonly PlayWav: 2;
366
+ readonly TextMessage: 3;
367
+ readonly MissionObjectives: 4;
368
+ readonly ShowPortrait: 5;
369
+ readonly HidePortrait: 6;
370
+ readonly DisplaySpeakingPortrait: 7;
371
+ readonly Transmission: 8;
372
+ readonly SkipTutorialEnabled: 9;
373
+ };
374
+ declare const PlayerGroup: {
375
+ readonly Player1: 0;
376
+ readonly Player2: 1;
377
+ readonly Player3: 2;
378
+ readonly Player4: 3;
379
+ readonly Player5: 4;
380
+ readonly Player6: 5;
381
+ readonly Player7: 6;
382
+ readonly Player8: 7;
383
+ readonly Player9: 8;
384
+ readonly Player10: 9;
385
+ readonly Player11: 10;
386
+ readonly Player12: 11;
387
+ readonly None: 12;
388
+ readonly CurrentPlayer: 13;
389
+ readonly Foes: 14;
390
+ readonly Allies: 15;
391
+ readonly NeutralPlayers: 16;
392
+ readonly AllPlayers: 17;
393
+ readonly Force1: 18;
394
+ readonly Force2: 19;
395
+ readonly Force3: 20;
396
+ readonly Force4: 21;
397
+ readonly Unused1: 22;
398
+ readonly Unused2: 23;
399
+ readonly Unused3: 24;
400
+ readonly Unused4: 25;
401
+ readonly NonAlliedVictoryPlayers: 26;
402
+ };
403
+ declare const Comparison: {
404
+ readonly AtLeast: 0;
405
+ readonly AtMost: 1;
406
+ readonly Exactly: 10;
407
+ };
408
+ declare const SwitchState: {
409
+ readonly Set: 2;
410
+ readonly Cleared: 3;
411
+ };
412
+ declare const SwitchAction: {
413
+ readonly Set: 4;
414
+ readonly Clear: 5;
415
+ readonly Toggle: 6;
416
+ readonly Randomize: 11;
417
+ };
418
+ declare const SetModifier: {
419
+ readonly SetTo: 7;
420
+ readonly Add: 8;
421
+ readonly Subtract: 9;
422
+ };
423
+ declare const UnitState: {
424
+ readonly Enable: 4;
425
+ readonly Disable: 5;
426
+ readonly Toggle: 6;
427
+ };
428
+ declare const Order: {
429
+ readonly Move: 0;
430
+ readonly Patrol: 1;
431
+ readonly Attack: 2;
432
+ };
433
+ declare const AllianceStatus: {
434
+ readonly Enemy: 0;
435
+ readonly Ally: 1;
436
+ readonly AlliedVictory: 2;
437
+ };
438
+ declare const ResourceType: {
439
+ readonly Ore: 0;
440
+ readonly Gas: 1;
441
+ readonly OreAndGas: 2;
442
+ };
443
+ declare const ScoreType: {
444
+ readonly Total: 0;
445
+ readonly Units: 1;
446
+ readonly Buildings: 2;
447
+ readonly UnitsAndBuildings: 3;
448
+ readonly Kills: 4;
449
+ readonly Razings: 5;
450
+ readonly KillsAndRazings: 6;
451
+ readonly Custom: 7;
452
+ };
453
+ declare const UnitClass: {
454
+ readonly Any: 228;
455
+ readonly Men: 229;
456
+ readonly Buildings: 230;
457
+ readonly Factories: 231;
458
+ };
459
+ declare const ConditionFlag: {
460
+ /** Game bookkeeping. */
461
+ readonly Unknown: 1;
462
+ readonly Disabled: 2;
463
+ readonly AlwaysDisplay: 4;
464
+ readonly UnitPropertiesUsed: 8;
465
+ readonly UnitTypeUsed: 16;
466
+ readonly UnitIdUsed: 32;
467
+ };
468
+ declare const ActionFlag: {
469
+ /** Ignore a Wait / Transmission once (game bookkeeping). */
470
+ readonly IgnoreWaitOnce: 1;
471
+ readonly Disabled: 2;
472
+ readonly AlwaysDisplay: 4;
473
+ readonly UnitPropertiesUsed: 8;
474
+ readonly UnitTypeUsed: 16;
475
+ readonly UnitIdUsed: 32;
476
+ };
477
+ declare const TriggerFlag: {
478
+ /** Game bookkeeping: every condition was met this cycle. */
479
+ readonly ConditionsMet: 1;
480
+ /** Ignore Defeat / Draw for this trigger. */
481
+ readonly IgnoreGameEnd: 2;
482
+ /** Same as a Preserve Trigger action. */
483
+ readonly Preserve: 4;
484
+ /** The trigger never runs. */
485
+ readonly Disabled: 8;
486
+ /** Skip Wait / text / view actions for the rest of this loop (game bookkeeping). */
487
+ readonly IgnoreDisplay: 16;
488
+ /** Game bookkeeping. */
489
+ readonly Paused: 32;
490
+ /** Game bookkeeping. */
491
+ readonly WaitSkipDisabled: 64;
492
+ };
274
493
  /**
275
494
  * A parsed scenario.
276
495
  *
@@ -683,6 +902,8 @@ export interface ImagesDat {
683
902
  lo: Uint32Array[];
684
903
  }
685
904
  export interface WeaponsDat {
905
+ /** The weapon's name: a 1-based `stat_txt.tbl` index, 0 for none. */
906
+ label: Uint16Array;
686
907
  damage: Uint16Array;
687
908
  /** Added per upgrade level. */
688
909
  bonus: Uint16Array;
@@ -701,6 +922,8 @@ export interface UpgradesDat {
701
922
  maxRepeats: Uint8Array;
702
923
  /** 1 for upgrades only Brood War has. */
703
924
  broodWar: Uint8Array;
925
+ /** The upgrade's name: a 1-based `stat_txt.tbl` index, 0 for none. */
926
+ label: Uint16Array;
704
927
  }
705
928
  /** The columns Technology Settings shows as defaults. */
706
929
  export interface TechdataDat {
@@ -711,6 +934,8 @@ export interface TechdataDat {
711
934
  energyCost: Uint16Array;
712
935
  /** 1 for abilities only Brood War has. */
713
936
  broodWar: Uint8Array;
937
+ /** The technology's name: a 1-based `stat_txt.tbl` index, 0 for none. */
938
+ label: Uint16Array;
714
939
  }
715
940
  export interface SpriteGroup {
716
941
  label: string;
@@ -1659,33 +1884,62 @@ export interface PluginInfo {
1659
1884
  export interface PluginApi {
1660
1885
  readonly apiVersion: number;
1661
1886
  readonly plugin: PluginInfo;
1887
+ /**
1888
+ * The open map: what it says, and the three ways of writing to it — `edit` (terrain and
1889
+ * objects, one undo entry), `update` (the tables every dialog's OK writes) and
1890
+ * `sections` (raw bytes). Opening, saving, exporting and closing are here too.
1891
+ */
1662
1892
  readonly document: DocumentApi;
1663
1893
  /** The settings dialogs' tables, read-only; `document.update` writes them. */
1664
1894
  readonly settings: SettingsApi;
1665
1895
  readonly triggers: TriggersApi;
1896
+ /**
1897
+ * Reading the terrain: the tileset's paintable types, the ISOM lattice, flood regions,
1898
+ * blend candidates and the symmetry mode. Painting goes through `document.edit`.
1899
+ */
1666
1900
  readonly terrain: TerrainApi;
1901
+ /** The loaded tileset graphics: whether they are there, and the decoded files behind them. */
1667
1902
  readonly tileset: TilesetApi;
1903
+ /** What is selected on each object layer, the marked area, the active layer and the locked ones. */
1668
1904
  readonly selection: SelectionApi;
1669
1905
  /** Cut / Copy / Paste: the clip, its parts, and pasting — what the clipboard layer does. */
1670
1906
  readonly clipboard: ClipboardApi;
1671
1907
  /** The file formats behind File ▸ Import / Export: `.trg` and the strings text. */
1672
1908
  readonly exchange: ExchangeApi;
1909
+ /**
1910
+ * The palettes' current picks — the terrain brush, the unit, sprite and doodad, the fog
1911
+ * mode — and the placement options a plugin that places things should honour.
1912
+ */
1673
1913
  readonly palette: PaletteApi;
1674
1914
  readonly names: NamesApi;
1675
1915
  /** StarCraft's `<XX>` text control codes: what they mean, and what a string looks like drawn. */
1676
1916
  readonly text: TextApi;
1677
1917
  readonly query: QueryApi;
1678
1918
  readonly data: DataApi;
1919
+ /** Which set of game files the editor draws from — the game's own or a mod's — and installing, switching and removing sets. */
1920
+ readonly gameData: GameDataApi;
1679
1921
  /** Bit masks, special unit ids and the pixels-per-tile every record is written in. */
1680
1922
  readonly consts: ConstsApi;
1681
1923
  readonly graphics: GraphicsApi;
1682
1924
  readonly view: ViewApi;
1925
+ /**
1926
+ * Everything a plugin puts on the screen: the status line, toasts, dialogs, floating
1927
+ * panels, `confirm` / `alert` / `prompt` / `progress`, a map tool that owns the pointer,
1928
+ * a passive overlay drawn over the map, and picking an area or a tile.
1929
+ */
1683
1930
  readonly ui: UiApi;
1931
+ /** Items in the editor's menu bar. A path whose last segment names no submenu makes one. */
1684
1932
  readonly menu: MenuApi;
1933
+ /** Items in the right-click menus of the map and the terrain palette. */
1685
1934
  readonly contextMenu: ContextMenuApi;
1935
+ /** Key combinations, tried before the editor's own and never while a text field has focus. */
1686
1936
  readonly hotkeys: HotkeyApi;
1687
1937
  readonly commands: CommandsApi;
1688
1938
  readonly events: EventsApi;
1939
+ /**
1940
+ * A small key-value store of the plugin's own, kept in the browser's local storage under
1941
+ * the plugin's id and listed with everything else in Preferences ▸ Browser storage.
1942
+ */
1689
1943
  readonly storage: StorageApi;
1690
1944
  /** `console.log` with the plugin's name in front. */
1691
1945
  log(...args: unknown[]): void;
@@ -1804,6 +2058,14 @@ export interface DocumentApi {
1804
2058
  *
1805
2059
  * `build` is synchronous — see `Sync`. Await what you need (graphics, a pick, a
1806
2060
  * fetch) before the call, then write in one go.
2061
+ *
2062
+ * @example
2063
+ * // One undo entry called "Fill", however many operations it takes.
2064
+ * const result = api.document.edit("Fill", (tx) => {
2065
+ * tx.stampTerrain({ x0: 0, y0: 0, x1: 8, y1: 8 }, terrainId);
2066
+ * tx.placeUnit(api.consts.unit.startLocation, 0, 4 * api.consts.tile, 4 * api.consts.tile);
2067
+ * });
2068
+ * api.ui.status(`${result.tiles} tiles, ${result.units} units`);
1807
2069
  */
1808
2070
  edit<R>(label: string, build: (tx: EditTransaction) => Sync<R>): EditResult;
1809
2071
  /**
@@ -1813,6 +2075,11 @@ export interface DocumentApi {
1813
2075
  * Operations apply as they are called; the commit marks the map modified and bumps
1814
2076
  * what the chrome reads. There is no undo entry: keep your own if you need one.
1815
2077
  * `build` is synchronous, as `edit`'s is.
2078
+ *
2079
+ * @example
2080
+ * api.document.update("Rename", (tx) => {
2081
+ * tx.properties({ name: "Lost Temple", description: "Four players." });
2082
+ * });
1816
2083
  */
1817
2084
  update<R>(label: string, build: (tx: UpdateTransaction) => Sync<R>): UpdateResult;
1818
2085
  undo(): string | null;
@@ -2585,10 +2852,94 @@ export interface DataApi {
2585
2852
  /** The GRP path an image id draws from, relative to `unit\`. */
2586
2853
  imagePath(imageId: number): string | null;
2587
2854
  }
2855
+ /**
2856
+ * A data set: one set of game files the editor draws from. The default is the game's
2857
+ * own; any other is a mod's, installed under an id of its own, the same formats and
2858
+ * table sizes with some of the files replaced.
2859
+ */
2860
+ export interface GameDataProfile {
2861
+ /** Lower-case letters, digits and hyphens, up to 40 characters. */
2862
+ id: string;
2863
+ /** What the dialog and the status line call it. */
2864
+ name: string;
2865
+ }
2866
+ /** Where the session's game data comes from. */
2867
+ export interface GameDataSource {
2868
+ /** `bundled` (this build's own files, or the desktop app's extraction), `stored` (a copy kept in the browser), or `none`. */
2869
+ kind: "bundled" | "stored" | "none";
2870
+ /** One line, as Help ▸ Game Data… shows it. */
2871
+ label: string;
2872
+ /** The data set the files belong to. */
2873
+ profile: GameDataProfile;
2874
+ /** Set when the desktop app extracted the files from a StarCraft installation. */
2875
+ desktop: boolean;
2876
+ }
2877
+ /** Bytes for an install: a `File` / `Blob`, or already an array. */
2878
+ export type GameDataBytes = Blob | Uint8Array;
2879
+ /** What a data set is installed from. */
2880
+ export interface GameDataFiles {
2881
+ /**
2882
+ * The archives, `StarDat.mpq` and `BrooDat.mpq` among them — a mod replaces files, it
2883
+ * does not bring the rest. The game's own are read first, then the others in the order
2884
+ * given, later ones winning as in the game.
2885
+ */
2886
+ archives: readonly {
2887
+ name: string;
2888
+ data: GameDataBytes;
2889
+ }[];
2890
+ /** Loose files by member path (`arr/units.dat`, `unit/terran/marine.grp`), read before any archive. */
2891
+ files?: readonly {
2892
+ path: string;
2893
+ data: GameDataBytes;
2894
+ }[];
2895
+ }
2896
+ /**
2897
+ * The game data as a whole: which set of files the editor draws from, and installing,
2898
+ * switching and removing sets — the plugin side of Help ▸ Game Data…. What is *in* the
2899
+ * files is `data` (the tables), `tileset` (the graphics), `graphics` (the pictures) and
2900
+ * `names` (the labels, which follow the loaded set: a unit, weapon, upgrade or
2901
+ * technology a mod renamed shows its new name, and the rest keep StarEdit's).
2902
+ *
2903
+ * A data set is a name over files in the game's own formats; a mod that extends the
2904
+ * tables past the game's sizes is not covered. Installing needs the game's two archives
2905
+ * every time, since a mod's files are laid over them the way its loader lays them.
2906
+ *
2907
+ * @example
2908
+ * // A mod plugin: install its files once, then draw with them.
2909
+ * const sets = await api.gameData.profiles();
2910
+ * if (!sets.some((p) => p.id === "my-mod")) {
2911
+ * const files = await api.ui.pickFiles({ multiple: true });
2912
+ * if (files) await api.gameData.install({ id: "my-mod", name: "My Mod" }, { archives: files.map((f) => ({ name: f.name, data: f })) });
2913
+ * }
2914
+ * await api.gameData.select("my-mod");
2915
+ */
2916
+ export interface GameDataApi {
2917
+ /** The session's source, or null while it is still being resolved at startup. */
2918
+ source(): GameDataSource | null;
2919
+ /** The data set in use — the game's own until another is selected. */
2920
+ profile(): GameDataProfile;
2921
+ /** Every data set with a copy here, the game's own first. */
2922
+ profiles(): Promise<GameDataProfile[]>;
2923
+ /**
2924
+ * Extract a data set from its files, store it under `profile.id` and switch to it. The
2925
+ * archives must include the game's own two; the promise rejects with the reason when
2926
+ * they do not or the extraction fails. `progress` is 0–1 with a label, as the dialog's bar.
2927
+ */
2928
+ install(profile: GameDataProfile, files: GameDataFiles, progress?: (fraction: number, label: string) => void): Promise<GameDataSource>;
2929
+ /**
2930
+ * Switch to a data set. Everything decoded from the previous one is dropped and the
2931
+ * viewport redraws from the new files; a set with no copy here falls back to the game's
2932
+ * own. Resolves with the source in use afterwards.
2933
+ */
2934
+ select(id: string): Promise<GameDataSource>;
2935
+ /** Remove a data set's copy (never the game's bundled files). True when there was one. */
2936
+ remove(id: string): Promise<boolean>;
2937
+ }
2588
2938
  /**
2589
2939
  * The constants a plugin needs to *write* a record rather than read one: the bit masks in
2590
- * a UNIT / THG2 / MRGN record, the few unit ids the game itself treats specially, and the
2591
- * one conversion — 32 pixels to a tile — every object position goes through.
2940
+ * a UNIT / THG2 / MRGN record, the condition, action and argument numbers of a TRIG /
2941
+ * MBRF one, the few unit ids the game itself treats specially, and the one conversion —
2942
+ * 32 pixels to a tile — every object position goes through.
2592
2943
  *
2593
2944
  * They are the editor's own (`sections/objects.ts`, `editor/units.ts`) and they arrive
2594
2945
  * here at run time rather than in the typings on purpose: `@scm-js/plugin-api` is erased
@@ -2600,9 +2951,14 @@ export interface DataApi {
2600
2951
  export interface ConstsApi {
2601
2952
  /** Map pixels to a tile. UNIT and THG2 store pixels; MTXM, MRGN and the brushes count tiles. */
2602
2953
  readonly tile: 32;
2954
+ /** UNIT: the special unit ids, the default resource amounts, and the record's four bit masks. */
2603
2955
  readonly unit: UnitConsts;
2956
+ /** THG2: the sprite record's flag word. */
2604
2957
  readonly sprite: SpriteConsts;
2958
+ /** MRGN: the Anywhere slot, and the elevation bits. */
2605
2959
  readonly location: LocationConsts;
2960
+ /** TRIG / MBRF: the condition and action types, and the enumerated arguments. */
2961
+ readonly triggers: TriggerConsts;
2606
2962
  /** Whether a unit type is a mineral field or a vespene geyser. */
2607
2963
  isResource(unitId: number): boolean;
2608
2964
  }
@@ -2680,6 +3036,56 @@ export interface LocationConsts {
2680
3036
  readonly HighAir: 32;
2681
3037
  };
2682
3038
  }
3039
+ /**
3040
+ * The numbers a TRIG / MBRF record is written in: the condition and action types, and the
3041
+ * enumerated arguments the game stores as bare bytes.
3042
+ *
3043
+ * A trigger record is sixteen conditions and sixty-four actions of plain numbers — the
3044
+ * codec knows no types — so writing one field by field means knowing that a Countdown
3045
+ * Timer condition is type 1 and `AtLeast` is 0. `triggers.defs` says which *field* an
3046
+ * argument lives in; this says what to put in it.
3047
+ *
3048
+ * The keys of the argument groups are `ArgDef.kind`, so a generic argument editor can
3049
+ * look one up by the kind the def gave it (`api.consts.triggers[arg.kind]`).
3050
+ *
3051
+ * Generating a whole run of triggers is usually better done through
3052
+ * `tx.triggers.fromText`, which resolves names against the open map; these are for
3053
+ * editing a field of an existing record, and for reading one back.
3054
+ */
3055
+ export interface TriggerConsts {
3056
+ /** Condition `type`. */
3057
+ readonly condition: typeof ConditionType;
3058
+ /** Action `type` in TRIG. */
3059
+ readonly action: typeof ActionType;
3060
+ /** Action `type` in MBRF, where the same byte means something else. */
3061
+ readonly briefingAction: typeof BriefingActionType;
3062
+ /** The 27 player-group values, which are also the indices of a trigger's `players`. */
3063
+ readonly player: typeof PlayerGroup;
3064
+ readonly comparison: typeof Comparison;
3065
+ readonly switchState: typeof SwitchState;
3066
+ readonly switchAction: typeof SwitchAction;
3067
+ /** Set Resources / Set Score / Modify …: `SetTo`, `Add`, `Subtract`. */
3068
+ readonly modifier: typeof SetModifier;
3069
+ /** Set Doodad State / Set Invincibility: `Enable`, `Disable`, `Toggle`. */
3070
+ readonly unitState: typeof UnitState;
3071
+ readonly order: typeof Order;
3072
+ readonly alliance: typeof AllianceStatus;
3073
+ readonly resource: typeof ResourceType;
3074
+ readonly score: typeof ScoreType;
3075
+ /** The unit ids past units.dat that a condition or action accepts: *Any unit*, *Men*, *Buildings*, *Factories*. */
3076
+ readonly unitClass: typeof UnitClass;
3077
+ /** A condition's `flags`. `UnitTypeUsed` is the hint bit the text format cannot carry. */
3078
+ readonly conditionFlags: typeof ConditionFlag;
3079
+ /** An action's `flags`. */
3080
+ readonly actionFlags: typeof ActionFlag;
3081
+ /** A trigger's `flags`; `Preserve` is what `triggers.isPreserved` reads. */
3082
+ readonly triggerFlags: typeof TriggerFlag;
3083
+ /**
3084
+ * The address of the game's death table, which is the base an EUD player value is
3085
+ * counted from: `epd = (address - deathsTable) / 4 + 0x2000`.
3086
+ */
3087
+ readonly deathsTable: number;
3088
+ }
2683
3089
  export interface ActiveBrush {
2684
3090
  mode: TerrainMode;
2685
3091
  /** The Rect / isometric brush's terrain id. */
@@ -3422,6 +3828,20 @@ export interface MenuItemSpec {
3422
3828
  command?: string;
3423
3829
  }
3424
3830
  export interface MenuApi {
3831
+ /**
3832
+ * Items in the editor's menu bar.
3833
+ *
3834
+ * @example
3835
+ * api.menu.add("Tools", {
3836
+ * label: "Count units\u2026",
3837
+ * icon: "plugin",
3838
+ * run: () => api.ui.alert(`Player 1 has ${api.query.unitsOf(0).length} units.`),
3839
+ * });
3840
+ *
3841
+ * @example
3842
+ * // A path whose last segment names no submenu makes one, at the end of that menu.
3843
+ * api.menu.add("Tools/My plugin", { label: "Settings\u2026", command: "settings" });
3844
+ */
3425
3845
  add(path: MenuPath, item: MenuItemSpec): Disposable;
3426
3846
  }
3427
3847
  export type ContextSurface = "viewport" | "terrainPalette";
@@ -3455,7 +3875,10 @@ export interface ContextMenuApi {
3455
3875
  add(surface: ContextSurface, item: ContextItemSpec): Disposable;
3456
3876
  }
3457
3877
  export interface HotkeyApi {
3458
- /** `"Ctrl+Shift+I"`, `"Alt+F9"`, `"F8"` — modifiers in any order, then a key name. */
3878
+ /** `"Ctrl+Shift+I"`, `"Alt+F9"`, `"F8"` — modifiers in any order, then a key name. *
3879
+ * @example
3880
+ * api.hotkeys.add("Ctrl+Shift+W", () => handle.setVisible(!handle.visible()));
3881
+ */
3459
3882
  add(combo: string, run: (() => void) | {
3460
3883
  command: string;
3461
3884
  }): Disposable;
@@ -3482,7 +3905,9 @@ export type PluginEvent =
3482
3905
  /** The document's file changed: its name or handle after a Save, the save options, the archive extras, the recent list. */
3483
3906
  | "file"
3484
3907
  /** A plugin registered or removed a command — how a plugin learns that one it calls by id has arrived. */
3485
- | "commands";
3908
+ | "commands"
3909
+ /** The game data source changed: installed, switched to another data set, or a copy removed. `gameData.source()` says what it is now. */
3910
+ | "gameData";
3486
3911
  /** Why the document changed. */
3487
3912
  export type DocumentChangeReason =
3488
3913
  /** File ▸ Open, drag-and-drop, `document.open`: a file the user chose. */
@@ -3504,10 +3929,26 @@ export interface DocumentEvent {
3504
3929
  * reason `"replace"`, which every other listener sees in turn.
3505
3930
  */
3506
3931
  export interface EventsApi {
3932
+ /**
3933
+ * @example
3934
+ * // Notifications, in activation order; a listener never intercepts what it hears.
3935
+ * api.events.on("document", (e) => {
3936
+ * if (e.reason === "open") check(e.fileName);
3937
+ * });
3938
+ * api.events.on("terrain", () => redraw());
3939
+ */
3507
3940
  on(event: "document", listener: (event: DocumentEvent) => void): Disposable;
3508
3941
  on(event: PluginEvent, listener: () => void): Disposable;
3509
3942
  }
3510
3943
  export interface StorageApi {
3944
+ /**
3945
+ * A small key-value store of the plugin's own, under its id in the browser's local
3946
+ * storage and listed in Preferences \u25b8 Browser storage.
3947
+ *
3948
+ * @example
3949
+ * const opts = api.storage.get("options", { showGrid: true });
3950
+ * api.storage.set("options", { ...opts, showGrid: false });
3951
+ */
3511
3952
  get<T>(key: string, fallback: T): T;
3512
3953
  set(key: string, value: unknown): void;
3513
3954
  remove(key: string): void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scm-js/plugin-api",
3
- "version": "1.3.0",
3
+ "version": "1.5.0",
4
4
  "description": "Type declarations for the scmJS plugin API",
5
5
  "license": "MIT",
6
6
  "types": "index.d.ts",