isaacscript-common 20.12.2 → 20.13.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.
Files changed (67) hide show
  1. package/dist/index.d.ts +79 -40
  2. package/dist/isaacscript-common.lua +315 -419
  3. package/dist/src/classes/ModFeature.lua +0 -4
  4. package/dist/src/classes/ModUpgradedBase.lua +3 -9
  5. package/dist/src/classes/callbacks/PostNewRoomEarly.lua +2 -2
  6. package/dist/src/classes/features/callbackLogic/CustomRevive.lua +2 -5
  7. package/dist/src/classes/features/other/CustomStages.lua +4 -16
  8. package/dist/src/classes/features/other/CustomTrapdoors.lua +1 -4
  9. package/dist/src/classes/features/other/DeployJSONRoom.lua +8 -14
  10. package/dist/src/classes/features/other/Pause.lua +2 -2
  11. package/dist/src/classes/features/other/TaintedLazarusPlayers.lua +1 -1
  12. package/dist/src/classes/features/other/customStages/utils.lua +4 -16
  13. package/dist/src/classes/features/other/extraConsoleCommands/commands.lua +4 -4
  14. package/dist/src/classes/features/other/extraConsoleCommands/subroutines.lua +2 -2
  15. package/dist/src/classes/features/other/saveDataManager/loadFromDisk.lua +4 -7
  16. package/dist/src/classes/features/other/saveDataManager/restoreDefaults.lua +2 -2
  17. package/dist/src/classes/features/other/saveDataManager/saveToDisk.lua +1 -1
  18. package/dist/src/enums/MysteriousPaperEffect.d.ts +13 -0
  19. package/dist/src/enums/MysteriousPaperEffect.d.ts.map +1 -0
  20. package/dist/src/enums/MysteriousPaperEffect.lua +15 -0
  21. package/dist/src/functions/benchmark.lua +2 -8
  22. package/dist/src/functions/debugFunctions.d.ts +2 -2
  23. package/dist/src/functions/debugFunctions.d.ts.map +1 -1
  24. package/dist/src/functions/debugFunctions.lua +4 -4
  25. package/dist/src/functions/deepCopy.lua +7 -7
  26. package/dist/src/functions/deepCopyTests.lua +1 -1
  27. package/dist/src/functions/globals.lua +3 -6
  28. package/dist/src/functions/hex.lua +4 -7
  29. package/dist/src/functions/jsonHelpers.lua +1 -1
  30. package/dist/src/functions/jsonRoom.lua +4 -16
  31. package/dist/src/functions/log.d.ts +8 -4
  32. package/dist/src/functions/log.d.ts.map +1 -1
  33. package/dist/src/functions/log.lua +18 -5
  34. package/dist/src/functions/logEntities.d.ts +8 -8
  35. package/dist/src/functions/logEntities.d.ts.map +1 -1
  36. package/dist/src/functions/logEntities.lua +24 -27
  37. package/dist/src/functions/logMisc.d.ts +26 -26
  38. package/dist/src/functions/logMisc.d.ts.map +1 -1
  39. package/dist/src/functions/logMisc.lua +114 -226
  40. package/dist/src/functions/merge.lua +6 -6
  41. package/dist/src/functions/revive.d.ts.map +1 -1
  42. package/dist/src/functions/revive.lua +10 -3
  43. package/dist/src/functions/run.lua +2 -5
  44. package/dist/src/functions/trinkets.d.ts +22 -0
  45. package/dist/src/functions/trinkets.d.ts.map +1 -1
  46. package/dist/src/functions/trinkets.lua +32 -0
  47. package/dist/src/functions/utils.d.ts.map +1 -1
  48. package/dist/src/functions/utils.lua +20 -1
  49. package/dist/src/index.d.ts +1 -0
  50. package/dist/src/index.d.ts.map +1 -1
  51. package/dist/src/index.lua +8 -0
  52. package/dist/src/lib/jsonLua.lua +16 -7
  53. package/dist/src/patchErrorFunctions.lua +1 -1
  54. package/package.json +1 -1
  55. package/src/classes/ModFeature.ts +0 -6
  56. package/src/classes/features/other/saveDataManager/saveToDisk.ts +3 -4
  57. package/src/enums/MysteriousPaperEffect.ts +12 -0
  58. package/src/functions/debugFunctions.ts +2 -2
  59. package/src/functions/deepCopy.ts +2 -0
  60. package/src/functions/log.ts +15 -4
  61. package/src/functions/logEntities.ts +14 -8
  62. package/src/functions/logMisc.ts +56 -39
  63. package/src/functions/revive.ts +12 -4
  64. package/src/functions/trinkets.ts +39 -0
  65. package/src/functions/utils.ts +30 -0
  66. package/src/index.ts +1 -0
  67. package/src/lib/jsonLua.lua +16 -7
