@gaialabs/core 0.2.13 → 0.2.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -936,7 +936,7 @@ var RomDataReader = class {
936
936
  romData;
937
937
  position;
938
938
  offset;
939
- constructor(romData, offset = 0) {
939
+ constructor(romData, offset) {
940
940
  if (!romData) throw new Error("romData cannot be null");
941
941
  this.romData = romData;
942
942
  this.position = 0;
@@ -1098,7 +1098,7 @@ var RomProcessingConstants = class RomProcessingConstants {
1098
1098
  * BlockReader specific constants
1099
1099
  */
1100
1100
  var BlockReaderConstants = class {
1101
- static REF_SEARCH_MAX_RANGE = 416;
1101
+ static REF_SEARCH_MAX_RANGE = 896;
1102
1102
  static BANK_MASK_CHECK = 64;
1103
1103
  static BYTE_DELIMITER_THRESHOLD = 256;
1104
1104
  static BANK_HIGH_MEMORY_1 = 126;
@@ -1130,6 +1130,7 @@ let AddressType = /* @__PURE__ */ function(AddressType) {
1130
1130
  AddressType["Relative"] = "Relative";
1131
1131
  AddressType["WRelative"] = "WRelative";
1132
1132
  AddressType["Location"] = "Location";
1133
+ AddressType["OddLocation"] = "OddLocation";
1133
1134
  return AddressType;
1134
1135
  }({});
1135
1136
  /**
@@ -1220,6 +1221,7 @@ var Address = class Address {
1220
1221
  case "@": return AddressType.Address;
1221
1222
  case "*": return AddressType.WBank;
1222
1223
  case "%": return AddressType.Location;
1224
+ case "!": return AddressType.OddLocation;
1223
1225
  default: return AddressType.Unknown;
1224
1226
  }
1225
1227
  }
@@ -1230,6 +1232,7 @@ var Address = class Address {
1230
1232
  case AddressType.Address: return "@";
1231
1233
  case AddressType.WBank: return "*";
1232
1234
  case AddressType.Location: return "%";
1235
+ case AddressType.OddLocation: return "!";
1233
1236
  default: return null;
1234
1237
  }
1235
1238
  }
@@ -1674,6 +1677,7 @@ var ChunkFile = class {
1674
1677
  scene;
1675
1678
  base;
1676
1679
  referenceManager;
1680
+ isFile;
1677
1681
  constructor(type, name, size = 0, location = 0) {
1678
1682
  this.type = type;
1679
1683
  this.name = name;
@@ -1681,6 +1685,7 @@ var ChunkFile = class {
1681
1685
  this.location = location;
1682
1686
  this.mnemonics = {};
1683
1687
  this.compressed = type.compressed;
1688
+ this.isFile = !type.isBlock;
1684
1689
  }
1685
1690
  enrichWithRawDataFromDbFile(file, rom, compression) {
1686
1691
  this.upper = file.upper ?? this.upper;
@@ -1689,7 +1694,8 @@ var ChunkFile = class {
1689
1694
  this.base = file.base ?? this.type.base ?? this.base;
1690
1695
  this.group = file.group ?? this.group;
1691
1696
  this.scene = file.scene ?? this.scene;
1692
- this.compressed = file.compressed;
1697
+ this.compressed = file.compressed ?? this.type.compressed ?? this.compressed;
1698
+ this.isFile = true;
1693
1699
  let start = this.location;
1694
1700
  let header = null;
1695
1701
  const fileType = this.type;
@@ -1715,6 +1721,8 @@ var ChunkFile = class {
1715
1721
  enrichWithAsmBlocksFromDbBlock(block, memoryMode) {
1716
1722
  this.group = block.group;
1717
1723
  this.scene = block.scene;
1724
+ this.base = block.base;
1725
+ this.isFile = false;
1718
1726
  this.parts = [];
1719
1727
  this.size = 0;
1720
1728
  if (!block.parts?.length) throw new Error(`Block ${block.name} has no parts`);
@@ -1925,20 +1933,30 @@ var ReferenceManager = class {
1925
1933
  structTable = /* @__PURE__ */ new Map();
1926
1934
  markerTable = /* @__PURE__ */ new Map();
1927
1935
  nameTable = /* @__PURE__ */ new Map();
1936
+ fileTable = /* @__PURE__ */ new Map();
1928
1937
  root;
1929
1938
  constructor(root) {
1930
1939
  if (!root) throw new Error("root cannot be null");
1931
1940
  this.root = root;
1932
1941
  }
1933
1942
  tryGetStruct(location) {
1934
- const chunkType = this.structTable.get(location);
1943
+ let chunkType = this.structTable.get(location);
1944
+ const found = chunkType !== void 0;
1945
+ let isSoft;
1946
+ if (chunkType) if (chunkType[0] === "~") {
1947
+ isSoft = true;
1948
+ chunkType = chunkType.substring(1);
1949
+ } else isSoft = false;
1935
1950
  return {
1936
- found: chunkType !== void 0,
1937
- chunkType
1951
+ found,
1952
+ chunkType,
1953
+ isSoft
1938
1954
  };
1939
1955
  }
1940
1956
  tryAddStruct(location, chunkType) {
1941
- if (this.structTable.has(location)) return false;
1957
+ const existingStruct = this.tryGetStruct(location);
1958
+ const isSoft = chunkType[0] === "~";
1959
+ if (existingStruct.isSoft === false || existingStruct.found && isSoft) return false;
1942
1960
  this.structTable.set(location, chunkType);
1943
1961
  return true;
1944
1962
  }
@@ -1946,14 +1964,23 @@ var ReferenceManager = class {
1946
1964
  return this.structTable.has(location);
1947
1965
  }
1948
1966
  tryGetName(location) {
1949
- const referenceName = this.nameTable.get(location);
1967
+ let referenceName = this.nameTable.get(location);
1968
+ const found = referenceName !== void 0;
1969
+ let isSoft;
1970
+ if (referenceName) if (referenceName[0] === "~") {
1971
+ isSoft = true;
1972
+ referenceName = referenceName.substring(1);
1973
+ } else isSoft = false;
1950
1974
  return {
1951
- found: referenceName !== void 0,
1952
- referenceName
1975
+ found,
1976
+ referenceName,
1977
+ isSoft
1953
1978
  };
1954
1979
  }
1955
1980
  tryAddName(location, referenceName) {
1956
- if (this.nameTable.has(location)) return false;
1981
+ const existingName = this.tryGetName(location);
1982
+ const isSoft = referenceName[0] === "~";
1983
+ if (existingName.isSoft === false || existingName.found && isSoft) return false;
1957
1984
  this.nameTable.set(location, referenceName);
1958
1985
  return true;
1959
1986
  }
@@ -1974,6 +2001,7 @@ var ReferenceManager = class {
1974
2001
  }
1975
2002
  createTypeName(type, location) {
1976
2003
  let name = type.toLowerCase();
2004
+ if (type[0] === "~") name = name.substring(1);
1977
2005
  if (name === "branch") name = "loc";
1978
2006
  while (name.length > 0 && BlockReaderConstants.POINTER_CHARACTERS.includes(name[0])) name = name.substring(1) + "_list";
1979
2007
  return `${name}_${location.toString(16).toUpperCase().padStart(6, "0")}`;
@@ -1995,7 +2023,7 @@ var ReferenceManager = class {
1995
2023
  resolveName(location, type, isBranch) {
1996
2024
  const prefix = Address.codeFromType(type);
1997
2025
  let name;
1998
- let label = null;
2026
+ let label;
1999
2027
  let resolvedLocation = location;
2000
2028
  const rewrite = this.root.rewrites[location];
2001
2029
  if (rewrite !== void 0) {
@@ -2003,9 +2031,8 @@ var ReferenceManager = class {
2003
2031
  resolvedLocation = result.location;
2004
2032
  label = result.label;
2005
2033
  }
2006
- const existingName = this.nameTable.get(resolvedLocation);
2007
- if (existingName) name = existingName;
2008
- else name = isBranch ? this.createBranchLabel(resolvedLocation) : this.findClosestReference(resolvedLocation) || this.createFallbackName(resolvedLocation);
2034
+ name = this.tryGetName(resolvedLocation).referenceName;
2035
+ if (!name) name = isBranch ? this.createBranchLabel(resolvedLocation) : this.findClosestReference(resolvedLocation) || this.createFallbackName(resolvedLocation);
2009
2036
  return `${prefix || ""}${name}${label || ""}`;
2010
2037
  }
2011
2038
  findClosestReference(location) {
@@ -2027,8 +2054,8 @@ var ReferenceManager = class {
2027
2054
  const offset = location - rewrite;
2028
2055
  const cmd = offset < 0 ? "-" : "+";
2029
2056
  const absOffset = Math.abs(offset);
2030
- let label = null;
2031
- if (this.structTable.get(rewrite) === BlockReaderConstants.WIDE_STRING_TYPE) {
2057
+ let label;
2058
+ if (this.tryGetStruct(rewrite).chunkType === BlockReaderConstants.WIDE_STRING_TYPE) {
2032
2059
  this.markerTable.set(rewrite, absOffset);
2033
2060
  this.markerTable.set(location, absOffset);
2034
2061
  label = cmd === "-" ? BlockReaderConstants.NEGATIVE_MARKER_FORMAT : BlockReaderConstants.MARKER_FORMAT;
@@ -2041,7 +2068,7 @@ var ReferenceManager = class {
2041
2068
  processClosestMatch(location, closestName, closestLocation, closestDistance) {
2042
2069
  if (!closestName || closestLocation === null) return null;
2043
2070
  let result = closestName;
2044
- if (this.structTable.get(closestLocation) === BlockReaderConstants.WIDE_STRING_TYPE) {
2071
+ if (this.tryGetStruct(closestLocation).chunkType === BlockReaderConstants.WIDE_STRING_TYPE) {
2045
2072
  this.markerTable.set(closestLocation, closestDistance);
2046
2073
  this.markerTable.set(location, closestDistance);
2047
2074
  result += BlockReaderConstants.MARKER_FORMAT;
@@ -2107,6 +2134,10 @@ var StackOperations = class {
2107
2134
  case "XBA":
2108
2135
  this.handleExchangeBytes();
2109
2136
  break;
2137
+ case "RTL":
2138
+ case "RTS":
2139
+ this._blockReader._referenceManager.tryAddStruct(this._blockReader._romDataReader.position, "~Code");
2140
+ break;
2110
2141
  }
2111
2142
  }
2112
2143
  handleAccumulatorPush() {
@@ -2156,7 +2187,16 @@ var CopCommandProcessor = class {
2156
2187
  * Parses a COP command based on its definition
2157
2188
  */
2158
2189
  parseCopCommand(copDef, operands) {
2159
- for (let partStr of copDef.parts) {
2190
+ let parts = copDef.parts;
2191
+ if (copDef.conditions) for (const condition of copDef.conditions) {
2192
+ let value = this._romDataReader.romData[this._romDataReader.position + condition.offset];
2193
+ if (condition.value >= 256) value |= this._romDataReader.romData[this._romDataReader.position + condition.offset + 1] << 8;
2194
+ if (value === condition.value) {
2195
+ parts = condition.parts;
2196
+ break;
2197
+ }
2198
+ }
2199
+ for (let partStr of parts) {
2160
2200
  let bank = null;
2161
2201
  const bankHintIx = partStr.indexOf("$");
2162
2202
  if (bankHintIx > 0) {
@@ -2339,6 +2379,7 @@ var AddressingModeHandler = class {
2339
2379
  if (address.isROM) {
2340
2380
  const wrapper = new LocationWrapper(address.toLocation(), AddressType.Address);
2341
2381
  if (this.isJumpInstruction(mnemonic)) this._blockReader.noteType(wrapper.location, "Code", false, reg);
2382
+ if (mnemonic === "JML") this._blockReader._referenceManager.tryAddStruct(this._dataReader.position, "Code");
2342
2383
  operands.push(wrapper);
2343
2384
  } else operands.push(address);
2344
2385
  }
@@ -2352,7 +2393,7 @@ var AddressingModeHandler = class {
2352
2393
  }
2353
2394
  handlePCRelativeMode(operands, nextAddress, reg, isLong) {
2354
2395
  const relative = isLong ? nextAddress + this._dataReader.readShort() : nextAddress + this._dataReader.readSByte();
2355
- this._blockReader._referenceManager.tryAddStruct(relative, "Branch");
2396
+ this._blockReader._referenceManager.tryAddStruct(relative, "~Branch");
2356
2397
  this._blockReader.updateRegisterState(relative, reg);
2357
2398
  operands.push(new LocationWrapper(relative, isLong ? AddressType.WRelative : AddressType.Relative));
2358
2399
  }
@@ -2377,12 +2418,13 @@ var AddressingModeHandler = class {
2377
2418
  const isPush = this.isPushInstruction(mnemonic);
2378
2419
  if (isPush) refLoc++;
2379
2420
  const isJump = isPush || isIndexedIndirect || this.isJumpInstruction(mnemonic);
2380
- const addr = new Address(xBank1 ?? (isJump ? Address.resolveBank(this._dataReader.position, registers.mode) : dataBank) ?? 129, refLoc, registers.mode);
2421
+ const addr = new Address(xBank1 ?? (isJump ? Address.resolveBank(this._dataReader.position, registers.mode) : dataBank) ?? this._blockReader._root.config.defaultBank ?? 129, refLoc, registers.mode);
2381
2422
  if (addr.isROM) {
2382
2423
  const wrapper = new LocationWrapper(addr.toLocation(), AddressType.Offset);
2383
2424
  if (isJump) {
2384
2425
  const type = isIndexedIndirect ? "&Code" : "Code";
2385
2426
  const name = this._blockReader.noteType(wrapper.location, type, isPush, registers);
2427
+ if (mnemonic === "JMP") this._blockReader._referenceManager.tryAddStruct(this._dataReader.position, "~Code");
2386
2428
  if (isPush) {
2387
2429
  operands.push(`&${name}-1`);
2388
2430
  return;
@@ -3017,10 +3059,11 @@ var StringReader = class StringReader {
3017
3059
  }
3018
3060
  parseString(stringType, fixedSize) {
3019
3061
  const commands = stringType.commandLookup;
3020
- stringType.dictionaries;
3062
+ const dictionaries = stringType.dictionaries;
3021
3063
  const builder = [];
3022
3064
  const strLoc = this._romDataReader.position;
3023
3065
  const terminator = stringType.terminator;
3066
+ const modifiers = stringType.modifiers;
3024
3067
  let currentLayer = stringType.layers[0];
3025
3068
  do {
3026
3069
  const c = this._romDataReader.readByte();
@@ -3028,23 +3071,35 @@ var StringReader = class StringReader {
3028
3071
  if (stringType.greedyTerminator) while (this._romDataReader.peekByte() === terminator && this._blockReader.partCanContinue()) this._romDataReader.position++;
3029
3072
  break;
3030
3073
  }
3031
- const cmd = commands[c];
3032
- if (cmd) {
3074
+ let cmd = void 0;
3075
+ const mod = modifiers ? modifiers[c] : void 0;
3076
+ if (mod) {
3077
+ const next = mod[builder[builder.length - 1]];
3078
+ if (next) builder[builder.length - 1] = next;
3079
+ else builder.push(currentLayer.map[c - (currentLayer.base ?? 0)]);
3080
+ } else if (cmd = commands[c]) {
3033
3081
  this.resolveCommand(cmd, builder);
3034
3082
  if (cmd.halt) break;
3035
3083
  } else {
3036
3084
  let found = false;
3037
- for (const layer of stringType.layers) if (layer.on !== void 0) {
3038
- if (c === layer.on) {
3039
- currentLayer = layer;
3040
- builder.push("[--]");
3085
+ for (const dictionary of Object.values(dictionaries)) if (dictionary.base !== void 0 && c >= dictionary.base && c <= dictionary.base + dictionary.entries.length) {
3086
+ builder.push(dictionary.entries[c - dictionary.base]);
3087
+ found = true;
3088
+ break;
3089
+ }
3090
+ if (!found) {
3091
+ for (const layer of stringType.layers) if (layer.on !== void 0) {
3092
+ if (c === layer.on) {
3093
+ currentLayer = layer;
3094
+ builder.push("[--]");
3095
+ found = true;
3096
+ break;
3097
+ }
3098
+ } else if (layer.base && c >= layer.base && c < layer.base + layer.map.length) {
3099
+ builder.push(layer.map[c - layer.base]);
3041
3100
  found = true;
3042
3101
  break;
3043
3102
  }
3044
- } else if (layer.base && c >= layer.base && c < layer.base + layer.map.length) {
3045
- builder.push(layer.map[c - layer.base]);
3046
- found = true;
3047
- break;
3048
3103
  }
3049
3104
  if (!found) {
3050
3105
  let index = c - (currentLayer.base ?? 0);
@@ -3120,27 +3175,33 @@ var TypeParser = class {
3120
3175
  this._stringReader = blockReader._stringReader;
3121
3176
  this._stringTypes = blockReader._root.stringTypes;
3122
3177
  }
3123
- parseType(typeName, reg, depth, bank) {
3124
- if (typeName[0] === "&") return this.parseLocation(this._romDataReader.readUShort(), bank, typeName.substring(1), AddressType.Offset);
3125
- if (typeName[0] === "@") return this.parseLocation(this._romDataReader.readUShort(), this._romDataReader.readByte(), typeName.substring(1), AddressType.Address);
3126
- if (typeName[0] === "%") return this.parseLocation(this._romDataReader.readUShort(), this._romDataReader.readByte(), typeName.substring(1), AddressType.Location);
3127
- const isFixed = typeName[typeName.length - 1] === ")";
3128
- let fixedTypeName = typeName;
3129
- let fixedSize = 0;
3130
- if (isFixed) {
3131
- const startIx = typeName.indexOf("(");
3132
- fixedTypeName = typeName.substring(0, startIx);
3133
- fixedSize = parseInt(typeName.substring(startIx + 1, typeName.length - 1), 10);
3134
- }
3178
+ parseType(typeName, reg, depth, bank, single) {
3179
+ const objects = [];
3180
+ const arrayIx = typeName.indexOf("[");
3181
+ const arrayCount = arrayIx !== -1 ? parseInt(typeName.substring(arrayIx + 1, typeName.length - 1), 16) : 0;
3182
+ const arrayTypeName = arrayIx !== -1 ? typeName.substring(0, arrayIx) : typeName;
3183
+ if (arrayCount > 0) {
3184
+ for (let i = 0; i < arrayCount; i++) objects.push(this.parseType(arrayTypeName, reg, depth + 1, bank, true));
3185
+ return objects;
3186
+ }
3187
+ const isSoft = arrayTypeName[0] === "~";
3188
+ const realTypeName = isSoft ? arrayTypeName.substring(1) : arrayTypeName;
3189
+ const fixedIx = realTypeName.indexOf("(");
3190
+ const fixedSize = fixedIx !== -1 ? parseInt(realTypeName.substring(fixedIx + 1, realTypeName.length - 1), 16) : 0;
3191
+ const fixedTypeName = fixedIx !== -1 ? realTypeName.substring(0, fixedIx) : realTypeName;
3135
3192
  const stringType = this._stringTypes[fixedTypeName];
3136
3193
  if (stringType) return this._stringReader.parseString(stringType, fixedSize);
3194
+ if (fixedTypeName[0] === "&") return this.parseLocation(this._romDataReader.readUShort(), bank, fixedTypeName.substring(1), AddressType.Offset, isSoft);
3195
+ if (fixedTypeName[0] === "@") return this.parseLocation(this._romDataReader.readUShort(), this._romDataReader.readByte(), fixedTypeName.substring(1), AddressType.Address, isSoft);
3196
+ if (fixedTypeName[0] === "%") return this.parseLocation(this._romDataReader.readUShort(), this._romDataReader.readByte(), fixedTypeName.substring(1), AddressType.Location, isSoft);
3197
+ if (fixedTypeName[0] === "!") return this.parseLocation(this._romDataReader.readUShort(), this._romDataReader.readByte(), fixedTypeName.substring(1), AddressType.OddLocation, isSoft);
3137
3198
  const mType = this.tryParseMemberType(fixedTypeName);
3138
3199
  if (mType !== null) switch (mType) {
3139
3200
  case MemberType.Byte: return new Byte(this._romDataReader.readByte());
3140
3201
  case MemberType.Word: return new Word(this.parseWordSafe());
3141
- case MemberType.Offset: return this.parseLocation(this._romDataReader.readUShort(), bank, null, AddressType.Offset);
3142
- case MemberType.Address: return this.parseLocation(this._romDataReader.readUShort(), this._romDataReader.readByte(), null, AddressType.Address);
3143
- case MemberType.Location: return this.parseLocation(this._romDataReader.readUShort(), this._romDataReader.readByte(), null, AddressType.Location);
3202
+ case MemberType.Offset: return this.parseLocation(this._romDataReader.readUShort(), bank, null, AddressType.Offset, isSoft);
3203
+ case MemberType.Address: return this.parseLocation(this._romDataReader.readUShort(), this._romDataReader.readByte(), null, AddressType.Address, isSoft);
3204
+ case MemberType.Location: return this.parseLocation(this._romDataReader.readUShort(), this._romDataReader.readByte(), null, AddressType.Location, isSoft);
3144
3205
  case MemberType.Binary: return this.parseBinary(fixedSize);
3145
3206
  case MemberType.Code:
3146
3207
  case MemberType.Branch: return this.parseCode(reg);
@@ -3150,29 +3211,52 @@ var TypeParser = class {
3150
3211
  if (!parentType) throw new Error(`Unknown type: ${fixedTypeName}`);
3151
3212
  const delimiter = parentType.delimiter;
3152
3213
  const discOffset = parentType.discriminator;
3153
- const objects = [];
3214
+ const discLogic = parentType.discriminatorLogic;
3215
+ const discSize = parentType.discriminatorSize ?? 1;
3216
+ const nullValue = parentType.null;
3217
+ if (delimiter === void 0 && this._blockReader.delimiterReached(nullValue)) {
3218
+ objects.push({
3219
+ name: parentType.name,
3220
+ parts: ["null"]
3221
+ });
3222
+ return objects;
3223
+ }
3154
3224
  let delReached;
3155
3225
  while (!(delReached = this._blockReader.delimiterReached(delimiter))) {
3156
3226
  const startPosition = this._romDataReader.position;
3157
3227
  let targetType = parentType;
3158
- if (discOffset !== void 0) {
3159
- const discPosition = this._romDataReader.position + discOffset;
3160
- const desc = this._romDataReader.romData[discPosition];
3161
- if (discOffset === 0) this._romDataReader.position++;
3162
- targetType = Object.values(this._blockReader._root.structs).find((x) => x.parent === fixedTypeName && x.discriminator === desc) || parentType;
3163
- }
3164
- const types = targetType.types;
3165
- if (types && types.length > 0) {
3166
- const memberCount = types.length;
3167
- const prevPosition = this._romDataReader.position;
3168
- const parts = new Array(memberCount);
3169
- const def = {
3170
- name: targetType.name,
3171
- parts
3172
- };
3173
- for (let i = 0; i < memberCount; i++) parts[i] = this.parseType(types[i], reg, depth + 1, bank);
3174
- if (discOffset !== void 0 && discOffset === this._romDataReader.position - prevPosition) this._romDataReader.position++;
3175
- objects.push(def);
3228
+ if (this._blockReader.delimiterReached(nullValue)) objects.push({
3229
+ name: parentType.name,
3230
+ parts: ["null"]
3231
+ });
3232
+ else {
3233
+ if (discOffset !== void 0) {
3234
+ const discPosition = this._romDataReader.position + discOffset;
3235
+ const disc = this._romDataReader.romData[discPosition];
3236
+ const disc16 = this._romDataReader.romData[discPosition + 1] << 8 | disc;
3237
+ const matchedStruct = Object.values(this._blockReader._root.structs).find((x) => x.parent === fixedTypeName && (discLogic === "&" ? ((x.discriminator ?? 0) & disc) !== 0 : (x.discriminator ?? 0) >= 256 ? x.discriminator === disc16 : x.discriminator === disc));
3238
+ targetType = matchedStruct || parentType;
3239
+ if (discOffset === 0 && parentType != targetType && discLogic === "=") {
3240
+ this._romDataReader.position++;
3241
+ if (discSize > 1 || (matchedStruct?.discriminator ?? 0) >= 256) this._romDataReader.position++;
3242
+ }
3243
+ }
3244
+ const types = targetType.types;
3245
+ if (types) {
3246
+ const memberCount = types.length;
3247
+ const prevPosition = this._romDataReader.position;
3248
+ const parts = new Array(memberCount);
3249
+ const def = {
3250
+ name: targetType.name,
3251
+ parts
3252
+ };
3253
+ for (let i = 0; i < memberCount; i++) parts[i] = this.parseType(types[i], reg, depth + 1, bank);
3254
+ if (discOffset !== void 0 && discOffset === this._romDataReader.position - prevPosition && types?.length > 0) {
3255
+ this._romDataReader.position++;
3256
+ if (discSize > 1) this._romDataReader.position++;
3257
+ }
3258
+ objects.push(def);
3259
+ } else this._romDataReader.position++;
3176
3260
  }
3177
3261
  let checkPosition = startPosition;
3178
3262
  while (++checkPosition < this._romDataReader.position) {
@@ -3183,9 +3267,12 @@ var TypeParser = class {
3183
3267
  }
3184
3268
  }
3185
3269
  if (!this._blockReader.partCanContinue()) break;
3270
+ if (nullValue !== void 0) break;
3271
+ if (single) break;
3186
3272
  }
3187
3273
  if (delReached && depth === 0) this._referenceManager.tryAddStruct(this._romDataReader.position, typeName);
3188
- return objects;
3274
+ if (single) return objects[0];
3275
+ else return objects;
3189
3276
  }
3190
3277
  tryParseMemberType(memberTypeName) {
3191
3278
  const upperName = memberTypeName.toUpperCase();
@@ -3206,22 +3293,41 @@ var TypeParser = class {
3206
3293
  for (let i = 0; i < len; i++) outBuffer[i] = this._romDataReader.romData[startPosition + i];
3207
3294
  return outBuffer;
3208
3295
  }
3209
- parseLocation(offset, bank, typeName, addrType) {
3210
- if ((bank === void 0 || bank === null) && offset === 0) return new Word(offset);
3211
- offset -= this._romDataReader.offset;
3296
+ parseLocation(offset, bank, typeName, addrType, isSoft = false) {
3297
+ if ((bank === void 0 || bank === null) && (offset === 0 || offset === 65535)) return new Word(offset);
3298
+ const hasOffset = this._romDataReader.offset !== void 0;
3299
+ if (hasOffset) offset -= this._romDataReader.offset;
3212
3300
  let adrs;
3213
3301
  let loc;
3214
- if (addrType === AddressType.Location || this._romDataReader.offset) loc = offset | bank << 16;
3215
- else {
3302
+ if (addrType === AddressType.Location || hasOffset) {
3303
+ loc = offset | bank << 16;
3304
+ if (hasOffset && !this._blockReader._currentChunk.isFile) loc += this._blockReader._currentChunk.location;
3305
+ } else {
3306
+ if (addrType === AddressType.OddLocation) {
3307
+ const bankFlag = this._blockReader._root.config.cpuMode === CpuMode.Fast ? 128 : 0;
3308
+ const bankReal = this._romDataReader.position >> 16;
3309
+ const isVeryOdd = !this._blockReader._root.config.oddLocationBase || bankReal < this._blockReader._root.config.oddLocationBase;
3310
+ const bankBase = (isVeryOdd ? 64 : 0) + bankReal | bankFlag;
3311
+ const bankMax = this._romDataReader.romData.length >> 16 | bankFlag;
3312
+ const bankSpan = isVeryOdd ? 0 : (64 | bankFlag) - bankMax;
3313
+ const hiOffset = offset >> 8 & 127;
3314
+ const hiAdjust = (hiOffset ^ (offset >> 8 | bank << 8)) << 1 | 128 | hiOffset;
3315
+ const hiBank = (hiAdjust >> 8) + bankBase;
3316
+ offset = (hiAdjust & 255) << 8 | offset & 255;
3317
+ bank = hiBank;
3318
+ if (hiBank >= bankMax) {
3319
+ bank += bankSpan;
3320
+ offset &= 32767;
3321
+ }
3322
+ }
3216
3323
  adrs = new Address(bank ?? Address.resolveBank(this._romDataReader.position, this._blockReader._root.config.memoryMode), offset, this._blockReader._root.config.memoryMode);
3217
3324
  if (!adrs.isROM) return adrs;
3218
3325
  loc = adrs.toLocation();
3219
3326
  }
3220
- if (typeName && (this._romDataReader.offset || !this._blockReader._root.rewrites[loc])) {
3221
- const oldStruct = this._referenceManager.structTable.get(loc);
3222
- if (!oldStruct || oldStruct === "Branch") this._referenceManager.structTable.set(loc, typeName);
3327
+ if (typeName && (hasOffset || !this._blockReader._root.rewrites[loc])) {
3328
+ this._referenceManager.tryAddStruct(loc, isSoft ? "~" + typeName : typeName);
3223
3329
  const referenceName = `${typeName.toLowerCase()}_${loc.toString(16).toUpperCase().padStart(6, "0")}`;
3224
- this._referenceManager.tryAddName(loc, referenceName);
3330
+ this._referenceManager.tryAddName(loc, isSoft ? "~" + referenceName : referenceName);
3225
3331
  }
3226
3332
  return new LocationWrapper(loc, addrType);
3227
3333
  }
@@ -3231,8 +3337,8 @@ var TypeParser = class {
3231
3337
  while (this._romDataReader.position < this._blockReader._partEnd) {
3232
3338
  if (first) first = false;
3233
3339
  else {
3234
- const struct = this._referenceManager.structTable.get(this._romDataReader.position);
3235
- if (struct && struct !== "Branch") break;
3340
+ const struct = this._referenceManager.tryGetStruct(this._romDataReader.position);
3341
+ if (struct.found && struct.chunkType !== "Branch") break;
3236
3342
  }
3237
3343
  if (reg) this._blockReader.hydrateRegisters(reg);
3238
3344
  const op = this._blockReader._asmReader.parseAsm(reg);
@@ -3435,9 +3541,6 @@ var BlockReader = class {
3435
3541
  /**
3436
3542
  * Processes predefined file references
3437
3543
  */
3438
- initializeFileReferences() {
3439
- for (const file of this._root.files) this._referenceManager.tryAddName(file.start, file.name);
3440
- }
3441
3544
  /**
3442
3545
  * Resolves mnemonic for a given address
3443
3546
  */
@@ -3475,13 +3578,13 @@ var BlockReader = class {
3475
3578
  * Notes a type at a location and manages chunk references
3476
3579
  */
3477
3580
  noteType(loc, type, silent = false, reg) {
3478
- const oldStruct = this._referenceManager.structTable.get(loc);
3479
- if (!oldStruct || oldStruct === "Branch") this._referenceManager.structTable.set(loc, type);
3581
+ const isSoft = type[0] === "~";
3582
+ this._referenceManager.tryAddStruct(loc, type);
3480
3583
  const nameResult = this._referenceManager.tryGetName(loc);
3481
3584
  let name;
3482
3585
  if (!nameResult.found) {
3483
3586
  name = this._referenceManager.createTypeName(type, loc);
3484
- this._referenceManager.tryAddName(loc, name);
3587
+ this._referenceManager.tryAddName(loc, isSoft ? "~" + name : name);
3485
3588
  } else name = nameResult.referenceName;
3486
3589
  if (!silent && type === BlockReaderConstants.CODE_TYPE && reg) this.updateRegisterState(loc, reg);
3487
3590
  return name;
@@ -3518,7 +3621,6 @@ var BlockReader = class {
3518
3621
  analyzeAndResolve() {
3519
3622
  console.log("analyzeAndResolve started");
3520
3623
  this.initializeOverrides();
3521
- this.initializeFileReferences();
3522
3624
  this.createChunkFilesFromDatabase();
3523
3625
  this.initializeBlocksAndParts();
3524
3626
  this.analyzeChunkFiles();
@@ -3534,9 +3636,12 @@ var BlockReader = class {
3534
3636
  */
3535
3637
  initializeBlocksAndParts() {
3536
3638
  console.log("initializeBlocksAndParts");
3537
- for (const block of this._enrichedChunks) for (const part of block.parts || []) {
3538
- if (part.structName) this._referenceManager.tryAddStruct(part.location, part.structName);
3539
- if (part.label) this._referenceManager.tryAddName(part.location, part.label);
3639
+ for (const block of this._enrichedChunks) {
3640
+ for (const part of block.parts || []) {
3641
+ if (part.structName) this._referenceManager.tryAddStruct(part.location, part.structName);
3642
+ if (part.label) this._referenceManager.tryAddName(part.location, part.label);
3643
+ }
3644
+ this._referenceManager.tryAddName(block.location, block.name);
3540
3645
  }
3541
3646
  }
3542
3647
  /**
@@ -3581,7 +3686,7 @@ var BlockReader = class {
3581
3686
  */
3582
3687
  processNewEntry(current, reg, bank, last) {
3583
3688
  let res = this._typeParser.parseType(current, reg, 0, bank);
3584
- if (BlockReaderConstants.POINTER_CHARACTERS.includes(current[0]) && !Array.isArray(res)) res = [res];
3689
+ if (current.indexOf("[") !== -1 || BlockReaderConstants.POINTER_CHARACTERS.includes(current[0]) && !Array.isArray(res)) res = [res];
3585
3690
  last.object = res;
3586
3691
  }
3587
3692
  /**
@@ -3670,6 +3775,7 @@ var BlockReader = class {
3670
3775
  if (!chunkFile.type.isBlock) continue;
3671
3776
  chunkFile.referenceManager = this._referenceManager;
3672
3777
  this._currentChunk = chunkFile;
3778
+ this._romDataReader.offset = chunkFile.base;
3673
3779
  for (const asmBlock of chunkFile.parts || []) {
3674
3780
  this._currentAsmBlock = asmBlock;
3675
3781
  this.processPart(asmBlock);
@@ -3685,7 +3791,7 @@ var BlockReader = class {
3685
3791
  chunkFile.parts = [asmBlock];
3686
3792
  this._currentAsmBlock = asmBlock;
3687
3793
  this._referenceManager = chunkFile.referenceManager = new ReferenceManager(this._root);
3688
- this._romDataReader = new RomDataReader(chunkFile.rawData, chunkFile.base ?? 0);
3794
+ this._romDataReader = new RomDataReader(chunkFile.rawData, chunkFile.base);
3689
3795
  this._typeParser = new TypeParser(this);
3690
3796
  this.processPart(asmBlock);
3691
3797
  }
@@ -3995,7 +4101,7 @@ var BlockWriter = class {
3995
4101
  objLines = [this._referenceManager.resolveName(obj.location, obj.type, isBranch)];
3996
4102
  break;
3997
4103
  case ObjectType.Address:
3998
- objLines = isArray ? [`$#${obj.offset.toString(16).toUpperCase().padStart(4, "0")}`] : [`$${obj.toString()}`];
4104
+ objLines = isArray ? [`$#${obj.toString()}`] : [`$${obj.toString()}`];
3999
4105
  break;
4000
4106
  case ObjectType.ByteArray:
4001
4107
  objLines = [`#${Array.from(obj).map((b) => b.toString(16).toUpperCase().padStart(2, "0")).join("")}`];
@@ -4055,14 +4161,14 @@ var BlockWriter = class {
4055
4161
  this._isInline = true;
4056
4162
  let first = true;
4057
4163
  for (const op of opList) {
4058
- if (first) first = false;
4059
- else {
4164
+ if (!first || depth > 0) {
4060
4165
  const labelResult = this._referenceManager.tryGetName(op.location);
4061
4166
  if (labelResult.found) {
4062
4167
  lines.push("");
4063
4168
  lines.push(` ${labelResult.referenceName}:`);
4064
4169
  }
4065
4170
  }
4171
+ first = false;
4066
4172
  let opLine = ` ${op.mnem} `;
4067
4173
  if (op.copDef) {
4068
4174
  opLine += `[${op.copDef.name}]`;
@@ -4554,7 +4660,7 @@ var RomWriter = class RomWriter {
4554
4660
  }
4555
4661
  } else if (file.parts && file.parts.length > 0) {
4556
4662
  if (file.parts[0].location !== file.location && (file.location || 0) !== 0) throw new Error("Assembly was not based properly");
4557
- RomWriter.parseAssembly(this.root, file.parts, fileLookup, file.includeLookup, this.outBuffer, void 0);
4663
+ RomWriter.parseAssembly(this.root, file.parts, fileLookup, file.includeLookup, this.outBuffer, file.base);
4558
4664
  }
4559
4665
  return pos - start;
4560
4666
  }
@@ -4569,6 +4675,7 @@ var RomWriter = class RomWriter {
4569
4675
  static parseAssembly(root, blocks, fileLookup, includeLookup, outBuffer, addrOffset) {
4570
4676
  if (!blocks) throw new Error("Assembly has not been parsed");
4571
4677
  let bix = 0;
4678
+ const rootLoc = blocks[0].location;
4572
4679
  for (const block of blocks) {
4573
4680
  let position = block.location;
4574
4681
  const objList = block.objList;
@@ -4656,8 +4763,10 @@ var RomWriter = class RomWriter {
4656
4763
  break;
4657
4764
  } else markerOffset += RomProcessingConstants.getSize(part);
4658
4765
  }
4659
- if (addrOffset !== void 0) loc += addrOffset;
4660
- else if (!isRelative && type !== AddressType.Location) loc = Address.fromLocation(loc, root.config.memoryMode, root.config.cpuMode).toInt();
4766
+ if (addrOffset !== void 0) {
4767
+ loc += addrOffset;
4768
+ if (fileLookup?.size) loc -= rootLoc;
4769
+ } else if (!isRelative && type !== AddressType.Location) loc = Address.fromLocation(loc, root.config.memoryMode, root.config.cpuMode).toInt();
4661
4770
  switch (type) {
4662
4771
  case AddressType.Offset:
4663
4772
  case AddressType.WRelative:
@@ -4772,7 +4881,7 @@ var RomProcessor = class RomProcessor {
4772
4881
  for (const b of file.parts) if (b.label) file.includeLookup.set(b.label.toUpperCase(), b);
4773
4882
  file.rawData = void 0;
4774
4883
  file.rawData = new Uint8Array(ChunkFileUtils.calculateSize(file));
4775
- RomWriter.parseAssembly(this.writer.root, file.parts, dummyMap, file.includeLookup, file.rawData, file.type.base ?? 0);
4884
+ RomWriter.parseAssembly(this.writer.root, file.parts, dummyMap, file.includeLookup, file.rawData, file.type.base);
4776
4885
  }
4777
4886
  }
4778
4887
  for (const file of allFiles) if (file.compressed === true && canCompress) if (this.writer.root.config.uncompress) file.compressed = false;
@@ -4829,7 +4938,7 @@ var RomProcessor = class RomProcessor {
4829
4938
  ix++;
4830
4939
  continue;
4831
4940
  }
4832
- file.includes = file.includes || /* @__PURE__ */ new Set();
4941
+ if (!file.includes) file.includes = /* @__PURE__ */ new Set();
4833
4942
  file.includes.add(patch.name.toUpperCase());
4834
4943
  patch.parts.splice(ix, 1);
4835
4944
  }
@@ -5523,20 +5632,19 @@ var DbBlock = class {
5523
5632
  transforms;
5524
5633
  postProcess;
5525
5634
  order;
5635
+ base;
5526
5636
  constructor(data) {
5527
5637
  this.name = data.name ?? "";
5528
5638
  this.movable = data.movable ?? false;
5529
5639
  this.group = data.group ?? void 0;
5530
5640
  this.scene = data.scene ?? void 0;
5531
5641
  this.parts = (data.parts ?? []).sort((a, b) => {
5532
- const orderA = a.order ?? 0;
5533
- const orderB = b.order ?? 0;
5534
- if (orderA !== orderB) return orderA - orderB;
5535
- return a.start - b.start;
5642
+ return (a.order ?? a.start ?? 0) - (b.order ?? b.start ?? 0);
5536
5643
  });
5537
5644
  this.transforms = data.transforms ?? [];
5538
5645
  this.postProcess = data.postProcess ?? void 0;
5539
5646
  this.order = data.order ?? void 0;
5647
+ this.base = data.base ?? void 0;
5540
5648
  if (!this.name) throw new Error("Name is required");
5541
5649
  }
5542
5650
  };
@@ -5607,12 +5715,18 @@ var DbStruct = class {
5607
5715
  parent;
5608
5716
  delimiter;
5609
5717
  discriminator;
5718
+ discriminatorLogic;
5719
+ discriminatorSize;
5720
+ null;
5610
5721
  constructor(data) {
5611
5722
  this.name = data.name ?? "";
5612
5723
  this.types = data.types ?? void 0;
5613
5724
  this.parent = data.parent ?? void 0;
5614
5725
  this.delimiter = data.delimiter ?? void 0;
5615
5726
  this.discriminator = data.discriminator ?? void 0;
5727
+ this.discriminatorLogic = data.discriminatorLogic ?? (this.discriminator !== void 0 ? "=" : void 0);
5728
+ this.discriminatorSize = data.discriminatorSize ?? void 0;
5729
+ this.null = data.null ?? void 0;
5616
5730
  if (!this.name) throw new Error("Name is required");
5617
5731
  }
5618
5732
  };
@@ -5667,14 +5781,16 @@ var DbStringCommand = class {
5667
5781
  }
5668
5782
  };
5669
5783
  var DbStringDictionary = class {
5784
+ base;
5670
5785
  command;
5671
5786
  commandName;
5672
5787
  name;
5673
5788
  entries;
5674
5789
  constructor(data) {
5675
- if (typeof data.command !== "number") throw new Error("Command is required");
5790
+ if (typeof data.command !== "number" && typeof data.base !== "number") throw new Error("Command or base is required");
5676
5791
  if (!data.name) throw new Error("Name is required");
5677
5792
  if (!data.entries || data.entries.length === 0) throw new Error("Entries is required");
5793
+ this.base = data.base ?? void 0;
5678
5794
  this.command = data.command ?? void 0;
5679
5795
  this.commandName = data.commandName ?? void 0;
5680
5796
  this.name = data.name;
@@ -5695,6 +5811,7 @@ var DbStringType = class {
5695
5811
  greedyTerminator;
5696
5812
  dictionaries;
5697
5813
  dictionaryLookup;
5814
+ modifiers;
5698
5815
  constructor(data) {
5699
5816
  if (!data.name) throw new Error("Name is required");
5700
5817
  if (!data.delimiter) throw new Error("Delimiter is required");
@@ -5715,6 +5832,7 @@ var DbStringType = class {
5715
5832
  text: z,
5716
5833
  id: (y.command ?? 0) << 8 | ix
5717
5834
  }))).sort((a, b) => b.text.length - a.text.length);
5835
+ this.modifiers = data.modifiers;
5718
5836
  }
5719
5837
  };
5720
5838
 
@@ -5730,6 +5848,7 @@ var CopDef = class {
5730
5848
  size;
5731
5849
  parts;
5732
5850
  halt;
5851
+ conditions;
5733
5852
  constructor(data) {
5734
5853
  if (!data.name) throw new Error("Name is required");
5735
5854
  if (typeof data.id !== "number") throw new Error("ID is required");
@@ -5738,6 +5857,7 @@ var CopDef = class {
5738
5857
  this.parts = data.parts ?? [];
5739
5858
  this.halt = data.halt ?? false;
5740
5859
  this.size = data.size ?? 0;
5860
+ this.conditions = data.conditions ?? [];
5741
5861
  }
5742
5862
  };
5743
5863