afnm-types 0.6.54 → 0.6.55-injecttest
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/avatarEffects.js +77 -77
- package/dist/cli/extract-mod-translations/index.js +0 -3
- package/dist/gameVersion.d.ts +1 -1
- package/dist/gameVersion.js +1 -1
- package/dist/keybindings.d.ts +13 -3
- package/dist/keybindings.js +15 -4
- package/dist/mod.d.ts +89 -35
- package/package.json +1 -1
- package/dist/itemAction.d.ts +0 -33
- package/dist/itemAction.js +0 -1
- package/dist/manual.d.ts +0 -8
- package/dist/manual.js +0 -1
- package/dist/typeTests.d.ts +0 -9
package/dist/avatarEffects.js
CHANGED
|
@@ -11,83 +11,83 @@
|
|
|
11
11
|
// Replicates the hand-authored glitch art style: strong persistent chromatic
|
|
12
12
|
// aberration (cyan/magenta fringing always visible), periodic brightness
|
|
13
13
|
// washout, and horizontal scanline tears during burst events.
|
|
14
|
-
const GLITCH_FRAG_SRC = `#version 300 es
|
|
15
|
-
precision mediump float;
|
|
16
|
-
in vec2 v_uv;
|
|
17
|
-
uniform sampler2D u_texA;
|
|
18
|
-
uniform sampler2D u_texB;
|
|
19
|
-
uniform float u_mix;
|
|
20
|
-
uniform float u_aspectA;
|
|
21
|
-
uniform float u_aspectB;
|
|
22
|
-
uniform float u_canvasAspect;
|
|
23
|
-
uniform float u_time;
|
|
24
|
-
out vec4 fragColor;
|
|
25
|
-
|
|
26
|
-
float hash(float n) {
|
|
27
|
-
return fract(sin(n) * 43758.5453);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
vec4 sampleContain(sampler2D tex, vec2 uv, float texAspect) {
|
|
31
|
-
float rel = texAspect / u_canvasAspect;
|
|
32
|
-
vec2 scale;
|
|
33
|
-
if (rel > 1.0) {
|
|
34
|
-
scale = vec2(1.0, 1.0 / rel);
|
|
35
|
-
} else {
|
|
36
|
-
scale = vec2(rel, 1.0);
|
|
37
|
-
}
|
|
38
|
-
vec2 offset = (1.0 - scale) * 0.5;
|
|
39
|
-
vec2 mapped = (uv - offset) / scale;
|
|
40
|
-
if (mapped.x < 0.0 || mapped.x > 1.0 || mapped.y < 0.0 || mapped.y > 1.0) {
|
|
41
|
-
return vec4(0.0);
|
|
42
|
-
}
|
|
43
|
-
return texture(tex, mapped);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
void main() {
|
|
47
|
-
vec2 uv = v_uv;
|
|
48
|
-
|
|
49
|
-
// Glitch burst timing — ~0.8 event slots per second, 35% chance each.
|
|
50
|
-
float eventT = floor(u_time * 0.8);
|
|
51
|
-
float isGlitching = step(0.65, hash(eventT * 1.618));
|
|
52
|
-
// Sharp onset, slow decay — the burst lingers before fading.
|
|
53
|
-
float slotFrac = fract(u_time * 0.8);
|
|
54
|
-
float decay = (1.0 - smoothstep(0.1, 0.9, slotFrac)) * isGlitching;
|
|
55
|
-
|
|
56
|
-
// Band-based horizontal displacement (scanline tearing) during bursts.
|
|
57
|
-
float band = floor(uv.y * 24.0);
|
|
58
|
-
float bandActive = step(0.55, hash(band + eventT * 23.7));
|
|
59
|
-
float bandShift = (hash(band * 5.2 + eventT * 7.1) * 2.0 - 1.0) * 0.025;
|
|
60
|
-
float shift = bandShift * bandActive * decay;
|
|
61
|
-
|
|
62
|
-
// Occasional large block tears.
|
|
63
|
-
float bigTear = step(0.92, hash(band * 3.7 + eventT * 11.3));
|
|
64
|
-
shift += (hash(band * 9.1 + eventT * 4.7) * 2.0 - 1.0) * 0.08 * bigTear * decay;
|
|
65
|
-
|
|
66
|
-
vec2 shiftedUv = vec2(uv.x + shift, uv.y);
|
|
67
|
-
|
|
68
|
-
// Chromatic aberration: strong baseline always present, amplified by bursts.
|
|
69
|
-
float aberr = 0.012 + 0.018 * decay;
|
|
70
|
-
|
|
71
|
-
float rA = sampleContain(u_texA, vec2(shiftedUv.x + aberr, shiftedUv.y), u_aspectA).r;
|
|
72
|
-
float gA = sampleContain(u_texA, shiftedUv, u_aspectA).g;
|
|
73
|
-
float bA = sampleContain(u_texA, vec2(shiftedUv.x - aberr, shiftedUv.y), u_aspectA).b;
|
|
74
|
-
float aA = sampleContain(u_texA, shiftedUv, u_aspectA).a;
|
|
75
|
-
vec4 colA = vec4(rA, gA, bA, aA);
|
|
76
|
-
|
|
77
|
-
float rB = sampleContain(u_texB, vec2(shiftedUv.x + aberr, shiftedUv.y), u_aspectB).r;
|
|
78
|
-
float gB = sampleContain(u_texB, shiftedUv, u_aspectB).g;
|
|
79
|
-
float bB = sampleContain(u_texB, vec2(shiftedUv.x - aberr, shiftedUv.y), u_aspectB).b;
|
|
80
|
-
float aB = sampleContain(u_texB, shiftedUv, u_aspectB).a;
|
|
81
|
-
vec4 colB = vec4(rB, gB, bB, aB);
|
|
82
|
-
|
|
83
|
-
vec4 col = mix(colA, colB, u_mix);
|
|
84
|
-
|
|
85
|
-
// Brightness washout during bursts — push toward overexposed white,
|
|
86
|
-
// scaled by alpha so transparent edges don't bloom.
|
|
87
|
-
float blowout = decay * 0.45;
|
|
88
|
-
col.rgb = mix(col.rgb, vec3(1.0), blowout * col.a);
|
|
89
|
-
|
|
90
|
-
fragColor = col;
|
|
14
|
+
const GLITCH_FRAG_SRC = `#version 300 es
|
|
15
|
+
precision mediump float;
|
|
16
|
+
in vec2 v_uv;
|
|
17
|
+
uniform sampler2D u_texA;
|
|
18
|
+
uniform sampler2D u_texB;
|
|
19
|
+
uniform float u_mix;
|
|
20
|
+
uniform float u_aspectA;
|
|
21
|
+
uniform float u_aspectB;
|
|
22
|
+
uniform float u_canvasAspect;
|
|
23
|
+
uniform float u_time;
|
|
24
|
+
out vec4 fragColor;
|
|
25
|
+
|
|
26
|
+
float hash(float n) {
|
|
27
|
+
return fract(sin(n) * 43758.5453);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
vec4 sampleContain(sampler2D tex, vec2 uv, float texAspect) {
|
|
31
|
+
float rel = texAspect / u_canvasAspect;
|
|
32
|
+
vec2 scale;
|
|
33
|
+
if (rel > 1.0) {
|
|
34
|
+
scale = vec2(1.0, 1.0 / rel);
|
|
35
|
+
} else {
|
|
36
|
+
scale = vec2(rel, 1.0);
|
|
37
|
+
}
|
|
38
|
+
vec2 offset = (1.0 - scale) * 0.5;
|
|
39
|
+
vec2 mapped = (uv - offset) / scale;
|
|
40
|
+
if (mapped.x < 0.0 || mapped.x > 1.0 || mapped.y < 0.0 || mapped.y > 1.0) {
|
|
41
|
+
return vec4(0.0);
|
|
42
|
+
}
|
|
43
|
+
return texture(tex, mapped);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
void main() {
|
|
47
|
+
vec2 uv = v_uv;
|
|
48
|
+
|
|
49
|
+
// Glitch burst timing — ~0.8 event slots per second, 35% chance each.
|
|
50
|
+
float eventT = floor(u_time * 0.8);
|
|
51
|
+
float isGlitching = step(0.65, hash(eventT * 1.618));
|
|
52
|
+
// Sharp onset, slow decay — the burst lingers before fading.
|
|
53
|
+
float slotFrac = fract(u_time * 0.8);
|
|
54
|
+
float decay = (1.0 - smoothstep(0.1, 0.9, slotFrac)) * isGlitching;
|
|
55
|
+
|
|
56
|
+
// Band-based horizontal displacement (scanline tearing) during bursts.
|
|
57
|
+
float band = floor(uv.y * 24.0);
|
|
58
|
+
float bandActive = step(0.55, hash(band + eventT * 23.7));
|
|
59
|
+
float bandShift = (hash(band * 5.2 + eventT * 7.1) * 2.0 - 1.0) * 0.025;
|
|
60
|
+
float shift = bandShift * bandActive * decay;
|
|
61
|
+
|
|
62
|
+
// Occasional large block tears.
|
|
63
|
+
float bigTear = step(0.92, hash(band * 3.7 + eventT * 11.3));
|
|
64
|
+
shift += (hash(band * 9.1 + eventT * 4.7) * 2.0 - 1.0) * 0.08 * bigTear * decay;
|
|
65
|
+
|
|
66
|
+
vec2 shiftedUv = vec2(uv.x + shift, uv.y);
|
|
67
|
+
|
|
68
|
+
// Chromatic aberration: strong baseline always present, amplified by bursts.
|
|
69
|
+
float aberr = 0.012 + 0.018 * decay;
|
|
70
|
+
|
|
71
|
+
float rA = sampleContain(u_texA, vec2(shiftedUv.x + aberr, shiftedUv.y), u_aspectA).r;
|
|
72
|
+
float gA = sampleContain(u_texA, shiftedUv, u_aspectA).g;
|
|
73
|
+
float bA = sampleContain(u_texA, vec2(shiftedUv.x - aberr, shiftedUv.y), u_aspectA).b;
|
|
74
|
+
float aA = sampleContain(u_texA, shiftedUv, u_aspectA).a;
|
|
75
|
+
vec4 colA = vec4(rA, gA, bA, aA);
|
|
76
|
+
|
|
77
|
+
float rB = sampleContain(u_texB, vec2(shiftedUv.x + aberr, shiftedUv.y), u_aspectB).r;
|
|
78
|
+
float gB = sampleContain(u_texB, shiftedUv, u_aspectB).g;
|
|
79
|
+
float bB = sampleContain(u_texB, vec2(shiftedUv.x - aberr, shiftedUv.y), u_aspectB).b;
|
|
80
|
+
float aB = sampleContain(u_texB, shiftedUv, u_aspectB).a;
|
|
81
|
+
vec4 colB = vec4(rB, gB, bB, aB);
|
|
82
|
+
|
|
83
|
+
vec4 col = mix(colA, colB, u_mix);
|
|
84
|
+
|
|
85
|
+
// Brightness washout during bursts — push toward overexposed white,
|
|
86
|
+
// scaled by alpha so transparent edges don't bloom.
|
|
87
|
+
float blowout = decay * 0.45;
|
|
88
|
+
col.rgb = mix(col.rgb, vec3(1.0), blowout * col.a);
|
|
89
|
+
|
|
90
|
+
fragColor = col;
|
|
91
91
|
}`;
|
|
92
92
|
// ─── Registry ─────────────────────────────────────────────────────────────────
|
|
93
93
|
/**
|
|
@@ -357,9 +357,6 @@ async function main() {
|
|
|
357
357
|
console.log(` 1. Open ${templatePath}`);
|
|
358
358
|
console.log(' 2. Copy it to a new language file, e.g. translations/ru.json');
|
|
359
359
|
console.log(' 3. Fill in the translated values for each key');
|
|
360
|
-
console.log(' 4. Register the translations in your mod:');
|
|
361
|
-
console.log(" import ruTranslations from './translations/ru.json';");
|
|
362
|
-
console.log(" api.addTranslation('ru', ruTranslations);");
|
|
363
360
|
}
|
|
364
361
|
main().catch((error) => {
|
|
365
362
|
console.error('Fatal error:', error);
|
package/dist/gameVersion.d.ts
CHANGED
package/dist/gameVersion.js
CHANGED
package/dist/keybindings.d.ts
CHANGED
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
export type KeybindingCategory = 'general' | 'navigation' | 'ui' | 'world' | 'combat' | 'crafting' | 'dialogs' | 'gamepad';
|
|
2
2
|
export type KeybindingAction = 'confirm' | 'cancel' | 'pause' | 'alternateConfirm' | 'moveUp' | 'moveDown' | 'moveLeft' | 'moveRight' | 'openInventory' | 'openQuests' | 'openCharacterStats' | 'openTechniques' | 'openCalendar' | 'openWorldMap' | 'combatSelectStance0' | 'combatSelectStance1' | 'combatSelectStance2' | 'combatSelectStance3' | 'combatSelectStance4' | 'combatSelectStance5' | 'combatSelectStance6' | 'combatSelectStance7' | 'combatSelectStance8' | 'combatSelectStance9' | 'combatToggleSpeed' | 'combatToggleLog' | 'combatShowStats' | 'combatAutoBattle' | 'combatUseItem' | 'combatCancel' | 'craftingAction1' | 'craftingAction2' | 'craftingAction3' | 'craftingAction4' | 'craftingAction5' | 'craftingAction6' | 'craftingAction7' | 'craftingAction8' | 'craftingAction9' | 'craftingAction10' | 'craftingAction11' | 'craftingAction12' | 'craftingAction13' | 'craftingAction14' | 'craftingAction15' | 'craftingAction16' | 'craftingAction17' | 'craftingAction18' | 'craftingAction19' | 'craftingAction20' | 'craftingAction21' | 'craftingAction22' | 'craftingAction23' | 'craftingAction24' | 'craftingAction25' | 'craftingAction26' | 'craftingAction27' | 'craftingAction28' | 'craftingAction29' | 'craftingAction30' | 'craftingAction31' | 'craftingAction32' | 'craftingAction33' | 'craftingAction34' | 'craftingAction35' | 'craftingAction36' | 'craftingAction37' | 'craftingAction38' | 'craftingAction39' | 'craftingAction40' | 'craftingAction41' | 'craftingAction42' | 'craftingAction43' | 'craftingAction44' | 'craftingAction45' | 'craftingAction46' | 'craftingAction47' | 'craftingAction48' | 'craftingAction49' | 'craftingAction50' | 'dialogChoice1' | 'dialogChoice2' | 'dialogChoice3' | 'dialogChoice4' | 'dialogChoice5' | 'dialogChoice6' | 'dialogChoice7' | 'dialogChoice8' | 'dialogChoice9' | 'gamepadConfirm' | 'gamepadCancel' | 'gamepadUp' | 'gamepadDown' | 'gamepadLeft' | 'gamepadRight';
|
|
3
3
|
export interface KeybindingDefinition {
|
|
4
|
-
action: KeybindingAction;
|
|
4
|
+
action: KeybindingAction | string;
|
|
5
5
|
category: KeybindingCategory;
|
|
6
6
|
displayName: string;
|
|
7
7
|
description: string;
|
|
8
8
|
defaultKey: string;
|
|
9
9
|
allowRebind: boolean;
|
|
10
|
+
modName?: string;
|
|
10
11
|
}
|
|
11
12
|
export type KeybindingsMap = Record<KeybindingAction | string, string>;
|
|
13
|
+
export interface RegisteredKeybind {
|
|
14
|
+
displayText: string;
|
|
15
|
+
code: string;
|
|
16
|
+
ctrlKey: boolean;
|
|
17
|
+
altKey: boolean;
|
|
18
|
+
shiftKey: boolean;
|
|
19
|
+
}
|
|
12
20
|
export declare const keybindingDefinitions: KeybindingDefinition[];
|
|
13
21
|
export declare const keybindingCategoryInfo: Record<KeybindingCategory, {
|
|
14
22
|
name: string;
|
|
@@ -20,6 +28,7 @@ export declare const MODIFIER_PREFIXES: {
|
|
|
20
28
|
readonly alt: "Alt+";
|
|
21
29
|
readonly shift: "Shift+";
|
|
22
30
|
};
|
|
31
|
+
export declare const baseKeyToCode: Record<string, string>;
|
|
23
32
|
export declare function getBaseKeyFromEvent(event: KeyboardEvent): string;
|
|
24
33
|
export declare function buildKeybindingString(key: string, modifiers: {
|
|
25
34
|
ctrl?: boolean;
|
|
@@ -34,8 +43,9 @@ export declare function parseKeybindingString(keybinding: string | undefined | n
|
|
|
34
43
|
shift: boolean;
|
|
35
44
|
};
|
|
36
45
|
export declare function matchesKeybinding(event: KeyboardEvent, keybinding: string): boolean;
|
|
37
|
-
export declare function
|
|
38
|
-
export declare function
|
|
46
|
+
export declare function matchKeybinding(event: KeyboardEvent, keybind: RegisteredKeybind): boolean;
|
|
47
|
+
export declare function getKeyDisplayName(keybinding: string | RegisteredKeybind | undefined | null): string;
|
|
48
|
+
export declare function getKeyShortDisplayName(keybinding: string | RegisteredKeybind | undefined | null): string;
|
|
39
49
|
export declare function isModifierKey(key: string): boolean;
|
|
40
50
|
export declare function isKeyAllowed(key: string): boolean;
|
|
41
51
|
export declare function getKeybindingsByCategory(category: KeybindingCategory): KeybindingDefinition[];
|
package/dist/keybindings.js
CHANGED
|
@@ -908,6 +908,8 @@ const codeToBaseKey = {
|
|
|
908
908
|
F11: 'F11',
|
|
909
909
|
F12: 'F12',
|
|
910
910
|
};
|
|
911
|
+
// Build reverse lookup from base key to code for matching KeyboardEvent.code
|
|
912
|
+
export const baseKeyToCode = Object.fromEntries(Object.entries(codeToBaseKey).map(([code, baseKey]) => [baseKey, code]));
|
|
911
913
|
// Get the base key from a keyboard event (uses code for consistent physical key)
|
|
912
914
|
export function getBaseKeyFromEvent(event) {
|
|
913
915
|
// Try to get base key from code first (handles Shift+2 -> '2' instead of '!')
|
|
@@ -964,6 +966,13 @@ export function matchesKeybinding(event, keybinding) {
|
|
|
964
966
|
event.altKey === parsed.alt &&
|
|
965
967
|
event.shiftKey === parsed.shift);
|
|
966
968
|
}
|
|
969
|
+
// Check if a keyboard event matches a registered keybind
|
|
970
|
+
export function matchKeybinding(event, keybind) {
|
|
971
|
+
return (event.code === keybind.code &&
|
|
972
|
+
event.ctrlKey === keybind.ctrlKey &&
|
|
973
|
+
event.altKey === keybind.altKey &&
|
|
974
|
+
event.shiftKey === keybind.shiftKey);
|
|
975
|
+
}
|
|
967
976
|
const singleKeyDisplayNames = {
|
|
968
977
|
Enter: 'Enter',
|
|
969
978
|
Escape: 'Esc',
|
|
@@ -986,9 +995,10 @@ const singleKeyDisplayNames = {
|
|
|
986
995
|
// Helper to get display name for a key (full version)
|
|
987
996
|
export function getKeyDisplayName(keybinding) {
|
|
988
997
|
var _a;
|
|
989
|
-
|
|
998
|
+
const displayText = typeof keybinding === 'object' && keybinding !== null ? keybinding.displayText : keybinding;
|
|
999
|
+
if (!displayText)
|
|
990
1000
|
return '';
|
|
991
|
-
const parsed = parseKeybindingString(
|
|
1001
|
+
const parsed = parseKeybindingString(displayText);
|
|
992
1002
|
let result = '';
|
|
993
1003
|
if (parsed.ctrl)
|
|
994
1004
|
result += 'Ctrl+';
|
|
@@ -1002,9 +1012,10 @@ export function getKeyDisplayName(keybinding) {
|
|
|
1002
1012
|
// Helper to get short display name for a key (compact version for UI previews)
|
|
1003
1013
|
export function getKeyShortDisplayName(keybinding) {
|
|
1004
1014
|
var _a;
|
|
1005
|
-
|
|
1015
|
+
const displayText = typeof keybinding === 'object' && keybinding !== null ? keybinding.displayText : keybinding;
|
|
1016
|
+
if (!displayText)
|
|
1006
1017
|
return '';
|
|
1007
|
-
const parsed = parseKeybindingString(
|
|
1018
|
+
const parsed = parseKeybindingString(displayText);
|
|
1008
1019
|
let result = '';
|
|
1009
1020
|
if (parsed.ctrl)
|
|
1010
1021
|
result += 'C+';
|
package/dist/mod.d.ts
CHANGED
|
@@ -47,7 +47,7 @@ import type { DamageType } from './DamageType';
|
|
|
47
47
|
import { AvatarEffectShader } from './avatarEffects';
|
|
48
48
|
import type { Translatable, TranslatableString } from './translatable';
|
|
49
49
|
import type { SaveFileInfo } from './electron';
|
|
50
|
-
import type { KeybindingDefinition } from './keybindings';
|
|
50
|
+
import type { KeybindingDefinition, RegisteredKeybind } from './keybindings';
|
|
51
51
|
import { ScreenType } from './GameScreen';
|
|
52
52
|
export type SkipDialogueMode = 'flash' | 'silent';
|
|
53
53
|
export type Sexuality = 'straight' | 'gay' | 'bisexual';
|
|
@@ -73,6 +73,42 @@ export interface GameSettingsProps {
|
|
|
73
73
|
eventHistoryLimit: number;
|
|
74
74
|
setEventHistoryLimit: (value: number) => void;
|
|
75
75
|
}
|
|
76
|
+
/**
|
|
77
|
+
* Where injected content is placed relative to the matched element.
|
|
78
|
+
*
|
|
79
|
+
* Sibling insertions:
|
|
80
|
+
* 'before' inserted as a sibling immediately before the target
|
|
81
|
+
* 'after' inserted as a sibling immediately after the target (default)
|
|
82
|
+
*
|
|
83
|
+
* Child insertions:
|
|
84
|
+
* 'prependChild' inserted as the first child inside the target
|
|
85
|
+
* 'appendChild' inserted as the last child inside the target
|
|
86
|
+
* { insertAt: N } inserted as the Nth child inside the target (0-based)
|
|
87
|
+
*
|
|
88
|
+
* Overlay:
|
|
89
|
+
* 'overlay' absolutely positioned layer covering the target (target gets position:relative if needed)
|
|
90
|
+
*
|
|
91
|
+
* Structural replacements (use with care on React-rendered elements):
|
|
92
|
+
* 'replaceContents' clears the target's children and renders content inside the target
|
|
93
|
+
* 'replaceElement' removes the target entirely and renders content in its place
|
|
94
|
+
* 'wrapElement' target becomes a DOM child of the content's outermost element (e.g. a border div wraps around target)
|
|
95
|
+
* 'wrapContents' target's existing children are moved inside the content's outermost element, which is then appended to target
|
|
96
|
+
*/
|
|
97
|
+
export type InjectPlacement = 'before' | 'after' | 'prependChild' | 'appendChild' | 'overlay' | 'replaceContents' | 'replaceElement' | 'wrapElement' | 'wrapContents' | {
|
|
98
|
+
insertAt: number;
|
|
99
|
+
};
|
|
100
|
+
export interface NewGameIntent {
|
|
101
|
+
items: ItemDesc[];
|
|
102
|
+
techniques: string[];
|
|
103
|
+
recipes: string[];
|
|
104
|
+
destinies: string[];
|
|
105
|
+
quests: string[];
|
|
106
|
+
money: number;
|
|
107
|
+
favour: number;
|
|
108
|
+
flags: Record<string, number>;
|
|
109
|
+
player: PlayerEntity;
|
|
110
|
+
craftingActions: string[];
|
|
111
|
+
}
|
|
76
112
|
/**
|
|
77
113
|
* Sprite images for a custom player character.
|
|
78
114
|
* All images should be strings (either mod:// URLs for mod assets, or data: URLs).
|
|
@@ -353,8 +389,6 @@ export interface ModReduxAPI {
|
|
|
353
389
|
TooltipLine: TooltipLineFC;
|
|
354
390
|
};
|
|
355
391
|
utils: {
|
|
356
|
-
hasSave: () => boolean;
|
|
357
|
-
getCurrentState: () => RootState | null;
|
|
358
392
|
parseTooltipLine: (tooltip: string) => React.ReactNode;
|
|
359
393
|
expandTooltipTemplate: (template: string, templateValues: Map<string, string>, addPeriod?: boolean) => string;
|
|
360
394
|
expandTooltipTags: (template: string) => string;
|
|
@@ -2051,14 +2085,22 @@ export interface ModAPI {
|
|
|
2051
2085
|
* Use this to check what key is currently bound to an action, useful for
|
|
2052
2086
|
* displaying key hints in custom UI or handling key events outside React components.
|
|
2053
2087
|
* @param action - The action name (e.g., 'myMod.specialAction')
|
|
2054
|
-
* @returns The
|
|
2088
|
+
* @returns The keybind info including displayText (e.g., 'Shift+F12'), code (e.g., 'F12'),
|
|
2089
|
+
* and modifier booleans (ctrlKey, altKey, shiftKey), or undefined if not bound
|
|
2055
2090
|
* @example
|
|
2056
2091
|
* const key = modAPI.utils.getRegisteredKeybindValue('myMod.specialAction');
|
|
2057
2092
|
* if (key) {
|
|
2058
|
-
* console.log(`Special action is bound to ${key}`);
|
|
2093
|
+
* console.log(`Special action is bound to ${key.displayText}`);
|
|
2094
|
+
* // Match against KeyboardEvent:
|
|
2095
|
+
* // if (event.code === key.code && event.shiftKey === key.shiftKey) { ... }
|
|
2059
2096
|
* }
|
|
2060
2097
|
*/
|
|
2061
|
-
getRegisteredKeybindValue: (action: string) =>
|
|
2098
|
+
getRegisteredKeybindValue: (action: string) => RegisteredKeybind | undefined;
|
|
2099
|
+
/**
|
|
2100
|
+
*
|
|
2101
|
+
* @returns true if a save is currently loaded and game state is available, false otherwise.
|
|
2102
|
+
*/
|
|
2103
|
+
getHasSaveLoaded: () => boolean;
|
|
2062
2104
|
};
|
|
2063
2105
|
hooks: {
|
|
2064
2106
|
/**
|
|
@@ -2351,45 +2393,46 @@ export interface ModAPI {
|
|
|
2351
2393
|
* return payload;
|
|
2352
2394
|
* });
|
|
2353
2395
|
*/
|
|
2354
|
-
onReduxActionPayload: (interceptor: (actionType: string, payload: unknown) => unknown | null) => void;
|
|
2396
|
+
onReduxActionPayload: (interceptor: (actionType: string, payload: unknown, stateBefore: RootState) => unknown | null) => void;
|
|
2355
2397
|
/**
|
|
2356
|
-
* Called before the equipment upgrade dialog is shown. Allows mutating upgrade cost items and
|
|
2398
|
+
* Called before the equipment upgrade dialog is shown. Allows mutating upgrade cost items and
|
|
2399
|
+
* result item quality tier (but not base item).
|
|
2357
2400
|
*
|
|
2358
2401
|
* @example
|
|
2359
|
-
* modAPI.hooks.onDeriveEquipmentUpgradeRequirement((baseItem, costItems,
|
|
2360
|
-
* //
|
|
2361
|
-
* return { costItems
|
|
2402
|
+
* modAPI.hooks.onDeriveEquipmentUpgradeRequirement((baseItem, costItems, resultItemName, resultQualityTier, flags) => {
|
|
2403
|
+
* // Override the result quality tier
|
|
2404
|
+
* return { costItems, resultItemName, resultQualityTier: resultQualityTier + 2 };
|
|
2362
2405
|
* });
|
|
2363
2406
|
*/
|
|
2364
|
-
onDeriveEquipmentUpgradeRequirement: (interceptor: (baseItem: Item, costItems: Item[],
|
|
2407
|
+
onDeriveEquipmentUpgradeRequirement: (interceptor: (baseItem: Item, costItems: Item[], resultItemName: string, resultQualityTier: number, gameFlags: Record<string, number>) => {
|
|
2365
2408
|
costItems?: Item[];
|
|
2366
|
-
|
|
2409
|
+
resultItemName?: string;
|
|
2410
|
+
resultQualityTier?: number;
|
|
2367
2411
|
} | undefined) => void;
|
|
2368
2412
|
/**
|
|
2369
|
-
* Called
|
|
2413
|
+
* Called when an equipment upgrade completes. Read-only: cannot modify the result item.
|
|
2414
|
+
* Use onDeriveEquipmentUpgradeRequirement to change the result before the upgrade.
|
|
2370
2415
|
*
|
|
2371
2416
|
* @example
|
|
2372
2417
|
* modAPI.hooks.onCompleteEquipmentUpgrade((baseItem, costItems, resultItem, flags) => {
|
|
2373
|
-
* //
|
|
2374
|
-
* return { costItems, resultItem: { ...resultItem, damage: (resultItem.damage ?? 0) + 10 } };
|
|
2418
|
+
* // React to the upgrade (e.g., trigger a side effect)
|
|
2375
2419
|
* });
|
|
2376
2420
|
*/
|
|
2377
|
-
onCompleteEquipmentUpgrade: (interceptor: (baseItem: Item, costItems: Item[], resultItem: Item, gameFlags: Record<string, number>) =>
|
|
2378
|
-
costItems?: Item[];
|
|
2379
|
-
resultItem?: Item;
|
|
2380
|
-
} | undefined) => void;
|
|
2421
|
+
onCompleteEquipmentUpgrade: (interceptor: (baseItem: Item, costItems: Item[], resultItem: Item, gameFlags: Record<string, number>) => void) => void;
|
|
2381
2422
|
/**
|
|
2382
|
-
* Called before the equipment reforge dialog is shown. Allows mutating reforge cost items and
|
|
2423
|
+
* Called before the equipment reforge dialog is shown. Allows mutating reforge cost items and
|
|
2424
|
+
* result item quality tier (but not base item).
|
|
2383
2425
|
*
|
|
2384
2426
|
* @example
|
|
2385
|
-
* modAPI.hooks.onDeriveEquipmentReforgeRequirement((baseItem, costItems,
|
|
2386
|
-
* //
|
|
2387
|
-
* return { costItems,
|
|
2427
|
+
* modAPI.hooks.onDeriveEquipmentReforgeRequirement((baseItem, costItems, resultItemName, resultQualityTier, flags) => {
|
|
2428
|
+
* // Override the result quality tier (e.g., set to max)
|
|
2429
|
+
* return { costItems, resultItemName, resultQualityTier: 10 };
|
|
2388
2430
|
* });
|
|
2389
2431
|
*/
|
|
2390
|
-
onDeriveEquipmentReforgeRequirement: (interceptor: (baseItem: Item, costItems: Item[],
|
|
2432
|
+
onDeriveEquipmentReforgeRequirement: (interceptor: (baseItem: Item, costItems: Item[], resultItemName: string, resultQualityTier: number, gameFlags: Record<string, number>) => {
|
|
2391
2433
|
costItems?: Item[];
|
|
2392
|
-
|
|
2434
|
+
resultItemName?: string;
|
|
2435
|
+
resultQualityTier?: number;
|
|
2393
2436
|
} | undefined) => void;
|
|
2394
2437
|
/**
|
|
2395
2438
|
* Called before the completion dialog showing the reforged equipment. Allows mutating reforge cost items and result (but not base item).
|
|
@@ -2404,6 +2447,17 @@ export interface ModAPI {
|
|
|
2404
2447
|
costItems?: Item[];
|
|
2405
2448
|
resultItem?: Item;
|
|
2406
2449
|
} | undefined) => void;
|
|
2450
|
+
/**
|
|
2451
|
+
* Intercept the full set of changes planned for a new game before they are applied.
|
|
2452
|
+
* Return a modified intent to change starting items, techniques, flags, etc.
|
|
2453
|
+
* @param interceptor - Receives the full intent and returns a modified copy
|
|
2454
|
+
* @example
|
|
2455
|
+
* modAPI.hooks.onNewGame((intent) => ({
|
|
2456
|
+
* ...intent,
|
|
2457
|
+
* flags: { ...intent.flags, my_mod_enabled: 1 },
|
|
2458
|
+
* }));
|
|
2459
|
+
*/
|
|
2460
|
+
onNewGame: (interceptor: (intent: NewGameIntent) => NewGameIntent) => void;
|
|
2407
2461
|
};
|
|
2408
2462
|
/**
|
|
2409
2463
|
* Inject UI into a named slot (dialog title or screen name).
|
|
@@ -2411,27 +2465,25 @@ export interface ModAPI {
|
|
|
2411
2465
|
* The generator receives (api, element, inject):
|
|
2412
2466
|
* - api: full ModReduxAPI with game state, actions, and components
|
|
2413
2467
|
* - element: root DOM element of the slot; use querySelector to find children
|
|
2414
|
-
* - inject(selector, content,
|
|
2415
|
-
* matched by selector.
|
|
2416
|
-
*
|
|
2417
|
-
* position controls where content is placed (see InjectPosition enum).
|
|
2468
|
+
* - inject(selector, content, placement?): helper to portal content relative to the element
|
|
2469
|
+
* matched by selector. placement controls where content appears (see InjectPlacement).
|
|
2470
|
+
* Defaults to 'after' (sibling inserted after the target).
|
|
2418
2471
|
*
|
|
2419
2472
|
* Slot names for dialogs are the id (e.g. 'combat-victory'). You can find these by inspecting the DOM in dev mode.
|
|
2420
2473
|
* Slot names for screens match the ScreenType value (e.g. 'combat').
|
|
2421
2474
|
*
|
|
2422
2475
|
* @example
|
|
2423
|
-
* // Add a button
|
|
2476
|
+
* // Add a button after an element in the combat victory dialog
|
|
2424
2477
|
* modAPI.ui.injectUI('combat-victory', (api, element, inject) => {
|
|
2425
2478
|
* return inject('[aria-live="assertive"]',
|
|
2426
2479
|
* <api.components.GameButton onClick={() => api.actions.changeQi(100)}>
|
|
2427
2480
|
* Absorb Qi
|
|
2428
2481
|
* </api.components.GameButton>,
|
|
2429
|
-
* '
|
|
2430
|
-
* InjectPosition.After
|
|
2482
|
+
* 'after'
|
|
2431
2483
|
* );
|
|
2432
2484
|
* });
|
|
2433
2485
|
*/
|
|
2434
|
-
injectUI: (slotName: string, generator: (api: ModReduxAPI, element: HTMLElement | null, inject: (selector: string, content: React.ReactNode,
|
|
2486
|
+
injectUI: (slotName: string, generator: (api: ModReduxAPI, element: HTMLElement | null, inject: (selector: string, content: React.ReactNode, placement?: InjectPlacement) => React.ReactNode) => React.ReactNode) => void;
|
|
2435
2487
|
/**
|
|
2436
2488
|
* Subscribe to any Redux state changes. The callback receives the new state.
|
|
2437
2489
|
* Returns an unsubscribe function.
|
|
@@ -2456,4 +2508,6 @@ export interface ModAPI {
|
|
|
2456
2508
|
*/
|
|
2457
2509
|
getGameStateSnapshot: () => RootState | null;
|
|
2458
2510
|
}
|
|
2459
|
-
export type
|
|
2511
|
+
export type ModHooks = {
|
|
2512
|
+
[K in keyof ModAPI['hooks']]: Parameters<ModAPI['hooks'][K]>[0][];
|
|
2513
|
+
};
|
package/package.json
CHANGED
package/dist/itemAction.d.ts
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import type { ReactNode } from 'react';
|
|
2
|
-
import type { AppDispatch } from '../store';
|
|
3
|
-
import type { BreakthroughState } from './breakthrough';
|
|
4
|
-
import type { SoundEffectName } from './audio';
|
|
5
|
-
import type { Item } from './item';
|
|
6
|
-
import type { PlayerEntity } from './entity';
|
|
7
|
-
import type { InventoryState } from './reduxState';
|
|
8
|
-
interface OpenItem {
|
|
9
|
-
item: Item;
|
|
10
|
-
data: unknown;
|
|
11
|
-
onComplete: () => void;
|
|
12
|
-
}
|
|
13
|
-
export interface ItemActionContext {
|
|
14
|
-
item: Item;
|
|
15
|
-
player: PlayerEntity;
|
|
16
|
-
inventory: InventoryState;
|
|
17
|
-
breakthrough: BreakthroughState;
|
|
18
|
-
flags: Record<string, number | string | boolean>;
|
|
19
|
-
dispatch: AppDispatch;
|
|
20
|
-
setResult: (result: ReactNode) => void;
|
|
21
|
-
setClicked: (clicked: boolean) => void;
|
|
22
|
-
setOpenItem?: (openItem: OpenItem) => void;
|
|
23
|
-
setDoEnchant?: (doEnchant: boolean) => void;
|
|
24
|
-
setDoUpgrade?: (doUpgrade: boolean) => void;
|
|
25
|
-
setDoAppearanceChange?: (doAppearanceChange: boolean) => void;
|
|
26
|
-
playSfx: (sound: SoundEffectName) => void;
|
|
27
|
-
usageRestricted: boolean;
|
|
28
|
-
}
|
|
29
|
-
export interface ItemActionResult {
|
|
30
|
-
buttons: ReactNode[];
|
|
31
|
-
}
|
|
32
|
-
export type ItemActionHandler = (context: ItemActionContext) => ItemActionResult;
|
|
33
|
-
export {};
|
package/dist/itemAction.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/manual.d.ts
DELETED
package/dist/manual.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/typeTests.d.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Type Tests - These files ensure type compatibility across the codebase
|
|
3
|
-
* If any of these fail to compile, it means we have a type mismatch
|
|
4
|
-
*/
|
|
5
|
-
import type { RootState as StoreRootState } from '../store';
|
|
6
|
-
import type { RootState as TypesRootState } from './reduxState';
|
|
7
|
-
type TestExactMatch = StoreRootState extends TypesRootState ? TypesRootState extends StoreRootState ? true : false : false;
|
|
8
|
-
export type RootStateIsConsistent = TestExactMatch;
|
|
9
|
-
export {};
|