@@ -31,7 +31,7 @@ import { isTable, isUserdata } from "./types";
31
31
  import { vectorToString } from "./vector";
32
32
 
33
33
  /** Helper function to enumerate all of the values in an array. */
34
- export function logArray<T>(array: T[] | readonly T[]): void {
34
+ export function logArray<T>(this: void, array: T[] | readonly T[]): void {
35
35
  // We do not assume the given array has contiguous values in order to be more permissive about the
36
36
  // kinds of arrays that will successfully log without a run-time error.
37
37
  if (!isArray(array, false)) {
@@ -43,7 +43,10 @@ export function logArray<T>(array: T[] | readonly T[]): void {
43
43
  log(`Array: ${arrayString}`);
44
44
  }
45
45
 
46
- export function logCollectibleTypes(collectibleTypes: CollectibleType[]): void {
46
+ export function logCollectibleTypes(
47
+ this: void,
48
+ collectibleTypes: CollectibleType[],
49
+ ): void {
47
50
  log("Collectibles:");
48
51
 
49
52
  let i = 1;
@@ -54,23 +57,29 @@ export function logCollectibleTypes(collectibleTypes: CollectibleType[]): void {
54
57
  }
55
58
  }
56
59
 
57
- export function logColor(color: Color): void {
60
+ export function logColor(this: void, color: Color): void {
58
61
  log(
59
62
  `Color: R${color.R}, G${color.G}, B${color.B}, A${color.A}, RO${color.RO}, BO${color.BO}, GO${color.GO}`,
60
63
  );
61
64
  }
62
65
 
63
66
  /** Helper function for printing out every damage flag that is turned on. Useful when debugging. */
64
- export function logDamageFlags(flags: DamageFlag | BitFlags<DamageFlag>): void {
67
+ export function logDamageFlags(
68
+ this: void,
69
+ flags: DamageFlag | BitFlags<DamageFlag>,
70
+ ): void {
65
71
  logFlags(flags, DamageFlag, "damage");
66
72
  }
67
73
 
68
74
  /** Helper function for printing out every entity flag that is turned on. Useful when debugging. */
69
- export function logEntityFlags(flags: EntityFlag | BitFlags<EntityFlag>): void {
75
+ export function logEntityFlags(
76
+ this: void,
77
+ flags: EntityFlag | BitFlags<EntityFlag>,
78
+ ): void {
70
79
  logFlags(flags, EntityFlag, "entity");
71
80
  }
72
81
 
73
- export function logEntityID(entity: Entity): void {
82
+ export function logEntityID(this: void, entity: Entity): void {
74
83
  const entityID = getEntityID(entity);
75
84
  log(`Entity: ${entityID}`);
76
85
  }
@@ -81,7 +90,7 @@ export function logEntityID(entity: Entity): void {
81
90
  * This is useful in situations where using the `error` function would be dangerous (since it
82
91
  * prevents all of the subsequent code in the callback from running).
83
92
  */
84
- export function logError(msg: string): void {
93
+ export function logError(this: void, msg: string): void {
85
94
  const errorMsg = `Error: ${msg}`;
86
95
  log(errorMsg);
87
96
  print(errorMsg);
@@ -89,6 +98,7 @@ export function logError(msg: string): void {
89
98
 
90
99
  /** Helper function for printing out every flag that is turned on. Useful when debugging. */
91
100
  export function logFlags<T extends BitFlag | BitFlag128>(
101
+ this: void,
92
102
  flags: T | BitFlags<T>,
93
103
  flagEnum: Record<string, T>,
94
104
  description = "",
@@ -116,7 +126,7 @@ export function logFlags<T extends BitFlag | BitFlag128>(
116
126
  /**
117
127
  * Helper function for printing out every game state flag that is turned on. Useful when debugging.
118
128
  */
119
- export function logGameStateFlags(): void {
129
+ export function logGameStateFlags(this: void): void {
120
130
  log("Logging game state flags:");
121
131
 
122
132
  const gameStateFlagEntries = getEnumEntries(GameStateFlag);
@@ -135,7 +145,7 @@ export function logGameStateFlags(): void {
135
145
  }
136
146
  }
137
147
 
138
- export function logKColor(kColor: KColor): void {
148
+ export function logKColor(this: void, kColor: KColor): void {
139
149
  log(
140
150
  `Color: R${kColor.Red}, G${kColor.Green}, B${kColor.Blue}, A${kColor.Alpha}`,
141
151
  );
@@ -144,7 +154,7 @@ export function logKColor(kColor: KColor): void {
144
154
  /**
145
155
  * Helper function for printing out every level state flag that is turned on. Useful when debugging.
146
156
  */
147
- export function logLevelStateFlags(): void {
157
+ export function logLevelStateFlags(this: void): void {
148
158
  const level = game.GetLevel();
149
159
 
150
160
  const levelStateFlagEntries = getEnumEntries(LevelStateFlag);
@@ -164,7 +174,7 @@ export function logLevelStateFlags(): void {
164
174
  }
165
175
  }
166
176
 
167
- export function logMap(map: Map<AnyNotNil, unknown>): void {
177
+ export function logMap(this: void, map: Map<AnyNotNil, unknown>): void {
168
178
  if (!isTSTLMap(map) && !isDefaultMap(map)) {
169
179
  log("Tried to log a TSTL map, but the given object was not a TSTL map.");
170
180
  return;
@@ -184,7 +194,7 @@ export function logMap(map: Map<AnyNotNil, unknown>): void {
184
194
  log(` The size of the map was: ${map.size}`);
185
195
  }
186
196
 
187
- export function logPlayerEffects(player: EntityPlayer): void {
197
+ export function logPlayerEffects(this: void, player: EntityPlayer): void {
188
198
  const effects = getEffectsList(player);
189
199
 
190
200
  log("Logging player effects:");
@@ -212,7 +222,7 @@ export function logPlayerEffects(player: EntityPlayer): void {
212
222
  });
213
223
  }
214
224
 
215
- export function logPlayerHealth(player: EntityPlayer): void {
225
+ export function logPlayerHealth(this: void, player: EntityPlayer): void {
216
226
  const playerName = getPlayerName(player);
217
227
  const playerHealth = getPlayerHealth(player);
218
228
 
@@ -238,13 +248,14 @@ export function logPlayerHealth(player: EntityPlayer): void {
238
248
  * Helper function for printing out every projectile flag that is turned on. Useful when debugging.
239
249
  */
240
250
  export function logProjectileFlags(
251
+ this: void,
241
252
  flags: ProjectileFlag | BitFlags<ProjectileFlag>,
242
253
  ): void {
243
254
  logFlags(flags, ProjectileFlag, "projectile");
244
255
  }
245
256
 
246
257
  /** Helper function for logging information about the current room. */
247
- export function logRoom(): void {
258
+ export function logRoom(this: void): void {
248
259
  const room = game.GetRoom();
249
260
  const bossID = room.GetBossID();
250
261
  const roomGridIndex = getRoomGridIndex();
@@ -277,7 +288,7 @@ export function logRoom(): void {
277
288
  * Helper function for printing out every seed effect (i.e. Easter Egg) that is turned on for the
278
289
  * particular run.
279
290
  */
280
- export function logSeedEffects(): void {
291
+ export function logSeedEffects(this: void): void {
281
292
  const seeds = game.GetSeeds();
282
293
 
283
294
  const seedEffectEntries = getEnumEntries(SeedEffect);
@@ -296,7 +307,10 @@ export function logSeedEffects(): void {
296
307
  }
297
308
  }
298
309
 
299
- export function logSet(set: Set<AnyNotNil> | ReadonlySet<AnyNotNil>): void {
310
+ export function logSet(
311
+ this: void,
312
+ set: Set<AnyNotNil> | ReadonlySet<AnyNotNil>,
313
+ ): void {
300
314
  if (!isTSTLSet(set)) {
301
315
  log("Tried to log a TSTL set, but the given object was not a TSTL set.");
302
316
  return;
@@ -314,7 +328,7 @@ export function logSet(set: Set<AnyNotNil> | ReadonlySet<AnyNotNil>): void {
314
328
  }
315
329
 
316
330
  /** Helper function for logging every sound effect that is currently playing. */
317
- export function logSounds(): void {
331
+ export function logSounds(this: void): void {
318
332
  const soundEffects = getEnumEntries(SoundEffect);
319
333
 
320
334
  for (const [key, soundEffect] of soundEffects) {
@@ -334,9 +348,13 @@ export function logSounds(): void {
334
348
  * In order to prevent infinite recursion, this function will not log a sub-table when there are 10
335
349
  * or more parent tables.
336
350
  */
337
- export function logTable(luaTable: unknown, parentTables = 0): void {
351
+ export function logTable(
352
+ this: void,
353
+ luaTable: unknown,
354
+ parentTables = 0,
355
+ ): void {
338
356
  if (parentTables === 0) {
339
- log("Printing out a Lua table:");
357
+ log("Printing out a Lua table:", false);
340
358
  } else if (parentTables > 10) {
341
359
  return;
342
360
  }
@@ -345,14 +363,10 @@ export function logTable(luaTable: unknown, parentTables = 0): void {
345
363
  const indentation = " ".repeat(numSpaces);
346
364
 
347
365
  if (!isTable(luaTable)) {
348
- // Put it in an IIFE so that it will show as "func" instead of "logTable" and align with the
349
- // other text. We have to use a non-arrow function to prevent Lua language server errors with
350
- // the self argument.
351
- (function func() {
352
- log(
353
- `${indentation}n/a (encountered a variable of type "${typeof luaTable}" instead of a table)`,
354
- );
355
- })();
366
+ log(
367
+ `${indentation}n/a (encountered a variable of type "${typeof luaTable}" instead of a table)`,
368
+ false,
369
+ );
356
370
 
357
371
  return;
358
372
  }
@@ -360,12 +374,13 @@ export function logTable(luaTable: unknown, parentTables = 0): void {
360
374
  let numElements = 0;
361
375
  iterateTableInOrder(luaTable, (key, value) => {
362
376
  // eslint-disable-next-line @typescript-eslint/no-base-to-string
363
- log(`${indentation}${key} --> ${value}`);
377
+ log(`${indentation}${key} --> ${value}`, false);
364
378
 
365
379
  if (isTable(value)) {
366
380
  if (key === "__class") {
367
381
  log(
368
382
  `${indentation} (skipping enumerating this key to avoid infinite recursion)`,
383
+ false,
369
384
  );
370
385
  } else {
371
386
  logTable(value, parentTables + 1);
@@ -375,12 +390,7 @@ export function logTable(luaTable: unknown, parentTables = 0): void {
375
390
  numElements++;
376
391
  });
377
392
 
378
- // Put it in an IIFE so that it will show as "func" instead of "logTable" and align with the other
379
- // text. We have to use a non-arrow function to prevent Lua language server errors with the self
380
- // argument.
381
- (function func() {
382
- log(`${indentation}The size of the table was: ${numElements}`);
383
- })();
393
+ log(`${indentation}The size of the table was: ${numElements}`, false);
384
394
  }
385
395
 
386
396
  /**
@@ -388,6 +398,7 @@ export function logTable(luaTable: unknown, parentTables = 0): void {
388
398
  * will only do a shallow comparison.
389
399
  */
390
400
  export function logTableDifferences<K extends AnyNotNil, V>(
401
+ this: void,
391
402
  table1: LuaMap<K, V>,
392
403
  table2: LuaMap<K, V>,
393
404
  ): void {
@@ -428,7 +439,7 @@ export function logTableDifferences<K extends AnyNotNil, V>(
428
439
  *
429
440
  * This function is useful for tables that have recursive references.
430
441
  */
431
- export function logTableKeys(luaTable: unknown): void {
442
+ export function logTableKeys(this: void, luaTable: unknown): void {
432
443
  log("Printing out the keys of a Lua table:");
433
444
 
434
445
  if (!isTable(luaTable)) {
@@ -449,12 +460,18 @@ export function logTableKeys(luaTable: unknown): void {
449
460
  }
450
461
 
451
462
  /** Helper function for printing out every tear flag that is turned on. Useful when debugging. */
452
- export function logTearFlags(flags: TearFlag | BitFlags<TearFlag>): void {
463
+ export function logTearFlags(
464
+ this: void,
465
+ flags: TearFlag | BitFlags<TearFlag>,
466
+ ): void {
453
467
  logFlags(flags, TearFlag, "tear");
454
468
  }
455
469
 
456
470
  /** Helper function for printing out every use flag that is turned on. Useful when debugging. */
457
- export function logUseFlags(flags: UseFlag | BitFlags<UseFlag>): void {
471
+ export function logUseFlags(
472
+ this: void,
473
+ flags: UseFlag | BitFlags<UseFlag>,
474
+ ): void {
458
475
  logFlags(flags, UseFlag, "use");
459
476
  }
460
477
 
@@ -462,7 +479,7 @@ export function logUseFlags(flags: UseFlag | BitFlags<UseFlag>): void {
462
479
  * Helper function to enumerate all of the properties of a "userdata" object (i.e. an object from
463
480
  * the Isaac API).
464
481
  */
465
- export function logUserdata(userdata: unknown): void {
482
+ export function logUserdata(this: void, userdata: unknown): void {
466
483
  if (!isUserdata(userdata)) {
467
484
  log("Userdata: [not userdata]");
468
485
  return;
@@ -484,7 +501,7 @@ export function logUserdata(userdata: unknown): void {
484
501
  logTable(metatable);
485
502
  }
486
503
 
487
- export function logVector(vector: Vector, round = false): void {
504
+ export function logVector(this: void, vector: Vector, round = false): void {
488
505
  const vectorString = vectorToString(vector, round);
489
506
  log(`Vector: ${vectorString}`);
490
507
  }
@@ -10,11 +10,13 @@ import {
10
10
  MAX_TAINTED_SAMSON_BERSERK_CHARGE,
11
11
  TAINTED_SAMSON_BERSERK_CHARGE_FROM_TAKING_DAMAGE,
12
12
  } from "../core/constants";
13
+ import { MysteriousPaperEffect } from "../enums/MysteriousPaperEffect";
13
14
  import { getCharacterDeathAnimationName } from "./characters";
14
15
  import { getPlayerMaxHeartContainers } from "./playerHealth";
15
16
  import { getPlayerNumHitsRemaining, hasLostCurse, isKeeper } from "./players";
16
17
  import { getLastFrameOfAnimation } from "./sprites";
17
18
  import { giveTrinketsBack, temporarilyRemoveTrinket } from "./trinketGive";
19
+ import { getMysteriousPaperEffectForFrame } from "./trinkets";
18
20
 
19
21
  /**
20
22
  * Uses the player's current health and other miscellaneous things to determine if incoming damage
@@ -123,7 +125,6 @@ export function isDamageToPlayerFatal(
123
125
  * Mysterious Paper be Missing Power is: `gameFrameCount % 4 === 3`
124
126
  */
125
127
  export function willMysteriousPaperRevive(player: EntityPlayer): boolean {
126
- const gameFrameCount = game.GetFrameCount();
127
128
  const sprite = player.GetSprite();
128
129
 
129
130
  // We want to explicitly check the length of the death animation because we might be playing on a
@@ -131,10 +132,17 @@ export function willMysteriousPaperRevive(player: EntityPlayer): boolean {
131
132
  const character = player.GetPlayerType();
132
133
  const animation = getCharacterDeathAnimationName(character);
133
134
  const deathAnimationFrames = getLastFrameOfAnimation(sprite, animation);
134
- const frameOfDeath = gameFrameCount + deathAnimationFrames + 1;
135
- // (We add 1 because it takes one frame for the death animation to begin.)
135
+ const frameOfDeath = player.FrameCount + deathAnimationFrames;
136
+
137
+ const mysteriousPaperEffect = getMysteriousPaperEffectForFrame(
138
+ player,
139
+ frameOfDeath,
140
+ );
141
+ if (mysteriousPaperEffect === undefined) {
142
+ return false;
143
+ }
136
144
 
137
- return frameOfDeath % 4 === 3;
145
+ return mysteriousPaperEffect === MysteriousPaperEffect.MISSING_POSTER;
138
146
  }
139
147
 
140
148
  /**
@@ -10,6 +10,7 @@ import {
10
10
  FIRST_TRINKET_TYPE,
11
11
  LAST_VANILLA_TRINKET_TYPE,
12
12
  } from "../core/constantsFirstLast";
13
+ import { MysteriousPaperEffect } from "../enums/MysteriousPaperEffect";
13
14
  import {
14
15
  DEFAULT_TRINKET_DESCRIPTION,
15
16
  TRINKET_DESCRIPTION_MAP,
@@ -19,6 +20,7 @@ import {
19
20
  TRINKET_TYPE_TO_NAME_MAP,
20
21
  } from "../maps/trinketTypeToNameMap";
21
22
  import { getEntityID } from "./entities";
23
+ import { getEnumLength } from "./enums";
22
24
  import { hasFlag } from "./flag";
23
25
  import { isTrinket } from "./pickupVariants";
24
26
  import { isCharacter } from "./players";
@@ -35,6 +37,8 @@ import { iRange } from "./utils";
35
37
  */
36
38
  const GOLDEN_TRINKET_ADJUSTMENT = 32768;
37
39
 
40
+ const NUM_MYSTERIOUS_PAPER_EFFECTS = getEnumLength(MysteriousPaperEffect);
41
+
38
42
  const TRINKET_ANM2_PATH = "gfx/005.350_trinket.anm2";
39
43
  const TRINKET_SPRITE_LAYER = 0;
40
44
 
@@ -48,6 +52,41 @@ export function getGoldenTrinketType(trinketType: TrinketType): TrinketType {
48
52
  return asNumber(trinketType) + GOLDEN_TRINKET_ADJUSTMENT;
49
53
  }
50
54
 
55
+ /**
56
+ * Helper function to get the current effect that the Mysterious Paper trinket is providing to the
57
+ * player. Returns undefined if the player does not have the Mysterious Paper trinket.
58
+ *
59
+ * The Mysterious Paper trinket has four different effects:
60
+ *
61
+ * - The Polaroid (collectible)
62
+ * - The Negative (collectible)
63
+ * - A Missing Page (trinket)
64
+ * - Missing Poster (trinket)
65
+ *
66
+ * It rotates between these four effects on every frame. Note that Mysterious Paper will cause the
67
+ * `EntityPlayer.HasCollectible` and `EntityPlayer.HasTrinket` methods to return true for the
68
+ * respective items on the particular frame, with the exception of the Missing Poster. (The player
69
+ * will never "have" the Missing Poster, even on the correct corresponding frame.)
70
+ *
71
+ * @param player The player to look at.
72
+ * @param frameCount Optional. The frame count that corresponds to time the effect will be active.
73
+ * Default is the current frame.
74
+ */
75
+ export function getMysteriousPaperEffectForFrame(
76
+ player: EntityPlayer,
77
+ frameCount?: int,
78
+ ): MysteriousPaperEffect | undefined {
79
+ if (frameCount === undefined) {
80
+ frameCount = player.FrameCount;
81
+ }
82
+
83
+ if (!player.HasTrinket(TrinketType.MYSTERIOUS_PAPER)) {
84
+ return undefined;
85
+ }
86
+
87
+ return frameCount % NUM_MYSTERIOUS_PAPER_EFFECTS;
88
+ }
89
+
51
90
  /**
52
91
  * Returns the slot number corresponding to where a trinket can be safely inserted.
53
92
  *
@@ -174,6 +174,28 @@ export function todo(...args: unknown[]): void {}
174
174
  * https://stackoverflow.com/questions/16096872/how-to-sort-2-dimensional-array-by-column-value
175
175
  */
176
176
  export function twoDimensionalSort<T>(array1: T[], array2: T[]): -1 | 0 | 1 {
177
+ const type1 = type(array1);
178
+ const type2 = type(array2);
179
+ if (type1 !== type2) {
180
+ error(
181
+ `Failed to two-dimensional sort since the two elements were disparate types: ${array1} & ${array2} (${type1} & ${type2})`,
182
+ );
183
+ }
184
+
185
+ if (type1 === "string" || type1 === "number") {
186
+ if (array1 === array2) {
187
+ return 0;
188
+ }
189
+
190
+ return array1 < array2 ? -1 : 1;
191
+ }
192
+
193
+ if (type1 !== "table") {
194
+ error(
195
+ "Failed to two-dimensional sort since the elements were not a string, number, or table.",
196
+ );
197
+ }
198
+
177
199
  const firstElement1 = array1[0];
178
200
  const firstElement2 = array2[0];
179
201
 
@@ -189,6 +211,14 @@ export function twoDimensionalSort<T>(array1: T[], array2: T[]): -1 | 0 | 1 {
189
211
  );
190
212
  }
191
213
 
214
+ const elementType1 = type(firstElement1);
215
+ const elementType2 = type(firstElement2);
216
+ if (elementType1 !== elementType2) {
217
+ error(
218
+ `Failed to two-dimensional sort since the first element of each array were disparate types: ${firstElement1} & ${firstElement2} (${elementType1} & ${elementType2})`,
219
+ );
220
+ }
221
+
192
222
  if (firstElement1 === firstElement2) {
193
223
  return 0;
194
224
  }
package/src/index.ts CHANGED
@@ -11,6 +11,7 @@ export * from "./enums/HealthType";
11
11
  export * from "./enums/ISCFeature";
12
12
  export * from "./enums/LadderSubTypeCustom";
13
13
  export * from "./enums/ModCallbackCustom";
14
+ export * from "./enums/MysteriousPaperEffect";
14
15
  export * from "./enums/PocketItemType";
15
16
  export * from "./enums/RockAltType";
16
17
  export * from "./enums/SaveDataKey";
@@ -24,6 +24,9 @@
24
24
  -- SOFTWARE.
25
25
  --
26
26
 
27
+ -- The IsaacScript version of this file contains modifications for better error messages, which
28
+ -- assist when debugging.
29
+
27
30
  local json = { _version = "0.1.2" }
28
31
 
29
32
  -------------------------------------------------------------------------------
@@ -58,9 +61,10 @@ local function encode_nil(val)
58
61
  end
59
62
 
60
63
 
61
- local function encode_table(val, stack)
64
+ local function encode_table(val, stack, traversalDescription)
62
65
  local res = {}
63
66
  stack = stack or {}
67
+ traversalDescription = traversalDescription or ""
64
68
 
65
69
  -- Circular reference?
66
70
  if stack[val] then error("circular reference") end
@@ -72,7 +76,7 @@ local function encode_table(val, stack)
72
76
  local n = 0
73
77
  for k in pairs(val) do
74
78
  if type(k) ~= "number" then
75
- error("invalid table: mixed or invalid key types")
79
+ error("invalid table: mixed or invalid key types for array, excepted number, got: " .. tostring(type(k)))
76
80
  end
77
81
  n = n + 1
78
82
  end
@@ -81,7 +85,8 @@ local function encode_table(val, stack)
81
85
  end
82
86
  -- Encode
83
87
  for i, v in ipairs(val) do
84
- table.insert(res, encode(v, stack))
88
+ local newTraversalDescription = traversalDescription .. tostring(i) .. " - "
89
+ table.insert(res, encode(v, stack, newTraversalDescription))
85
90
  end
86
91
  stack[val] = nil
87
92
  return "[" .. table.concat(res, ",") .. "]"
@@ -89,10 +94,14 @@ local function encode_table(val, stack)
89
94
  else
90
95
  -- Treat as an object
91
96
  for k, v in pairs(val) do
97
+ local newTraversalDescription = traversalDescription .. tostring(k) .. " - "
92
98
  if type(k) ~= "string" then
93
- error("invalid table: mixed or invalid key types")
99
+ error(
100
+ "invalid table: mixed or invalid key types for object \"" .. newTraversalDescription .. "\", "
101
+ .. "excepted string, got: " .. tostring(type(k))
102
+ )
94
103
  end
95
- table.insert(res, encode(k, stack) .. ":" .. encode(v, stack))
104
+ table.insert(res, encode(k, stack, newTraversalDescription) .. ":" .. encode(v, stack, newTraversalDescription))
96
105
  end
97
106
  stack[val] = nil
98
107
  return "{" .. table.concat(res, ",") .. "}"
@@ -123,11 +132,11 @@ local type_func_map = {
123
132
  }
124
133
 
125
134
 
126
- encode = function(val, stack)
135
+ encode = function(val, stack, traversalDescription)
127
136
  local t = type(val)
128
137
  local f = type_func_map[t]
129
138
  if f then
130
- return f(val, stack)
139
+ return f(val, stack, traversalDescription)
131
140
  end
132
141
  error("unexpected type '" .. t .. "'")
133
142
  end