@scm-js/plugin-api 1.4.0 → 1.6.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/index.d.ts +221 -3
- package/package.json +1 -1
package/index.d.ts
CHANGED
|
@@ -902,6 +902,8 @@ export interface ImagesDat {
|
|
|
902
902
|
lo: Uint32Array[];
|
|
903
903
|
}
|
|
904
904
|
export interface WeaponsDat {
|
|
905
|
+
/** The weapon's name: a 1-based `stat_txt.tbl` index, 0 for none. */
|
|
906
|
+
label: Uint16Array;
|
|
905
907
|
damage: Uint16Array;
|
|
906
908
|
/** Added per upgrade level. */
|
|
907
909
|
bonus: Uint16Array;
|
|
@@ -920,6 +922,8 @@ export interface UpgradesDat {
|
|
|
920
922
|
maxRepeats: Uint8Array;
|
|
921
923
|
/** 1 for upgrades only Brood War has. */
|
|
922
924
|
broodWar: Uint8Array;
|
|
925
|
+
/** The upgrade's name: a 1-based `stat_txt.tbl` index, 0 for none. */
|
|
926
|
+
label: Uint16Array;
|
|
923
927
|
}
|
|
924
928
|
/** The columns Technology Settings shows as defaults. */
|
|
925
929
|
export interface TechdataDat {
|
|
@@ -930,6 +934,8 @@ export interface TechdataDat {
|
|
|
930
934
|
energyCost: Uint16Array;
|
|
931
935
|
/** 1 for abilities only Brood War has. */
|
|
932
936
|
broodWar: Uint8Array;
|
|
937
|
+
/** The technology's name: a 1-based `stat_txt.tbl` index, 0 for none. */
|
|
938
|
+
label: Uint16Array;
|
|
933
939
|
}
|
|
934
940
|
export interface SpriteGroup {
|
|
935
941
|
label: string;
|
|
@@ -1910,6 +1916,8 @@ export interface PluginApi {
|
|
|
1910
1916
|
readonly text: TextApi;
|
|
1911
1917
|
readonly query: QueryApi;
|
|
1912
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;
|
|
1913
1921
|
/** Bit masks, special unit ids and the pixels-per-tile every record is written in. */
|
|
1914
1922
|
readonly consts: ConstsApi;
|
|
1915
1923
|
readonly graphics: GraphicsApi;
|
|
@@ -2737,6 +2745,16 @@ export interface ViewApi {
|
|
|
2737
2745
|
/** Grid spacing in map pixels (32 = one tile). */
|
|
2738
2746
|
gridSize(): number;
|
|
2739
2747
|
setGridSize(size: 8 | 16 | 32 | 64 | 128): void;
|
|
2748
|
+
/**
|
|
2749
|
+
* Highlight something on the map for a moment: the rect an edit filled, the units it
|
|
2750
|
+
* placed, the location it moved. Fades by itself; several may run at once. Nothing to
|
|
2751
|
+
* clean up.
|
|
2752
|
+
*
|
|
2753
|
+
* @example
|
|
2754
|
+
* const r = api.document.edit("Fill", (tx) => tx.fillFlat(rect, terrain));
|
|
2755
|
+
* if (r.changed) api.view.flash({ rect });
|
|
2756
|
+
*/
|
|
2757
|
+
flash(target: FlashTarget): void;
|
|
2740
2758
|
}
|
|
2741
2759
|
export interface CommandSpec {
|
|
2742
2760
|
/**
|
|
@@ -2844,6 +2862,89 @@ export interface DataApi {
|
|
|
2844
2862
|
/** The GRP path an image id draws from, relative to `unit\`. */
|
|
2845
2863
|
imagePath(imageId: number): string | null;
|
|
2846
2864
|
}
|
|
2865
|
+
/**
|
|
2866
|
+
* A data set: one set of game files the editor draws from. The default is the game's
|
|
2867
|
+
* own; any other is a mod's, installed under an id of its own, the same formats and
|
|
2868
|
+
* table sizes with some of the files replaced.
|
|
2869
|
+
*/
|
|
2870
|
+
export interface GameDataProfile {
|
|
2871
|
+
/** Lower-case letters, digits and hyphens, up to 40 characters. */
|
|
2872
|
+
id: string;
|
|
2873
|
+
/** What the dialog and the status line call it. */
|
|
2874
|
+
name: string;
|
|
2875
|
+
}
|
|
2876
|
+
/** Where the session's game data comes from. */
|
|
2877
|
+
export interface GameDataSource {
|
|
2878
|
+
/** `bundled` (this build's own files, or the desktop app's extraction), `stored` (a copy kept in the browser), or `none`. */
|
|
2879
|
+
kind: "bundled" | "stored" | "none";
|
|
2880
|
+
/** One line, as Help ▸ Game Data… shows it. */
|
|
2881
|
+
label: string;
|
|
2882
|
+
/** The data set the files belong to. */
|
|
2883
|
+
profile: GameDataProfile;
|
|
2884
|
+
/** Set when the desktop app extracted the files from a StarCraft installation. */
|
|
2885
|
+
desktop: boolean;
|
|
2886
|
+
}
|
|
2887
|
+
/** Bytes for an install: a `File` / `Blob`, or already an array. */
|
|
2888
|
+
export type GameDataBytes = Blob | Uint8Array;
|
|
2889
|
+
/** What a data set is installed from. */
|
|
2890
|
+
export interface GameDataFiles {
|
|
2891
|
+
/**
|
|
2892
|
+
* The archives, `StarDat.mpq` and `BrooDat.mpq` among them — a mod replaces files, it
|
|
2893
|
+
* does not bring the rest. The game's own are read first, then the others in the order
|
|
2894
|
+
* given, later ones winning as in the game.
|
|
2895
|
+
*/
|
|
2896
|
+
archives: readonly {
|
|
2897
|
+
name: string;
|
|
2898
|
+
data: GameDataBytes;
|
|
2899
|
+
}[];
|
|
2900
|
+
/** Loose files by member path (`arr/units.dat`, `unit/terran/marine.grp`), read before any archive. */
|
|
2901
|
+
files?: readonly {
|
|
2902
|
+
path: string;
|
|
2903
|
+
data: GameDataBytes;
|
|
2904
|
+
}[];
|
|
2905
|
+
}
|
|
2906
|
+
/**
|
|
2907
|
+
* The game data as a whole: which set of files the editor draws from, and installing,
|
|
2908
|
+
* switching and removing sets — the plugin side of Help ▸ Game Data…. What is *in* the
|
|
2909
|
+
* files is `data` (the tables), `tileset` (the graphics), `graphics` (the pictures) and
|
|
2910
|
+
* `names` (the labels, which follow the loaded set: a unit, weapon, upgrade or
|
|
2911
|
+
* technology a mod renamed shows its new name, and the rest keep StarEdit's).
|
|
2912
|
+
*
|
|
2913
|
+
* A data set is a name over files in the game's own formats; a mod that extends the
|
|
2914
|
+
* tables past the game's sizes is not covered. Installing needs the game's two archives
|
|
2915
|
+
* every time, since a mod's files are laid over them the way its loader lays them.
|
|
2916
|
+
*
|
|
2917
|
+
* @example
|
|
2918
|
+
* // A mod plugin: install its files once, then draw with them.
|
|
2919
|
+
* const sets = await api.gameData.profiles();
|
|
2920
|
+
* if (!sets.some((p) => p.id === "my-mod")) {
|
|
2921
|
+
* const files = await api.ui.pickFiles({ multiple: true });
|
|
2922
|
+
* if (files) await api.gameData.install({ id: "my-mod", name: "My Mod" }, { archives: files.map((f) => ({ name: f.name, data: f })) });
|
|
2923
|
+
* }
|
|
2924
|
+
* await api.gameData.select("my-mod");
|
|
2925
|
+
*/
|
|
2926
|
+
export interface GameDataApi {
|
|
2927
|
+
/** The session's source, or null while it is still being resolved at startup. */
|
|
2928
|
+
source(): GameDataSource | null;
|
|
2929
|
+
/** The data set in use — the game's own until another is selected. */
|
|
2930
|
+
profile(): GameDataProfile;
|
|
2931
|
+
/** Every data set with a copy here, the game's own first. */
|
|
2932
|
+
profiles(): Promise<GameDataProfile[]>;
|
|
2933
|
+
/**
|
|
2934
|
+
* Extract a data set from its files, store it under `profile.id` and switch to it. The
|
|
2935
|
+
* archives must include the game's own two; the promise rejects with the reason when
|
|
2936
|
+
* they do not or the extraction fails. `progress` is 0–1 with a label, as the dialog's bar.
|
|
2937
|
+
*/
|
|
2938
|
+
install(profile: GameDataProfile, files: GameDataFiles, progress?: (fraction: number, label: string) => void): Promise<GameDataSource>;
|
|
2939
|
+
/**
|
|
2940
|
+
* Switch to a data set. Everything decoded from the previous one is dropped and the
|
|
2941
|
+
* viewport redraws from the new files; a set with no copy here falls back to the game's
|
|
2942
|
+
* own. Resolves with the source in use afterwards.
|
|
2943
|
+
*/
|
|
2944
|
+
select(id: string): Promise<GameDataSource>;
|
|
2945
|
+
/** Remove a data set's copy (never the game's bundled files). True when there was one. */
|
|
2946
|
+
remove(id: string): Promise<boolean>;
|
|
2947
|
+
}
|
|
2847
2948
|
/**
|
|
2848
2949
|
* The constants a plugin needs to *write* a record rather than read one: the bit masks in
|
|
2849
2950
|
* a UNIT / THG2 / MRGN record, the condition, action and argument numbers of a TRIG /
|
|
@@ -3364,8 +3465,19 @@ export interface DialogHandle {
|
|
|
3364
3465
|
*/
|
|
3365
3466
|
export interface PanelSpec {
|
|
3366
3467
|
title: string;
|
|
3367
|
-
/** In CSS pixels; 260 by default. The panel is as tall as its content, up to the map's height. */
|
|
3468
|
+
/** In CSS pixels; 260 by default. The panel is as tall as its content, up to the map's height. Ignored when docked. */
|
|
3368
3469
|
width?: number;
|
|
3470
|
+
/**
|
|
3471
|
+
* Where the panel lives. `"float"` (the default) is a frame over the map the user drags
|
|
3472
|
+
* about. `"right"` puts it in the right dock as a panel of its own, under Minimap, Layers
|
|
3473
|
+
* and Properties, with the same head and hide button the built-in panels have — the
|
|
3474
|
+
* choice for anything the user keeps open while working, such as an assistant or a
|
|
3475
|
+
* readout. A docked panel shows the dock even when the user has hidden every built-in
|
|
3476
|
+
* panel in it.
|
|
3477
|
+
*/
|
|
3478
|
+
dock?: "float" | "right";
|
|
3479
|
+
/** A docked panel that takes the dock's spare height (a transcript, a long list); off by default. */
|
|
3480
|
+
grow?: boolean;
|
|
3369
3481
|
/** Fill `body` (an empty `<div>` inside the panel); return a cleanup if you need one. */
|
|
3370
3482
|
mount(body: HTMLElement, panel: PanelHandle): void | (() => void);
|
|
3371
3483
|
/** The panel closed, whichever way. */
|
|
@@ -3376,6 +3488,85 @@ export interface PanelHandle {
|
|
|
3376
3488
|
isOpen(): boolean;
|
|
3377
3489
|
setTitle(title: string): void;
|
|
3378
3490
|
}
|
|
3491
|
+
/**
|
|
3492
|
+
* One cell in the status bar (`ui.statusItem`): a line of text with the plugin's icon,
|
|
3493
|
+
* a spinner while `busy`, and a click. It is how a plugin that works in the background
|
|
3494
|
+
* stays visible without a panel — "AI · working 12 s", "3 problems", "Synced".
|
|
3495
|
+
*/
|
|
3496
|
+
export interface StatusItemSpec {
|
|
3497
|
+
text: string;
|
|
3498
|
+
/** The tooltip. */
|
|
3499
|
+
title?: string;
|
|
3500
|
+
/** Show a spinner in the cell. */
|
|
3501
|
+
busy?: boolean;
|
|
3502
|
+
/** Paint the cell as a warning. */
|
|
3503
|
+
warn?: boolean;
|
|
3504
|
+
onClick?: () => void;
|
|
3505
|
+
}
|
|
3506
|
+
export interface StatusItemHandle {
|
|
3507
|
+
/** Change any of the fields; the cell redraws. */
|
|
3508
|
+
set(patch: Partial<StatusItemSpec>): void;
|
|
3509
|
+
remove(): void;
|
|
3510
|
+
isShown(): boolean;
|
|
3511
|
+
}
|
|
3512
|
+
/**
|
|
3513
|
+
* The dialogs a plugin may add to (`ui.dialogSlot`), and the fields each one exposes to
|
|
3514
|
+
* the slot. A field is the dialog's *working copy* — what the person sees in the form,
|
|
3515
|
+
* not yet applied to the map — so a slot's button can fill it in and leave OK to them.
|
|
3516
|
+
*
|
|
3517
|
+
* - `mapProperties`: `name`, `description`.
|
|
3518
|
+
* - `textTriggerEditor`: `text` (the whole editor); `payload.briefing` says which list.
|
|
3519
|
+
* - `triggerEditor`, `stringEditor`, `playerSettings`, `missionBriefing`: no fields, a slot only.
|
|
3520
|
+
*/
|
|
3521
|
+
export type SlottedDialogId = "mapProperties" | "textTriggerEditor" | "triggerEditor" | "stringEditor" | "playerSettings" | "missionBriefing";
|
|
3522
|
+
/** A form field a dialog lends to a slot: read it, set it, hear it change. */
|
|
3523
|
+
export interface DialogField {
|
|
3524
|
+
get(): string;
|
|
3525
|
+
set(value: string): void;
|
|
3526
|
+
}
|
|
3527
|
+
/** What a slot's `mount` is handed: which dialog, its payload, its fields, and a way to close it. */
|
|
3528
|
+
export interface DialogSlotHost {
|
|
3529
|
+
readonly dialog: SlottedDialogId;
|
|
3530
|
+
readonly payload: Readonly<Record<string, unknown>>;
|
|
3531
|
+
readonly fields: Readonly<Record<string, DialogField>>;
|
|
3532
|
+
close(): void;
|
|
3533
|
+
}
|
|
3534
|
+
/**
|
|
3535
|
+
* Something a plugin mounts *inside* a built-in dialog — a button in Map Properties
|
|
3536
|
+
* that suggests a name, one in the Text Trigger Editor that explains the text. The slot
|
|
3537
|
+
* is a row at the left of the dialog's footer; fill it with the widgets, and it looks like
|
|
3538
|
+
* part of the dialog. `mount` runs every time the dialog opens, with a cleanup on close.
|
|
3539
|
+
*/
|
|
3540
|
+
export interface DialogSlotSpec {
|
|
3541
|
+
mount(body: HTMLElement, host: DialogSlotHost): void | (() => void);
|
|
3542
|
+
}
|
|
3543
|
+
/**
|
|
3544
|
+
* What `view.flash` highlights: a tile rect, or units / locations by index. The
|
|
3545
|
+
* highlight fades over `ms` (600 by default) and never blocks or takes the pointer; it is
|
|
3546
|
+
* the shared way to say "this just changed" or "look here", so every plugin's flash looks
|
|
3547
|
+
* the same. `kind` picks the colour: `"change"` (gold, the default) or `"attention"` (teal).
|
|
3548
|
+
*/
|
|
3549
|
+
export type FlashTarget = {
|
|
3550
|
+
rect: Rect;
|
|
3551
|
+
kind?: FlashKind;
|
|
3552
|
+
ms?: number;
|
|
3553
|
+
} | {
|
|
3554
|
+
units: number[];
|
|
3555
|
+
kind?: FlashKind;
|
|
3556
|
+
ms?: number;
|
|
3557
|
+
} | {
|
|
3558
|
+
locations: number[];
|
|
3559
|
+
kind?: FlashKind;
|
|
3560
|
+
ms?: number;
|
|
3561
|
+
} | {
|
|
3562
|
+
tiles: {
|
|
3563
|
+
x: number;
|
|
3564
|
+
y: number;
|
|
3565
|
+
}[];
|
|
3566
|
+
kind?: FlashKind;
|
|
3567
|
+
ms?: number;
|
|
3568
|
+
};
|
|
3569
|
+
export type FlashKind = "change" | "attention";
|
|
3379
3570
|
/** The pointer over the map, in the map's own units. A tile is 32 × 32 pixels. */
|
|
3380
3571
|
export interface MapPointer {
|
|
3381
3572
|
/** Map pixels. Kept inside the map while a button is held, as the built-in brushes do. */
|
|
@@ -3519,8 +3710,33 @@ export interface UiApi {
|
|
|
3519
3710
|
fileName: string;
|
|
3520
3711
|
} | null>;
|
|
3521
3712
|
dialog(spec: DialogSpec): DialogHandle;
|
|
3522
|
-
/**
|
|
3713
|
+
/**
|
|
3714
|
+
* Open a panel: floating over the map, or docked at the right with the built-in panels
|
|
3715
|
+
* (`spec.dock`). As many as you like; each closes with the plugin.
|
|
3716
|
+
*/
|
|
3523
3717
|
panel(spec: PanelSpec): PanelHandle;
|
|
3718
|
+
/**
|
|
3719
|
+
* A cell of your own in the status bar. One line of text beside the plugin's icon, a
|
|
3720
|
+
* spinner while `busy`, a click. Keep the handle and `set` it as things move; it
|
|
3721
|
+
* leaves with `remove()` or the plugin.
|
|
3722
|
+
*/
|
|
3723
|
+
statusItem(spec: StatusItemSpec): StatusItemHandle;
|
|
3724
|
+
/**
|
|
3725
|
+
* Add to a built-in dialog. `mount` runs in a row at the left of the dialog's footer each
|
|
3726
|
+
* time that dialog opens, with the dialog's working-copy fields to read and fill
|
|
3727
|
+
* (`SlottedDialogId` lists which dialogs and fields). Returns the registration; it
|
|
3728
|
+
* leaves with `dispose()` or the plugin.
|
|
3729
|
+
*
|
|
3730
|
+
* @example
|
|
3731
|
+
* api.ui.dialogSlot("mapProperties", {
|
|
3732
|
+
* mount(body, dlg) {
|
|
3733
|
+
* body.append(api.ui.widgets.button("Suggest a name", { onClick: async () => {
|
|
3734
|
+
* dlg.fields.name.set(await suggestName(dlg.fields.description.get()));
|
|
3735
|
+
* } }));
|
|
3736
|
+
* },
|
|
3737
|
+
* });
|
|
3738
|
+
*/
|
|
3739
|
+
dialogSlot(dialog: SlottedDialogId, spec: DialogSlotSpec): Disposable;
|
|
3524
3740
|
/**
|
|
3525
3741
|
* Take over the pointer on the map until `stop()`, Esc, a right-click, a map change
|
|
3526
3742
|
* or another tool. One tool runs at a time — starting one stops the previous — and a
|
|
@@ -3814,7 +4030,9 @@ export type PluginEvent =
|
|
|
3814
4030
|
/** The document's file changed: its name or handle after a Save, the save options, the archive extras, the recent list. */
|
|
3815
4031
|
| "file"
|
|
3816
4032
|
/** A plugin registered or removed a command — how a plugin learns that one it calls by id has arrived. */
|
|
3817
|
-
| "commands"
|
|
4033
|
+
| "commands"
|
|
4034
|
+
/** The game data source changed: installed, switched to another data set, or a copy removed. `gameData.source()` says what it is now. */
|
|
4035
|
+
| "gameData";
|
|
3818
4036
|
/** Why the document changed. */
|
|
3819
4037
|
export type DocumentChangeReason =
|
|
3820
4038
|
/** File ▸ Open, drag-and-drop, `document.open`: a file the user chose. */
|