hoi4-agent-tools 2.8.1 → 2.8.3
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 +13 -0
- package/dist/hoi4_agent_tools/core/artifacts.js +126 -4
- package/dist/hoi4_agent_tools/core/index.js +3 -1
- package/dist/hoi4_agent_tools/core/scanner.js +43 -2
- package/dist/hoi4_agent_tools/gui/assets.js +63 -14
- package/dist/hoi4_agent_tools/gui/inspection-artifact.js +85 -14
- package/dist/hoi4_agent_tools/gui/layout.js +234 -27
- package/dist/hoi4_agent_tools/gui/scenario.js +1 -0
- package/dist/hoi4_agent_tools/gui/source-graph.js +116 -7
- package/dist/hoi4_agent_tools/gui/studio.js +166 -34
- package/dist/hoi4_agent_tools/gui/validators.js +47 -27
- package/dist/hoi4_agent_tools/mcp/server/progress.js +3 -0
- package/dist/hoi4_agent_tools/version.js +1 -1
- package/docs/gui.md +11 -1
- 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
|
@@ -213,9 +213,17 @@ function resolveTokenText(value, scenario, localisation, rowValues) {
|
|
|
213
213
|
}
|
|
214
214
|
return replacement;
|
|
215
215
|
}, 'GUI localisation substitution');
|
|
216
|
-
text = replaceTextBounded(text, /\[\?([
|
|
216
|
+
text = replaceTextBounded(text, /\[\?([^\]|]+)(?:\|[^\]]+)?\]/gu, (match) => {
|
|
217
217
|
const key = match[1] ?? '';
|
|
218
|
-
const
|
|
218
|
+
const shortKey = key.slice(key.lastIndexOf('.') + 1);
|
|
219
|
+
const replacement = rowValues?.[key] ??
|
|
220
|
+
rowValues?.[shortKey] ??
|
|
221
|
+
scenario.values[key] ??
|
|
222
|
+
scenario.values[shortKey] ??
|
|
223
|
+
scenario.variables[key] ??
|
|
224
|
+
scenario.variables[shortKey] ??
|
|
225
|
+
scenario.scriptedGui[key] ??
|
|
226
|
+
scenario.scriptedGui[shortKey];
|
|
219
227
|
if (replacement === undefined) {
|
|
220
228
|
unresolved.push(match[0]);
|
|
221
229
|
return /(?:^|\.)Get[A-Za-z0-9_]+$/u.test(key)
|
|
@@ -229,7 +237,10 @@ function resolveTokenText(value, scenario, localisation, rowValues) {
|
|
|
229
237
|
if (key === 'X' || key === 'dynamic_loc')
|
|
230
238
|
return match[0];
|
|
231
239
|
const countryKey = key.replace(/^(?:ROOT|This)\./u, '');
|
|
232
|
-
const replacement = rowValues?.[
|
|
240
|
+
const replacement = rowValues?.[key] ??
|
|
241
|
+
rowValues?.[countryKey] ??
|
|
242
|
+
scenario.values[key] ??
|
|
243
|
+
scenario.values[countryKey] ??
|
|
233
244
|
scenario.country?.[countryKey] ??
|
|
234
245
|
scenario.stateValues?.[countryKey] ??
|
|
235
246
|
scenario.scriptedGui[key];
|
|
@@ -241,6 +252,15 @@ function resolveTokenText(value, scenario, localisation, rowValues) {
|
|
|
241
252
|
}, 'GUI scope substitution');
|
|
242
253
|
return { text, unresolved: [...new Set(unresolved)].sort(), missingLocalisation };
|
|
243
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
|
+
}
|
|
244
264
|
function measureTextWithInlineIcons(catalog, fontName, text, fontSize, inlineIcons) {
|
|
245
265
|
if (inlineIcons.size === 0 || ![...inlineIcons.keys()].some((marker) => text.includes(marker)))
|
|
246
266
|
return catalog.measureText(fontName, text, fontSize);
|
|
@@ -454,11 +474,16 @@ function colourRunsForLine(catalog, fontName, line, colours, fontSize, work, inl
|
|
|
454
474
|
}
|
|
455
475
|
return runs;
|
|
456
476
|
}
|
|
457
|
-
function frameFor(element, sprite, scenario) {
|
|
477
|
+
function frameFor(element, sprite, scenario, rowValues) {
|
|
458
478
|
const frameCount = Math.max(1, sprite.frameCount);
|
|
459
479
|
const selected = scenario.selectedFrames[element.name] ?? scenario.selectedFrames[sprite.name];
|
|
460
480
|
if (selected !== undefined)
|
|
461
481
|
return Math.min(frameCount - 1, selected);
|
|
482
|
+
const scriptedFrame = rowValues?.[`${element.name}.frame`] ??
|
|
483
|
+
scenario.values[`${element.name}.frame`] ??
|
|
484
|
+
scenario.scriptedGui[`${element.name}.frame`];
|
|
485
|
+
if (typeof scriptedFrame === 'number' && Number.isFinite(scriptedFrame))
|
|
486
|
+
return Math.min(frameCount - 1, Math.max(0, Math.trunc(scriptedFrame > 0 ? scriptedFrame - 1 : scriptedFrame)));
|
|
462
487
|
const explicit = scalarNumber(property(element.attributes, 'frame'), frameCount);
|
|
463
488
|
if (explicit !== undefined)
|
|
464
489
|
return Math.min(frameCount - 1, Math.max(0, Math.trunc(explicit > 0 ? explicit - 1 : explicit)));
|
|
@@ -583,7 +608,7 @@ class GuiSceneWorkBudget {
|
|
|
583
608
|
this.textLayoutOperations += amount;
|
|
584
609
|
}
|
|
585
610
|
}
|
|
586
|
-
async function layoutElement(definition, parentRect, inheritedClip, parentScale, depth, context, instanceSuffix = '', rowIndex, rowValues, parentInstanceId, inheritedOrientation = 'upper_left') {
|
|
611
|
+
async function layoutElement(definition, parentRect, inheritedClip, parentScale, depth, context, instanceSuffix = '', rowIndex, rowValues, parentInstanceId, inheritedOrientation = 'upper_left', inheritedVisible = true) {
|
|
587
612
|
context.work.admitElement(depth);
|
|
588
613
|
const { scenario, catalog, fidelity, diagnostics } = context;
|
|
589
614
|
const instanceId = instanceSuffix.length === 0 ? definition.id : `${definition.id}${instanceSuffix}`;
|
|
@@ -591,12 +616,33 @@ async function layoutElement(definition, parentRect, inheritedClip, parentScale,
|
|
|
591
616
|
const scale = parentScale * localScale;
|
|
592
617
|
const position = objectProperty(property(definition.attributes, 'position'));
|
|
593
618
|
const size = objectProperty(property(definition.attributes, 'size'));
|
|
594
|
-
const
|
|
595
|
-
|
|
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`];
|
|
625
|
+
const localX = (typeof scriptedX === 'number' && Number.isFinite(scriptedX)
|
|
626
|
+
? scriptedX * parentScale
|
|
627
|
+
: undefined) ??
|
|
628
|
+
scaledNumber(position === undefined ? undefined : property(position, 'x'), parentRect.width, parentScale) ??
|
|
629
|
+
0;
|
|
630
|
+
const localY = (typeof scriptedY === 'number' && Number.isFinite(scriptedY)
|
|
631
|
+
? scriptedY * parentScale
|
|
632
|
+
: undefined) ??
|
|
633
|
+
scaledNumber(position === undefined ? undefined : property(position, 'y'), parentRect.height, parentScale) ??
|
|
634
|
+
0;
|
|
596
635
|
let width = scaledNumber(size === undefined ? undefined : property(size, 'width', 'x'), parentRect.width, scale) ?? 0;
|
|
597
636
|
let height = scaledNumber(size === undefined ? undefined : property(size, 'height', 'y'), parentRect.height, scale) ?? 0;
|
|
598
637
|
const background = objectProperty(property(definition.attributes, 'background'));
|
|
599
|
-
const
|
|
638
|
+
const scriptedImage = rowValues?.[`${definition.name}.image`] ??
|
|
639
|
+
rowValues?.[definition.name] ??
|
|
640
|
+
scenario.values[`${definition.name}.image`] ??
|
|
641
|
+
scenario.values[definition.name] ??
|
|
642
|
+
scenario.scriptedGui[`${definition.name}.image`] ??
|
|
643
|
+
scenario.scriptedGui[definition.name];
|
|
644
|
+
const spriteName = (typeof scriptedImage === 'string' && scriptedImage.length > 0 ? scriptedImage : undefined) ??
|
|
645
|
+
scalarString(property(definition.attributes, 'spriteType', 'quadTextureSprite')) ??
|
|
600
646
|
scalarString(background === undefined
|
|
601
647
|
? undefined
|
|
602
648
|
: property(background, 'spriteType', 'quadTextureSprite'));
|
|
@@ -632,7 +678,7 @@ async function layoutElement(definition, parentRect, inheritedClip, parentScale,
|
|
|
632
678
|
}
|
|
633
679
|
if (partialAppearance.length > 0)
|
|
634
680
|
diagnostics.push(diagnostic('GUI_SPRITE_RENDER_PARTIAL', 'warning', `Element ${definition.name} has a partial sprite appearance: ${partialAppearance.join(' ')}`, definition));
|
|
635
|
-
const frame = frameFor(definition, spriteDefinition, scenario);
|
|
681
|
+
const frame = frameFor(definition, spriteDefinition, scenario, rowValues);
|
|
636
682
|
sprite = await catalog.loadSpriteFrame(spriteDefinition, frame);
|
|
637
683
|
if (spriteDefinition.texturePath2 !== undefined)
|
|
638
684
|
secondarySprite = await catalog.loadSecondarySpriteFrame(spriteDefinition, frame);
|
|
@@ -676,8 +722,14 @@ async function layoutElement(definition, parentRect, inheritedClip, parentScale,
|
|
|
676
722
|
}
|
|
677
723
|
}
|
|
678
724
|
}
|
|
725
|
+
if (typeof scriptedImage === 'string' && scriptedImage.length > 0)
|
|
726
|
+
addFidelity(fidelity, 'modelled', 'scripted_gui_image', `Scenario property selected ${scriptedImage} for ${definition.name}.`, definition);
|
|
727
|
+
if (typeof scriptedX === 'number' || typeof scriptedY === 'number')
|
|
728
|
+
addFidelity(fidelity, 'modelled', 'scripted_gui_position', `Scenario properties positioned ${definition.name} at ${localX},${localY} before anchoring.`, definition);
|
|
679
729
|
const rawButtonText = scalarString(property(definition.attributes, 'buttonText'));
|
|
680
730
|
const rawText = scalarString(property(definition.attributes, 'text')) ?? rawButtonText;
|
|
731
|
+
const embeddedButtonText = rawText !== undefined &&
|
|
732
|
+
(rawButtonText !== undefined || definition.elementType.toLowerCase().includes('button'));
|
|
681
733
|
let text;
|
|
682
734
|
if (rawText !== undefined) {
|
|
683
735
|
const resolved = resolveTokenText(rawText, scenario, context.localisation, rowValues);
|
|
@@ -758,7 +810,7 @@ async function layoutElement(definition, parentRect, inheritedClip, parentScale,
|
|
|
758
810
|
measuredWidth,
|
|
759
811
|
measuredHeight,
|
|
760
812
|
metricSource: wrapped.metricSource,
|
|
761
|
-
...alignment(definition.attributes,
|
|
813
|
+
...alignment(definition.attributes, embeddedButtonText),
|
|
762
814
|
...(fontName === undefined ? {} : { fontName }),
|
|
763
815
|
glyphLines,
|
|
764
816
|
overflowX: width > 0 && measuredWidth > width + 0.01,
|
|
@@ -817,17 +869,35 @@ async function layoutElement(definition, parentRect, inheritedClip, parentScale,
|
|
|
817
869
|
const clipRect = inheritedClip;
|
|
818
870
|
const clipped = clipRect !== undefined &&
|
|
819
871
|
(availableClip === undefined || !equalRect(unclippedRect, availableClip));
|
|
820
|
-
const
|
|
821
|
-
|
|
872
|
+
const scriptedVisible = rowValues?.[`${definition.name}.visible`] ??
|
|
873
|
+
scenario.values[`${definition.name}.visible`] ??
|
|
874
|
+
scenario.scriptedGui[`${definition.name}.visible`];
|
|
875
|
+
const explicitlyVisible = scenario.visibility[definition.name] ??
|
|
876
|
+
scenario.visibility[definition.id] ??
|
|
877
|
+
(typeof scriptedVisible === 'boolean' ? scriptedVisible : undefined);
|
|
878
|
+
const visible = inheritedVisible &&
|
|
879
|
+
(explicitlyVisible ?? (availableClip !== undefined || inheritedClip === undefined));
|
|
822
880
|
const clickThrough = scalarBoolean(property(definition.attributes, 'clickThrough', 'alwaystransparent', 'allwaystransparent')) ?? false;
|
|
823
|
-
const
|
|
881
|
+
const scriptedEnabled = rowValues?.[`${definition.name}.enabled`] ??
|
|
882
|
+
scenario.values[`${definition.name}.enabled`] ??
|
|
883
|
+
scenario.scriptedGui[`${definition.name}.enabled`] ??
|
|
884
|
+
context.constantElementEnabled[definition.name];
|
|
885
|
+
const clickable = clickableTypes.test(definition.elementType) && !clickThrough && scriptedEnabled !== false;
|
|
824
886
|
const state = scenario.elementStates[definition.name] ?? scenario.state;
|
|
825
887
|
const zPriority = scalarNumber(property(definition.attributes, 'priority'), 0) ?? 0;
|
|
826
888
|
let progressRatio;
|
|
827
889
|
if (/progressbar/iu.test(definition.elementType)) {
|
|
828
890
|
const minimum = scalarNumber(property(definition.attributes, 'minValue'), 1) ?? 0;
|
|
829
891
|
const maximum = scalarNumber(property(definition.attributes, 'maxValue'), 1) ?? 100;
|
|
830
|
-
const
|
|
892
|
+
const startValueToken = scalarString(property(definition.attributes, 'startValue'));
|
|
893
|
+
const shortStartValueToken = startValueToken?.slice(startValueToken.lastIndexOf('.') + 1);
|
|
894
|
+
const scriptedValue = rowValues?.[definition.name] ??
|
|
895
|
+
scenario.values[definition.name] ??
|
|
896
|
+
(startValueToken === undefined ? undefined : scenario.values[startValueToken]) ??
|
|
897
|
+
(shortStartValueToken === undefined ? undefined : scenario.values[shortStartValueToken]) ??
|
|
898
|
+
(startValueToken === undefined ? undefined : scenario.variables[startValueToken]) ??
|
|
899
|
+
(shortStartValueToken === undefined ? undefined : scenario.variables[shortStartValueToken]) ??
|
|
900
|
+
scenario.scriptedGui[definition.name];
|
|
831
901
|
let value = typeof scriptedValue === 'number'
|
|
832
902
|
? scriptedValue
|
|
833
903
|
: (scalarNumber(property(definition.attributes, 'startValue'), maximum) ?? minimum);
|
|
@@ -911,9 +981,11 @@ async function layoutElement(definition, parentRect, inheritedClip, parentScale,
|
|
|
911
981
|
rows = [];
|
|
912
982
|
if (state === 'full-list' && rows === undefined)
|
|
913
983
|
rows = Array.from({ length: 12 }, (_unused, index) => ({ index }));
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
984
|
+
const dynamicList = context.dynamicListsByName.get(definition.name);
|
|
985
|
+
const listElement = /(?:grid|listbox|scroll)/iu.test(definition.elementType);
|
|
986
|
+
const slotSize = objectProperty(property(definition.attributes, 'slotsize'));
|
|
987
|
+
const slotHeight = scaledNumber(slotSize === undefined ? undefined : property(slotSize, 'height', 'y'), height, scale);
|
|
988
|
+
if (rows !== undefined && childDefinitions.length > 0 && listElement) {
|
|
917
989
|
const spacingValue = objectProperty(property(definition.attributes, 'spacing'));
|
|
918
990
|
const spacingY = scalarNumber(spacingValue === undefined
|
|
919
991
|
? property(definition.attributes, 'spacing')
|
|
@@ -930,18 +1002,50 @@ async function layoutElement(definition, parentRect, inheritedClip, parentScale,
|
|
|
930
1002
|
...childParentRect,
|
|
931
1003
|
y: childParentRect.y + rowY - originalY * scale,
|
|
932
1004
|
};
|
|
933
|
-
await layoutElement(child, shiftedParent, childClip, scale, depth + 1, context, `${instanceSuffix}#row-${index}`, index, row, instanceId, origo);
|
|
1005
|
+
await layoutElement(child, shiftedParent, childClip, scale, depth + 1, context, `${instanceSuffix}#row-${index}`, index, row, instanceId, origo, visible);
|
|
934
1006
|
const rendered = context.instancesById.get(`${child.id}${instanceSuffix}#row-${index}`);
|
|
935
1007
|
rowHeight = Math.max(rowHeight, rendered?.unclippedRect.height ?? 0);
|
|
936
1008
|
}
|
|
937
|
-
rowY += rowHeight + spacingY * scale;
|
|
1009
|
+
rowY += (slotHeight ?? rowHeight) + spacingY * scale;
|
|
938
1010
|
}
|
|
939
1011
|
addFidelity(fidelity, 'modelled', 'scroll_rows', `Expanded ${rows.length} scenario rows for ${definition.name}.`, definition);
|
|
940
1012
|
}
|
|
1013
|
+
else if (rows !== undefined && dynamicList !== undefined && listElement) {
|
|
1014
|
+
let rowY = 0;
|
|
1015
|
+
let renderedRows = 0;
|
|
1016
|
+
for (const [index, row] of rows.entries()) {
|
|
1017
|
+
context.work.spend('scripted GUI dynamic-list row expansion');
|
|
1018
|
+
const explicitTemplate = row.entryContainer;
|
|
1019
|
+
const templateName = (typeof explicitTemplate === 'string' && explicitTemplate.length > 0
|
|
1020
|
+
? explicitTemplate
|
|
1021
|
+
: undefined) ??
|
|
1022
|
+
(row.countryScope === true
|
|
1023
|
+
? (dynamicList.countryScopeEntryContainer ?? dynamicList.entryContainer)
|
|
1024
|
+
: (dynamicList.entryContainer ?? dynamicList.countryScopeEntryContainer));
|
|
1025
|
+
const template = templateName === undefined ? undefined : context.elementsByName.get(templateName);
|
|
1026
|
+
if (template === undefined) {
|
|
1027
|
+
diagnostics.push(diagnostic('GUI_DYNAMIC_LIST_TEMPLATE_MISSING', 'error', templateName === undefined
|
|
1028
|
+
? `Dynamic list ${definition.name} has no entry container for scenario row ${index}.`
|
|
1029
|
+
: `Dynamic list ${definition.name} cannot resolve entry container ${templateName}.`, definition));
|
|
1030
|
+
continue;
|
|
1031
|
+
}
|
|
1032
|
+
const templatePosition = objectProperty(property(template.attributes, 'position'));
|
|
1033
|
+
const originalY = scalarNumber(templatePosition === undefined ? undefined : property(templatePosition, 'y'), height) ?? 0;
|
|
1034
|
+
const shiftedParent = {
|
|
1035
|
+
...childParentRect,
|
|
1036
|
+
y: childParentRect.y + rowY - originalY * scale,
|
|
1037
|
+
};
|
|
1038
|
+
await layoutElement(template, shiftedParent, childClip, scale, depth + 1, context, `${instanceSuffix}#row-${index}`, index, row, instanceId, origo, visible);
|
|
1039
|
+
const rendered = context.instancesById.get(`${template.id}${instanceSuffix}#row-${index}`);
|
|
1040
|
+
rowY += slotHeight ?? rendered?.unclippedRect.height ?? 0;
|
|
1041
|
+
renderedRows += 1;
|
|
1042
|
+
}
|
|
1043
|
+
addFidelity(fidelity, renderedRows === rows.length ? 'modelled' : 'missing', 'scripted_gui_dynamic_list', `Expanded ${renderedRows}/${rows.length} scenario rows for ${definition.name} through its scripted-GUI entry containers.`, definition);
|
|
1044
|
+
}
|
|
941
1045
|
else {
|
|
942
1046
|
for (const child of childDefinitions) {
|
|
943
1047
|
context.work.spend('nested child expansion');
|
|
944
|
-
await layoutElement(child, childParentRect, childClip, scale, depth + 1, context, instanceSuffix, rowIndex, rowValues, instanceId, origo);
|
|
1048
|
+
await layoutElement(child, childParentRect, childClip, scale, depth + 1, context, instanceSuffix, rowIndex, rowValues, instanceId, origo, visible);
|
|
945
1049
|
}
|
|
946
1050
|
}
|
|
947
1051
|
}
|
|
@@ -998,24 +1102,86 @@ export async function buildGuiScene(graph, scannedFiles, windowName, scenario, c
|
|
|
998
1102
|
localisation.set(entry.key, entry.value);
|
|
999
1103
|
addFidelity(fidelity, 'approximated', 'language', `No exact ${scenario.language} bucket; used available localisation entries.`);
|
|
1000
1104
|
}
|
|
1001
|
-
|
|
1002
|
-
|
|
1105
|
+
const relevantScriptedGuiNames = new Set(graph.scriptedGuis
|
|
1106
|
+
.filter((definition) => definition.windowName === windowName || definition.parentWindowName === windowName)
|
|
1107
|
+
.map(({ name }) => name));
|
|
1108
|
+
let addedRelatedScriptedGui = true;
|
|
1109
|
+
while (addedRelatedScriptedGui) {
|
|
1110
|
+
addedRelatedScriptedGui = false;
|
|
1111
|
+
for (const definition of graph.scriptedGuis) {
|
|
1112
|
+
if (definition.parentScriptedGui === undefined ||
|
|
1113
|
+
!relevantScriptedGuiNames.has(definition.parentScriptedGui) ||
|
|
1114
|
+
relevantScriptedGuiNames.has(definition.name))
|
|
1115
|
+
continue;
|
|
1116
|
+
relevantScriptedGuiNames.add(definition.name);
|
|
1117
|
+
addedRelatedScriptedGui = true;
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
const scriptedWindowVisibility = {};
|
|
1121
|
+
const constantElementVisibility = {};
|
|
1122
|
+
const constantElementEnabled = {};
|
|
1123
|
+
const resolvedScriptedProperties = {};
|
|
1124
|
+
const dynamicListsByName = new Map();
|
|
1125
|
+
for (const scripted of graph.scriptedGuis.filter(({ name }) => relevantScriptedGuiNames.has(name))) {
|
|
1126
|
+
for (const dynamicList of scripted.dynamicListDefinitions)
|
|
1127
|
+
dynamicListsByName.set(dynamicList.name, dynamicList);
|
|
1128
|
+
for (const propertyDefinition of scripted.propertyDefinitions) {
|
|
1129
|
+
for (const [attribute, expression] of Object.entries(propertyDefinition.attributes)) {
|
|
1130
|
+
const suffix = attribute.toLowerCase();
|
|
1131
|
+
if (!['image', 'frame', 'x', 'y', 'visible', 'enabled'].includes(suffix))
|
|
1132
|
+
continue;
|
|
1133
|
+
const resolved = scenarioExpressionValue(expression, scenario.values);
|
|
1134
|
+
if (resolved === undefined)
|
|
1135
|
+
continue;
|
|
1136
|
+
const key = `${propertyDefinition.elementName}.${suffix}`;
|
|
1137
|
+
if (scenario.values[key] === undefined)
|
|
1138
|
+
resolvedScriptedProperties[key] = resolved;
|
|
1139
|
+
addFidelity(fidelity, 'modelled', 'scripted_gui_scenario_property', `${key} resolved from a scenario runtime value.`);
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
for (const trigger of scripted.triggerDefinitions) {
|
|
1143
|
+
if (trigger.constantResult === undefined)
|
|
1144
|
+
continue;
|
|
1145
|
+
if (trigger.name.endsWith('_visible'))
|
|
1146
|
+
constantElementVisibility[trigger.elementName] = trigger.constantResult;
|
|
1147
|
+
if (trigger.name.endsWith('_click_enabled'))
|
|
1148
|
+
constantElementEnabled[trigger.elementName] = trigger.constantResult;
|
|
1149
|
+
addFidelity(fidelity, 'modelled', 'scripted_gui_constant_trigger', `${trigger.name} resolves to ${trigger.constantResult ? 'yes' : 'no'}.`);
|
|
1150
|
+
}
|
|
1003
1151
|
addFidelity(fidelity, 'modelled', 'scripted_gui_context', `${scripted.name} uses ${scripted.contextType ?? '<unspecified>'} context.`);
|
|
1004
1152
|
if (scripted.visibleExpression === undefined)
|
|
1005
1153
|
continue;
|
|
1006
|
-
const mockedVisibility = scenario.visibility[scripted.name] ??
|
|
1154
|
+
const mockedVisibility = scenario.visibility[scripted.name] ??
|
|
1155
|
+
scenario.values[`${scripted.name}.visible`] ??
|
|
1156
|
+
scenario.scriptedGui[`${scripted.name}.visible`];
|
|
1007
1157
|
if (typeof mockedVisibility === 'boolean') {
|
|
1008
|
-
|
|
1158
|
+
if (scripted.windowName !== undefined)
|
|
1159
|
+
scriptedWindowVisibility[scripted.windowName] =
|
|
1160
|
+
(scriptedWindowVisibility[scripted.windowName] ?? true) && mockedVisibility;
|
|
1009
1161
|
addFidelity(fidelity, 'modelled', 'scripted_gui_visibility', `${scripted.name}.visible was supplied by the preview scenario.`);
|
|
1010
1162
|
}
|
|
1011
1163
|
else {
|
|
1012
1164
|
addFidelity(fidelity, 'unresolved', 'scripted_gui_visibility', `${scripted.name}.visible requires an explicit scenario mock; the offline renderer leaves it visible.`);
|
|
1013
1165
|
}
|
|
1014
1166
|
}
|
|
1015
|
-
const layoutScenario =
|
|
1016
|
-
|
|
1017
|
-
: {
|
|
1167
|
+
const layoutScenario = {
|
|
1168
|
+
...scenario,
|
|
1169
|
+
values: {
|
|
1170
|
+
...resolvedScriptedProperties,
|
|
1171
|
+
...scenario.values,
|
|
1172
|
+
},
|
|
1173
|
+
visibility: {
|
|
1174
|
+
...scriptedWindowVisibility,
|
|
1175
|
+
...constantElementVisibility,
|
|
1176
|
+
...scenario.visibility,
|
|
1177
|
+
},
|
|
1178
|
+
};
|
|
1018
1179
|
const output = [];
|
|
1180
|
+
const elementsByName = new Map();
|
|
1181
|
+
for (const element of [...graph.elements].sort((left, right) => compareCodeUnits(right.sourcePath, left.sourcePath) ||
|
|
1182
|
+
right.definitionOrder - left.definitionOrder))
|
|
1183
|
+
if (!elementsByName.has(element.name))
|
|
1184
|
+
elementsByName.set(element.name, element);
|
|
1019
1185
|
const context = {
|
|
1020
1186
|
graph,
|
|
1021
1187
|
scenario: layoutScenario,
|
|
@@ -1023,6 +1189,9 @@ export async function buildGuiScene(graph, scannedFiles, windowName, scenario, c
|
|
|
1023
1189
|
fidelity,
|
|
1024
1190
|
diagnostics,
|
|
1025
1191
|
elementsById,
|
|
1192
|
+
elementsByName,
|
|
1193
|
+
dynamicListsByName,
|
|
1194
|
+
constantElementEnabled,
|
|
1026
1195
|
spritesByName: new Map(graph.sprites.map((sprite) => [sprite.name.toLowerCase(), sprite])),
|
|
1027
1196
|
localisation,
|
|
1028
1197
|
output,
|
|
@@ -1037,6 +1206,44 @@ export async function buildGuiScene(graph, scannedFiles, windowName, scenario, c
|
|
|
1037
1206
|
height: scenario.resolution.height,
|
|
1038
1207
|
};
|
|
1039
1208
|
await layoutElement(root, viewport, viewport, baseScale, 0, context);
|
|
1209
|
+
const scriptedByName = new Map(graph.scriptedGuis.map((scripted) => [scripted.name, scripted]));
|
|
1210
|
+
const pendingAttached = graph.scriptedGuis
|
|
1211
|
+
.filter(({ name, parentScriptedGui, windowName: scriptedWindowName }) => relevantScriptedGuiNames.has(name) &&
|
|
1212
|
+
parentScriptedGui !== undefined &&
|
|
1213
|
+
scriptedWindowName !== undefined &&
|
|
1214
|
+
scriptedWindowName !== windowName)
|
|
1215
|
+
.sort((left, right) => compareCodeUnits(left.name, right.name));
|
|
1216
|
+
let attachmentProgress = true;
|
|
1217
|
+
while (pendingAttached.length > 0 && attachmentProgress) {
|
|
1218
|
+
attachmentProgress = false;
|
|
1219
|
+
for (let index = pendingAttached.length - 1; index >= 0; index -= 1) {
|
|
1220
|
+
const scripted = pendingAttached[index];
|
|
1221
|
+
const parentScripted = scripted.parentScriptedGui === undefined
|
|
1222
|
+
? undefined
|
|
1223
|
+
: scriptedByName.get(scripted.parentScriptedGui);
|
|
1224
|
+
const parentWindowName = parentScripted?.windowName;
|
|
1225
|
+
const parentDefinition = parentWindowName === undefined ? undefined : elementsByName.get(parentWindowName);
|
|
1226
|
+
const parentScene = parentDefinition === undefined ? undefined : context.instancesById.get(parentDefinition.id);
|
|
1227
|
+
const attachedDefinition = scripted.windowName === undefined ? undefined : elementsByName.get(scripted.windowName);
|
|
1228
|
+
if (parentScene === undefined || attachedDefinition === undefined)
|
|
1229
|
+
continue;
|
|
1230
|
+
if (!context.instancesById.has(attachedDefinition.id)) {
|
|
1231
|
+
await layoutElement(attachedDefinition, parentScene.unclippedRect, parentScene.unclippedRect, parentScene.scale, parentScene.depth + 1, context, '', undefined, undefined, parentScene.id, 'upper_left', parentScene.visible);
|
|
1232
|
+
addFidelity(fidelity, 'modelled', 'parent_scripted_gui_attachment', `${scripted.windowName} is attached to ${parentWindowName} through ${scripted.parentScriptedGui}.`, attachedDefinition);
|
|
1233
|
+
}
|
|
1234
|
+
pendingAttached.splice(index, 1);
|
|
1235
|
+
attachmentProgress = true;
|
|
1236
|
+
}
|
|
1237
|
+
}
|
|
1238
|
+
for (const scripted of pendingAttached) {
|
|
1239
|
+
diagnostics.push({
|
|
1240
|
+
code: 'GUI_PARENT_SCRIPTED_WINDOW_UNRESOLVED',
|
|
1241
|
+
severity: 'error',
|
|
1242
|
+
category: 'reference',
|
|
1243
|
+
message: `Could not attach ${scripted.windowName ?? '<missing window>'} through parent scripted GUI ${scripted.parentScriptedGui ?? '<missing parent>'}.`,
|
|
1244
|
+
...(scripted.location === undefined ? {} : { location: scripted.location }),
|
|
1245
|
+
});
|
|
1246
|
+
}
|
|
1040
1247
|
output.sort((left, right) => left.zIndex - right.zIndex || compareCodeUnits(left.id, right.id));
|
|
1041
1248
|
const bounds = unionRects(output.filter(({ visible }) => visible).map(({ unclippedRect }) => unclippedRect));
|
|
1042
1249
|
return {
|
|
@@ -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({}),
|
|
@@ -63,6 +63,8 @@ const modelledElementAttributes = new Set([
|
|
|
63
63
|
'allwaystransparent',
|
|
64
64
|
'clickThrough',
|
|
65
65
|
'spacing',
|
|
66
|
+
'slotsize',
|
|
67
|
+
'max_slots_horizontal',
|
|
66
68
|
'priority',
|
|
67
69
|
'minValue',
|
|
68
70
|
'maxValue',
|
|
@@ -420,6 +422,9 @@ function indexSpritesAndFonts(document, file, fileNodeId, nodes, edges, sprites,
|
|
|
420
422
|
.concat(childBlocks(child, 'fontfiles').flatMap((fontFiles) => fontFiles.entries
|
|
421
423
|
.filter((entry) => entry.type === 'scalar')
|
|
422
424
|
.map((entry) => entry.value)));
|
|
425
|
+
const languages = childBlocks(child, 'languages').flatMap((languageBlock) => languageBlock.entries
|
|
426
|
+
.filter((entry) => entry.type === 'scalar')
|
|
427
|
+
.map((entry) => entry.value));
|
|
423
428
|
const id = deterministicId('gui_font', { path: file.displayPath, name });
|
|
424
429
|
const font = {
|
|
425
430
|
id,
|
|
@@ -427,6 +432,8 @@ function indexSpritesAndFonts(document, file, fileNodeId, nodes, edges, sprites,
|
|
|
427
432
|
sourcePath: file.displayPath,
|
|
428
433
|
location: nodeLocation(document, assignment, name),
|
|
429
434
|
kind: 'bitmapfont',
|
|
435
|
+
override: assignment.key.value === 'bitmapfont_override',
|
|
436
|
+
languages,
|
|
430
437
|
assetPaths,
|
|
431
438
|
rawSource: raw(document, assignment),
|
|
432
439
|
};
|
|
@@ -437,7 +444,12 @@ function indexSpritesAndFonts(document, file, fileNodeId, nodes, edges, sprites,
|
|
|
437
444
|
name,
|
|
438
445
|
path: file.displayPath,
|
|
439
446
|
...(font.location === undefined ? {} : { location: font.location }),
|
|
440
|
-
metadata: {
|
|
447
|
+
metadata: {
|
|
448
|
+
kind: font.kind,
|
|
449
|
+
override: font.override,
|
|
450
|
+
languages,
|
|
451
|
+
assetPaths,
|
|
452
|
+
},
|
|
441
453
|
});
|
|
442
454
|
addEdge(edges, 'contains', fileNodeId, id, true, {}, font.location);
|
|
443
455
|
}
|
|
@@ -476,6 +488,21 @@ function directEffectCosts(block) {
|
|
|
476
488
|
}
|
|
477
489
|
return costs;
|
|
478
490
|
}
|
|
491
|
+
function constantTriggerResult(value) {
|
|
492
|
+
if (value.type !== 'block')
|
|
493
|
+
return undefined;
|
|
494
|
+
const entries = assignments(value);
|
|
495
|
+
if (entries.length !== 1 || entries[0]?.key.value.toLowerCase() !== 'always')
|
|
496
|
+
return undefined;
|
|
497
|
+
const result = entries[0].value;
|
|
498
|
+
if (result.type !== 'scalar')
|
|
499
|
+
return undefined;
|
|
500
|
+
if (result.value.toLowerCase() === 'yes')
|
|
501
|
+
return true;
|
|
502
|
+
if (result.value.toLowerCase() === 'no')
|
|
503
|
+
return false;
|
|
504
|
+
return undefined;
|
|
505
|
+
}
|
|
479
506
|
function indexScriptedGuis(document, file, fileNodeId, nodes, edges, scriptedGuis) {
|
|
480
507
|
for (const root of childBlocks(document.root, 'scripted_gui')) {
|
|
481
508
|
for (const assignment of assignments(root)) {
|
|
@@ -493,9 +520,43 @@ function indexScriptedGuis(document, file, fileNodeId, nodes, edges, scriptedGui
|
|
|
493
520
|
location: nodeLocation(document, effect, effect.key.value),
|
|
494
521
|
}));
|
|
495
522
|
const effects = effectDefinitions.map(({ name: effect }) => effect);
|
|
496
|
-
const
|
|
497
|
-
|
|
498
|
-
|
|
523
|
+
const triggerDefinitions = namedAssignments(block, 'triggers').map((trigger) => {
|
|
524
|
+
const constantResult = constantTriggerResult(trigger.value);
|
|
525
|
+
return {
|
|
526
|
+
name: trigger.key.value,
|
|
527
|
+
elementName: actionElementName(trigger.key.value),
|
|
528
|
+
...(constantResult === undefined ? {} : { constantResult }),
|
|
529
|
+
rawSource: raw(document, trigger),
|
|
530
|
+
location: nodeLocation(document, trigger, trigger.key.value),
|
|
531
|
+
};
|
|
532
|
+
});
|
|
533
|
+
const triggers = triggerDefinitions.map(({ name: trigger }) => trigger);
|
|
534
|
+
const propertyAssignments = namedAssignments(block, 'properties');
|
|
535
|
+
const properties = propertyAssignments.map(({ key }) => key.value);
|
|
536
|
+
const propertyDefinitions = propertyAssignments.map((property) => ({
|
|
537
|
+
elementName: property.key.value,
|
|
538
|
+
attributes: property.value.type === 'block'
|
|
539
|
+
? sourceValueToProperty(property.value, constantsFor(document))
|
|
540
|
+
: {},
|
|
541
|
+
rawSource: raw(document, property),
|
|
542
|
+
location: nodeLocation(document, property, property.key.value),
|
|
543
|
+
}));
|
|
544
|
+
const dynamicListDefinitions = namedAssignments(block, 'dynamic_lists').map((dynamicList) => {
|
|
545
|
+
const entryContainer = dynamicList.value.type === 'block'
|
|
546
|
+
? firstScalarInsensitive(dynamicList.value, 'entry_container')
|
|
547
|
+
: undefined;
|
|
548
|
+
const countryScopeEntryContainer = dynamicList.value.type === 'block'
|
|
549
|
+
? firstScalarInsensitive(dynamicList.value, 'country_scope_entry_container')
|
|
550
|
+
: undefined;
|
|
551
|
+
return {
|
|
552
|
+
name: dynamicList.key.value,
|
|
553
|
+
...(entryContainer === undefined ? {} : { entryContainer }),
|
|
554
|
+
...(countryScopeEntryContainer === undefined ? {} : { countryScopeEntryContainer }),
|
|
555
|
+
rawSource: raw(document, dynamicList),
|
|
556
|
+
location: nodeLocation(document, dynamicList, dynamicList.key.value),
|
|
557
|
+
};
|
|
558
|
+
});
|
|
559
|
+
const dynamicLists = dynamicListDefinitions.map(({ name: dynamicList }) => dynamicList);
|
|
499
560
|
const aiWeights = namedAssignments(block, 'ai_weights').map(({ key }) => key.value);
|
|
500
561
|
const contextType = firstScalarInsensitive(block, 'context_type');
|
|
501
562
|
const windowName = firstScalarInsensitive(block, 'window_name');
|
|
@@ -517,8 +578,11 @@ function indexScriptedGuis(document, file, fileNodeId, nodes, edges, scriptedGui
|
|
|
517
578
|
effects: effects.sort((a, b) => compareCodeUnits(a, b)),
|
|
518
579
|
effectDefinitions: effectDefinitions.sort((a, b) => compareCodeUnits(a.name, b.name)),
|
|
519
580
|
triggers: triggers.sort((a, b) => compareCodeUnits(a, b)),
|
|
581
|
+
triggerDefinitions: triggerDefinitions.sort((a, b) => compareCodeUnits(a.name, b.name)),
|
|
520
582
|
properties: properties.sort((a, b) => compareCodeUnits(a, b)),
|
|
583
|
+
propertyDefinitions: propertyDefinitions.sort((a, b) => compareCodeUnits(a.elementName, b.elementName)),
|
|
521
584
|
dynamicLists: dynamicLists.sort((a, b) => compareCodeUnits(a, b)),
|
|
585
|
+
dynamicListDefinitions: dynamicListDefinitions.sort((left, right) => compareCodeUnits(left.name, right.name)),
|
|
522
586
|
aiWeights: aiWeights.sort((a, b) => compareCodeUnits(a, b)),
|
|
523
587
|
aiEnabled: childBlocks(block, 'ai_enabled').length > 0 || childBlocks(block, 'ai_check').length > 0,
|
|
524
588
|
rawSource: raw(document, assignment),
|
|
@@ -533,8 +597,23 @@ function indexScriptedGuis(document, file, fileNodeId, nodes, edges, scriptedGui
|
|
|
533
597
|
metadata: {
|
|
534
598
|
effects: definition.effects,
|
|
535
599
|
triggers: definition.triggers,
|
|
600
|
+
constantTriggers: definition.triggerDefinitions.flatMap(({ name: trigger, elementName, constantResult }) => constantResult === undefined ? [] : [{ trigger, elementName, constantResult }]),
|
|
536
601
|
properties: definition.properties,
|
|
537
602
|
dynamicLists: definition.dynamicLists,
|
|
603
|
+
dynamicListEntryContainers: definition.dynamicListDefinitions.flatMap(({ name: dynamicList, entryContainer, countryScopeEntryContainer }) => [
|
|
604
|
+
...(entryContainer === undefined
|
|
605
|
+
? []
|
|
606
|
+
: [{ dynamicList, scope: 'generic', container: entryContainer }]),
|
|
607
|
+
...(countryScopeEntryContainer === undefined
|
|
608
|
+
? []
|
|
609
|
+
: [
|
|
610
|
+
{
|
|
611
|
+
dynamicList,
|
|
612
|
+
scope: 'country',
|
|
613
|
+
container: countryScopeEntryContainer,
|
|
614
|
+
},
|
|
615
|
+
]),
|
|
616
|
+
]),
|
|
538
617
|
aiWeights: definition.aiWeights,
|
|
539
618
|
aiEnabled: definition.aiEnabled,
|
|
540
619
|
},
|
|
@@ -718,7 +797,15 @@ function indexDecisionEntries(document, file, nodes, pendingDecisionEdges) {
|
|
|
718
797
|
}
|
|
719
798
|
function linkGraph(nodes, edges, elements, sprites, fonts, scriptedGuis, scriptedLocalisation, localisation, textureNodes, fontAssetNodes, pendingDecisionEdges) {
|
|
720
799
|
const spriteByName = new Map(sprites.map((sprite) => [sprite.name.toLocaleLowerCase('en-US'), sprite]));
|
|
721
|
-
const fontByName = new Map(
|
|
800
|
+
const fontByName = new Map();
|
|
801
|
+
for (const font of fonts) {
|
|
802
|
+
const key = font.name.toLocaleLowerCase('en-US');
|
|
803
|
+
const existing = fontByName.get(key);
|
|
804
|
+
if (existing === undefined ||
|
|
805
|
+
(existing.override && !font.override) ||
|
|
806
|
+
(existing.languages.length > 0 && font.languages.length === 0))
|
|
807
|
+
fontByName.set(key, font);
|
|
808
|
+
}
|
|
722
809
|
const elementByName = new Map();
|
|
723
810
|
for (const element of [...elements].sort((a, b) => a.definitionOrder - b.definitionOrder)) {
|
|
724
811
|
if (!elementByName.has(element.name))
|
|
@@ -778,7 +865,9 @@ function linkGraph(nodes, edges, elements, sprites, fonts, scriptedGuis, scripte
|
|
|
778
865
|
}
|
|
779
866
|
for (const key of localisationAttributeNames) {
|
|
780
867
|
const value = element.attributes[key];
|
|
781
|
-
if (typeof value !== 'string' ||
|
|
868
|
+
if (typeof value !== 'string' ||
|
|
869
|
+
value.trim().length === 0 ||
|
|
870
|
+
!isStaticGuiLocalisationReference(value))
|
|
782
871
|
continue;
|
|
783
872
|
const entry = localisationByKey.get(value);
|
|
784
873
|
addEdge(edges, 'uses_localisation', element.id, entry === undefined ? `localisation:${value}` : deterministicId('gui_loc', entry), entry !== undefined, { field: key, key: value }, element.location);
|
|
@@ -824,6 +913,17 @@ function linkGraph(nodes, edges, elements, sprites, fonts, scriptedGuis, scripte
|
|
|
824
913
|
const element = elementByName.get(property);
|
|
825
914
|
addEdge(edges, 'property_target', gui.id, element?.id ?? `gui_element:${property}`, element !== undefined, { property }, gui.location);
|
|
826
915
|
}
|
|
916
|
+
for (const dynamicList of gui.dynamicListDefinitions) {
|
|
917
|
+
for (const [scope, containerName] of [
|
|
918
|
+
['generic', dynamicList.entryContainer],
|
|
919
|
+
['country', dynamicList.countryScopeEntryContainer],
|
|
920
|
+
]) {
|
|
921
|
+
if (containerName === undefined)
|
|
922
|
+
continue;
|
|
923
|
+
const element = elementByName.get(containerName);
|
|
924
|
+
addEdge(edges, 'dynamic_list_template', gui.id, element?.id ?? `gui_element:${containerName}`, element !== undefined, { dynamicList: dynamicList.name, scope, containerName }, dynamicList.location);
|
|
925
|
+
}
|
|
926
|
+
}
|
|
827
927
|
}
|
|
828
928
|
for (const pending of pendingDecisionEdges) {
|
|
829
929
|
const target = scriptedByName.get(pending.target);
|
|
@@ -837,12 +937,18 @@ const localisationAttributeNames = [
|
|
|
837
937
|
'pdx_tooltip_delayed',
|
|
838
938
|
'hint_tag',
|
|
839
939
|
];
|
|
940
|
+
function isStaticGuiLocalisationReference(value) {
|
|
941
|
+
const trimmed = value.trim();
|
|
942
|
+
return !(trimmed.startsWith('[') && trimmed.endsWith(']'));
|
|
943
|
+
}
|
|
840
944
|
function referencedGuiLocalisationKeys(elements, scriptedLocalisation) {
|
|
841
945
|
const keys = new Set(scriptedLocalisation.flatMap(({ localisationKeys }) => localisationKeys));
|
|
842
946
|
for (const element of elements) {
|
|
843
947
|
for (const attribute of localisationAttributeNames) {
|
|
844
948
|
const value = element.attributes[attribute];
|
|
845
|
-
if (typeof value === 'string' &&
|
|
949
|
+
if (typeof value === 'string' &&
|
|
950
|
+
value.trim().length > 0 &&
|
|
951
|
+
isStaticGuiLocalisationReference(value))
|
|
846
952
|
keys.add(value);
|
|
847
953
|
}
|
|
848
954
|
}
|
|
@@ -862,6 +968,7 @@ function skippedInventoryCouldResolve(edge, sharedIndex) {
|
|
|
862
968
|
case 'button_effect':
|
|
863
969
|
case 'button_trigger':
|
|
864
970
|
case 'property_target':
|
|
971
|
+
case 'dynamic_list_template':
|
|
865
972
|
return sharedIndex.hasSkippedSourceForKind('gui_element');
|
|
866
973
|
case 'parent_scripted_gui':
|
|
867
974
|
case 'decision_category_entry':
|
|
@@ -1016,6 +1123,8 @@ export function buildGuiSourceGraph(files, sharedIndex) {
|
|
|
1016
1123
|
name: path.posix.basename(normalized, '.fnt'),
|
|
1017
1124
|
sourcePath: file.displayPath,
|
|
1018
1125
|
kind: 'bmfont',
|
|
1126
|
+
override: false,
|
|
1127
|
+
languages: [],
|
|
1019
1128
|
assetPaths: [file.relativePath],
|
|
1020
1129
|
}, 'font');
|
|
1021
1130
|
}
|