hoi4-agent-tools 2.8.2 → 2.8.4
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/CHANGELOG.md +10 -0
- package/dist/hoi4_agent_tools/gui/assets.js +24 -0
- package/dist/hoi4_agent_tools/gui/layout.js +75 -12
- package/dist/hoi4_agent_tools/gui/renderer.js +53 -11
- package/dist/hoi4_agent_tools/gui/scenario.js +1 -0
- package/dist/hoi4_agent_tools/gui/source-graph.js +26 -1
- package/dist/hoi4_agent_tools/gui/studio.js +1 -1
- package/dist/hoi4_agent_tools/version.js +1 -1
- package/docs/gui.md +9 -3
- package/package.json +1 -1
- package/schemas/configuration.schema.json +1 -1
- package/schemas/continuous-focus-palette.schema.json +1 -1
- package/schemas/custom-weighted-pool.schema.json +1 -1
- package/schemas/event-feature-manifest.schema.json +1 -1
- package/schemas/focus-plan.schema.json +1 -1
- package/schemas/focus-planning-sidecar.schema.json +1 -1
- package/schemas/gui-animation-source.schema.json +1 -1
- package/schemas/gui-helper.schema.json +1 -1
- package/schemas/gui-scenario.schema.json +29 -22
- package/schemas/map-operation.schema.json +1 -1
- package/schemas/operation-result.schema.json +1 -1
- package/schemas/probability-analysis-result.schema.json +1 -1
- package/schemas/probability-compare-input.schema.json +1 -1
- package/schemas/probability-evaluate-input.schema.json +1 -1
- package/schemas/probability-inspect-input.schema.json +1 -1
- package/schemas/probability-render-input.schema.json +1 -1
- package/schemas/probability-scenario-set.schema.json +1 -1
- package/schemas/probability-sequence-input.schema.json +1 -1
- package/schemas/probability-simulate-input.schema.json +1 -1
- package/schemas/probability-sweep-input.schema.json +1 -1
- package/server.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,16 @@
|
|
|
4
4
|
|
|
5
5
|
No unreleased changes.
|
|
6
6
|
|
|
7
|
+
## 2.8.4 - 2026-08-28
|
|
8
|
+
|
|
9
|
+
- Render each declared HOI4 font face with its own glyph atlas, native metrics, face colour, border colour, and inherited language-override styling.
|
|
10
|
+
- Keep native HOI4 bitmap or outline glyphs when localisation colour markup changes part of a line instead of replacing the line with the generic tool font.
|
|
11
|
+
|
|
12
|
+
## 2.8.3 - 2026-08-27
|
|
13
|
+
|
|
14
|
+
- Centered native button labels when HOI4 GUI source uses `text =` instead of `buttonText =`, matching the in-game horizontal and vertical alignment inside button frames.
|
|
15
|
+
- Added one scenario `values` map for concrete runtime variables, dynamic text, meter fills, sprites, frames, positions, visibility, and enabled states so agents can render complete value-driven GUI versions without assembling several low-level override maps.
|
|
16
|
+
|
|
7
17
|
## 2.8.2 - 2026-08-27
|
|
8
18
|
|
|
9
19
|
- Composed top-level scripted-GUI child windows through `parent_scripted_gui`, instantiated external dynamic-list entry containers, and applied row-scoped image, frame, position, visibility, and enabled values.
|
|
@@ -180,6 +180,30 @@ export class GuiAssetCatalog {
|
|
|
180
180
|
definition.languages.length === 0))
|
|
181
181
|
this.fontDefinitions.set(key, definition);
|
|
182
182
|
}
|
|
183
|
+
const baseDefinitions = new Map();
|
|
184
|
+
for (const definition of graph.fonts) {
|
|
185
|
+
if (definition.override || definition.languages.length > 0)
|
|
186
|
+
continue;
|
|
187
|
+
const key = definition.name.toLocaleLowerCase('en-US');
|
|
188
|
+
if (!baseDefinitions.has(key))
|
|
189
|
+
baseDefinitions.set(key, definition);
|
|
190
|
+
}
|
|
191
|
+
for (const [key, definition] of this.fontDefinitions) {
|
|
192
|
+
if (!definition.override)
|
|
193
|
+
continue;
|
|
194
|
+
const base = baseDefinitions.get(key);
|
|
195
|
+
if (base === undefined)
|
|
196
|
+
continue;
|
|
197
|
+
this.fontDefinitions.set(key, {
|
|
198
|
+
...definition,
|
|
199
|
+
...(definition.colour === undefined && base.colour !== undefined
|
|
200
|
+
? { colour: base.colour }
|
|
201
|
+
: {}),
|
|
202
|
+
...(definition.borderColour === undefined && base.borderColour !== undefined
|
|
203
|
+
? { borderColour: base.borderColour }
|
|
204
|
+
: {}),
|
|
205
|
+
});
|
|
206
|
+
}
|
|
183
207
|
}
|
|
184
208
|
resolveFile(assetPath, relativeTo) {
|
|
185
209
|
const normalized = normalizeAssetPath(assetPath);
|
|
@@ -218,6 +218,8 @@ function resolveTokenText(value, scenario, localisation, rowValues) {
|
|
|
218
218
|
const shortKey = key.slice(key.lastIndexOf('.') + 1);
|
|
219
219
|
const replacement = rowValues?.[key] ??
|
|
220
220
|
rowValues?.[shortKey] ??
|
|
221
|
+
scenario.values[key] ??
|
|
222
|
+
scenario.values[shortKey] ??
|
|
221
223
|
scenario.variables[key] ??
|
|
222
224
|
scenario.variables[shortKey] ??
|
|
223
225
|
scenario.scriptedGui[key] ??
|
|
@@ -235,7 +237,10 @@ function resolveTokenText(value, scenario, localisation, rowValues) {
|
|
|
235
237
|
if (key === 'X' || key === 'dynamic_loc')
|
|
236
238
|
return match[0];
|
|
237
239
|
const countryKey = key.replace(/^(?:ROOT|This)\./u, '');
|
|
238
|
-
const replacement = rowValues?.[
|
|
240
|
+
const replacement = rowValues?.[key] ??
|
|
241
|
+
rowValues?.[countryKey] ??
|
|
242
|
+
scenario.values[key] ??
|
|
243
|
+
scenario.values[countryKey] ??
|
|
239
244
|
scenario.country?.[countryKey] ??
|
|
240
245
|
scenario.stateValues?.[countryKey] ??
|
|
241
246
|
scenario.scriptedGui[key];
|
|
@@ -247,6 +252,15 @@ function resolveTokenText(value, scenario, localisation, rowValues) {
|
|
|
247
252
|
}, 'GUI scope substitution');
|
|
248
253
|
return { text, unresolved: [...new Set(unresolved)].sort(), missingLocalisation };
|
|
249
254
|
}
|
|
255
|
+
function scenarioExpressionValue(expression, values) {
|
|
256
|
+
if (typeof expression !== 'string')
|
|
257
|
+
return undefined;
|
|
258
|
+
const variableMatch = /^\[\?([^\]|]+)(?:\|[^\]]+)?\]$/u.exec(expression);
|
|
259
|
+
const localisationMatch = /^\[([^\]]+)\]$/u.exec(expression);
|
|
260
|
+
const token = variableMatch?.[1] ?? localisationMatch?.[1] ?? expression;
|
|
261
|
+
const shortToken = token.slice(token.lastIndexOf('.') + 1);
|
|
262
|
+
return values[token] ?? values[shortToken];
|
|
263
|
+
}
|
|
250
264
|
function measureTextWithInlineIcons(catalog, fontName, text, fontSize, inlineIcons) {
|
|
251
265
|
if (inlineIcons.size === 0 || ![...inlineIcons.keys()].some((marker) => text.includes(marker)))
|
|
252
266
|
return catalog.measureText(fontName, text, fontSize);
|
|
@@ -432,7 +446,7 @@ function wrapText(catalog, fontName, text, colours, fontSize, maximumWidth, work
|
|
|
432
446
|
missingGlyphs: [...missingGlyphs].sort((a, b) => a - b),
|
|
433
447
|
};
|
|
434
448
|
}
|
|
435
|
-
function colourRunsForLine(catalog, fontName, line, colours, fontSize, work, inlineIcons = new Map()) {
|
|
449
|
+
function colourRunsForLine(catalog, fontName, line, colours, fontSize, work, inlineIcons = new Map(), defaultColour = defaultTextColour) {
|
|
436
450
|
if (!colours.some((colour) => colour !== undefined) || line.length === 0)
|
|
437
451
|
return [];
|
|
438
452
|
const runs = [];
|
|
@@ -445,11 +459,11 @@ function colourRunsForLine(catalog, fontName, line, colours, fontSize, work, inl
|
|
|
445
459
|
start += 1;
|
|
446
460
|
continue;
|
|
447
461
|
}
|
|
448
|
-
const colour = colours[start] ??
|
|
462
|
+
const colour = colours[start] ?? defaultColour;
|
|
449
463
|
let end = start + 1;
|
|
450
464
|
while (end < line.length &&
|
|
451
465
|
!inlineIcons.has(line[end] ?? '') &&
|
|
452
|
-
(colours[end] ??
|
|
466
|
+
(colours[end] ?? defaultColour) === colour)
|
|
453
467
|
end += 1;
|
|
454
468
|
const text = line.slice(start, end);
|
|
455
469
|
work.spendTextLayout('localisation colour-run measurement');
|
|
@@ -465,7 +479,9 @@ function frameFor(element, sprite, scenario, rowValues) {
|
|
|
465
479
|
const selected = scenario.selectedFrames[element.name] ?? scenario.selectedFrames[sprite.name];
|
|
466
480
|
if (selected !== undefined)
|
|
467
481
|
return Math.min(frameCount - 1, selected);
|
|
468
|
-
const scriptedFrame = rowValues?.[`${element.name}.frame`] ??
|
|
482
|
+
const scriptedFrame = rowValues?.[`${element.name}.frame`] ??
|
|
483
|
+
scenario.values[`${element.name}.frame`] ??
|
|
484
|
+
scenario.scriptedGui[`${element.name}.frame`];
|
|
469
485
|
if (typeof scriptedFrame === 'number' && Number.isFinite(scriptedFrame))
|
|
470
486
|
return Math.min(frameCount - 1, Math.max(0, Math.trunc(scriptedFrame > 0 ? scriptedFrame - 1 : scriptedFrame)));
|
|
471
487
|
const explicit = scalarNumber(property(element.attributes, 'frame'), frameCount);
|
|
@@ -600,8 +616,12 @@ async function layoutElement(definition, parentRect, inheritedClip, parentScale,
|
|
|
600
616
|
const scale = parentScale * localScale;
|
|
601
617
|
const position = objectProperty(property(definition.attributes, 'position'));
|
|
602
618
|
const size = objectProperty(property(definition.attributes, 'size'));
|
|
603
|
-
const scriptedX = rowValues?.[`${definition.name}.x`] ??
|
|
604
|
-
|
|
619
|
+
const scriptedX = rowValues?.[`${definition.name}.x`] ??
|
|
620
|
+
scenario.values[`${definition.name}.x`] ??
|
|
621
|
+
scenario.scriptedGui[`${definition.name}.x`];
|
|
622
|
+
const scriptedY = rowValues?.[`${definition.name}.y`] ??
|
|
623
|
+
scenario.values[`${definition.name}.y`] ??
|
|
624
|
+
scenario.scriptedGui[`${definition.name}.y`];
|
|
605
625
|
const localX = (typeof scriptedX === 'number' && Number.isFinite(scriptedX)
|
|
606
626
|
? scriptedX * parentScale
|
|
607
627
|
: undefined) ??
|
|
@@ -617,6 +637,8 @@ async function layoutElement(definition, parentRect, inheritedClip, parentScale,
|
|
|
617
637
|
const background = objectProperty(property(definition.attributes, 'background'));
|
|
618
638
|
const scriptedImage = rowValues?.[`${definition.name}.image`] ??
|
|
619
639
|
rowValues?.[definition.name] ??
|
|
640
|
+
scenario.values[`${definition.name}.image`] ??
|
|
641
|
+
scenario.values[definition.name] ??
|
|
620
642
|
scenario.scriptedGui[`${definition.name}.image`] ??
|
|
621
643
|
scenario.scriptedGui[definition.name];
|
|
622
644
|
const spriteName = (typeof scriptedImage === 'string' && scriptedImage.length > 0 ? scriptedImage : undefined) ??
|
|
@@ -706,6 +728,8 @@ async function layoutElement(definition, parentRect, inheritedClip, parentScale,
|
|
|
706
728
|
addFidelity(fidelity, 'modelled', 'scripted_gui_position', `Scenario properties positioned ${definition.name} at ${localX},${localY} before anchoring.`, definition);
|
|
707
729
|
const rawButtonText = scalarString(property(definition.attributes, 'buttonText'));
|
|
708
730
|
const rawText = scalarString(property(definition.attributes, 'text')) ?? rawButtonText;
|
|
731
|
+
const embeddedButtonText = rawText !== undefined &&
|
|
732
|
+
(rawButtonText !== undefined || definition.elementType.toLowerCase().includes('button'));
|
|
709
733
|
let text;
|
|
710
734
|
if (rawText !== undefined) {
|
|
711
735
|
const resolved = resolveTokenText(rawText, scenario, context.localisation, rowValues);
|
|
@@ -719,6 +743,7 @@ async function layoutElement(definition, parentRect, inheritedClip, parentScale,
|
|
|
719
743
|
displayText = visibleText.text;
|
|
720
744
|
context.work.admitText(displayText, `GUI text for ${definition.name}`);
|
|
721
745
|
const fontName = scalarString(property(definition.attributes, 'font', 'buttonFont'));
|
|
746
|
+
const fontDefinition = fontName === undefined ? undefined : catalog.fontDefinition(fontName);
|
|
722
747
|
const resolvedFontMetrics = catalog.resolvedFontMetrics(fontName);
|
|
723
748
|
const explicitFontSize = scalarNumber(property(definition.attributes, 'fontSize'), 16);
|
|
724
749
|
const fontSize = explicitFontSize ??
|
|
@@ -768,7 +793,7 @@ async function layoutElement(definition, parentRect, inheritedClip, parentScale,
|
|
|
768
793
|
inlineIcons.push(...shaped.icons);
|
|
769
794
|
}
|
|
770
795
|
const colourRuns = visibleText.hasColourMarkup
|
|
771
|
-
? wrapped.lines.map((line, index) => colourRunsForLine(catalog, fontName, line, wrapped.colourLines[index] ?? [], fontSize * scale, context.work, resolvedInlineIcons))
|
|
796
|
+
? wrapped.lines.map((line, index) => colourRunsForLine(catalog, fontName, line, wrapped.colourLines[index] ?? [], fontSize * scale, context.work, resolvedInlineIcons, fontDefinition?.colour ?? defaultTextColour))
|
|
772
797
|
: undefined;
|
|
773
798
|
const maximumLineWidth = wrapped.widths.reduce((maximum, value) => Math.max(maximum, value), 0);
|
|
774
799
|
if (width === 0)
|
|
@@ -786,8 +811,12 @@ async function layoutElement(definition, parentRect, inheritedClip, parentScale,
|
|
|
786
811
|
measuredWidth,
|
|
787
812
|
measuredHeight,
|
|
788
813
|
metricSource: wrapped.metricSource,
|
|
789
|
-
...alignment(definition.attributes,
|
|
814
|
+
...alignment(definition.attributes, embeddedButtonText),
|
|
790
815
|
...(fontName === undefined ? {} : { fontName }),
|
|
816
|
+
...(fontDefinition?.colour === undefined ? {} : { colour: fontDefinition.colour }),
|
|
817
|
+
...(fontDefinition?.borderColour === undefined
|
|
818
|
+
? {}
|
|
819
|
+
: { borderColour: fontDefinition.borderColour }),
|
|
791
820
|
glyphLines,
|
|
792
821
|
overflowX: width > 0 && measuredWidth > width + 0.01,
|
|
793
822
|
overflowY: height > 0 && measuredHeight > height + 0.01,
|
|
@@ -800,6 +829,8 @@ async function layoutElement(definition, parentRect, inheritedClip, parentScale,
|
|
|
800
829
|
addFidelity(fidelity, 'approximated', 'font_metrics', `No supplied font metrics for ${fontName ?? '<default>'}.`, definition);
|
|
801
830
|
else
|
|
802
831
|
addFidelity(fidelity, 'modelled', 'font_metrics', `${wrapped.metricSource} metrics for ${fontName ?? '<default>'}.`, definition);
|
|
832
|
+
if (fontDefinition?.colour !== undefined || fontDefinition?.borderColour !== undefined)
|
|
833
|
+
addFidelity(fidelity, 'modelled', 'font_definition_style', `Font ${fontDefinition.name} uses its declared face and colour styling.`, definition);
|
|
803
834
|
const missingGlyphs = [
|
|
804
835
|
...new Set([...wrapped.missingGlyphs, ...glyphLines.flatMap((line) => line.missingGlyphs)]),
|
|
805
836
|
].slice(0, GUI_TEXT_MAX_MISSING_GLYPH_SAMPLES);
|
|
@@ -845,7 +876,9 @@ async function layoutElement(definition, parentRect, inheritedClip, parentScale,
|
|
|
845
876
|
const clipRect = inheritedClip;
|
|
846
877
|
const clipped = clipRect !== undefined &&
|
|
847
878
|
(availableClip === undefined || !equalRect(unclippedRect, availableClip));
|
|
848
|
-
const scriptedVisible = rowValues?.[`${definition.name}.visible`] ??
|
|
879
|
+
const scriptedVisible = rowValues?.[`${definition.name}.visible`] ??
|
|
880
|
+
scenario.values[`${definition.name}.visible`] ??
|
|
881
|
+
scenario.scriptedGui[`${definition.name}.visible`];
|
|
849
882
|
const explicitlyVisible = scenario.visibility[definition.name] ??
|
|
850
883
|
scenario.visibility[definition.id] ??
|
|
851
884
|
(typeof scriptedVisible === 'boolean' ? scriptedVisible : undefined);
|
|
@@ -853,6 +886,7 @@ async function layoutElement(definition, parentRect, inheritedClip, parentScale,
|
|
|
853
886
|
(explicitlyVisible ?? (availableClip !== undefined || inheritedClip === undefined));
|
|
854
887
|
const clickThrough = scalarBoolean(property(definition.attributes, 'clickThrough', 'alwaystransparent', 'allwaystransparent')) ?? false;
|
|
855
888
|
const scriptedEnabled = rowValues?.[`${definition.name}.enabled`] ??
|
|
889
|
+
scenario.values[`${definition.name}.enabled`] ??
|
|
856
890
|
scenario.scriptedGui[`${definition.name}.enabled`] ??
|
|
857
891
|
context.constantElementEnabled[definition.name];
|
|
858
892
|
const clickable = clickableTypes.test(definition.elementType) && !clickThrough && scriptedEnabled !== false;
|
|
@@ -862,7 +896,15 @@ async function layoutElement(definition, parentRect, inheritedClip, parentScale,
|
|
|
862
896
|
if (/progressbar/iu.test(definition.elementType)) {
|
|
863
897
|
const minimum = scalarNumber(property(definition.attributes, 'minValue'), 1) ?? 0;
|
|
864
898
|
const maximum = scalarNumber(property(definition.attributes, 'maxValue'), 1) ?? 100;
|
|
865
|
-
const
|
|
899
|
+
const startValueToken = scalarString(property(definition.attributes, 'startValue'));
|
|
900
|
+
const shortStartValueToken = startValueToken?.slice(startValueToken.lastIndexOf('.') + 1);
|
|
901
|
+
const scriptedValue = rowValues?.[definition.name] ??
|
|
902
|
+
scenario.values[definition.name] ??
|
|
903
|
+
(startValueToken === undefined ? undefined : scenario.values[startValueToken]) ??
|
|
904
|
+
(shortStartValueToken === undefined ? undefined : scenario.values[shortStartValueToken]) ??
|
|
905
|
+
(startValueToken === undefined ? undefined : scenario.variables[startValueToken]) ??
|
|
906
|
+
(shortStartValueToken === undefined ? undefined : scenario.variables[shortStartValueToken]) ??
|
|
907
|
+
scenario.scriptedGui[definition.name];
|
|
866
908
|
let value = typeof scriptedValue === 'number'
|
|
867
909
|
? scriptedValue
|
|
868
910
|
: (scalarNumber(property(definition.attributes, 'startValue'), maximum) ?? minimum);
|
|
@@ -1085,10 +1127,25 @@ export async function buildGuiScene(graph, scannedFiles, windowName, scenario, c
|
|
|
1085
1127
|
const scriptedWindowVisibility = {};
|
|
1086
1128
|
const constantElementVisibility = {};
|
|
1087
1129
|
const constantElementEnabled = {};
|
|
1130
|
+
const resolvedScriptedProperties = {};
|
|
1088
1131
|
const dynamicListsByName = new Map();
|
|
1089
1132
|
for (const scripted of graph.scriptedGuis.filter(({ name }) => relevantScriptedGuiNames.has(name))) {
|
|
1090
1133
|
for (const dynamicList of scripted.dynamicListDefinitions)
|
|
1091
1134
|
dynamicListsByName.set(dynamicList.name, dynamicList);
|
|
1135
|
+
for (const propertyDefinition of scripted.propertyDefinitions) {
|
|
1136
|
+
for (const [attribute, expression] of Object.entries(propertyDefinition.attributes)) {
|
|
1137
|
+
const suffix = attribute.toLowerCase();
|
|
1138
|
+
if (!['image', 'frame', 'x', 'y', 'visible', 'enabled'].includes(suffix))
|
|
1139
|
+
continue;
|
|
1140
|
+
const resolved = scenarioExpressionValue(expression, scenario.values);
|
|
1141
|
+
if (resolved === undefined)
|
|
1142
|
+
continue;
|
|
1143
|
+
const key = `${propertyDefinition.elementName}.${suffix}`;
|
|
1144
|
+
if (scenario.values[key] === undefined)
|
|
1145
|
+
resolvedScriptedProperties[key] = resolved;
|
|
1146
|
+
addFidelity(fidelity, 'modelled', 'scripted_gui_scenario_property', `${key} resolved from a scenario runtime value.`);
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1092
1149
|
for (const trigger of scripted.triggerDefinitions) {
|
|
1093
1150
|
if (trigger.constantResult === undefined)
|
|
1094
1151
|
continue;
|
|
@@ -1101,7 +1158,9 @@ export async function buildGuiScene(graph, scannedFiles, windowName, scenario, c
|
|
|
1101
1158
|
addFidelity(fidelity, 'modelled', 'scripted_gui_context', `${scripted.name} uses ${scripted.contextType ?? '<unspecified>'} context.`);
|
|
1102
1159
|
if (scripted.visibleExpression === undefined)
|
|
1103
1160
|
continue;
|
|
1104
|
-
const mockedVisibility = scenario.visibility[scripted.name] ??
|
|
1161
|
+
const mockedVisibility = scenario.visibility[scripted.name] ??
|
|
1162
|
+
scenario.values[`${scripted.name}.visible`] ??
|
|
1163
|
+
scenario.scriptedGui[`${scripted.name}.visible`];
|
|
1105
1164
|
if (typeof mockedVisibility === 'boolean') {
|
|
1106
1165
|
if (scripted.windowName !== undefined)
|
|
1107
1166
|
scriptedWindowVisibility[scripted.windowName] =
|
|
@@ -1114,6 +1173,10 @@ export async function buildGuiScene(graph, scannedFiles, windowName, scenario, c
|
|
|
1114
1173
|
}
|
|
1115
1174
|
const layoutScenario = {
|
|
1116
1175
|
...scenario,
|
|
1176
|
+
values: {
|
|
1177
|
+
...resolvedScriptedProperties,
|
|
1178
|
+
...scenario.values,
|
|
1179
|
+
},
|
|
1117
1180
|
visibility: {
|
|
1118
1181
|
...scriptedWindowVisibility,
|
|
1119
1182
|
...constantElementVisibility,
|
|
@@ -62,6 +62,31 @@ function sceneGlyphDefinitions(scene) {
|
|
|
62
62
|
.map(([key, glyph]) => `<image id="${bitmapDefinitionId(key)}" width="${finite(glyph.width)}" height="${finite(glyph.height)}" href="${glyph.dataUri}" preserveAspectRatio="none"/>`),
|
|
63
63
|
].join('');
|
|
64
64
|
}
|
|
65
|
+
function colourMatrix(colour) {
|
|
66
|
+
const match = /^#([0-9a-f]{6})([0-9a-f]{2})?$/iu.exec(colour);
|
|
67
|
+
if (match === null)
|
|
68
|
+
return '1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0';
|
|
69
|
+
const rgb = match[1];
|
|
70
|
+
const alpha = match[2] ?? 'ff';
|
|
71
|
+
const component = (offset) => Number.parseInt(rgb.slice(offset, offset + 2), 16) / 255;
|
|
72
|
+
return `${finite(component(0))} 0 0 0 0 0 ${finite(component(2))} 0 0 0 0 0 ${finite(component(4))} 0 0 0 0 0 ${finite(Number.parseInt(alpha, 16) / 255)} 0`;
|
|
73
|
+
}
|
|
74
|
+
function bitmapTintDefinition(id, colour) {
|
|
75
|
+
return `<filter id="${id}" color-interpolation-filters="sRGB"><feColorMatrix type="matrix" values="${colourMatrix(colour)}"/></filter>`;
|
|
76
|
+
}
|
|
77
|
+
function actualGlyphMarkup(glyphLine, originX, baseline, horizontalScale) {
|
|
78
|
+
if (glyphLine.source === 'fontkit-path')
|
|
79
|
+
return glyphLine.glyphs
|
|
80
|
+
.filter((glyph) => glyph.kind === 'outline')
|
|
81
|
+
.map((glyph) => `<use href="#${outlineDefinitionId(glyph.key)}" transform="translate(${finite(originX + glyph.x * horizontalScale)} ${finite(baseline + glyph.y)}) scale(${finite(glyph.scale * horizontalScale)} ${finite(-glyph.scale)})"/>`)
|
|
82
|
+
.join('');
|
|
83
|
+
if (glyphLine.source === 'bmfont-atlas')
|
|
84
|
+
return glyphLine.glyphs
|
|
85
|
+
.filter((glyph) => glyph.kind === 'bitmap')
|
|
86
|
+
.map((glyph) => `<use href="#${bitmapDefinitionId(glyph.key)}" transform="translate(${finite(originX + glyph.x * horizontalScale)} ${finite(baseline + glyph.y - glyphLine.baseline)}) scale(${finite(horizontalScale)} 1)"/>`)
|
|
87
|
+
.join('');
|
|
88
|
+
return '';
|
|
89
|
+
}
|
|
65
90
|
function renderText(element, toolText) {
|
|
66
91
|
const text = element.text;
|
|
67
92
|
if (text === undefined || text.lines.length === 0)
|
|
@@ -102,6 +127,25 @@ function renderText(element, toolText) {
|
|
|
102
127
|
})
|
|
103
128
|
.join('');
|
|
104
129
|
const colourRuns = text.colourRuns?.[index] ?? [];
|
|
130
|
+
if (colourRuns.length > 0 &&
|
|
131
|
+
glyphLine !== undefined &&
|
|
132
|
+
glyphLine.source !== 'deterministic-fallback') {
|
|
133
|
+
const definitions = [];
|
|
134
|
+
const renderedRuns = colourRuns.map((run, runIndex) => {
|
|
135
|
+
const key = `${element.id}:${index}:${runIndex}:${run.colour}`;
|
|
136
|
+
const clipId = `gui-font-run-clip-${sha256Bytes(key).slice(0, 20)}`;
|
|
137
|
+
const runX = originX + run.offsetX * horizontalScale;
|
|
138
|
+
definitions.push(`<clipPath id="${clipId}"><rect x="${finite(runX - 0.25)}" y="${finite(lineTop)}" width="${finite(run.width * horizontalScale + 0.5)}" height="${finite(text.lineHeight)}"/></clipPath>`);
|
|
139
|
+
const glyphs = actualGlyphMarkup(glyphLine, originX, baseline, horizontalScale);
|
|
140
|
+
if (glyphLine.source === 'bmfont-atlas') {
|
|
141
|
+
const filterId = `gui-font-tint-${sha256Bytes(key).slice(0, 20)}`;
|
|
142
|
+
definitions.push(bitmapTintDefinition(filterId, run.colour));
|
|
143
|
+
return `<g clip-path="url(#${clipId})" filter="url(#${filterId})" data-font-colour="${run.colour}">${glyphs}</g>`;
|
|
144
|
+
}
|
|
145
|
+
return `<g clip-path="url(#${clipId})" fill="${run.colour}" stroke="${text.borderColour ?? '#12151a'}" data-font-colour="${run.colour}">${glyphs}</g>`;
|
|
146
|
+
});
|
|
147
|
+
return `<g data-hoi4-colour-runs="true" data-font-sha256="${glyphLine.sourceHash}"><defs>${definitions.join('')}</defs>${renderedRuns.join('')}${inlineIconMarkup}</g>`;
|
|
148
|
+
}
|
|
105
149
|
if (colourRuns.length > 0) {
|
|
106
150
|
return `<g data-hoi4-colour-runs="true">${colourRuns
|
|
107
151
|
.map((run) => toolText.render(run.text, {
|
|
@@ -109,31 +153,29 @@ function renderText(element, toolText) {
|
|
|
109
153
|
y: baseline,
|
|
110
154
|
fontSize: text.fontSize,
|
|
111
155
|
fill: run.colour,
|
|
112
|
-
stroke: '#12151a',
|
|
156
|
+
stroke: text.borderColour ?? '#12151a',
|
|
113
157
|
strokeWidth: 0.6,
|
|
114
158
|
...(run.width > 0 ? { targetWidth: run.width * horizontalScale } : {}),
|
|
115
159
|
}))
|
|
116
160
|
.join('')}${inlineIconMarkup}</g>`;
|
|
117
161
|
}
|
|
118
162
|
if (glyphLine?.source === 'fontkit-path') {
|
|
119
|
-
return `<g data-font-sha256="${glyphLine.sourceHash}">${glyphLine
|
|
120
|
-
.filter((glyph) => glyph.kind === 'outline')
|
|
121
|
-
.map((glyph) => `<use href="#${outlineDefinitionId(glyph.key)}" transform="translate(${finite(originX + glyph.x * horizontalScale)} ${finite(baseline + glyph.y)}) scale(${finite(glyph.scale * horizontalScale)} ${finite(-glyph.scale)})"/>`)
|
|
122
|
-
.join('')}${inlineIconMarkup}</g>`;
|
|
163
|
+
return `<g data-font-sha256="${glyphLine.sourceHash}" fill="${text.colour ?? '#f5f2e8'}" stroke="${text.borderColour ?? '#12151a'}" data-font-colour="${text.colour ?? '#f5f2e8'}">${actualGlyphMarkup(glyphLine, originX, baseline, horizontalScale)}${inlineIconMarkup}</g>`;
|
|
123
164
|
}
|
|
124
165
|
if (glyphLine?.source === 'bmfont-atlas') {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
166
|
+
const glyphs = actualGlyphMarkup(glyphLine, originX, baseline, horizontalScale);
|
|
167
|
+
if (text.colour === undefined)
|
|
168
|
+
return `<g data-font-sha256="${glyphLine.sourceHash}">${glyphs}${inlineIconMarkup}</g>`;
|
|
169
|
+
const filterId = `gui-font-tint-${sha256Bytes(`${element.id}:${index}:${text.colour}`).slice(0, 20)}`;
|
|
170
|
+
return `<g data-font-sha256="${glyphLine.sourceHash}" data-font-colour="${text.colour}"><defs>${bitmapTintDefinition(filterId, text.colour)}</defs><g filter="url(#${filterId})">${glyphs}</g>${inlineIconMarkup}</g>`;
|
|
129
171
|
}
|
|
130
172
|
const visibleLine = line.replace(/[\uE000-\uF8FF]/gu, ' ');
|
|
131
173
|
return `<g>${toolText.render(visibleLine, {
|
|
132
174
|
x: originX,
|
|
133
175
|
y: baseline,
|
|
134
176
|
fontSize: text.fontSize,
|
|
135
|
-
fill: '#f5f2e8',
|
|
136
|
-
stroke: '#12151a',
|
|
177
|
+
fill: text.colour ?? '#f5f2e8',
|
|
178
|
+
stroke: text.borderColour ?? '#12151a',
|
|
137
179
|
strokeWidth: 0.6,
|
|
138
180
|
...(width > 0 ? { targetWidth: width } : {}),
|
|
139
181
|
})}${inlineIconMarkup}</g>`;
|
|
@@ -118,6 +118,7 @@ const GuiPreviewScenarioBodySchema = z
|
|
|
118
118
|
flags: z.record(z.string(), z.boolean()).default({}),
|
|
119
119
|
lists: z.record(z.string(), z.array(objectSchema).max(10_000)).default({}),
|
|
120
120
|
localisation: z.record(z.string(), z.string()).default({}),
|
|
121
|
+
values: objectSchema.default({}),
|
|
121
122
|
scriptedGui: objectSchema.default({}),
|
|
122
123
|
visibility: z.record(z.string(), z.boolean()).default({}),
|
|
123
124
|
elementStates: z.record(z.string(), previewStateSchema).default({}),
|
|
@@ -188,6 +188,15 @@ function boolScalar(block, ...keys) {
|
|
|
188
188
|
return false;
|
|
189
189
|
return undefined;
|
|
190
190
|
}
|
|
191
|
+
function paradoxColour(value) {
|
|
192
|
+
if (value === undefined)
|
|
193
|
+
return undefined;
|
|
194
|
+
const match = /^0x([0-9a-f]{8})$/iu.exec(value.trim());
|
|
195
|
+
if (match === null)
|
|
196
|
+
return undefined;
|
|
197
|
+
const argb = match[1];
|
|
198
|
+
return `#${argb.slice(2)}${argb.slice(0, 2)}`.toLowerCase();
|
|
199
|
+
}
|
|
191
200
|
function sizeFrom(block) {
|
|
192
201
|
const size = childBlocks(block, 'size')[0];
|
|
193
202
|
if (size === undefined)
|
|
@@ -425,6 +434,8 @@ function indexSpritesAndFonts(document, file, fileNodeId, nodes, edges, sprites,
|
|
|
425
434
|
const languages = childBlocks(child, 'languages').flatMap((languageBlock) => languageBlock.entries
|
|
426
435
|
.filter((entry) => entry.type === 'scalar')
|
|
427
436
|
.map((entry) => entry.value));
|
|
437
|
+
const colour = paradoxColour(firstScalarInsensitive(child, 'color', 'colour'));
|
|
438
|
+
const borderColour = paradoxColour(firstScalarInsensitive(child, 'border_color', 'borderColor', 'border_colour'));
|
|
428
439
|
const id = deterministicId('gui_font', { path: file.displayPath, name });
|
|
429
440
|
const font = {
|
|
430
441
|
id,
|
|
@@ -435,6 +446,8 @@ function indexSpritesAndFonts(document, file, fileNodeId, nodes, edges, sprites,
|
|
|
435
446
|
override: assignment.key.value === 'bitmapfont_override',
|
|
436
447
|
languages,
|
|
437
448
|
assetPaths,
|
|
449
|
+
...(colour === undefined ? {} : { colour }),
|
|
450
|
+
...(borderColour === undefined ? {} : { borderColour }),
|
|
438
451
|
rawSource: raw(document, assignment),
|
|
439
452
|
};
|
|
440
453
|
addDomainEntry(fonts, font, 'font');
|
|
@@ -449,6 +462,8 @@ function indexSpritesAndFonts(document, file, fileNodeId, nodes, edges, sprites,
|
|
|
449
462
|
override: font.override,
|
|
450
463
|
languages,
|
|
451
464
|
assetPaths,
|
|
465
|
+
...(colour === undefined ? {} : { colour }),
|
|
466
|
+
...(borderColour === undefined ? {} : { borderColour }),
|
|
452
467
|
},
|
|
453
468
|
});
|
|
454
469
|
addEdge(edges, 'contains', fileNodeId, id, true, {}, font.location);
|
|
@@ -531,7 +546,16 @@ function indexScriptedGuis(document, file, fileNodeId, nodes, edges, scriptedGui
|
|
|
531
546
|
};
|
|
532
547
|
});
|
|
533
548
|
const triggers = triggerDefinitions.map(({ name: trigger }) => trigger);
|
|
534
|
-
const
|
|
549
|
+
const propertyAssignments = namedAssignments(block, 'properties');
|
|
550
|
+
const properties = propertyAssignments.map(({ key }) => key.value);
|
|
551
|
+
const propertyDefinitions = propertyAssignments.map((property) => ({
|
|
552
|
+
elementName: property.key.value,
|
|
553
|
+
attributes: property.value.type === 'block'
|
|
554
|
+
? sourceValueToProperty(property.value, constantsFor(document))
|
|
555
|
+
: {},
|
|
556
|
+
rawSource: raw(document, property),
|
|
557
|
+
location: nodeLocation(document, property, property.key.value),
|
|
558
|
+
}));
|
|
535
559
|
const dynamicListDefinitions = namedAssignments(block, 'dynamic_lists').map((dynamicList) => {
|
|
536
560
|
const entryContainer = dynamicList.value.type === 'block'
|
|
537
561
|
? firstScalarInsensitive(dynamicList.value, 'entry_container')
|
|
@@ -571,6 +595,7 @@ function indexScriptedGuis(document, file, fileNodeId, nodes, edges, scriptedGui
|
|
|
571
595
|
triggers: triggers.sort((a, b) => compareCodeUnits(a, b)),
|
|
572
596
|
triggerDefinitions: triggerDefinitions.sort((a, b) => compareCodeUnits(a.name, b.name)),
|
|
573
597
|
properties: properties.sort((a, b) => compareCodeUnits(a, b)),
|
|
598
|
+
propertyDefinitions: propertyDefinitions.sort((a, b) => compareCodeUnits(a.elementName, b.elementName)),
|
|
574
599
|
dynamicLists: dynamicLists.sort((a, b) => compareCodeUnits(a, b)),
|
|
575
600
|
dynamicListDefinitions: dynamicListDefinitions.sort((left, right) => compareCodeUnits(left.name, right.name)),
|
|
576
601
|
aiWeights: aiWeights.sort((a, b) => compareCodeUnits(a, b)),
|
|
@@ -379,7 +379,7 @@ function referencedAssetPatternsForWindow(graph, windowName, additionalSpriteNam
|
|
|
379
379
|
}
|
|
380
380
|
function scenarioSpriteNames(scenarios) {
|
|
381
381
|
return [
|
|
382
|
-
...new Set(scenarios.flatMap(({ scriptedGui }) => Object.entries(scriptedGui)
|
|
382
|
+
...new Set(scenarios.flatMap(({ values, scriptedGui }) => Object.entries({ ...scriptedGui, ...values })
|
|
383
383
|
.filter(([key, value]) => typeof value === 'string' &&
|
|
384
384
|
value.startsWith('GFX_') &&
|
|
385
385
|
(key.endsWith('.image') || !key.includes('.')))
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { LATEST_PROTOCOL_VERSION } from '@modelcontextprotocol/sdk/types.js';
|
|
2
2
|
export const PACKAGE_NAME = 'hoi4-agent-tools';
|
|
3
|
-
export const PACKAGE_VERSION = '2.8.
|
|
3
|
+
export const PACKAGE_VERSION = '2.8.4';
|
|
4
4
|
export const MCP_PROTOCOL_VERSION = LATEST_PROTOCOL_VERSION;
|
|
5
5
|
export const CONFIG_VERSION = 1;
|
|
6
6
|
export const TRANSACTION_VERSION = 1;
|
package/docs/gui.md
CHANGED
|
@@ -33,17 +33,23 @@ Inspection checks missing assets and localisation, invalid sizes, overlap, clipp
|
|
|
33
33
|
|
|
34
34
|
The renderer resolves sprites and fonts through the complete mod, dependency, and installed-game load order. Mod windows therefore render ordinary vanilla sprites, tiled vanilla panels, progress bars, masked shields, button frames, and localisation icons such as `£command_power` without copying game assets into the mod. Case differences in GFX and font identifiers do not prevent a valid asset from resolving.
|
|
35
35
|
|
|
36
|
-
Bitmap text uses the language-appropriate HOI4 font definition and its real glyph atlas. The default language uses the base font rather than an unrelated language override, and the renderer recognizes installed-game atlases whose filename omits a page suffix declared by the matching `.fnt` file.
|
|
36
|
+
Bitmap text uses the language-appropriate HOI4 font definition and its real glyph atlas. Header, serif, compact, typewriter, black, inverted, and other declared faces keep their own glyph shapes, native metrics, face colour, border colour, and language override. HOI4 localisation colour runs such as `§Y` and `§R` recolour those same native glyphs instead of switching to the tool font. The default language uses the base font rather than an unrelated language override, and the renderer recognizes installed-game atlases whose filename omits a page suffix declared by the matching `.fnt` file.
|
|
37
37
|
|
|
38
38
|
Layout follows Clausewitz orientation and element-origin anchors, including `CENTER_LEFT`, `CENTER_RIGHT`, `CENTER_UP`, `CENTER_DOWN`, `origo`, `centerposition`, inherited container coordinate origins, local scale, and both `%` and `%%` relative dimensions. Text boxes use native font metrics together with `maxWidth`, `maxHeight`, alignment, wrapping, and `fixedsize` clipping. Cornered tile sprites use fixed nine-slice borders and optional center tiling; progress bars composite their filled and background textures; masked shields composite their background and mask textures.
|
|
39
39
|
|
|
40
|
-
Scripted-GUI composition follows `parent_scripted_gui` chains even when the linked child window is a top-level sibling in the `.gui` file. Literal `always = yes` and `always = no` visibility and click-enabled blocks are applied automatically.
|
|
40
|
+
Scripted-GUI composition follows `parent_scripted_gui` chains even when the linked child window is a top-level sibling in the `.gui` file. Literal `always = yes` and `always = no` visibility and click-enabled blocks are applied automatically. A scenario's `values` object supplies concrete runtime values in one place: variable names resolve numeric text, scripted-localisation names resolve dynamic labels, a progress-bar element name sets its fill value, and element keys ending in `.image`, `.frame`, `.x`, `.y`, `.visible`, or `.enabled` update that visual property. Scripted-GUI property expressions such as `image = "[GetMeterSprite]"` or `x = meter_fill_width` consume matching scenario values automatically. Dynamic lists instantiate their declared `entry_container` or `country_scope_entry_container`; each scenario row can select the country template with `countryScope`, choose an explicit `entryContainer`, and provide row-scoped text, image, frame, position, visibility, and enabled values.
|
|
41
41
|
|
|
42
42
|
Preview scenarios can include exact layout expectations:
|
|
43
43
|
|
|
44
44
|
```json
|
|
45
45
|
{
|
|
46
46
|
"id": "populated-unlocked",
|
|
47
|
+
"values": {
|
|
48
|
+
"threat": 73,
|
|
49
|
+
"GetThreatLabel": "High",
|
|
50
|
+
"threat_meter": 73,
|
|
51
|
+
"confirm_button.enabled": true
|
|
52
|
+
},
|
|
47
53
|
"flags": { "panel_open": true },
|
|
48
54
|
"lists": { "target_list": [{ "id": 1, "label": "First target" }] },
|
|
49
55
|
"visibility": { "target_list": true, "confirm_button": true },
|
|
@@ -68,6 +74,6 @@ Large inspections, renders, and rewrites send periodic MCP progress heartbeats w
|
|
|
68
74
|
|
|
69
75
|
The renderer does not run the game engine. Each render includes a fidelity report that separates fields it models from fields it approximates, ignores, cannot resolve, or does not support. Treat that report as part of the review.
|
|
70
76
|
|
|
71
|
-
Unresolved numeric runtime values such as `[?variable|format]` render as `[X]`. Unresolved text-returning scripted or scoped localisation such as `[GetStatusText]`, `[FROM.GetName]`, and `[?leader_scope.GetName]` renders as `[dynamic_loc]`.
|
|
77
|
+
Unresolved numeric runtime values such as `[?variable|format]` render as `[X]`. Unresolved text-returning scripted or scoped localisation such as `[GetStatusText]`, `[FROM.GetName]`, and `[?leader_scope.GetName]` renders as `[dynamic_loc]`. Put `variable` or `GetStatusText` in the scenario's `values` object when the exact value matters; the same scenario can set the related meter or state-dependent controls. Supported HOI4 `§` localisation colour controls are applied to preview text and `§!` restores the default colour.
|
|
72
78
|
|
|
73
79
|
A rewrite stops if malformed or unsupported GUI script makes the requested change ambiguous. Frame-sheet animation, nine-slice tiling, progress composition, masking, and the primary and secondary textures referenced by vanilla GFX definitions render offline. Engine shader programs, hardcoded controls, and dynamic values that are not supplied by a scenario remain fidelity-report entries; an unexecuted shader never hides its resolved base texture.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hoi4-agent-tools",
|
|
3
3
|
"mcpName": "io.github.klimPaskov/hoi4-agent-tools",
|
|
4
|
-
"version": "2.8.
|
|
4
|
+
"version": "2.8.4",
|
|
5
5
|
"description": "Analyze HOI4 events, tech trees, AI weights, and MTTH; build focus trees, GUIs, and maps.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"license": "Apache-2.0",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.8.
|
|
2
|
+
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.8.4/schemas/configuration.schema.json",
|
|
3
3
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
4
4
|
"type": "object",
|
|
5
5
|
"properties": {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.8.
|
|
2
|
+
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.8.4/schemas/continuous-focus-palette.schema.json",
|
|
3
3
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
4
4
|
"type": "object",
|
|
5
5
|
"properties": {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.8.
|
|
2
|
+
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.8.4/schemas/custom-weighted-pool.schema.json",
|
|
3
3
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
4
4
|
"type": "object",
|
|
5
5
|
"properties": {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.8.
|
|
2
|
+
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.8.4/schemas/event-feature-manifest.schema.json",
|
|
3
3
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
4
4
|
"type": "object",
|
|
5
5
|
"properties": {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.8.
|
|
2
|
+
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.8.4/schemas/focus-plan.schema.json",
|
|
3
3
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
4
4
|
"type": "object",
|
|
5
5
|
"properties": {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.8.
|
|
2
|
+
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.8.4/schemas/focus-planning-sidecar.schema.json",
|
|
3
3
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
4
4
|
"type": "object",
|
|
5
5
|
"properties": {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.8.
|
|
2
|
+
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.8.4/schemas/gui-animation-source.schema.json",
|
|
3
3
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
4
4
|
"type": "object",
|
|
5
5
|
"properties": {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.8.
|
|
2
|
+
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.8.4/schemas/gui-helper.schema.json",
|
|
3
3
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
4
4
|
"type": "object",
|
|
5
5
|
"properties": {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.8.
|
|
2
|
+
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.8.4/schemas/gui-scenario.schema.json",
|
|
3
3
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
4
4
|
"type": "object",
|
|
5
5
|
"properties": {
|
|
@@ -45,29 +45,32 @@
|
|
|
45
45
|
"localisation": {
|
|
46
46
|
"$ref": "#/$defs/__schema17"
|
|
47
47
|
},
|
|
48
|
-
"
|
|
48
|
+
"values": {
|
|
49
49
|
"$ref": "#/$defs/__schema18"
|
|
50
50
|
},
|
|
51
|
-
"
|
|
51
|
+
"scriptedGui": {
|
|
52
52
|
"$ref": "#/$defs/__schema19"
|
|
53
53
|
},
|
|
54
|
-
"
|
|
54
|
+
"visibility": {
|
|
55
55
|
"$ref": "#/$defs/__schema20"
|
|
56
56
|
},
|
|
57
|
-
"
|
|
57
|
+
"elementStates": {
|
|
58
58
|
"$ref": "#/$defs/__schema21"
|
|
59
59
|
},
|
|
60
|
-
"
|
|
60
|
+
"selectedFrames": {
|
|
61
61
|
"$ref": "#/$defs/__schema22"
|
|
62
62
|
},
|
|
63
|
-
"
|
|
63
|
+
"scrollOffsets": {
|
|
64
64
|
"$ref": "#/$defs/__schema23"
|
|
65
65
|
},
|
|
66
|
-
"
|
|
66
|
+
"guiCosts": {
|
|
67
67
|
"$ref": "#/$defs/__schema24"
|
|
68
68
|
},
|
|
69
|
-
"
|
|
69
|
+
"scriptCosts": {
|
|
70
70
|
"$ref": "#/$defs/__schema25"
|
|
71
|
+
},
|
|
72
|
+
"expectations": {
|
|
73
|
+
"$ref": "#/$defs/__schema26"
|
|
71
74
|
}
|
|
72
75
|
},
|
|
73
76
|
"required": [
|
|
@@ -235,6 +238,10 @@
|
|
|
235
238
|
"$ref": "#/$defs/__schema12"
|
|
236
239
|
},
|
|
237
240
|
"__schema19": {
|
|
241
|
+
"default": {},
|
|
242
|
+
"$ref": "#/$defs/__schema12"
|
|
243
|
+
},
|
|
244
|
+
"__schema20": {
|
|
238
245
|
"default": {},
|
|
239
246
|
"type": "object",
|
|
240
247
|
"propertyNames": {
|
|
@@ -244,7 +251,7 @@
|
|
|
244
251
|
"type": "boolean"
|
|
245
252
|
}
|
|
246
253
|
},
|
|
247
|
-
"
|
|
254
|
+
"__schema21": {
|
|
248
255
|
"default": {},
|
|
249
256
|
"type": "object",
|
|
250
257
|
"propertyNames": {
|
|
@@ -254,7 +261,7 @@
|
|
|
254
261
|
"$ref": "#/$defs/__schema7"
|
|
255
262
|
}
|
|
256
263
|
},
|
|
257
|
-
"
|
|
264
|
+
"__schema22": {
|
|
258
265
|
"default": {},
|
|
259
266
|
"type": "object",
|
|
260
267
|
"propertyNames": {
|
|
@@ -266,7 +273,7 @@
|
|
|
266
273
|
"maximum": 9007199254740991
|
|
267
274
|
}
|
|
268
275
|
},
|
|
269
|
-
"
|
|
276
|
+
"__schema23": {
|
|
270
277
|
"default": {},
|
|
271
278
|
"type": "object",
|
|
272
279
|
"propertyNames": {
|
|
@@ -277,7 +284,7 @@
|
|
|
277
284
|
"minimum": 0
|
|
278
285
|
}
|
|
279
286
|
},
|
|
280
|
-
"
|
|
287
|
+
"__schema24": {
|
|
281
288
|
"default": {},
|
|
282
289
|
"type": "object",
|
|
283
290
|
"propertyNames": {
|
|
@@ -287,7 +294,7 @@
|
|
|
287
294
|
"type": "number"
|
|
288
295
|
}
|
|
289
296
|
},
|
|
290
|
-
"
|
|
297
|
+
"__schema25": {
|
|
291
298
|
"default": {},
|
|
292
299
|
"type": "object",
|
|
293
300
|
"propertyNames": {
|
|
@@ -297,7 +304,7 @@
|
|
|
297
304
|
"type": "number"
|
|
298
305
|
}
|
|
299
306
|
},
|
|
300
|
-
"
|
|
307
|
+
"__schema26": {
|
|
301
308
|
"default": {
|
|
302
309
|
"visible": [],
|
|
303
310
|
"hidden": [],
|
|
@@ -311,7 +318,7 @@
|
|
|
311
318
|
"maxItems": 10000,
|
|
312
319
|
"type": "array",
|
|
313
320
|
"items": {
|
|
314
|
-
"$ref": "#/$defs/
|
|
321
|
+
"$ref": "#/$defs/__schema27"
|
|
315
322
|
}
|
|
316
323
|
},
|
|
317
324
|
"hidden": {
|
|
@@ -319,33 +326,33 @@
|
|
|
319
326
|
"maxItems": 10000,
|
|
320
327
|
"type": "array",
|
|
321
328
|
"items": {
|
|
322
|
-
"$ref": "#/$defs/
|
|
329
|
+
"$ref": "#/$defs/__schema27"
|
|
323
330
|
}
|
|
324
331
|
},
|
|
325
332
|
"containedBy": {
|
|
326
333
|
"default": {},
|
|
327
334
|
"type": "object",
|
|
328
335
|
"propertyNames": {
|
|
329
|
-
"$ref": "#/$defs/
|
|
336
|
+
"$ref": "#/$defs/__schema27"
|
|
330
337
|
},
|
|
331
338
|
"additionalProperties": {
|
|
332
|
-
"$ref": "#/$defs/
|
|
339
|
+
"$ref": "#/$defs/__schema27"
|
|
333
340
|
}
|
|
334
341
|
},
|
|
335
342
|
"centeredOn": {
|
|
336
343
|
"default": {},
|
|
337
344
|
"type": "object",
|
|
338
345
|
"propertyNames": {
|
|
339
|
-
"$ref": "#/$defs/
|
|
346
|
+
"$ref": "#/$defs/__schema27"
|
|
340
347
|
},
|
|
341
348
|
"additionalProperties": {
|
|
342
|
-
"$ref": "#/$defs/
|
|
349
|
+
"$ref": "#/$defs/__schema27"
|
|
343
350
|
}
|
|
344
351
|
}
|
|
345
352
|
},
|
|
346
353
|
"additionalProperties": false
|
|
347
354
|
},
|
|
348
|
-
"
|
|
355
|
+
"__schema27": {
|
|
349
356
|
"type": "string",
|
|
350
357
|
"minLength": 1,
|
|
351
358
|
"maxLength": 256
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.8.
|
|
2
|
+
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.8.4/schemas/map-operation.schema.json",
|
|
3
3
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
4
4
|
"oneOf": [
|
|
5
5
|
{
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.8.
|
|
2
|
+
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.8.4/schemas/operation-result.schema.json",
|
|
3
3
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
4
4
|
"type": "object",
|
|
5
5
|
"properties": {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.8.
|
|
2
|
+
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.8.4/schemas/probability-analysis-result.schema.json",
|
|
3
3
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
4
4
|
"type": "object",
|
|
5
5
|
"properties": {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.8.
|
|
2
|
+
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.8.4/schemas/probability-compare-input.schema.json",
|
|
3
3
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
4
4
|
"type": "object",
|
|
5
5
|
"properties": {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.8.
|
|
2
|
+
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.8.4/schemas/probability-evaluate-input.schema.json",
|
|
3
3
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
4
4
|
"type": "object",
|
|
5
5
|
"properties": {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.8.
|
|
2
|
+
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.8.4/schemas/probability-inspect-input.schema.json",
|
|
3
3
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
4
4
|
"type": "object",
|
|
5
5
|
"properties": {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.8.
|
|
2
|
+
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.8.4/schemas/probability-render-input.schema.json",
|
|
3
3
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
4
4
|
"type": "object",
|
|
5
5
|
"properties": {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.8.
|
|
2
|
+
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.8.4/schemas/probability-scenario-set.schema.json",
|
|
3
3
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
4
4
|
"type": "object",
|
|
5
5
|
"properties": {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.8.
|
|
2
|
+
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.8.4/schemas/probability-sequence-input.schema.json",
|
|
3
3
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
4
4
|
"type": "object",
|
|
5
5
|
"properties": {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.8.
|
|
2
|
+
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.8.4/schemas/probability-simulate-input.schema.json",
|
|
3
3
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
4
4
|
"type": "object",
|
|
5
5
|
"properties": {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.8.
|
|
2
|
+
"$id": "https://github.com/klimPaskov/hoi4-agent-tools/blob/v2.8.4/schemas/probability-sweep-input.schema.json",
|
|
3
3
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
4
4
|
"type": "object",
|
|
5
5
|
"properties": {
|
package/server.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"name": "io.github.klimPaskov/hoi4-agent-tools",
|
|
4
4
|
"title": "HOI4 Agent Tools",
|
|
5
5
|
"description": "Analyze HOI4 events, tech trees, AI weights, and MTTH; build focus trees, GUIs, and maps.",
|
|
6
|
-
"version": "2.8.
|
|
6
|
+
"version": "2.8.4",
|
|
7
7
|
"repository": {
|
|
8
8
|
"url": "https://github.com/klimPaskov/hoi4-agent-tools",
|
|
9
9
|
"source": "github"
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
{
|
|
14
14
|
"registryType": "npm",
|
|
15
15
|
"identifier": "hoi4-agent-tools",
|
|
16
|
-
"version": "2.8.
|
|
16
|
+
"version": "2.8.4",
|
|
17
17
|
"transport": {
|
|
18
18
|
"type": "stdio"
|
|
19
19
|
}
|