@neocompose/cli 0.72.2 → 0.73.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1561,6 +1561,260 @@ function isGeneratedCSharpReservedKeyword(value) {
1561
1561
  function generatedCSharpMemberNameForSchemaKey(schemaKey) {
1562
1562
  return isGeneratedCSharpReservedKeyword(schemaKey) ? `${schemaKey}Value` : schemaKey;
1563
1563
  }
1564
+ function generatedCSharpTypeName(value, fallback) {
1565
+ const parts = value.match(/[A-Za-z0-9]+/g) ?? [];
1566
+ const joined = parts.map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join("");
1567
+ const candidate = joined.length > 0 ? joined : fallback;
1568
+ const safe = /^[0-9]/.test(candidate) ? `_${candidate}` : candidate;
1569
+ return isGeneratedCSharpReservedKeyword(safe) ? `${safe}Type` : safe;
1570
+ }
1571
+ function generatedCSharpShortId(id) {
1572
+ return id.replace(/[^A-Za-z0-9_]/g, "").slice(0, 8) || "Id";
1573
+ }
1574
+ function dialogueGroupPropertyNames(groups, onCollision) {
1575
+ const ordered = [...groups].sort(compareGroupIds);
1576
+ const used = /* @__PURE__ */ new Set();
1577
+ const names = /* @__PURE__ */ new Map();
1578
+ for (const group of ordered) {
1579
+ const propertyName = generatedCSharpTypeName(group.name, "DialogueGroup");
1580
+ if (!used.has(propertyName)) {
1581
+ used.add(propertyName);
1582
+ names.set(group.id, propertyName);
1583
+ continue;
1584
+ }
1585
+ const uniqueName = `${propertyName}_${generatedCSharpShortId(group.id)}`;
1586
+ onCollision?.({
1587
+ groupId: group.id,
1588
+ groupName: group.name,
1589
+ propertyName,
1590
+ uniqueName
1591
+ });
1592
+ names.set(group.id, uniqueName);
1593
+ }
1594
+ return names;
1595
+ }
1596
+ function compareGroupIds(left, right) {
1597
+ if (left.id < right.id) return -1;
1598
+ if (left.id > right.id) return 1;
1599
+ return 0;
1600
+ }
1601
+
1602
+ // ../packages/neoscript-language/src/dialogue-types.ts
1603
+ var NEOSCRIPT_DIALOGUES_MEMBER_NAME = "Dialogues";
1604
+ var NEOSCRIPT_DIALOGUES_TYPE_ID = "builtin:Dialogues";
1605
+ var RENAMED_DIALOGUE_TYPES = /* @__PURE__ */ new Map([
1606
+ ["Dialogue", { base: "NeoDialogue", value: "NeoDialogueReference" }],
1607
+ [
1608
+ "DialogueRef",
1609
+ { base: "NeoDialogueReference", value: "NeoDialogueReference" }
1610
+ ],
1611
+ ["DialogueGroup", { base: "NeoDialogueGroup", value: "NeoDialogueGroup" }],
1612
+ ["PriorityGroup", { base: "NeoPriorityGroup", value: "NeoPriorityGroup" }]
1613
+ ]);
1614
+ function renamedDialogueTypeMessage(name, position) {
1615
+ const replacement = RENAMED_DIALOGUE_TYPES.get(name)?.[position];
1616
+ if (replacement === void 0) return void 0;
1617
+ return `\`${name}\` was renamed to \`${replacement}\`.`;
1618
+ }
1619
+ var BOOL_TYPE = { kind: "primitive", name: "bool" };
1620
+ var INT_TYPE = { kind: "primitive", name: "int" };
1621
+ var STRING_TYPE = { kind: "primitive", name: "string" };
1622
+ var NEOSCRIPT_DIALOGUE_ON_FINISH_TYPE = {
1623
+ kind: "delegate",
1624
+ returnType: { kind: "primitive", name: "void" },
1625
+ parameterTypes: [],
1626
+ nullable: true
1627
+ };
1628
+ var ON_FINISH_PARAMETER = {
1629
+ name: "onFinish",
1630
+ type: NEOSCRIPT_DIALOGUE_ON_FINISH_TYPE,
1631
+ defaultValue: { displayText: "null", value: null },
1632
+ documentation: "Runs once the dialogue ends, whether it finished, failed, or was disposed."
1633
+ };
1634
+ function method(ownerId, name, returnType, parameters, documentation) {
1635
+ return {
1636
+ id: `${ownerId}:${name}`,
1637
+ name,
1638
+ kind: "method",
1639
+ type: returnType,
1640
+ returnType,
1641
+ parameters,
1642
+ documentation
1643
+ };
1644
+ }
1645
+ function neoScriptDialogueReferenceMethods(ownerId) {
1646
+ return [
1647
+ method(
1648
+ ownerId,
1649
+ "TryTrigger",
1650
+ BOOL_TYPE,
1651
+ [ON_FINISH_PARAMETER],
1652
+ "Triggers the referenced dialogue. Returns true when it started or was queued."
1653
+ ),
1654
+ method(
1655
+ ownerId,
1656
+ "CanTrigger",
1657
+ BOOL_TYPE,
1658
+ [],
1659
+ "Checks whether the referenced dialogue's conditions are met, without triggering it."
1660
+ )
1661
+ ];
1662
+ }
1663
+ function rootMethods() {
1664
+ const dialogueId = {
1665
+ name: "dialogueId",
1666
+ type: STRING_TYPE
1667
+ };
1668
+ const pointer = { name: "pointer", type: STRING_TYPE };
1669
+ return [
1670
+ method(
1671
+ NEOSCRIPT_DIALOGUES_TYPE_ID,
1672
+ "TryTrigger",
1673
+ BOOL_TYPE,
1674
+ [dialogueId, ON_FINISH_PARAMETER],
1675
+ "Triggers a direct dialogue. Returns true when it started or was queued."
1676
+ ),
1677
+ method(
1678
+ NEOSCRIPT_DIALOGUES_TYPE_ID,
1679
+ "CanTrigger",
1680
+ BOOL_TYPE,
1681
+ [dialogueId],
1682
+ "Checks whether a direct dialogue's conditions are met, without triggering it."
1683
+ ),
1684
+ method(
1685
+ NEOSCRIPT_DIALOGUES_TYPE_ID,
1686
+ "VisitCount",
1687
+ INT_TYPE,
1688
+ [pointer],
1689
+ "Returns how many times a dialogue or text node was visited."
1690
+ ),
1691
+ method(
1692
+ NEOSCRIPT_DIALOGUES_TYPE_ID,
1693
+ "HasVisited",
1694
+ BOOL_TYPE,
1695
+ [pointer],
1696
+ "Returns whether a dialogue or text node was visited."
1697
+ )
1698
+ ];
1699
+ }
1700
+ function groupMethods(typeId, receiver) {
1701
+ if (receiver.kind === "standard") {
1702
+ return [
1703
+ method(
1704
+ typeId,
1705
+ "TryTrigger",
1706
+ BOOL_TYPE,
1707
+ [ON_FINISH_PARAMETER],
1708
+ "Triggers this group's highest-priority eligible dialogue. Returns true when it started or was queued."
1709
+ ),
1710
+ method(
1711
+ typeId,
1712
+ "CanTrigger",
1713
+ BOOL_TYPE,
1714
+ [],
1715
+ "Checks whether this group has an eligible dialogue, without triggering it."
1716
+ )
1717
+ ];
1718
+ }
1719
+ if (receiver.kind !== "lookup" || receiver.entryType === void 0) return [];
1720
+ const value = {
1721
+ name: "value",
1722
+ type: receiver.entryType
1723
+ };
1724
+ return [
1725
+ method(
1726
+ typeId,
1727
+ "TryTrigger",
1728
+ BOOL_TYPE,
1729
+ [value, ON_FINISH_PARAMETER],
1730
+ "Triggers the highest-priority eligible dialogue for the lookup value. Returns true when it started or was queued."
1731
+ ),
1732
+ method(
1733
+ typeId,
1734
+ "CanTrigger",
1735
+ BOOL_TYPE,
1736
+ [value],
1737
+ "Checks whether the lookup value has an eligible dialogue, without triggering it."
1738
+ )
1739
+ ];
1740
+ }
1741
+ var KIND_LABELS = {
1742
+ standard: "Dialogue group",
1743
+ lookup: "Lookup dialogue group",
1744
+ folder: "Dialogue folder"
1745
+ };
1746
+ function neoScriptDialogueTypes(groups) {
1747
+ const names = dialogueGroupPropertyNames(groups);
1748
+ const children = /* @__PURE__ */ new Map();
1749
+ for (const group of groups) {
1750
+ const siblings = children.get(group.parentId);
1751
+ if (siblings === void 0) children.set(group.parentId, [group]);
1752
+ else siblings.push(group);
1753
+ }
1754
+ const rootPath = `root.${NEOSCRIPT_DIALOGUES_MEMBER_NAME}`;
1755
+ const types = [];
1756
+ const typeFor = (parentId, path) => {
1757
+ const members = [];
1758
+ for (const group of children.get(parentId) ?? []) {
1759
+ const name = names.get(group.id);
1760
+ const groupPath = `${path}.${name}`;
1761
+ const typeId = `${NEOSCRIPT_DIALOGUES_TYPE_ID}:${group.id}`;
1762
+ const receiver = {
1763
+ kind: group.kind,
1764
+ path: groupPath,
1765
+ groupId: group.id,
1766
+ ...group.lookup ? { entryType: group.lookup.entryType } : {}
1767
+ };
1768
+ const lookup = group.lookup ? ` Looks up ${group.lookup.entryTypeName} in \`${group.lookup.collection}\`.` : "";
1769
+ const documentation = `${KIND_LABELS[group.kind]} \`${groupPath}\`.${lookup}`;
1770
+ types.push({
1771
+ id: typeId,
1772
+ name: groupPath,
1773
+ kind: "synthetic",
1774
+ documentation,
1775
+ dialogues: receiver,
1776
+ members: [
1777
+ ...typeFor(group.id, groupPath),
1778
+ ...groupMethods(typeId, receiver)
1779
+ ]
1780
+ });
1781
+ members.push({
1782
+ id: `${typeId}:member`,
1783
+ name,
1784
+ kind: "property",
1785
+ type: { kind: "named", typeId },
1786
+ documentation,
1787
+ detail: KIND_LABELS[group.kind],
1788
+ writable: false,
1789
+ writability: "readOnly",
1790
+ ...group.location ? { location: group.location } : {},
1791
+ ...group.selectionLocation ? { selectionLocation: group.selectionLocation } : {}
1792
+ });
1793
+ }
1794
+ return members;
1795
+ };
1796
+ const topLevel = typeFor(null, rootPath);
1797
+ types.push({
1798
+ id: NEOSCRIPT_DIALOGUES_TYPE_ID,
1799
+ name: rootPath,
1800
+ kind: "synthetic",
1801
+ documentation: "The project's dialogues and dialogue groups, the same paths as the generated C# Dialogues.",
1802
+ dialogues: { kind: "root", path: rootPath },
1803
+ members: [...topLevel, ...rootMethods()]
1804
+ });
1805
+ return {
1806
+ member: {
1807
+ id: `${NEOSCRIPT_DIALOGUES_TYPE_ID}:member`,
1808
+ name: NEOSCRIPT_DIALOGUES_MEMBER_NAME,
1809
+ kind: "property",
1810
+ type: { kind: "named", typeId: NEOSCRIPT_DIALOGUES_TYPE_ID },
1811
+ documentation: "The project's dialogues. Trigger them, check them, and read dialogue memory.",
1812
+ writable: false,
1813
+ writability: "readOnly"
1814
+ },
1815
+ types
1816
+ };
1817
+ }
1564
1818
 
1565
1819
  // ../packages/neoscript-language/src/language-spec.ts
1566
1820
  var NEOSCRIPT_KEYWORDS = [
@@ -1620,7 +1874,7 @@ var NEOSCRIPT_BUILTIN_ANNOTATION_TYPES = [
1620
1874
  "FunctionRef",
1621
1875
  "NeoDelegate",
1622
1876
  "NeoAction",
1623
- "Dialogue",
1877
+ "NeoDialogue",
1624
1878
  "Trigger",
1625
1879
  "Node",
1626
1880
  "Text",
@@ -1630,7 +1884,7 @@ var NEOSCRIPT_BUILTIN_ANNOTATION_TYPES = [
1630
1884
  "Outcome",
1631
1885
  "SpriteInfo",
1632
1886
  "AudioClipInfo",
1633
- "DialogueRef",
1887
+ "NeoDialogueReference",
1634
1888
  "Vector2",
1635
1889
  "Vector2Int",
1636
1890
  "Vector3",
@@ -1677,10 +1931,10 @@ var NEOSCRIPT_OPERATORS = [
1677
1931
  "<",
1678
1932
  ">"
1679
1933
  ];
1680
- var STRING_TYPE = { kind: "primitive", name: "string" };
1681
- var INT_TYPE = { kind: "primitive", name: "int" };
1934
+ var STRING_TYPE2 = { kind: "primitive", name: "string" };
1935
+ var INT_TYPE2 = { kind: "primitive", name: "int" };
1682
1936
  var FLOAT_TYPE = { kind: "primitive", name: "float" };
1683
- var BOOL_TYPE = { kind: "primitive", name: "bool" };
1937
+ var BOOL_TYPE2 = { kind: "primitive", name: "bool" };
1684
1938
  var IMAGE_REF_TYPE = {
1685
1939
  kind: "primitive",
1686
1940
  name: "ImageRef"
@@ -1705,7 +1959,7 @@ var NEOSCRIPT_STRUCTURED_LEAF_FIELDS = {
1705
1959
  {
1706
1960
  name: "SliceIndex",
1707
1961
  key: "sliceIndex",
1708
- type: INT_TYPE,
1962
+ type: INT_TYPE2,
1709
1963
  documentation: "Index into the file's slices."
1710
1964
  }
1711
1965
  ],
@@ -1727,13 +1981,13 @@ var NEOSCRIPT_STRUCTURED_LEAF_FIELDS = {
1727
1981
  {
1728
1982
  name: "x",
1729
1983
  key: "x",
1730
- type: INT_TYPE,
1984
+ type: INT_TYPE2,
1731
1985
  documentation: "Vector2Int x component."
1732
1986
  },
1733
1987
  {
1734
1988
  name: "y",
1735
1989
  key: "y",
1736
- type: INT_TYPE,
1990
+ type: INT_TYPE2,
1737
1991
  documentation: "Vector2Int y component."
1738
1992
  }
1739
1993
  ],
@@ -1761,19 +2015,19 @@ var NEOSCRIPT_STRUCTURED_LEAF_FIELDS = {
1761
2015
  {
1762
2016
  name: "x",
1763
2017
  key: "x",
1764
- type: INT_TYPE,
2018
+ type: INT_TYPE2,
1765
2019
  documentation: "Vector3Int x component."
1766
2020
  },
1767
2021
  {
1768
2022
  name: "y",
1769
2023
  key: "y",
1770
- type: INT_TYPE,
2024
+ type: INT_TYPE2,
1771
2025
  documentation: "Vector3Int y component."
1772
2026
  },
1773
2027
  {
1774
2028
  name: "z",
1775
2029
  key: "z",
1776
- type: INT_TYPE,
2030
+ type: INT_TYPE2,
1777
2031
  documentation: "Vector3Int z component."
1778
2032
  }
1779
2033
  ],
@@ -1856,14 +2110,14 @@ function builtinFunction(name, returnType, parameters, documentation) {
1856
2110
  var NEOSCRIPT_GLOBALS = [
1857
2111
  builtinFunction(
1858
2112
  "VisitCount",
1859
- INT_TYPE,
1860
- [parameter("pointer", STRING_TYPE)],
2113
+ INT_TYPE2,
2114
+ [parameter("pointer", STRING_TYPE2)],
1861
2115
  "Returns the number of visits recorded for a dialogue pointer."
1862
2116
  ),
1863
2117
  builtinFunction(
1864
2118
  "HasVisited",
1865
- BOOL_TYPE,
1866
- [parameter("pointer", STRING_TYPE)],
2119
+ BOOL_TYPE2,
2120
+ [parameter("pointer", STRING_TYPE2)],
1867
2121
  "Returns whether a dialogue pointer has been visited."
1868
2122
  )
1869
2123
  ];
@@ -1931,8 +2185,8 @@ var NEOSCRIPT_BUILTIN_TYPE_SYMBOLS = [
1931
2185
  // `FileId` and `SliceIndex` come from the field table above — they are
1932
2186
  // the writable, addressable fields, not derived properties (D11).
1933
2187
  ...structuredLeafFieldProperties("SpriteInfo"),
1934
- property("SpriteInfo", "FileName", STRING_TYPE, "Asset file name."),
1935
- property("SpriteInfo", "Name", STRING_TYPE, "Sprite name."),
2188
+ property("SpriteInfo", "FileName", STRING_TYPE2, "Asset file name."),
2189
+ property("SpriteInfo", "Name", STRING_TYPE2, "Sprite name."),
1936
2190
  property(
1937
2191
  "SpriteInfo",
1938
2192
  "Size",
@@ -1962,8 +2216,8 @@ var NEOSCRIPT_BUILTIN_TYPE_SYMBOLS = [
1962
2216
  name: "AudioClipInfo",
1963
2217
  kind: "builtin",
1964
2218
  members: [
1965
- property("AudioClipInfo", "FileId", STRING_TYPE, "Asset file id."),
1966
- property("AudioClipInfo", "Name", STRING_TYPE, "Audio clip name."),
2219
+ property("AudioClipInfo", "FileId", STRING_TYPE2, "Asset file id."),
2220
+ property("AudioClipInfo", "Name", STRING_TYPE2, "Audio clip name."),
1967
2221
  property(
1968
2222
  "AudioClipInfo",
1969
2223
  "DurationSeconds",
@@ -1973,10 +2227,13 @@ var NEOSCRIPT_BUILTIN_TYPE_SYMBOLS = [
1973
2227
  ]
1974
2228
  },
1975
2229
  {
1976
- id: "builtin:DialogueRef",
1977
- name: "DialogueRef",
2230
+ id: "builtin:NeoDialogueReference",
2231
+ name: "NeoDialogueReference",
1978
2232
  kind: "builtin",
1979
- members: [property("DialogueRef", "id", STRING_TYPE, "Dialogue id.")]
2233
+ members: [
2234
+ property("NeoDialogueReference", "id", STRING_TYPE2, "Dialogue id."),
2235
+ ...neoScriptDialogueReferenceMethods("builtin:NeoDialogueReference")
2236
+ ]
1980
2237
  },
1981
2238
  ...vectorTypes(),
1982
2239
  {
@@ -1998,7 +2255,7 @@ var NEOSCRIPT_BUILTIN_TYPE_SYMBOLS = [
1998
2255
  returnType: { kind: "primitive", name: "void" },
1999
2256
  static: true,
2000
2257
  parameters: [
2001
- ...name === "Assert" ? [parameter("condition", BOOL_TYPE)] : [],
2258
+ ...name === "Assert" ? [parameter("condition", BOOL_TYPE2)] : [],
2002
2259
  parameter("message", { kind: "primitive", name: "unknown" })
2003
2260
  ],
2004
2261
  documentation: name === "Assert" ? "Emits an assertion event when condition is false. Both arguments are evaluated. Does not throw." : "Emits a bounded message and the current NeoScript stack. Does not throw when the sink fails."
@@ -2029,25 +2286,25 @@ var NEOSCRIPT_BUILTIN_TYPE_SYMBOLS = [
2029
2286
  "Round",
2030
2287
  ["x"],
2031
2288
  `Rounds to the nearest integer; midpoints round to even (banker's rounding). ${MATH_INTEGRAL_RULE}`,
2032
- INT_TYPE
2289
+ INT_TYPE2
2033
2290
  ),
2034
2291
  mathFunction(
2035
2292
  "Floor",
2036
2293
  ["x"],
2037
2294
  `Rounds toward negative infinity. ${MATH_INTEGRAL_RULE}`,
2038
- INT_TYPE
2295
+ INT_TYPE2
2039
2296
  ),
2040
2297
  mathFunction(
2041
2298
  "Ceiling",
2042
2299
  ["x"],
2043
2300
  `Rounds toward positive infinity. ${MATH_INTEGRAL_RULE}`,
2044
- INT_TYPE
2301
+ INT_TYPE2
2045
2302
  ),
2046
2303
  mathFunction(
2047
2304
  "Truncate",
2048
2305
  ["x"],
2049
2306
  `Rounds toward zero. ${MATH_INTEGRAL_RULE}`,
2050
- INT_TYPE
2307
+ INT_TYPE2
2051
2308
  ),
2052
2309
  mathFunction(
2053
2310
  "Abs",
@@ -2058,7 +2315,7 @@ var NEOSCRIPT_BUILTIN_TYPE_SYMBOLS = [
2058
2315
  "Sign",
2059
2316
  ["x"],
2060
2317
  "Returns -1, 0, or 1 for a negative, zero, or positive value. Accepts int, float, or decimal and always returns int.",
2061
- INT_TYPE
2318
+ INT_TYPE2
2062
2319
  ),
2063
2320
  mathFunction(
2064
2321
  "Sqrt",
@@ -2099,7 +2356,7 @@ var NEOSCRIPT_BUILTIN_TYPE_SYMBOLS = [
2099
2356
  returnType: { kind: "list", elementType: LIST_ENTRY_TYPE },
2100
2357
  parameters: [
2101
2358
  parameter("value", LIST_ENTRY_TYPE),
2102
- parameter("count", INT_TYPE)
2359
+ parameter("count", INT_TYPE2)
2103
2360
  ],
2104
2361
  documentation: "Returns a list of count copies of value. The entry type is inferred from value and the assignment context \u2014 never spell it. value is evaluated exactly once, then count exactly once, so a reference-typed value is the same reference in every entry; count must be a non-negative int, and 0 produces an empty list.",
2105
2362
  static: true
@@ -2187,6 +2444,11 @@ function relativeDebugUri(uri) {
2187
2444
 
2188
2445
  // ../packages/neoscript-language/src/strict-ir.ts
2189
2446
  var NEOSCRIPT_COMPILER_REVISION = 17;
2447
+ var NeoScriptDialogueOp = /* @__PURE__ */ ((NeoScriptDialogueOp2) => {
2448
+ NeoScriptDialogueOp2["TryTrigger"] = "TryTrigger";
2449
+ NeoScriptDialogueOp2["CanTrigger"] = "CanTrigger";
2450
+ return NeoScriptDialogueOp2;
2451
+ })(NeoScriptDialogueOp || {});
2190
2452
 
2191
2453
  // ../src/models/neoscript/neoscript-compiler-revision.ts
2192
2454
  var ACTIVE_NEOSCRIPT_COMPILER_REVISION_ROLLOUT = (
@@ -3074,6 +3336,31 @@ function isNSFunctionHasVisited(value) {
3074
3336
  const v = value;
3075
3337
  return v?.type === "hasVisited" /* hasVisited */ && isNSDialogueMemoryFunctionInfo(v.info);
3076
3338
  }
3339
+ function isNSDialogueOp(value) {
3340
+ return value === "TryTrigger" || value === "CanTrigger";
3341
+ }
3342
+ function isOptionalNSPointer(value) {
3343
+ return value === void 0 || isNSPointer(value);
3344
+ }
3345
+ function isNSFunctionDialogueGroup(value) {
3346
+ const v = value;
3347
+ if (v?.type !== "dialogueGroup" /* dialogueGroup */) return false;
3348
+ const info = v.info;
3349
+ if (typeof info !== "object" || info === null) return false;
3350
+ if (!isNSDialogueOp(Reflect.get(info, "op"))) return false;
3351
+ if (typeof Reflect.get(info, "groupId") !== "string") return false;
3352
+ if (!isOptionalNSPointer(Reflect.get(info, "valuePointer"))) return false;
3353
+ return isOptionalNSPointer(Reflect.get(info, "onFinishPointer"));
3354
+ }
3355
+ function isNSFunctionDialogue(value) {
3356
+ const v = value;
3357
+ if (v?.type !== "dialogue" /* dialogue */) return false;
3358
+ const info = v.info;
3359
+ if (typeof info !== "object" || info === null) return false;
3360
+ if (!isNSDialogueOp(Reflect.get(info, "op"))) return false;
3361
+ if (!isNSPointer(Reflect.get(info, "dialogueIdPointer"))) return false;
3362
+ return isOptionalNSPointer(Reflect.get(info, "onFinishPointer"));
3363
+ }
3077
3364
  function isNSVectorConstructorType(value) {
3078
3365
  return value === 14 /* Vector2 */ || value === 15 /* Vector2Int */ || value === 16 /* Vector3 */ || value === 17 /* Vector3Int */;
3079
3366
  }
@@ -3133,7 +3420,7 @@ function isNSFunction(value) {
3133
3420
  return isNSFunctionClassConstructor(value) || isNSFunctionClassClone(value) || isNSFunctionListIndex(value) || isNSFunctionSelect(value) || isNSFunctionCollectionQuery(value) || isNSFunctionFirst(value) || isNSFunctionFirstOrDefault(value) || isNSFunctionWhere(value) || isNSFunctionContains(value) || isNSFunctionIndexOf(value) || // stringOp was missing from this chain since its introduction — a
3134
3421
  // compiled getter using ToLower()/StartsWith() would fail pointer
3135
3422
  // validation anywhere isNSFunction gates. Fixed alongside decimalOp.
3136
- isNSFunctionStringOp(value) || isNSFunctionDecimalOp(value) || isNSFunctionMathOp(value) || isNSFunctionListRepeat(value) || isNSFunctionCount(value) || isNSFunctionVisitCount(value) || isNSFunctionHasVisited(value) || isNSFunctionVectorConstructor(value) || isNSFunctionImageSlice(value) || isNSFunctionVariantInitialize(value) || isNSFunctionVariantApply(value) || isNSFunctionDeclaredConstructor(value);
3423
+ isNSFunctionStringOp(value) || isNSFunctionDecimalOp(value) || isNSFunctionMathOp(value) || isNSFunctionListRepeat(value) || isNSFunctionCount(value) || isNSFunctionVisitCount(value) || isNSFunctionHasVisited(value) || isNSFunctionDialogueGroup(value) || isNSFunctionDialogue(value) || isNSFunctionVectorConstructor(value) || isNSFunctionImageSlice(value) || isNSFunctionVariantInitialize(value) || isNSFunctionVariantApply(value) || isNSFunctionDeclaredConstructor(value);
3137
3424
  }
3138
3425
  function isNSInstructionVariable(value) {
3139
3426
  const v = value;
@@ -22268,6 +22555,26 @@ function evalFunction(fn, scope, ctx) {
22268
22555
  const pointer = evalPointer(fn.info.pointer, scope, ctx);
22269
22556
  return dialogueMemoryVisitCount(pointer, ctx) > 0;
22270
22557
  }
22558
+ case "dialogueGroup" /* dialogueGroup */: {
22559
+ if (fn.info.valuePointer !== void 0)
22560
+ evalPointer(fn.info.valuePointer, scope, ctx);
22561
+ if (fn.info.onFinishPointer !== void 0)
22562
+ evalPointer(fn.info.onFinishPointer, scope, ctx);
22563
+ return false;
22564
+ }
22565
+ case "dialogue" /* dialogue */: {
22566
+ const idPointer = fn.info.dialogueIdPointer;
22567
+ const dialogueId = evalPointer(idPointer, scope, ctx);
22568
+ if (dialogueId === null && idPointer.type === "keyOf" /* keyOf */ && idPointer.optional === true)
22569
+ return null;
22570
+ if (typeof dialogueId !== "string")
22571
+ throw new NSGetterRuntimeError(
22572
+ `${fn.info.op} needs a dialogue id string, but got ${dialogueId === null ? "null" : typeof dialogueId}.`
22573
+ );
22574
+ if (fn.info.onFinishPointer !== void 0)
22575
+ evalPointer(fn.info.onFinishPointer, scope, ctx);
22576
+ return false;
22577
+ }
22271
22578
  case "vectorConstructor" /* vectorConstructor */: {
22272
22579
  return evalVectorConstructor(
22273
22580
  fn.info.vectorType,
@@ -33780,14 +34087,17 @@ var Scope = class {
33780
34087
  return this.invalidatedRoots;
33781
34088
  }
33782
34089
  effectiveNarrowedPaths() {
33783
- const effective = this.parent ? new Map(this.parent.effectiveNarrowedPaths()) : /* @__PURE__ */ new Map();
33784
- for (const invalidated of this.invalidatedRoots) {
33785
- for (const [path, narrowed] of effective) {
33786
- if (narrowed.rootEntry === invalidated) effective.delete(path);
34090
+ const effective = new Map(this.narrowedPaths);
34091
+ const invalidated = new Set(this.invalidatedRoots);
34092
+ for (const root of this.hiddenNarrowingRoots) invalidated.add(root);
34093
+ for (let current = this.parent; current; current = current.parent) {
34094
+ for (const [path, narrowed] of current.narrowedPaths) {
34095
+ if (!effective.has(path) && !invalidated.has(narrowed.rootEntry)) {
34096
+ effective.set(path, narrowed);
34097
+ }
33787
34098
  }
33788
- }
33789
- for (const [path, narrowed] of this.narrowedPaths) {
33790
- effective.set(path, narrowed);
34099
+ for (const root of current.invalidatedRoots) invalidated.add(root);
34100
+ for (const root of current.hiddenNarrowingRoots) invalidated.add(root);
33791
34101
  }
33792
34102
  return effective;
33793
34103
  }
@@ -33813,6 +34123,9 @@ var Scope = class {
33813
34123
  hideInheritedNarrowing(rootEntry) {
33814
34124
  this.hiddenNarrowingRoots.add(rootEntry);
33815
34125
  this.updatePatternType(rootEntry, rootEntry.type);
34126
+ for (const [path, narrowed] of this.narrowedPaths) {
34127
+ if (narrowed.rootEntry === rootEntry) this.narrowedPaths.delete(path);
34128
+ }
33816
34129
  }
33817
34130
  invalidate(rootEntry) {
33818
34131
  this.invalidatedRoots.add(rootEntry);
@@ -34370,24 +34683,26 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
34370
34683
  const branchExitNarrowings = [];
34371
34684
  const branchExitOwnershipScopes = [];
34372
34685
  const branches = statement.branches.map((branch) => {
34686
+ const conditionScope = new Scope(scope);
34687
+ this.applyFactsToScope(conditionScope, cumulativeFalseFacts);
34373
34688
  const condition = this.toBool(
34374
- this.resolveExpression(branch.cond, scope),
34689
+ this.resolveExpression(branch.cond, conditionScope),
34375
34690
  branch.cond.pos
34376
34691
  );
34377
34692
  const child = new Scope(scope);
34378
34693
  const branchFacts = [
34379
34694
  ...cumulativeFalseFacts,
34380
- ...this.conditionFacts(branch.cond, scope, true)
34695
+ ...this.conditionFacts(branch.cond, conditionScope, true)
34381
34696
  ];
34382
34697
  this.applyFactsToScope(child, branchFacts);
34383
34698
  const instructions = this.resolveStatements(branch.body, child);
34384
34699
  if (!instructionsTerminate(instructions)) {
34385
34700
  branchExitFacts.push(branchFacts);
34386
- branchExitNarrowings.push(new Map(child.narrowedPaths));
34701
+ branchExitNarrowings.push(child.effectiveNarrowedPaths());
34387
34702
  branchExitOwnershipScopes.push(child);
34388
34703
  }
34389
34704
  cumulativeFalseFacts.push(
34390
- ...this.conditionFacts(branch.cond, scope, false)
34705
+ ...this.conditionFacts(branch.cond, conditionScope, false)
34391
34706
  );
34392
34707
  return {
34393
34708
  expression: pointerToBooleanExpression(condition.pointer),
@@ -34401,14 +34716,14 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
34401
34716
  otherwise = this.resolveStatements(statement.elseBody, elseScope);
34402
34717
  if (!instructionsTerminate(otherwise)) {
34403
34718
  branchExitFacts.push([...cumulativeFalseFacts]);
34404
- branchExitNarrowings.push(new Map(elseScope.narrowedPaths));
34719
+ branchExitNarrowings.push(elseScope.effectiveNarrowedPaths());
34405
34720
  branchExitOwnershipScopes.push(elseScope);
34406
34721
  }
34407
34722
  } else {
34408
34723
  const noBranchScope = new Scope(scope);
34409
34724
  this.applyFactsToScope(noBranchScope, cumulativeFalseFacts);
34410
34725
  branchExitFacts.push([...cumulativeFalseFacts]);
34411
- branchExitNarrowings.push(new Map(noBranchScope.narrowedPaths));
34726
+ branchExitNarrowings.push(noBranchScope.effectiveNarrowedPaths());
34412
34727
  branchExitOwnershipScopes.push(noBranchScope);
34413
34728
  }
34414
34729
  mergeBranchInvalidations(scope, branchExitOwnershipScopes);
@@ -34642,12 +34957,15 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
34642
34957
  statement.body,
34643
34958
  conditionLocals
34644
34959
  );
34645
- this.invalidateLoopEntryNarrowingsAssignedBy(
34646
- loopEntryScope,
34647
- loopScope,
34648
- [statement.iterator],
34649
- conditionLocals
34650
- );
34960
+ const bodyFlow = statementFlow(statement.body, /* @__PURE__ */ new WeakMap());
34961
+ if (bodyFlow.has("fallthrough") || bodyFlow.has("continue")) {
34962
+ this.invalidateLoopEntryNarrowingsAssignedBy(
34963
+ loopEntryScope,
34964
+ loopScope,
34965
+ [statement.iterator],
34966
+ conditionLocals
34967
+ );
34968
+ }
34651
34969
  const condition = this.toBool(
34652
34970
  this.resolveExpression(statement.condition, loopEntryScope),
34653
34971
  statement.condition.pos
@@ -35084,23 +35402,23 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
35084
35402
  resolveDebugStatement(expr, scope) {
35085
35403
  if (expr.kind !== "call" || expr.callee.kind !== "member" || expr.callee.receiver.kind !== "ident" || expr.callee.receiver.name !== "Debug" || this.hasValueReceiver("Debug", scope) || this.project.typeByName.get("Debug")?.id !== "builtin:Debug" && this.project.typeByName.has("Debug"))
35086
35404
  return null;
35087
- const method = expr.callee.name;
35405
+ const method2 = expr.callee.name;
35088
35406
  const severities = {
35089
35407
  Log: "log",
35090
35408
  LogWarning: "warning",
35091
35409
  LogError: "error",
35092
35410
  Assert: "assert"
35093
35411
  };
35094
- if (!Object.hasOwn(severities, method))
35095
- throw new CompileError(`Unknown Debug method '${method}'.`, expr.pos);
35096
- const severity = severities[method];
35097
- const expected = method === "Assert" ? 2 : 1;
35412
+ if (!Object.hasOwn(severities, method2))
35413
+ throw new CompileError(`Unknown Debug method '${method2}'.`, expr.pos);
35414
+ const severity = severities[method2];
35415
+ const expected = method2 === "Assert" ? 2 : 1;
35098
35416
  if (expr.args.length !== expected)
35099
35417
  throw new CompileError(
35100
- `Debug.${method} expects ${expected} argument(s).`,
35418
+ `Debug.${method2} expects ${expected} argument(s).`,
35101
35419
  expr.pos
35102
35420
  );
35103
- const condition = method === "Assert" ? this.resolveExpression(requiredAt(expr.args, 0), scope) : void 0;
35421
+ const condition = method2 === "Assert" ? this.resolveExpression(requiredAt(expr.args, 0), scope) : void 0;
35104
35422
  if (condition && (!isPrimitive(condition.type, "bool") || isNullable(condition.type)))
35105
35423
  throw new CompileError(
35106
35424
  "Debug.Assert requires a non-null bool condition.",
@@ -35514,13 +35832,13 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
35514
35832
  if (assignedPath) {
35515
35833
  const rootEntry = scope.lookup(pathRoot(assignedPath));
35516
35834
  if (rootEntry) {
35517
- const receiverFacts = receiverNarrowings(
35835
+ const retainedFacts = unaffectedNarrowings(
35518
35836
  assignedPath,
35519
35837
  rootEntry,
35520
35838
  scope
35521
35839
  );
35522
35840
  scope.invalidate(rootEntry);
35523
- for (const [path, type] of receiverFacts) {
35841
+ for (const [path, type] of retainedFacts) {
35524
35842
  scope.narrow(path, rootEntry, type);
35525
35843
  }
35526
35844
  if (statement.op === "=" && !isNullable(value.type)) {
@@ -35737,13 +36055,13 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
35737
36055
  if (assignedPath) {
35738
36056
  const rootEntry = scope.lookup(pathRoot(assignedPath));
35739
36057
  if (rootEntry) {
35740
- const receiverFacts = receiverNarrowings(
36058
+ const retainedFacts = unaffectedNarrowings(
35741
36059
  assignedPath,
35742
36060
  rootEntry,
35743
36061
  scope
35744
36062
  );
35745
36063
  scope.invalidate(rootEntry);
35746
- for (const [path, type] of receiverFacts) {
36064
+ for (const [path, type] of retainedFacts) {
35747
36065
  scope.narrow(path, rootEntry, type);
35748
36066
  }
35749
36067
  }
@@ -35990,6 +36308,17 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
35990
36308
  }
35991
36309
  }
35992
36310
  resolveExpression(expression, scope, expected) {
36311
+ const result = this.resolveReceiverExpression(expression, scope, expected);
36312
+ if (result.dialogues !== void 0) {
36313
+ throw new CompileError(
36314
+ dialogueValueError(result.dialogues),
36315
+ expression.pos
36316
+ );
36317
+ }
36318
+ return result;
36319
+ }
36320
+ /** {@link resolveExpression} that also admits a `root.Dialogues` receiver. */
36321
+ resolveReceiverExpression(expression, scope, expected) {
35993
36322
  let result = this.resolveExpressionCore(expression, scope, expected);
35994
36323
  if (result.pointer.type === "function" /* Function */ || result.pointer.type === "callFunction" /* CallFunction */ || result.pointer.type === "callDelegate" /* CallDelegate */ || result.pointer.type === "callAction" /* CallAction */ || result.pointer.type === "callGetter" /* CallGetter */) {
35995
36324
  result = {
@@ -36358,18 +36687,19 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
36358
36687
  case "coalesce": {
36359
36688
  const left = this.resolveExpression(expression.left, scope);
36360
36689
  const leftOptional = { ...left.type, nullable: true };
36690
+ const nullLeft = isNull(left.type);
36361
36691
  const right = this.resolveExpression(
36362
36692
  expression.right,
36363
36693
  scope,
36364
- leftOptional
36694
+ nullLeft ? expected : leftOptional
36365
36695
  );
36366
- if (!isNeoScriptTypeAssignable(right.type, leftOptional, this.project)) {
36696
+ if (!nullLeft && !isNeoScriptTypeAssignable(right.type, leftOptional, this.project)) {
36367
36697
  throw new CompileError(
36368
36698
  `\`??\` right operand ${this.describe(right.type)} is not assignable to ${this.describe(leftOptional)}`,
36369
36699
  expression.pos
36370
36700
  );
36371
36701
  }
36372
- const resultType = {
36702
+ const resultType = nullLeft ? right.type : {
36373
36703
  ...left.type,
36374
36704
  nullable: isNullable(left.type) && isNullable(right.type)
36375
36705
  };
@@ -37070,20 +37400,25 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
37070
37400
  return whenTrue ? factsWhenTrue(expression, pathOf) : factsWhenFalse(expression, pathOf);
37071
37401
  }
37072
37402
  /**
37073
- * A loop body is resolved once but can execute repeatedly. Any narrowing rooted
37074
- * in an outer binding that the body or iterator may write is therefore stale
37075
- * at a later iteration entry. Invalidate those roots before resolving the
37076
- * shared iteration so only the loop's own condition can narrow them again.
37403
+ * A loop body is resolved once but can execute repeatedly. Hide facts about
37404
+ * paths it may replace before resolving the shared iteration; unrelated facts
37405
+ * still hold, and the loop condition can narrow the written paths again.
37077
37406
  */
37078
37407
  invalidateLoopEntryNarrowingsAssignedBy(loopEntryScope, outerScope, statements, locals = /* @__PURE__ */ new Set()) {
37079
- for (const rootName of collectAssignedPathRoots(
37408
+ for (const assignedPath of collectAssignedPaths(
37080
37409
  statements,
37081
37410
  /* @__PURE__ */ new Set(),
37082
37411
  locals
37083
37412
  )) {
37084
- const path = this.narrowingPath(rootName, outerScope);
37413
+ const path = this.narrowingPath(assignedPath, outerScope);
37085
37414
  const outerEntry = path === null ? null : outerScope.lookup(pathRoot(path));
37086
- if (outerEntry) loopEntryScope.hideInheritedNarrowing(outerEntry);
37415
+ if (outerEntry && path !== null) {
37416
+ const retained = unaffectedNarrowings(path, outerEntry, loopEntryScope);
37417
+ loopEntryScope.hideInheritedNarrowing(outerEntry);
37418
+ for (const [retainedPath, type] of retained) {
37419
+ loopEntryScope.narrow(retainedPath, outerEntry, type);
37420
+ }
37421
+ }
37087
37422
  }
37088
37423
  }
37089
37424
  applyFactsToScope(targetScope, facts, mode = "all") {
@@ -37561,7 +37896,7 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
37561
37896
  return this.resolveStaticMemberValue(staticType, member, pos);
37562
37897
  }
37563
37898
  }
37564
- const resolvedReceiver = receiverValue ? receiverValue() : this.resolveExpression(receiverAst, scope);
37899
+ const resolvedReceiver = receiverValue ? receiverValue() : this.resolveReceiverExpression(receiverAst, scope);
37565
37900
  if (optional2 && !isNullable(resolvedReceiver.type)) {
37566
37901
  throw new CompileError(
37567
37902
  `\`?.\` requires an optional receiver; got ${this.describe(resolvedReceiver.type)}`,
@@ -37657,7 +37992,7 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
37657
37992
  }
37658
37993
  const primitiveMember = resolvePrimitiveMember(receiver.type, name);
37659
37994
  if (primitiveMember) {
37660
- if (isPrimitive(receiver.type, "DialogueRef")) {
37995
+ if (isPrimitive(receiver.type, "NeoDialogueReference")) {
37661
37996
  return {
37662
37997
  pointer: {
37663
37998
  type: "keyOf" /* KeyOf */,
@@ -37690,12 +38025,15 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
37690
38025
  pos
37691
38026
  );
37692
38027
  }
37693
- if (isPrimitive(receiver.type, "DialogueRef")) {
38028
+ if (isPrimitive(receiver.type, "NeoDialogueReference")) {
37694
38029
  throw new CompileError(
37695
38030
  `${this.describe(receiver.type)} has no member '${name}'`,
37696
38031
  pos
37697
38032
  );
37698
38033
  }
38034
+ if (receiver.dialogues !== void 0) {
38035
+ return this.resolveDialogueGroupRead(receiver, name, pos);
38036
+ }
37699
38037
  const memberReceiverType = neoScriptMemberLookupType(receiver.type);
37700
38038
  if (memberReceiverType.kind === "named") {
37701
38039
  const type = this.project.typeById.get(memberReceiverType.typeId);
@@ -37724,6 +38062,10 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
37724
38062
  if (this.userClassCode && type.id === this.rootTypeId && member.writability !== "user") {
37725
38063
  throw new CompileError("User code can only read `root.User`.", pos);
37726
38064
  }
38065
+ const dialogues = this.dialogueReceiverOf(member.type);
38066
+ if (dialogues !== void 0) {
38067
+ return { ...literal(member.type, null), dialogues, symbol: member };
38068
+ }
37727
38069
  if (member.static === true) {
37728
38070
  throw new CompileError(
37729
38071
  `Static member '${type.name}.${name}' must be accessed through the type name, not an instance.`,
@@ -38078,6 +38420,227 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
38078
38420
  );
38079
38421
  }
38080
38422
  }
38423
+ /** P105 §2.1. The receiver a value of this type is, if it is one. */
38424
+ dialogueReceiverOf(type) {
38425
+ if (type.kind !== "named") return void 0;
38426
+ return this.project.typeById.get(type.typeId)?.dialogues;
38427
+ }
38428
+ /** P105 §2.1. `<receiver>.<Group>`; the methods are only callable. */
38429
+ resolveDialogueGroupRead(receiver, name, pos) {
38430
+ const path = receiver.dialogues.path;
38431
+ const type = receiver.type.kind === "named" ? this.project.typeById.get(receiver.type.typeId) : void 0;
38432
+ const member = type?.members.find((candidate) => candidate.name === name);
38433
+ if (member === void 0) {
38434
+ throw new CompileError(`${path} has no dialogue group '${name}'.`, pos);
38435
+ }
38436
+ if (member.kind === "method") {
38437
+ throw new CompileError(
38438
+ `'${path}.${name}' must be called with \`()\`; it cannot be read as a value.`,
38439
+ pos
38440
+ );
38441
+ }
38442
+ const dialogues = this.dialogueReceiverOf(member.type);
38443
+ if (dialogues === void 0) {
38444
+ throw new Error(
38445
+ `Dialogue group member '${path}.${name}' has no group type.`
38446
+ );
38447
+ }
38448
+ return { ...literal(member.type, null), dialogues, symbol: member };
38449
+ }
38450
+ /** P105 §2.1. A call on `root.Dialogues` or one of its groups. */
38451
+ resolveDialogueReceiverCall(receiver, name, args, scope, pos) {
38452
+ if (receiver.kind === "root") {
38453
+ if (name === "VisitCount" || name === "HasVisited") {
38454
+ return this.resolveDialogueMemoryRead(name, args, scope, pos);
38455
+ }
38456
+ if (!isDialogueRequestName(name)) {
38457
+ throw new CompileError(
38458
+ `${receiver.path} has no method '${name}'.`,
38459
+ pos
38460
+ );
38461
+ }
38462
+ this.assertDialogueRequestAllowed(name, pos);
38463
+ requireDialogueArgCount(name, args, 1, name === "TryTrigger", pos);
38464
+ const dialogueId = this.resolveExpression(requiredAt(args, 0), scope, {
38465
+ kind: "primitive",
38466
+ name: "string"
38467
+ });
38468
+ this.requireAssignable(
38469
+ dialogueId.type,
38470
+ { kind: "primitive", name: "string" },
38471
+ requiredAt(args, 0).pos,
38472
+ "dialogueId"
38473
+ );
38474
+ return dialogueIntrinsic({
38475
+ type: "dialogue" /* Dialogue */,
38476
+ info: {
38477
+ op: NeoScriptDialogueOp[name],
38478
+ dialogueIdPointer: dialogueId.pointer,
38479
+ ...this.dialogueOnFinish(args[1], scope)
38480
+ }
38481
+ });
38482
+ }
38483
+ if (!isDialogueRequestName(name)) {
38484
+ throw new CompileError(`${receiver.path} has no member '${name}'.`, pos);
38485
+ }
38486
+ if (receiver.kind === "folder") {
38487
+ throw new CompileError(
38488
+ `${receiver.path} is a dialogue folder, so it has no '${name}'. Use one of its groups' members.`,
38489
+ pos
38490
+ );
38491
+ }
38492
+ this.assertDialogueRequestAllowed(name, pos);
38493
+ if (receiver.kind === "standard") {
38494
+ requireDialogueArgCount(name, args, 0, name === "TryTrigger", pos);
38495
+ return dialogueIntrinsic({
38496
+ type: "dialogueGroup" /* DialogueGroup */,
38497
+ info: {
38498
+ op: NeoScriptDialogueOp[name],
38499
+ groupId: receiver.groupId,
38500
+ ...this.dialogueOnFinish(args[0], scope)
38501
+ }
38502
+ });
38503
+ }
38504
+ const entryType = receiver.entryType;
38505
+ if (entryType === void 0) {
38506
+ throw new CompileError(
38507
+ `${receiver.path} can't be triggered: its lookup collection has no entry class.`,
38508
+ pos
38509
+ );
38510
+ }
38511
+ requireDialogueArgCount(name, args, 1, name === "TryTrigger", pos);
38512
+ const value = this.resolveExpression(requiredAt(args, 0), scope, entryType);
38513
+ this.requireAssignable(
38514
+ value.type,
38515
+ entryType,
38516
+ requiredAt(args, 0).pos,
38517
+ "lookup value"
38518
+ );
38519
+ return dialogueIntrinsic({
38520
+ type: "dialogueGroup" /* DialogueGroup */,
38521
+ info: {
38522
+ op: NeoScriptDialogueOp[name],
38523
+ groupId: receiver.groupId,
38524
+ valuePointer: value.pointer,
38525
+ ...this.dialogueOnFinish(args[1], scope)
38526
+ }
38527
+ });
38528
+ }
38529
+ /**
38530
+ * P105 §2.2. `NeoDialogueReference` methods request the dialogue by the
38531
+ * reference's `id`, the same index-0 read `.id` lowers to.
38532
+ */
38533
+ resolveDialogueReferenceCall(receiver, name, args, scope, pos, optional2) {
38534
+ if (this.userClassCode) {
38535
+ throw new CompileError(
38536
+ `User code can't use ${name}. Dialogues run against a save.`,
38537
+ pos
38538
+ );
38539
+ }
38540
+ const nullPropagating = optional2 || receiver.optionalChainType !== void 0;
38541
+ if (!optional2 && isNullable(receiver.type)) {
38542
+ throw new CompileError(
38543
+ `Member '${name}' is called on ${this.describe(receiver.type)}, which may be null. Handle null before calling through it \u2014 use \`!\` if it is always set, or \`?.\` or a null check that narrows it.`,
38544
+ pos
38545
+ );
38546
+ }
38547
+ this.assertDialogueRequestAllowed(name, pos);
38548
+ requireDialogueArgCount(name, args, 0, name === "TryTrigger", pos);
38549
+ const resolved = dialogueIntrinsic({
38550
+ type: "dialogue" /* Dialogue */,
38551
+ info: {
38552
+ op: NeoScriptDialogueOp[name],
38553
+ dialogueIdPointer: {
38554
+ type: "keyOf" /* KeyOf */,
38555
+ keyOf: { pointer: receiver.pointer, key: numberPointer(0) },
38556
+ ...nullPropagating ? { optional: true } : {}
38557
+ },
38558
+ ...this.dialogueOnFinish(args[0], scope)
38559
+ }
38560
+ });
38561
+ if (!nullPropagating) return resolved;
38562
+ return {
38563
+ ...resolved,
38564
+ type: { ...resolved.type, nullable: true },
38565
+ optionalChainType: resolved.type
38566
+ };
38567
+ }
38568
+ dialogueOnFinish(argument2, scope) {
38569
+ if (argument2 === void 0) return {};
38570
+ const onFinish = this.resolveExpression(
38571
+ argument2,
38572
+ scope,
38573
+ NEOSCRIPT_DIALOGUE_ON_FINISH_TYPE
38574
+ );
38575
+ this.requireAssignable(
38576
+ onFinish.type,
38577
+ NEOSCRIPT_DIALOGUE_ON_FINISH_TYPE,
38578
+ argument2.pos,
38579
+ "onFinish"
38580
+ );
38581
+ return { onFinishPointer: onFinish.pointer };
38582
+ }
38583
+ /**
38584
+ * P105 §2.4. Requests run only from bodies that run once per call; reads
38585
+ * run wherever dialogue memory has a value.
38586
+ */
38587
+ assertDialogueRequestAllowed(name, pos) {
38588
+ if (name === "CanTrigger") {
38589
+ this.assertDialogueMemoryReadable(name, pos);
38590
+ return;
38591
+ }
38592
+ const kind = this.context.kind;
38593
+ if (kind === "function" || kind === "action") return;
38594
+ if (kind === "getter" || kind === "property" || kind === "condition") {
38595
+ throw new CompileError(
38596
+ "A getter can't trigger a dialogue. It runs whenever its value is read.",
38597
+ pos
38598
+ );
38599
+ }
38600
+ if (kind === "setter") {
38601
+ throw new CompileError(
38602
+ "A setter can't trigger a dialogue. Trigger it from a function.",
38603
+ pos
38604
+ );
38605
+ }
38606
+ throw new CompileError(
38607
+ `${capitalize(dialogueBodyKindLabel(kind))} body can't trigger a dialogue. Dialogues only run during play.`,
38608
+ pos
38609
+ );
38610
+ }
38611
+ /**
38612
+ * P43 §7.2.2. Dialogue memory is runtime state; it has no value at push
38613
+ * time, in a freshly constructed instance, or while migrating a save.
38614
+ */
38615
+ assertDialogueMemoryReadable(name, pos) {
38616
+ const kind = this.context.kind;
38617
+ if (!isNeoScriptConstructionDocumentKind(kind) && kind !== "migration") {
38618
+ return;
38619
+ }
38620
+ throw new CompileError(
38621
+ `${name} reads runtime dialogue memory, which has no meaning in ${dialogueBodyKindLabel(kind)} body.`,
38622
+ pos
38623
+ );
38624
+ }
38625
+ resolveDialogueMemoryRead(name, args, scope, pos) {
38626
+ this.assertDialogueMemoryReadable(name, pos);
38627
+ requireArgCount(name, args, 1, pos);
38628
+ const pointer = this.resolveExpression(requiredAt(args, 0), scope, {
38629
+ kind: "primitive",
38630
+ name: "string"
38631
+ });
38632
+ if (!isPrimitive(pointer.type, "string")) {
38633
+ throw new CompileError(
38634
+ `${name} pointer must be a string; got ${this.describe(pointer.type)}`,
38635
+ pos
38636
+ );
38637
+ }
38638
+ return intrinsic(
38639
+ name === "VisitCount" ? "visitCount" /* VisitCount */ : "hasVisited" /* HasVisited */,
38640
+ { pointer: pointer.pointer },
38641
+ { kind: "primitive", name: name === "VisitCount" ? "int" : "bool" }
38642
+ );
38643
+ }
38081
38644
  /**
38082
38645
  * P69 §2.7. A member read on the `Math` namespace: the two constants lower
38083
38646
  * to `float` literals, and nothing else on `Math` is readable as a value.
@@ -38283,7 +38846,9 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
38283
38846
  return () => {
38284
38847
  if (!result) {
38285
38848
  try {
38286
- result = { value: this.resolveExpression(callee.receiver, scope) };
38849
+ result = {
38850
+ value: this.resolveReceiverExpression(callee.receiver, scope)
38851
+ };
38287
38852
  } catch (error) {
38288
38853
  result = { error };
38289
38854
  }
@@ -38338,31 +38903,11 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
38338
38903
  if (vector3)
38339
38904
  return this.resolveVectorConstructor(vector3, argumentsList2, scope, pos);
38340
38905
  if (callee.name === "VisitCount" || callee.name === "HasVisited") {
38341
- if (isNeoScriptConstructionDocumentKind(this.context.kind)) {
38342
- throw new CompileError(
38343
- `${callee.name} reads runtime dialogue memory, which has no meaning in a ${this.context.kind} body.`,
38344
- pos
38345
- );
38346
- }
38347
- requireArgCount(callee.name, argumentsList2, 1, pos);
38348
- const pointer = this.resolveExpression(
38349
- requiredAt(argumentsList2, 0),
38906
+ return this.resolveDialogueMemoryRead(
38907
+ callee.name,
38908
+ argumentsList2,
38350
38909
  scope,
38351
- { kind: "primitive", name: "string" }
38352
- );
38353
- if (!isPrimitive(pointer.type, "string")) {
38354
- throw new CompileError(
38355
- `${callee.name} pointer must be a string; got ${this.describe(pointer.type)}`,
38356
- pos
38357
- );
38358
- }
38359
- return intrinsic(
38360
- callee.name === "VisitCount" ? "visitCount" /* VisitCount */ : "hasVisited" /* HasVisited */,
38361
- { pointer: pointer.pointer },
38362
- {
38363
- kind: "primitive",
38364
- name: callee.name === "VisitCount" ? "int" : "bool"
38365
- }
38910
+ pos
38366
38911
  );
38367
38912
  }
38368
38913
  const global = this.context.project.globals.find(
@@ -38467,12 +39012,37 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
38467
39012
  }
38468
39013
  const receiver = receiverValue();
38469
39014
  const optional2 = callee.optional === true;
39015
+ if (receiver.dialogues !== void 0) {
39016
+ if (optional2) {
39017
+ throw new CompileError(
39018
+ `\`?.\` is not valid on ${receiver.dialogues.path}; it is never null.`,
39019
+ pos
39020
+ );
39021
+ }
39022
+ return this.resolveDialogueReceiverCall(
39023
+ receiver.dialogues,
39024
+ callee.name,
39025
+ argumentsList2,
39026
+ scope,
39027
+ pos
39028
+ );
39029
+ }
38470
39030
  if (optional2 && !isNullable(receiver.type)) {
38471
39031
  throw new CompileError(
38472
39032
  `\`?.\` requires an optional receiver; got ${this.describe(receiver.type)}`,
38473
39033
  pos
38474
39034
  );
38475
39035
  }
39036
+ if (isPrimitive(receiver.type, "NeoDialogueReference") && isDialogueRequestName(callee.name)) {
39037
+ return this.resolveDialogueReferenceCall(
39038
+ receiver,
39039
+ callee.name,
39040
+ argumentsList2,
39041
+ scope,
39042
+ pos,
39043
+ optional2
39044
+ );
39045
+ }
38476
39046
  if (callee.name === "Slice" && isPrimitive(receiver.type, "ImageRef")) {
38477
39047
  return this.resolveImageSlice(receiver, argumentsList2, scope, pos);
38478
39048
  }
@@ -40754,6 +41324,7 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
40754
41324
  }
40755
41325
  }
40756
41326
  const receiver = receiverValue();
41327
+ if (receiver.dialogues !== void 0) return null;
40757
41328
  const memberReceiverType = neoScriptMemberLookupType(receiver.type);
40758
41329
  if (memberReceiverType.kind !== "named") return null;
40759
41330
  const type = this.project.typeById.get(memberReceiverType.typeId);
@@ -41503,12 +42074,18 @@ function identPathSegments(expression) {
41503
42074
  if (receiver === null) return null;
41504
42075
  return [...receiver, expression.name];
41505
42076
  }
41506
- function receiverNarrowings(path, rootEntry, scope) {
42077
+ function unaffectedNarrowings(path, rootEntry, scope) {
41507
42078
  const facts = [];
41508
- for (let dot = path.indexOf("."); dot !== -1; dot = path.indexOf(".", dot + 1)) {
41509
- const prefix = path.slice(0, dot);
41510
- const type = scope.lookupNarrowedType(prefix, rootEntry);
41511
- if (type !== null) facts.push([prefix, type]);
42079
+ const prefix = `${path}.`;
42080
+ const dot = path.lastIndexOf(".");
42081
+ if (dot === -1) return facts;
42082
+ const member = path.slice(dot);
42083
+ for (const [candidate, narrowed] of scope.effectiveNarrowedPaths()) {
42084
+ if (narrowed.rootEntry !== rootEntry) continue;
42085
+ if (candidate === path || candidate.startsWith(prefix)) continue;
42086
+ if (candidate.endsWith(member) || candidate.includes(`${member}.`))
42087
+ continue;
42088
+ facts.push([candidate, narrowed.type]);
41512
42089
  }
41513
42090
  return facts;
41514
42091
  }
@@ -41832,22 +42409,22 @@ function localsWithBindings(locals, expression, whenTrue) {
41832
42409
  ...facts.flatMap((fact) => fact.bindingName ? [fact.bindingName] : [])
41833
42410
  ]);
41834
42411
  }
41835
- function collectAssignedPathRoots(statements, roots = /* @__PURE__ */ new Set(), inheritedLocals = /* @__PURE__ */ new Set(), flowCache = /* @__PURE__ */ new WeakMap()) {
42412
+ function collectAssignedPaths(statements, roots = /* @__PURE__ */ new Set(), inheritedLocals = /* @__PURE__ */ new Set(), flowCache = /* @__PURE__ */ new WeakMap()) {
41836
42413
  const locals = new Set(inheritedLocals);
41837
42414
  for (const statement of statements) {
41838
42415
  if (statement.kind === "assign") {
41839
42416
  const assignedPath = canonicalPath(statement.target);
41840
42417
  if (assignedPath && !locals.has(pathRoot(assignedPath))) {
41841
- roots.add(pathRoot(assignedPath));
42418
+ roots.add(assignedPath);
41842
42419
  }
41843
- collectAssignedPathRootsInExpression(
42420
+ collectAssignedPathsInExpression(
41844
42421
  statement.target,
41845
42422
  roots,
41846
42423
  locals,
41847
42424
  flowCache
41848
42425
  );
41849
42426
  if (statement.value)
41850
- collectAssignedPathRootsInExpression(
42427
+ collectAssignedPathsInExpression(
41851
42428
  statement.value,
41852
42429
  roots,
41853
42430
  locals,
@@ -41856,7 +42433,7 @@ function collectAssignedPathRoots(statements, roots = /* @__PURE__ */ new Set(),
41856
42433
  continue;
41857
42434
  }
41858
42435
  if (statement.kind === "varDecl") {
41859
- collectAssignedPathRootsInExpression(
42436
+ collectAssignedPathsInExpression(
41860
42437
  statement.init,
41861
42438
  roots,
41862
42439
  locals,
@@ -41870,7 +42447,7 @@ function collectAssignedPathRoots(statements, roots = /* @__PURE__ */ new Set(),
41870
42447
  const falseFacts = [];
41871
42448
  const fallthroughFacts = [];
41872
42449
  for (const branch of statement.branches) {
41873
- collectAssignedPathRootsInExpression(
42450
+ collectAssignedPathsInExpression(
41874
42451
  branch.cond,
41875
42452
  roots,
41876
42453
  falseLocals,
@@ -41880,7 +42457,7 @@ function collectAssignedPathRoots(statements, roots = /* @__PURE__ */ new Set(),
41880
42457
  ...falseFacts,
41881
42458
  ...factsWhenTrue(branch.cond, canonicalPath)
41882
42459
  ];
41883
- collectAssignedPathRoots(
42460
+ collectAssignedPaths(
41884
42461
  branch.body,
41885
42462
  roots,
41886
42463
  localsWithBindings(falseLocals, branch.cond, true),
@@ -41892,12 +42469,7 @@ function collectAssignedPathRoots(statements, roots = /* @__PURE__ */ new Set(),
41892
42469
  falseLocals = localsWithBindings(falseLocals, branch.cond, false);
41893
42470
  }
41894
42471
  if (statement.elseBody) {
41895
- collectAssignedPathRoots(
41896
- statement.elseBody,
41897
- roots,
41898
- falseLocals,
41899
- flowCache
41900
- );
42472
+ collectAssignedPaths(statement.elseBody, roots, falseLocals, flowCache);
41901
42473
  if (statementFlow(statement.elseBody, flowCache).has("fallthrough"))
41902
42474
  fallthroughFacts.push(falseFacts);
41903
42475
  } else {
@@ -41909,18 +42481,18 @@ function collectAssignedPathRoots(statements, roots = /* @__PURE__ */ new Set(),
41909
42481
  continue;
41910
42482
  }
41911
42483
  if (statement.kind === "try") {
41912
- collectAssignedPathRoots(statement.body, roots, locals, flowCache);
42484
+ collectAssignedPaths(statement.body, roots, locals, flowCache);
41913
42485
  for (const clause of statement.catches) {
41914
42486
  const catchLocals = /* @__PURE__ */ new Set([...locals, clause.name]);
41915
42487
  if (clause.filter) {
41916
- collectAssignedPathRootsInExpression(
42488
+ collectAssignedPathsInExpression(
41917
42489
  clause.filter,
41918
42490
  roots,
41919
42491
  catchLocals,
41920
42492
  flowCache
41921
42493
  );
41922
42494
  }
41923
- collectAssignedPathRoots(
42495
+ collectAssignedPaths(
41924
42496
  clause.body,
41925
42497
  roots,
41926
42498
  clause.filter ? localsWithBindings(catchLocals, clause.filter, true) : catchLocals,
@@ -41930,13 +42502,13 @@ function collectAssignedPathRoots(statements, roots = /* @__PURE__ */ new Set(),
41930
42502
  continue;
41931
42503
  }
41932
42504
  if (statement.kind === "while" || statement.kind === "doWhile") {
41933
- collectAssignedPathRootsInExpression(
42505
+ collectAssignedPathsInExpression(
41934
42506
  statement.condition,
41935
42507
  roots,
41936
42508
  locals,
41937
42509
  flowCache
41938
42510
  );
41939
- collectAssignedPathRoots(
42511
+ collectAssignedPaths(
41940
42512
  statement.body,
41941
42513
  roots,
41942
42514
  statement.kind === "while" ? localsWithBindings(locals, statement.condition, true) : locals,
@@ -41945,14 +42517,14 @@ function collectAssignedPathRoots(statements, roots = /* @__PURE__ */ new Set(),
41945
42517
  continue;
41946
42518
  }
41947
42519
  if (statement.kind === "for") {
41948
- collectAssignedPathRootsInExpression(
42520
+ collectAssignedPathsInExpression(
41949
42521
  statement.initializer.init,
41950
42522
  roots,
41951
42523
  locals,
41952
42524
  flowCache
41953
42525
  );
41954
42526
  const loopLocals = /* @__PURE__ */ new Set([...locals, statement.initializer.name]);
41955
- collectAssignedPathRootsInExpression(
42527
+ collectAssignedPathsInExpression(
41956
42528
  statement.condition,
41957
42529
  roots,
41958
42530
  loopLocals,
@@ -41963,22 +42535,17 @@ function collectAssignedPathRoots(statements, roots = /* @__PURE__ */ new Set(),
41963
42535
  statement.condition,
41964
42536
  true
41965
42537
  );
41966
- collectAssignedPathRoots(
42538
+ collectAssignedPaths(
41967
42539
  [statement.iterator],
41968
42540
  roots,
41969
42541
  iterationLocals,
41970
42542
  flowCache
41971
42543
  );
41972
- collectAssignedPathRoots(
41973
- statement.body,
41974
- roots,
41975
- iterationLocals,
41976
- flowCache
41977
- );
42544
+ collectAssignedPaths(statement.body, roots, iterationLocals, flowCache);
41978
42545
  continue;
41979
42546
  }
41980
42547
  if (statement.kind === "forEach") {
41981
- collectAssignedPathRootsInExpression(
42548
+ collectAssignedPathsInExpression(
41982
42549
  statement.collection,
41983
42550
  roots,
41984
42551
  locals,
@@ -41986,11 +42553,11 @@ function collectAssignedPathRoots(statements, roots = /* @__PURE__ */ new Set(),
41986
42553
  );
41987
42554
  const loopLocals = /* @__PURE__ */ new Set([...locals, statement.name]);
41988
42555
  if (statement.key) loopLocals.add(statement.key.name);
41989
- collectAssignedPathRoots(statement.body, roots, loopLocals, flowCache);
42556
+ collectAssignedPaths(statement.body, roots, loopLocals, flowCache);
41990
42557
  continue;
41991
42558
  }
41992
42559
  if (statement.kind === "switch") {
41993
- collectAssignedPathRootsInExpression(
42560
+ collectAssignedPathsInExpression(
41994
42561
  statement.selector,
41995
42562
  roots,
41996
42563
  locals,
@@ -41999,7 +42566,7 @@ function collectAssignedPathRoots(statements, roots = /* @__PURE__ */ new Set(),
41999
42566
  for (const section of statement.sections) {
42000
42567
  for (const label of section.labels) {
42001
42568
  if (label.kind === "case") {
42002
- collectAssignedPathRootsInExpression(
42569
+ collectAssignedPathsInExpression(
42003
42570
  label.expression,
42004
42571
  roots,
42005
42572
  locals,
@@ -42007,13 +42574,13 @@ function collectAssignedPathRoots(statements, roots = /* @__PURE__ */ new Set(),
42007
42574
  );
42008
42575
  }
42009
42576
  }
42010
- collectAssignedPathRoots(section.body, roots, locals, flowCache);
42577
+ collectAssignedPaths(section.body, roots, locals, flowCache);
42011
42578
  }
42012
42579
  continue;
42013
42580
  }
42014
42581
  if (statement.kind === "return" || statement.kind === "throw") {
42015
42582
  if (statement.expr)
42016
- collectAssignedPathRootsInExpression(
42583
+ collectAssignedPathsInExpression(
42017
42584
  statement.expr,
42018
42585
  roots,
42019
42586
  locals,
@@ -42022,7 +42589,7 @@ function collectAssignedPathRoots(statements, roots = /* @__PURE__ */ new Set(),
42022
42589
  continue;
42023
42590
  }
42024
42591
  if (statement.kind === "exprStmt") {
42025
- collectAssignedPathRootsInExpression(
42592
+ collectAssignedPathsInExpression(
42026
42593
  statement.expr,
42027
42594
  roots,
42028
42595
  locals,
@@ -42032,43 +42599,28 @@ function collectAssignedPathRoots(statements, roots = /* @__PURE__ */ new Set(),
42032
42599
  }
42033
42600
  return roots;
42034
42601
  }
42035
- function collectAssignedPathRootsInExpression(expression, roots, locals, flowCache) {
42602
+ function collectAssignedPathsInExpression(expression, roots, locals, flowCache) {
42036
42603
  switch (expression.kind) {
42037
42604
  case "litInterp":
42038
42605
  for (const part of expression.parts) {
42039
42606
  if (part.kind === "expr") {
42040
- collectAssignedPathRootsInExpression(
42041
- part.expr,
42042
- roots,
42043
- locals,
42044
- flowCache
42045
- );
42607
+ collectAssignedPathsInExpression(part.expr, roots, locals, flowCache);
42046
42608
  }
42047
42609
  }
42048
42610
  return;
42049
42611
  case "litList":
42050
42612
  for (const element of expression.elements) {
42051
- collectAssignedPathRootsInExpression(element, roots, locals, flowCache);
42613
+ collectAssignedPathsInExpression(element, roots, locals, flowCache);
42052
42614
  }
42053
42615
  return;
42054
42616
  case "litDict":
42055
42617
  for (const entry of expression.entries) {
42056
- collectAssignedPathRootsInExpression(
42057
- entry.key,
42058
- roots,
42059
- locals,
42060
- flowCache
42061
- );
42062
- collectAssignedPathRootsInExpression(
42063
- entry.value,
42064
- roots,
42065
- locals,
42066
- flowCache
42067
- );
42618
+ collectAssignedPathsInExpression(entry.key, roots, locals, flowCache);
42619
+ collectAssignedPathsInExpression(entry.value, roots, locals, flowCache);
42068
42620
  }
42069
42621
  return;
42070
42622
  case "member":
42071
- collectAssignedPathRootsInExpression(
42623
+ collectAssignedPathsInExpression(
42072
42624
  expression.receiver,
42073
42625
  roots,
42074
42626
  locals,
@@ -42076,13 +42628,13 @@ function collectAssignedPathRootsInExpression(expression, roots, locals, flowCac
42076
42628
  );
42077
42629
  return;
42078
42630
  case "index":
42079
- collectAssignedPathRootsInExpression(
42631
+ collectAssignedPathsInExpression(
42080
42632
  expression.receiver,
42081
42633
  roots,
42082
42634
  locals,
42083
42635
  flowCache
42084
42636
  );
42085
- collectAssignedPathRootsInExpression(
42637
+ collectAssignedPathsInExpression(
42086
42638
  expression.index,
42087
42639
  roots,
42088
42640
  locals,
@@ -42090,32 +42642,22 @@ function collectAssignedPathRootsInExpression(expression, roots, locals, flowCac
42090
42642
  );
42091
42643
  return;
42092
42644
  case "call":
42093
- collectAssignedPathRootsInExpression(
42645
+ collectAssignedPathsInExpression(
42094
42646
  expression.callee,
42095
42647
  roots,
42096
42648
  locals,
42097
42649
  flowCache
42098
42650
  );
42099
42651
  for (const argument2 of expression.args) {
42100
- collectAssignedPathRootsInExpression(
42101
- argument2,
42102
- roots,
42103
- locals,
42104
- flowCache
42105
- );
42652
+ collectAssignedPathsInExpression(argument2, roots, locals, flowCache);
42106
42653
  }
42107
42654
  return;
42108
42655
  case "new":
42109
42656
  for (const argument2 of expression.args) {
42110
- collectAssignedPathRootsInExpression(
42111
- argument2,
42112
- roots,
42113
- locals,
42114
- flowCache
42115
- );
42657
+ collectAssignedPathsInExpression(argument2, roots, locals, flowCache);
42116
42658
  }
42117
42659
  for (const initializer of expression.initializer ?? []) {
42118
- collectAssignedPathRootsInExpression(
42660
+ collectAssignedPathsInExpression(
42119
42661
  initializer.value,
42120
42662
  roots,
42121
42663
  locals,
@@ -42126,15 +42668,10 @@ function collectAssignedPathRootsInExpression(expression, roots, locals, flowCac
42126
42668
  case "annotated":
42127
42669
  for (const annotation2 of expression.annotations) {
42128
42670
  for (const argument2 of annotation2.args) {
42129
- collectAssignedPathRootsInExpression(
42130
- argument2,
42131
- roots,
42132
- locals,
42133
- flowCache
42134
- );
42671
+ collectAssignedPathsInExpression(argument2, roots, locals, flowCache);
42135
42672
  }
42136
42673
  }
42137
- collectAssignedPathRootsInExpression(
42674
+ collectAssignedPathsInExpression(
42138
42675
  expression.expression,
42139
42676
  roots,
42140
42677
  locals,
@@ -42143,13 +42680,13 @@ function collectAssignedPathRootsInExpression(expression, roots, locals, flowCac
42143
42680
  return;
42144
42681
  case "binary":
42145
42682
  case "coalesce":
42146
- collectAssignedPathRootsInExpression(
42683
+ collectAssignedPathsInExpression(
42147
42684
  expression.left,
42148
42685
  roots,
42149
42686
  locals,
42150
42687
  flowCache
42151
42688
  );
42152
- collectAssignedPathRootsInExpression(
42689
+ collectAssignedPathsInExpression(
42153
42690
  expression.right,
42154
42691
  roots,
42155
42692
  locals,
@@ -42157,19 +42694,19 @@ function collectAssignedPathRootsInExpression(expression, roots, locals, flowCac
42157
42694
  );
42158
42695
  return;
42159
42696
  case "conditional":
42160
- collectAssignedPathRootsInExpression(
42697
+ collectAssignedPathsInExpression(
42161
42698
  expression.condition,
42162
42699
  roots,
42163
42700
  locals,
42164
42701
  flowCache
42165
42702
  );
42166
- collectAssignedPathRootsInExpression(
42703
+ collectAssignedPathsInExpression(
42167
42704
  expression.whenTrue,
42168
42705
  roots,
42169
42706
  locals,
42170
42707
  flowCache
42171
42708
  );
42172
- collectAssignedPathRootsInExpression(
42709
+ collectAssignedPathsInExpression(
42173
42710
  expression.whenFalse,
42174
42711
  roots,
42175
42712
  locals,
@@ -42178,7 +42715,7 @@ function collectAssignedPathRootsInExpression(expression, roots, locals, flowCac
42178
42715
  return;
42179
42716
  case "unary":
42180
42717
  case "force":
42181
- collectAssignedPathRootsInExpression(
42718
+ collectAssignedPathsInExpression(
42182
42719
  expression.operand,
42183
42720
  roots,
42184
42721
  locals,
@@ -42186,7 +42723,7 @@ function collectAssignedPathRootsInExpression(expression, roots, locals, flowCac
42186
42723
  );
42187
42724
  return;
42188
42725
  case "is":
42189
- collectAssignedPathRootsInExpression(
42726
+ collectAssignedPathsInExpression(
42190
42727
  expression.operand,
42191
42728
  roots,
42192
42729
  locals,
@@ -42194,7 +42731,7 @@ function collectAssignedPathRootsInExpression(expression, roots, locals, flowCac
42194
42731
  );
42195
42732
  return;
42196
42733
  case "lambda":
42197
- collectAssignedPathRoots(
42734
+ collectAssignedPaths(
42198
42735
  expression.body,
42199
42736
  roots,
42200
42737
  /* @__PURE__ */ new Set([
@@ -42260,6 +42797,43 @@ function enumLiteralKeyOptionId(pointer) {
42260
42797
  }
42261
42798
  return pointer.value.value[0];
42262
42799
  }
42800
+ function isDialogueRequestName(name) {
42801
+ return name === "TryTrigger" || name === "CanTrigger";
42802
+ }
42803
+ function dialogueBodyKindLabel(kind) {
42804
+ if (kind === "initializer" || kind === "initializerExpression")
42805
+ return "an initializer";
42806
+ return `a ${kind}`;
42807
+ }
42808
+ function capitalize(text) {
42809
+ return `${text.charAt(0).toUpperCase()}${text.slice(1)}`;
42810
+ }
42811
+ function requireDialogueArgCount(name, args, required, acceptsOnFinish, pos) {
42812
+ if (!acceptsOnFinish) {
42813
+ requireArgCount(name, args, required, pos);
42814
+ return;
42815
+ }
42816
+ if (args.length === required || args.length === required + 1) return;
42817
+ throw new CompileError(
42818
+ `${name} expects ${required} or ${required + 1} arguments, got ${args.length}.`,
42819
+ pos
42820
+ );
42821
+ }
42822
+ function dialogueValueError(receiver) {
42823
+ if (receiver.kind === "root") {
42824
+ return `\`${receiver.path}\` is not a value. Use one of its members.`;
42825
+ }
42826
+ if (receiver.kind === "folder") {
42827
+ return `\`${receiver.path}\` is a dialogue folder, not a value. Use one of its groups' members.`;
42828
+ }
42829
+ return `\`${receiver.path}\` is a dialogue group, not a value. Use one of its members.`;
42830
+ }
42831
+ function dialogueIntrinsic(fn) {
42832
+ return {
42833
+ pointer: { type: "function" /* Function */, function: fn },
42834
+ type: { kind: "primitive", name: "bool" }
42835
+ };
42836
+ }
42263
42837
  function intrinsic(kind, info, type) {
42264
42838
  return {
42265
42839
  pointer: {
@@ -42466,7 +43040,7 @@ function primitiveValueKind(name) {
42466
43040
  return 11 /* Sprite */;
42467
43041
  case "AudioClipInfo":
42468
43042
  return 12 /* Audio */;
42469
- case "DialogueRef":
43043
+ case "NeoDialogueReference":
42470
43044
  return 18 /* DialogueLookup */;
42471
43045
  case "Vector2":
42472
43046
  return 14 /* Vector2 */;
@@ -42499,7 +43073,7 @@ function valueKindPrimitive(kind) {
42499
43073
  case 12 /* Audio */:
42500
43074
  return "AudioClipInfo";
42501
43075
  case 18 /* DialogueLookup */:
42502
- return "DialogueRef";
43076
+ return "NeoDialogueReference";
42503
43077
  case 14 /* Vector2 */:
42504
43078
  return "Vector2";
42505
43079
  case 15 /* Vector2Int */:
@@ -42690,7 +43264,7 @@ function resolvePrimitiveMember(type, name) {
42690
43264
  if (name === "length")
42691
43265
  return { type: { kind: "primitive", name: "float" } };
42692
43266
  }
42693
- if (type.name === "DialogueRef" && name === "id")
43267
+ if (type.name === "NeoDialogueReference" && name === "id")
42694
43268
  return { type: { kind: "primitive", name: "string" } };
42695
43269
  return null;
42696
43270
  }
@@ -42789,7 +43363,7 @@ function namedPrimitive(name) {
42789
43363
  case "decimal":
42790
43364
  case "SpriteInfo":
42791
43365
  case "AudioClipInfo":
42792
- case "DialogueRef":
43366
+ case "NeoDialogueReference":
42793
43367
  case "Vector2":
42794
43368
  case "Vector2Int":
42795
43369
  case "Vector3":
@@ -43024,7 +43598,10 @@ function resolveNeoScriptType(type, context, project) {
43024
43598
  }
43025
43599
  const named = project.typeByName.get(type.name);
43026
43600
  if (!named)
43027
- throw new CompileError(`Unknown type '${type.name}'`, type.pos);
43601
+ throw new CompileError(
43602
+ renamedDialogueTypeMessage(type.name, "value") ?? `Unknown type '${type.name}'`,
43603
+ type.pos
43604
+ );
43028
43605
  resolved = {
43029
43606
  kind: "named",
43030
43607
  typeId: named.id,
@@ -43365,7 +43942,8 @@ function projectSchemaManifest(input, options = {}) {
43365
43942
  (item, index) => enumType(item, environment, `enums[${index}]`)
43366
43943
  )
43367
43944
  ];
43368
- const rootType = createRootType(rootMemberIds, environment);
43945
+ const dialogues = neoScriptDialogueTypes(options.dialogueGroups ?? []);
43946
+ const rootType = createRootType(rootMemberIds, environment, dialogues.member);
43369
43947
  declaredTypes.push(rootType);
43370
43948
  const roots = options.roots ?? [
43371
43949
  {
@@ -43384,7 +43962,7 @@ function projectSchemaManifest(input, options = {}) {
43384
43962
  return {
43385
43963
  project: {
43386
43964
  version: options.version ?? `manifest:${nextManifestProjectionVersion++}`,
43387
- types: languageTypes,
43965
+ types: [...languageTypes, ...dialogues.types],
43388
43966
  globals: options.globals ?? [],
43389
43967
  roots,
43390
43968
  listIndexes: members.flatMap(
@@ -43519,7 +44097,7 @@ function staticDefaultWritability(classId, environment) {
43519
44097
  resolvedAllowedStorage(classId, environment)
43520
44098
  );
43521
44099
  }
43522
- function createRootType(ids, environment) {
44100
+ function createRootType(ids, environment, dialogues) {
43523
44101
  const definitions = [
43524
44102
  ["Assets", ids.assets, false, "immutable"],
43525
44103
  ["Save", ids.save, true, "save"],
@@ -43542,6 +44120,7 @@ function createRootType(ids, environment) {
43542
44120
  ...sourceLocation(member.source, environment, `root.${name}.source`)
43543
44121
  });
43544
44122
  }
44123
+ members.push(dialogues);
43545
44124
  return {
43546
44125
  id: "__root__",
43547
44126
  name: "Root",
@@ -44318,8 +44897,7 @@ function memberType(member, environment, visiting, field) {
44318
44897
  return member.multiselect === true ? { kind: "set", elementType: entryType, nullable: nullable2 } : { ...entryType, nullable: nullable2 };
44319
44898
  }
44320
44899
  if (kind === "dialogueLookup") {
44321
- const dialogue = primitive("DialogueRef", false);
44322
- return member.multiselect === true ? { kind: "set", elementType: dialogue, nullable: nullable2 } : { ...dialogue, nullable: nullable2 };
44900
+ return member.multiselect === true ? { kind: "set", elementType: primitive("string", false), nullable: nullable2 } : { ...primitive("NeoDialogueReference", false), nullable: nullable2 };
44323
44901
  }
44324
44902
  if (kind === "computed") {
44325
44903
  return manifestType(member.returnType, environment, `${field}.returnType`);
@@ -44801,7 +45379,7 @@ function manifestPrimitive(kind) {
44801
45379
  case "vector3Int":
44802
45380
  return "Vector3Int";
44803
45381
  case "dialogueLookup":
44804
- return "DialogueRef";
45382
+ return "NeoDialogueReference";
44805
45383
  case "color":
44806
45384
  return "Color";
44807
45385
  default:
@@ -45197,6 +45775,164 @@ function pascalIdentifier(value) {
45197
45775
  return identifier;
45198
45776
  }
45199
45777
 
45778
+ // ../src/models/dialogue/dialogue-source-identifiers.ts
45779
+ function isDialogueSourceIdentifier(value) {
45780
+ return isValidProjectSourceIdentifier(value);
45781
+ }
45782
+
45783
+ // ../src/models/dialogue/logic-types.ts
45784
+ function isNSBoolGetter(value) {
45785
+ if (!isNSGetter(value)) return false;
45786
+ if (value.typeInfo.type !== 1 /* Bool */) return false;
45787
+ return value.typeInfo.required === true;
45788
+ }
45789
+ function isNSVoidBody2(value) {
45790
+ if (!isNSGetter(value)) return false;
45791
+ if (value.typeInfo.type !== 0 /* Null */) return false;
45792
+ return value.typeInfo.required === true;
45793
+ }
45794
+ function isUILogicCondition(value) {
45795
+ const v = value;
45796
+ if (typeof v !== "object") return false;
45797
+ if (v === null) return false;
45798
+ if (!isNonEmptyString(v.id)) return false;
45799
+ if (v.type !== 0 /* UI */) return false;
45800
+ if (!isNSBoolGetter(v.getter)) return false;
45801
+ return isUIRenderableCondition(v.getter);
45802
+ }
45803
+ function isCodeLogicCondition(value) {
45804
+ const v = value;
45805
+ if (typeof v !== "object") return false;
45806
+ if (v === null) return false;
45807
+ if (!isNonEmptyString(v.id)) return false;
45808
+ if (v.type !== 1 /* Code */) return false;
45809
+ if (!isNonEmptyString(v.sourceFunctionId)) return false;
45810
+ if (!isDialogueSourceIdentifier(v.sourceFunctionName)) return false;
45811
+ if (typeof v.code !== "string") return false;
45812
+ return isNSBoolGetter(v.getter);
45813
+ }
45814
+ function isLogicCondition(value) {
45815
+ return isUILogicCondition(value) || isCodeLogicCondition(value);
45816
+ }
45817
+ function isUILogicAction(value) {
45818
+ const v = value;
45819
+ if (typeof v !== "object") return false;
45820
+ if (v === null) return false;
45821
+ if (v.type !== 0 /* UI */) return false;
45822
+ if (!isNSVoidBody2(v.action)) return false;
45823
+ return isUIRenderableAction(v.action);
45824
+ }
45825
+ function isCodeLogicAction(value) {
45826
+ const v = value;
45827
+ if (typeof v !== "object") return false;
45828
+ if (v === null) return false;
45829
+ if (v.type !== 1 /* Code */) return false;
45830
+ if (!isNonEmptyString(v.sourceFunctionId)) return false;
45831
+ if (!isDialogueSourceIdentifier(v.sourceFunctionName)) return false;
45832
+ if (typeof v.code !== "string") return false;
45833
+ return isNSVoidBody2(v.action);
45834
+ }
45835
+ function isNonEmptyString(value) {
45836
+ return typeof value === "string" && value.length > 0;
45837
+ }
45838
+ function isLogicAction(value) {
45839
+ return isUILogicAction(value) || isCodeLogicAction(value);
45840
+ }
45841
+ function isUIRenderableCondition(getter) {
45842
+ if (getter.instructions.length !== 1) return false;
45843
+ return getter.instructions[0]?.type === "return" /* return */;
45844
+ }
45845
+ function isUIRenderableAction(action) {
45846
+ if (action.instructions.length === 0) return true;
45847
+ if (action.instructions.length !== 1) return false;
45848
+ const instruction = action.instructions[0];
45849
+ if (!instruction) return false;
45850
+ return instruction.type === "return" /* return */ || instruction.type === "assign" /* assign */ || instruction.type === "collectionCall" /* collectionCall */ || instruction.type === "functionCall" /* functionCall */;
45851
+ }
45852
+
45853
+ // ../src/models/dialogue/dialogue-group-types.ts
45854
+ function isOptionalNullableString2(value) {
45855
+ if (value === void 0) return true;
45856
+ if (value === null) return true;
45857
+ return typeof value === "string";
45858
+ }
45859
+ function isDialogueGroupType(value) {
45860
+ return value === 0 /* Standard */ || value === 1 /* Lookup */ || value === 2 /* Folder */;
45861
+ }
45862
+ function isDialogueGroupBase(value, expectedType) {
45863
+ const v = value;
45864
+ if (typeof v !== "object") return false;
45865
+ if (v === null) return false;
45866
+ if (typeof v.name !== "string") return false;
45867
+ if (!isDialogueGroupType(v.type)) return false;
45868
+ if (expectedType !== void 0 && v.type !== expectedType) return false;
45869
+ if (!isOptionalNullableString2(v.parentDialogueGroupId)) return false;
45870
+ if (!Array.isArray(v.conditions)) return false;
45871
+ if (!v.conditions.every(isLogicCondition)) return false;
45872
+ return isOptionalNullableString2(v.priorityGroupIdOverride);
45873
+ }
45874
+ function isStandardDialogueGroupBase(value) {
45875
+ return isDialogueGroupBase(value, 0 /* Standard */);
45876
+ }
45877
+ function isLookupDialogueGroupBase(value) {
45878
+ const v = value;
45879
+ if (!isDialogueGroupBase(value, 1 /* Lookup */)) return false;
45880
+ if (typeof v?.collectionMemberId !== "string") return false;
45881
+ return isOptionalNullableString2(v.collectionValueId);
45882
+ }
45883
+ function isFolderDialogueGroupBase(value) {
45884
+ return isDialogueGroupBase(value, 2 /* Folder */);
45885
+ }
45886
+ function isDialogueGroupProps(value, expectedType) {
45887
+ const v = value;
45888
+ if (!isDialogueGroupBase(value, expectedType)) return false;
45889
+ if (!isWithId(value)) return false;
45890
+ if (!isIWithTimestamps(value)) return false;
45891
+ return typeof v?.projectId === "string";
45892
+ }
45893
+ function isDialogueGroup(value, expectedType) {
45894
+ return isDialogueGroupProps(value, expectedType);
45895
+ }
45896
+ function isAnyDialogueGroup(value) {
45897
+ if (!isDialogueGroup(value)) return false;
45898
+ return isStandardDialogueGroupBase(value) || isLookupDialogueGroupBase(value) || isFolderDialogueGroupBase(value);
45899
+ }
45900
+
45901
+ // ../src/models/dialogue/dialogue-group-language.ts
45902
+ var KINDS = {
45903
+ [0 /* Standard */]: "standard",
45904
+ [1 /* Lookup */]: "lookup",
45905
+ [2 /* Folder */]: "folder"
45906
+ };
45907
+ function storedDialogueGroupSources(groups, memberById, classById) {
45908
+ const sources2 = [];
45909
+ for (const group of groups) {
45910
+ const lookup = group.type === 1 /* Lookup */ ? lookupEntry(group.collectionMemberId, memberById, classById) : void 0;
45911
+ sources2.push({
45912
+ id: group.id,
45913
+ name: group.name,
45914
+ parentId: group.parentDialogueGroupId ?? null,
45915
+ kind: KINDS[group.type],
45916
+ ...lookup ? { lookup } : {}
45917
+ });
45918
+ }
45919
+ return sources2;
45920
+ }
45921
+ function lookupEntry(collectionMemberId, memberById, classById) {
45922
+ const collection = memberById(collectionMemberId);
45923
+ if (!isMemberListBase(collection) && !isMemberDictionaryBase(collection))
45924
+ return void 0;
45925
+ const entry = memberById(collection.entryMemberId);
45926
+ if (!isMemberClassBase(entry)) return void 0;
45927
+ const entryClass = classById(entry.classId);
45928
+ if (!entryClass) return void 0;
45929
+ return {
45930
+ collection: collection.name,
45931
+ entryType: { kind: "named", typeId: entryClass.id },
45932
+ entryTypeName: entryClass.name
45933
+ };
45934
+ }
45935
+
45200
45936
  // ../src/runtime/neoscript/analyzer-types.ts
45201
45937
  var AnalyzerRootClassId = "__root__";
45202
45938
  var AnalyzerDialogueContextClassId = "__dialogue_context__";
@@ -45238,7 +45974,7 @@ function resolveAnalyzerMember(context, member) {
45238
45974
  }
45239
45975
 
45240
45976
  // ../src/runtime/neoscript/neoscript-language-context-adapter.ts
45241
- var NEOSCRIPT_COMPILER_ADAPTER_REVISION = 5;
45977
+ var NEOSCRIPT_COMPILER_ADAPTER_REVISION = 6;
45242
45978
  var UNKNOWN_TYPE = {
45243
45979
  kind: "primitive",
45244
45980
  name: "unknown"
@@ -45415,8 +46151,15 @@ function createNeoScriptProjectInScope(context) {
45415
46151
  })
45416
46152
  });
45417
46153
  }
45418
- const rootType = createRootType2(context);
45419
- languageTypes.push(rootType);
46154
+ const dialogues = neoScriptDialogueTypes(
46155
+ storedDialogueGroupSources(
46156
+ context.vm.dialogueGroups ?? [],
46157
+ (id) => analyzerMemberById(context, id),
46158
+ (id) => analyzerSchemaIndex(context).classesById.get(id)
46159
+ )
46160
+ );
46161
+ const rootType = createRootType2(context, dialogues.member);
46162
+ languageTypes.push(rootType, ...dialogues.types);
45420
46163
  if (context.dialogueContext) {
45421
46164
  languageTypes.push(createDialogueContextType(context));
45422
46165
  }
@@ -45951,7 +46694,7 @@ var ROOT_WRITABILITY = {
45951
46694
  [3 /* Session */]: "session",
45952
46695
  [5 /* User */]: "user"
45953
46696
  };
45954
- function createRootType2(context) {
46697
+ function createRootType2(context, dialogues) {
45955
46698
  const members = [];
45956
46699
  for (const [index, root] of PROJECT_ROOTS.entries()) {
45957
46700
  const name = root.key;
@@ -45976,6 +46719,7 @@ function createRootType2(context) {
45976
46719
  )
45977
46720
  });
45978
46721
  }
46722
+ members.push(dialogues);
45979
46723
  return {
45980
46724
  id: AnalyzerRootClassId,
45981
46725
  name: "Root",
@@ -46078,11 +46822,11 @@ function memberRuntimeType(record4, context, seen = /* @__PURE__ */ new Set(), g
46078
46822
  if (isMemberDialogueLookupBase(member) && isMultiSelectionMember(member)) {
46079
46823
  return {
46080
46824
  kind: "set",
46081
- elementType: primitive2("DialogueRef", true),
46825
+ elementType: primitive2("string", true),
46082
46826
  nullable: !required
46083
46827
  };
46084
46828
  }
46085
- return primitive2("DialogueRef", required);
46829
+ return primitive2("NeoDialogueReference", required);
46086
46830
  case 14 /* Vector2 */:
46087
46831
  return primitive2("Vector2", required);
46088
46832
  case 15 /* Vector2Int */:
@@ -46330,7 +47074,7 @@ function toLanguageType(type, context, genericEnvironment) {
46330
47074
  case 12 /* Audio */:
46331
47075
  return primitive2("AudioClipInfo", required);
46332
47076
  case 18 /* DialogueLookup */:
46333
- return primitive2("DialogueRef", required);
47077
+ return primitive2("NeoDialogueReference", required);
46334
47078
  case 14 /* Vector2 */:
46335
47079
  return primitive2("Vector2", required);
46336
47080
  case 15 /* Vector2Int */:
@@ -46530,7 +47274,9 @@ function projectLanguageVersion(context) {
46530
47274
  ...context.vm.projectFiles ?? [],
46531
47275
  // P43 §6. Editing a constructor's parameters changes what a `new Foo(…)`
46532
47276
  // call site resolves to, so an open editor's cached context must rebuild.
46533
- ...context.constructors ?? []
47277
+ ...context.constructors ?? [],
47278
+ // P105 §2.6. Group names, parents, and kinds shape `root.Dialogues`.
47279
+ ...context.vm.dialogueGroups ?? []
46534
47280
  ];
46535
47281
  return [
46536
47282
  `adapter:${NEOSCRIPT_COMPILER_ADAPTER_REVISION}`,
@@ -46748,6 +47494,7 @@ function createAnalyzerProject(ctx) {
46748
47494
  return {
46749
47495
  project: ctx.project,
46750
47496
  projectFiles: [...ctx.projectFiles ?? []],
47497
+ dialogueGroups: [...ctx.dialogueGroups ?? []],
46751
47498
  members,
46752
47499
  classes: [...ctx.classes],
46753
47500
  enums: [...ctx.enums],
@@ -46992,6 +47739,7 @@ function compileDelegateClosureValue(code, signature) {
46992
47739
  const compiled = compileNSGetter(`return ${code};`, {
46993
47740
  project: signature.project,
46994
47741
  projectFiles: [...signature.projectFiles ?? []],
47742
+ dialogueGroups: signature.dialogueGroups ?? [],
46995
47743
  members: [...signature.members],
46996
47744
  classes: [...signature.classes],
46997
47745
  enums: [...signature.enums],
@@ -47051,6 +47799,7 @@ function compilationProjectContext(args, members = args.members) {
47051
47799
  return {
47052
47800
  project: args.project,
47053
47801
  projectFiles: args.projectFiles ?? [],
47802
+ dialogueGroups: args.dialogueGroups ?? [],
47054
47803
  members: [...members],
47055
47804
  classes: [...args.classes],
47056
47805
  enums: [...args.enums],
@@ -47252,6 +48001,7 @@ function compilationProjectForDocument(document2, state) {
47252
48001
  state.compilationProject ??= createNeoScriptCompilationProject({
47253
48002
  project: document2.project,
47254
48003
  projectFiles: document2.projectFiles,
48004
+ dialogueGroups: document2.dialogueGroups,
47255
48005
  members: document2.members,
47256
48006
  classes: document2.classes,
47257
48007
  enums: document2.enums,
@@ -47346,6 +48096,7 @@ function compileValueInitializerDependency(document2, valueId, compilationProjec
47346
48096
  compileValueRowInitializerBody({
47347
48097
  project: document2.project,
47348
48098
  projectFiles: document2.projectFiles,
48099
+ dialogueGroups: document2.dialogueGroups,
47349
48100
  members: document2.members,
47350
48101
  classes: document2.classes,
47351
48102
  enums: document2.enums,
@@ -47364,6 +48115,7 @@ function compileMemberInitializerDependency(document2, memberId, compilationProj
47364
48115
  const compileArgs = {
47365
48116
  project: document2.project,
47366
48117
  projectFiles: document2.projectFiles,
48118
+ dialogueGroups: document2.dialogueGroups,
47367
48119
  members: document2.members,
47368
48120
  classes: document2.classes,
47369
48121
  enums: document2.enums,
@@ -47512,7 +48264,7 @@ async function restartProjectRead(read) {
47512
48264
  // ../src/models/project/project-types.ts
47513
48265
  function isProject(value) {
47514
48266
  const v = value;
47515
- return typeof v?.name === "string" && typeof v?.id === "string" && isProjectOwner(v.owner) && isActorIdentifier(v.author) && typeof v?.createdAt === "number" && typeof v?.updatedAt === "number" && typeof v?.rootAssetsMemberId === "string" && typeof v?.rootSaveFileMemberId === "string" && typeof v?.rootSessionMemberId === "string" && typeof v?.rootUserMemberId === "string" && isOptionalNullableString2(v.defaultPriorityGroupId) && isOptionalNullableString2(v.defaultTextureTemplateId) && isOptionalNullableString2(v.defaultAudioClipTemplateId) && isProjectExportSettingsOrEmpty(v.exportSettings);
48267
+ return typeof v?.name === "string" && typeof v?.id === "string" && isProjectOwner(v.owner) && isActorIdentifier(v.author) && typeof v?.createdAt === "number" && typeof v?.updatedAt === "number" && typeof v?.rootAssetsMemberId === "string" && typeof v?.rootSaveFileMemberId === "string" && typeof v?.rootSessionMemberId === "string" && typeof v?.rootUserMemberId === "string" && isOptionalNullableString3(v.defaultPriorityGroupId) && isOptionalNullableString3(v.defaultTextureTemplateId) && isOptionalNullableString3(v.defaultAudioClipTemplateId) && isProjectExportSettingsOrEmpty(v.exportSettings);
47516
48268
  }
47517
48269
  function isProjectOwner(value) {
47518
48270
  if (!isActorIdentifier(value)) return false;
@@ -47524,7 +48276,7 @@ function isProjectExportSettingsOrEmpty(value) {
47524
48276
  const settings = value;
47525
48277
  return isUnityExportSettingsOrEmpty(settings.unity);
47526
48278
  }
47527
- function isOptionalNullableString2(value) {
48279
+ function isOptionalNullableString3(value) {
47528
48280
  if (value === void 0) return true;
47529
48281
  if (value === null) return true;
47530
48282
  return typeof value === "string";
@@ -47558,7 +48310,7 @@ function isProjectMigration(value) {
47558
48310
  }
47559
48311
 
47560
48312
  // ../src/models/variants/variants.ts
47561
- function isNonEmptyString(value) {
48313
+ function isNonEmptyString2(value) {
47562
48314
  if (typeof value !== "string") return false;
47563
48315
  return value.length > 0;
47564
48316
  }
@@ -47566,151 +48318,28 @@ function isNeoClassVariant(value) {
47566
48318
  if (typeof value !== "object" || value === null) return false;
47567
48319
  if (Array.isArray(value)) return false;
47568
48320
  const v = value;
47569
- if (!isNonEmptyString(v.id)) return false;
47570
- if (!isNonEmptyString(v.classId)) return false;
47571
- if (!isNonEmptyString(v.name)) return false;
47572
- if (!isNonEmptyString(v.valueId)) return false;
47573
- if (v.folderId !== null && !isNonEmptyString(v.folderId)) return false;
48321
+ if (!isNonEmptyString2(v.id)) return false;
48322
+ if (!isNonEmptyString2(v.classId)) return false;
48323
+ if (!isNonEmptyString2(v.name)) return false;
48324
+ if (!isNonEmptyString2(v.valueId)) return false;
48325
+ if (v.folderId !== null && !isNonEmptyString2(v.folderId)) return false;
47574
48326
  return true;
47575
48327
  }
47576
48328
  function isNeoClassVariantFolder(value) {
47577
48329
  if (typeof value !== "object" || value === null) return false;
47578
48330
  if (Array.isArray(value)) return false;
47579
48331
  const v = value;
47580
- if (!isNonEmptyString(v.id)) return false;
47581
- if (!isNonEmptyString(v.classId)) return false;
48332
+ if (!isNonEmptyString2(v.id)) return false;
48333
+ if (!isNonEmptyString2(v.classId)) return false;
47582
48334
  if (typeof v.path !== "string") return false;
47583
48335
  if (v.binding === void 0) return v.path.length > 0;
47584
48336
  if (typeof v.binding !== "object" || Array.isArray(v.binding)) return false;
47585
48337
  const binding = v.binding;
47586
- if (!isNonEmptyString(binding.collectionMemberId)) return false;
47587
- if (!isNonEmptyString(binding.collectionValueId)) return false;
48338
+ if (!isNonEmptyString2(binding.collectionMemberId)) return false;
48339
+ if (!isNonEmptyString2(binding.collectionValueId)) return false;
47588
48340
  return true;
47589
48341
  }
47590
48342
 
47591
- // ../src/models/dialogue/dialogue-source-identifiers.ts
47592
- function isDialogueSourceIdentifier(value) {
47593
- return isValidProjectSourceIdentifier(value);
47594
- }
47595
-
47596
- // ../src/models/dialogue/logic-types.ts
47597
- function isNSBoolGetter(value) {
47598
- if (!isNSGetter(value)) return false;
47599
- if (value.typeInfo.type !== 1 /* Bool */) return false;
47600
- return value.typeInfo.required === true;
47601
- }
47602
- function isNSVoidBody2(value) {
47603
- if (!isNSGetter(value)) return false;
47604
- if (value.typeInfo.type !== 0 /* Null */) return false;
47605
- return value.typeInfo.required === true;
47606
- }
47607
- function isUILogicCondition(value) {
47608
- const v = value;
47609
- if (typeof v !== "object") return false;
47610
- if (v === null) return false;
47611
- if (!isNonEmptyString2(v.id)) return false;
47612
- if (v.type !== 0 /* UI */) return false;
47613
- if (!isNSBoolGetter(v.getter)) return false;
47614
- return isUIRenderableCondition(v.getter);
47615
- }
47616
- function isCodeLogicCondition(value) {
47617
- const v = value;
47618
- if (typeof v !== "object") return false;
47619
- if (v === null) return false;
47620
- if (!isNonEmptyString2(v.id)) return false;
47621
- if (v.type !== 1 /* Code */) return false;
47622
- if (!isNonEmptyString2(v.sourceFunctionId)) return false;
47623
- if (!isDialogueSourceIdentifier(v.sourceFunctionName)) return false;
47624
- if (typeof v.code !== "string") return false;
47625
- return isNSBoolGetter(v.getter);
47626
- }
47627
- function isLogicCondition(value) {
47628
- return isUILogicCondition(value) || isCodeLogicCondition(value);
47629
- }
47630
- function isUILogicAction(value) {
47631
- const v = value;
47632
- if (typeof v !== "object") return false;
47633
- if (v === null) return false;
47634
- if (v.type !== 0 /* UI */) return false;
47635
- if (!isNSVoidBody2(v.action)) return false;
47636
- return isUIRenderableAction(v.action);
47637
- }
47638
- function isCodeLogicAction(value) {
47639
- const v = value;
47640
- if (typeof v !== "object") return false;
47641
- if (v === null) return false;
47642
- if (v.type !== 1 /* Code */) return false;
47643
- if (!isNonEmptyString2(v.sourceFunctionId)) return false;
47644
- if (!isDialogueSourceIdentifier(v.sourceFunctionName)) return false;
47645
- if (typeof v.code !== "string") return false;
47646
- return isNSVoidBody2(v.action);
47647
- }
47648
- function isNonEmptyString2(value) {
47649
- return typeof value === "string" && value.length > 0;
47650
- }
47651
- function isLogicAction(value) {
47652
- return isUILogicAction(value) || isCodeLogicAction(value);
47653
- }
47654
- function isUIRenderableCondition(getter) {
47655
- if (getter.instructions.length !== 1) return false;
47656
- return getter.instructions[0]?.type === "return" /* return */;
47657
- }
47658
- function isUIRenderableAction(action) {
47659
- if (action.instructions.length === 0) return true;
47660
- if (action.instructions.length !== 1) return false;
47661
- const instruction = action.instructions[0];
47662
- if (!instruction) return false;
47663
- return instruction.type === "return" /* return */ || instruction.type === "assign" /* assign */ || instruction.type === "collectionCall" /* collectionCall */ || instruction.type === "functionCall" /* functionCall */;
47664
- }
47665
-
47666
- // ../src/models/dialogue/dialogue-group-types.ts
47667
- function isOptionalNullableString3(value) {
47668
- if (value === void 0) return true;
47669
- if (value === null) return true;
47670
- return typeof value === "string";
47671
- }
47672
- function isDialogueGroupType(value) {
47673
- return value === 0 /* Standard */ || value === 1 /* Lookup */ || value === 2 /* Folder */;
47674
- }
47675
- function isDialogueGroupBase(value, expectedType) {
47676
- const v = value;
47677
- if (typeof v !== "object") return false;
47678
- if (v === null) return false;
47679
- if (typeof v.name !== "string") return false;
47680
- if (!isDialogueGroupType(v.type)) return false;
47681
- if (expectedType !== void 0 && v.type !== expectedType) return false;
47682
- if (!isOptionalNullableString3(v.parentDialogueGroupId)) return false;
47683
- if (!Array.isArray(v.conditions)) return false;
47684
- if (!v.conditions.every(isLogicCondition)) return false;
47685
- return isOptionalNullableString3(v.priorityGroupIdOverride);
47686
- }
47687
- function isStandardDialogueGroupBase(value) {
47688
- return isDialogueGroupBase(value, 0 /* Standard */);
47689
- }
47690
- function isLookupDialogueGroupBase(value) {
47691
- const v = value;
47692
- if (!isDialogueGroupBase(value, 1 /* Lookup */)) return false;
47693
- if (typeof v?.collectionMemberId !== "string") return false;
47694
- return isOptionalNullableString3(v.collectionValueId);
47695
- }
47696
- function isFolderDialogueGroupBase(value) {
47697
- return isDialogueGroupBase(value, 2 /* Folder */);
47698
- }
47699
- function isDialogueGroupProps(value, expectedType) {
47700
- const v = value;
47701
- if (!isDialogueGroupBase(value, expectedType)) return false;
47702
- if (!isWithId(value)) return false;
47703
- if (!isIWithTimestamps(value)) return false;
47704
- return typeof v?.projectId === "string";
47705
- }
47706
- function isDialogueGroup(value, expectedType) {
47707
- return isDialogueGroupProps(value, expectedType);
47708
- }
47709
- function isAnyDialogueGroup(value) {
47710
- if (!isDialogueGroup(value)) return false;
47711
- return isStandardDialogueGroupBase(value) || isLookupDialogueGroupBase(value) || isFolderDialogueGroupBase(value);
47712
- }
47713
-
47714
48343
  // ../src/models/dialogue/dialogue-types.ts
47715
48344
  function isNonArrayObject(value) {
47716
48345
  if (!isRequiredType(value, isObject)) return false;
@@ -54658,7 +55287,7 @@ var SPECIALIZED_RELATION_KINDS = /* @__PURE__ */ new Set([
54658
55287
 
54659
55288
  // ../packages/manifest/schema-contract/registry.mjs
54660
55289
  var PROJECT_SCHEMA_CONTRACT = Object.freeze({
54661
- cliVersion: "0.72.2",
55290
+ cliVersion: "0.73.0",
54662
55291
  projectFileUploadBatchSize: 32,
54663
55292
  documentRecords: {
54664
55293
  member: {
@@ -56140,6 +56769,7 @@ function createCliNeoScriptContext(options) {
56140
56769
  const vm = {
56141
56770
  project: options.documents.project,
56142
56771
  projectFiles: [...options.documents.projectFiles ?? []],
56772
+ dialogueGroups: [...options.documents.dialogueGroups ?? []],
56143
56773
  members,
56144
56774
  classes: [...options.documents.classes],
56145
56775
  enums: [...options.documents.enums],
@@ -56166,10 +56796,25 @@ function createCliNeoScriptContext(options) {
56166
56796
  // root placement is server context, not authored schema-manifest state.
56167
56797
  roots: compilerContext.project.roots,
56168
56798
  globals: compilerContext.project.globals,
56169
- version: compilerContext.project.version
56799
+ version: compilerContext.project.version,
56800
+ dialogueGroups: cliDialogueGroupSources(options.documents)
56170
56801
  });
56171
56802
  return { ...compilerContext, project: projection.project };
56172
56803
  }
56804
+ function cliDialogueGroupSources(documents) {
56805
+ if (!documents.dialogueGroups?.length) return [];
56806
+ const members = new Map(
56807
+ documents.members.map((member) => [member.id, member])
56808
+ );
56809
+ const classes = new Map(
56810
+ documents.classes.map((schemaClass2) => [schemaClass2.id, schemaClass2])
56811
+ );
56812
+ return storedDialogueGroupSources(
56813
+ documents.dialogueGroups,
56814
+ (id) => members.get(id),
56815
+ (id) => classes.get(id)
56816
+ );
56817
+ }
56173
56818
  function compileCliNeoScript(uri, source, context, projectIndex) {
56174
56819
  const result = compileNeoScriptStrict(
56175
56820
  {
@@ -56404,7 +57049,7 @@ var WORLD_OBJECT_CONTRACT_WORLD_KINDS = /* @__PURE__ */ new Set([
56404
57049
  ]);
56405
57050
 
56406
57051
  // ../src/models/exports/unity-codegen-revision.ts
56407
- var UNITY_CODEGEN_REVISION = "45a0847addd4616acfc29f142556dcb2e0a27daae14d6aa456430228e66dbc07";
57052
+ var UNITY_CODEGEN_REVISION = "e4a632a177c87244e19da71c9840b8007735773ae5f81578f58ce246ec6cb03d";
56408
57053
 
56409
57054
  // src/export-cache.ts
56410
57055
  var CACHE_BUILD = JSON.stringify([
@@ -56602,6 +57247,7 @@ function sharedEvaluatorBase(rawDocument) {
56602
57247
  variants: document2.variants,
56603
57248
  variantFolders: document2.variantFolders,
56604
57249
  projectFiles: document2.projectFiles,
57250
+ dialogueGroups: document2.dialogueGroups,
56605
57251
  textureTemplates: document2.textureTemplates,
56606
57252
  localizationConfig: document2.localizationConfig,
56607
57253
  localizedTexts: document2.localizedTexts,