isaacscript-common 31.4.0 → 31.6.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 (196) hide show
  1. package/dist/index.rollup.d.ts +38 -4
  2. package/dist/isaacscript-common.lua +722 -684
  3. package/dist/src/classes/ModFeature.d.ts.map +1 -1
  4. package/dist/src/classes/ModFeature.lua +5 -9
  5. package/dist/src/classes/ModUpgraded.d.ts.map +1 -1
  6. package/dist/src/classes/ModUpgraded.lua +8 -14
  7. package/dist/src/classes/callbacks/PostNewRoomEarly.lua +2 -2
  8. package/dist/src/classes/features/callbackLogic/CustomGridEntities.d.ts.map +1 -1
  9. package/dist/src/classes/features/callbackLogic/CustomGridEntities.lua +3 -3
  10. package/dist/src/classes/features/other/CharacterHealthConversion.lua +1 -1
  11. package/dist/src/classes/features/other/CustomItemPools.d.ts.map +1 -1
  12. package/dist/src/classes/features/other/CustomItemPools.lua +12 -6
  13. package/dist/src/classes/features/other/CustomStages.d.ts.map +1 -1
  14. package/dist/src/classes/features/other/CustomStages.lua +12 -14
  15. package/dist/src/classes/features/other/CustomTrapdoors.d.ts.map +1 -1
  16. package/dist/src/classes/features/other/CustomTrapdoors.lua +6 -8
  17. package/dist/src/classes/features/other/DeployJSONRoom.d.ts.map +1 -1
  18. package/dist/src/classes/features/other/DeployJSONRoom.lua +15 -15
  19. package/dist/src/classes/features/other/ModdedElementSets.d.ts.map +1 -1
  20. package/dist/src/classes/features/other/ModdedElementSets.lua +21 -12
  21. package/dist/src/classes/features/other/Pause.d.ts.map +1 -1
  22. package/dist/src/classes/features/other/Pause.lua +4 -6
  23. package/dist/src/classes/features/other/SaveDataManager.d.ts.map +1 -1
  24. package/dist/src/classes/features/other/SaveDataManager.lua +5 -9
  25. package/dist/src/classes/features/other/customStages/backdrop.lua +9 -10
  26. package/dist/src/classes/features/other/debugDisplay/DebugDisplayBomb.d.ts.map +1 -1
  27. package/dist/src/classes/features/other/debugDisplay/DebugDisplayBomb.lua +2 -1
  28. package/dist/src/classes/features/other/debugDisplay/DebugDisplayDoor.d.ts.map +1 -1
  29. package/dist/src/classes/features/other/debugDisplay/DebugDisplayDoor.lua +2 -1
  30. package/dist/src/classes/features/other/debugDisplay/DebugDisplayEffect.d.ts.map +1 -1
  31. package/dist/src/classes/features/other/debugDisplay/DebugDisplayEffect.lua +2 -1
  32. package/dist/src/classes/features/other/debugDisplay/DebugDisplayFamiliar.d.ts.map +1 -1
  33. package/dist/src/classes/features/other/debugDisplay/DebugDisplayFamiliar.lua +2 -1
  34. package/dist/src/classes/features/other/debugDisplay/DebugDisplayKnife.d.ts.map +1 -1
  35. package/dist/src/classes/features/other/debugDisplay/DebugDisplayKnife.lua +2 -1
  36. package/dist/src/classes/features/other/debugDisplay/DebugDisplayLaser.d.ts.map +1 -1
  37. package/dist/src/classes/features/other/debugDisplay/DebugDisplayLaser.lua +2 -1
  38. package/dist/src/classes/features/other/debugDisplay/DebugDisplayNPC.d.ts.map +1 -1
  39. package/dist/src/classes/features/other/debugDisplay/DebugDisplayNPC.lua +2 -1
  40. package/dist/src/classes/features/other/debugDisplay/DebugDisplayPickup.d.ts.map +1 -1
  41. package/dist/src/classes/features/other/debugDisplay/DebugDisplayPickup.lua +2 -1
  42. package/dist/src/classes/features/other/debugDisplay/DebugDisplayPit.d.ts.map +1 -1
  43. package/dist/src/classes/features/other/debugDisplay/DebugDisplayPit.lua +2 -1
  44. package/dist/src/classes/features/other/debugDisplay/DebugDisplayPlayer.d.ts.map +1 -1
  45. package/dist/src/classes/features/other/debugDisplay/DebugDisplayPlayer.lua +2 -1
  46. package/dist/src/classes/features/other/debugDisplay/DebugDisplayPoop.d.ts.map +1 -1
  47. package/dist/src/classes/features/other/debugDisplay/DebugDisplayPoop.lua +2 -1
  48. package/dist/src/classes/features/other/debugDisplay/DebugDisplayPressurePlate.d.ts.map +1 -1
  49. package/dist/src/classes/features/other/debugDisplay/DebugDisplayPressurePlate.lua +2 -1
  50. package/dist/src/classes/features/other/debugDisplay/DebugDisplayProjectile.d.ts.map +1 -1
  51. package/dist/src/classes/features/other/debugDisplay/DebugDisplayProjectile.lua +2 -1
  52. package/dist/src/classes/features/other/debugDisplay/DebugDisplayRock.d.ts.map +1 -1
  53. package/dist/src/classes/features/other/debugDisplay/DebugDisplayRock.lua +2 -1
  54. package/dist/src/classes/features/other/debugDisplay/DebugDisplaySlot.d.ts.map +1 -1
  55. package/dist/src/classes/features/other/debugDisplay/DebugDisplaySlot.lua +2 -1
  56. package/dist/src/classes/features/other/debugDisplay/DebugDisplaySpikes.d.ts.map +1 -1
  57. package/dist/src/classes/features/other/debugDisplay/DebugDisplaySpikes.lua +2 -1
  58. package/dist/src/classes/features/other/debugDisplay/DebugDisplayTNT.d.ts.map +1 -1
  59. package/dist/src/classes/features/other/debugDisplay/DebugDisplayTNT.lua +2 -1
  60. package/dist/src/classes/features/other/debugDisplay/DebugDisplayTear.d.ts.map +1 -1
  61. package/dist/src/classes/features/other/debugDisplay/DebugDisplayTear.lua +2 -1
  62. package/dist/src/classes/features/other/debugDisplay/utils.d.ts +0 -1
  63. package/dist/src/classes/features/other/debugDisplay/utils.d.ts.map +1 -1
  64. package/dist/src/classes/features/other/debugDisplay/utils.lua +0 -17
  65. package/dist/src/classes/features/other/saveDataManager/restoreDefaults.lua +1 -1
  66. package/dist/src/functions/array.d.ts +3 -0
  67. package/dist/src/functions/array.d.ts.map +1 -1
  68. package/dist/src/functions/array.lua +9 -3
  69. package/dist/src/functions/bitSet128.d.ts.map +1 -1
  70. package/dist/src/functions/bitSet128.lua +4 -6
  71. package/dist/src/functions/bitwise.d.ts.map +1 -1
  72. package/dist/src/functions/bitwise.lua +7 -3
  73. package/dist/src/functions/color.d.ts.map +1 -1
  74. package/dist/src/functions/color.lua +5 -9
  75. package/dist/src/functions/deepCopy.lua +23 -31
  76. package/dist/src/functions/entities.d.ts.map +1 -1
  77. package/dist/src/functions/entities.lua +20 -18
  78. package/dist/src/functions/entitiesSpecific.d.ts.map +1 -1
  79. package/dist/src/functions/entitiesSpecific.lua +11 -27
  80. package/dist/src/functions/enums.d.ts +6 -4
  81. package/dist/src/functions/enums.d.ts.map +1 -1
  82. package/dist/src/functions/enums.lua +13 -9
  83. package/dist/src/functions/gridEntities.d.ts.map +1 -1
  84. package/dist/src/functions/gridEntities.lua +18 -11
  85. package/dist/src/functions/gridEntitiesSpecific.d.ts.map +1 -1
  86. package/dist/src/functions/gridEntitiesSpecific.lua +16 -28
  87. package/dist/src/functions/input.d.ts +3 -0
  88. package/dist/src/functions/input.d.ts.map +1 -1
  89. package/dist/src/functions/input.lua +14 -14
  90. package/dist/src/functions/jsonRoom.d.ts.map +1 -1
  91. package/dist/src/functions/jsonRoom.lua +35 -23
  92. package/dist/src/functions/kColor.d.ts.map +1 -1
  93. package/dist/src/functions/kColor.lua +6 -12
  94. package/dist/src/functions/map.d.ts.map +1 -1
  95. package/dist/src/functions/map.lua +3 -3
  96. package/dist/src/functions/minimap.d.ts.map +1 -1
  97. package/dist/src/functions/minimap.lua +17 -9
  98. package/dist/src/functions/players.d.ts.map +1 -1
  99. package/dist/src/functions/players.lua +17 -22
  100. package/dist/src/functions/render.d.ts +16 -0
  101. package/dist/src/functions/render.d.ts.map +1 -0
  102. package/dist/src/functions/render.lua +50 -0
  103. package/dist/src/functions/rng.d.ts.map +1 -1
  104. package/dist/src/functions/rng.lua +3 -3
  105. package/dist/src/functions/roomShapeWalls.d.ts.map +1 -1
  106. package/dist/src/functions/roomShapeWalls.lua +7 -3
  107. package/dist/src/functions/roomTransition.d.ts.map +1 -1
  108. package/dist/src/functions/roomTransition.lua +7 -3
  109. package/dist/src/functions/rooms.d.ts.map +1 -1
  110. package/dist/src/functions/rooms.lua +8 -5
  111. package/dist/src/functions/serialization.d.ts.map +1 -1
  112. package/dist/src/functions/serialization.lua +8 -18
  113. package/dist/src/functions/table.d.ts.map +1 -1
  114. package/dist/src/functions/table.lua +6 -12
  115. package/dist/src/functions/tstlClass.d.ts.map +1 -1
  116. package/dist/src/functions/tstlClass.lua +3 -3
  117. package/dist/src/functions/utils.d.ts +9 -10
  118. package/dist/src/functions/utils.d.ts.map +1 -1
  119. package/dist/src/functions/utils.lua +14 -22
  120. package/dist/src/functions/vector.d.ts.map +1 -1
  121. package/dist/src/functions/vector.lua +4 -6
  122. package/dist/src/functions/weighted.d.ts.map +1 -1
  123. package/dist/src/functions/weighted.lua +7 -3
  124. package/dist/src/index.d.ts +2 -0
  125. package/dist/src/index.d.ts.map +1 -1
  126. package/dist/src/index.lua +8 -0
  127. package/dist/src/sets/bossSets.d.ts.map +1 -1
  128. package/dist/src/sets/bossSets.lua +3 -3
  129. package/dist/src/types/Expand.d.ts +8 -0
  130. package/dist/src/types/Expand.d.ts.map +1 -0
  131. package/dist/src/types/Expand.lua +2 -0
  132. package/package.json +2 -2
  133. package/src/classes/ModFeature.ts +16 -12
  134. package/src/classes/ModUpgraded.ts +18 -16
  135. package/src/classes/callbacks/PostNewRoomEarly.ts +2 -2
  136. package/src/classes/features/callbackLogic/CustomGridEntities.ts +2 -3
  137. package/src/classes/features/other/CharacterHealthConversion.ts +1 -1
  138. package/src/classes/features/other/CustomItemPools.ts +9 -8
  139. package/src/classes/features/other/CustomStages.ts +9 -10
  140. package/src/classes/features/other/CustomTrapdoors.ts +9 -10
  141. package/src/classes/features/other/DeployJSONRoom.ts +21 -21
  142. package/src/classes/features/other/ModdedElementSets.ts +18 -21
  143. package/src/classes/features/other/Pause.ts +9 -6
  144. package/src/classes/features/other/SaveDataManager.ts +14 -16
  145. package/src/classes/features/other/customStages/backdrop.ts +5 -6
  146. package/src/classes/features/other/debugDisplay/DebugDisplayBomb.ts +2 -1
  147. package/src/classes/features/other/debugDisplay/DebugDisplayDoor.ts +2 -1
  148. package/src/classes/features/other/debugDisplay/DebugDisplayEffect.ts +2 -1
  149. package/src/classes/features/other/debugDisplay/DebugDisplayFamiliar.ts +2 -1
  150. package/src/classes/features/other/debugDisplay/DebugDisplayKnife.ts +2 -1
  151. package/src/classes/features/other/debugDisplay/DebugDisplayLaser.ts +2 -1
  152. package/src/classes/features/other/debugDisplay/DebugDisplayNPC.ts +2 -1
  153. package/src/classes/features/other/debugDisplay/DebugDisplayPickup.ts +2 -1
  154. package/src/classes/features/other/debugDisplay/DebugDisplayPit.ts +2 -1
  155. package/src/classes/features/other/debugDisplay/DebugDisplayPlayer.ts +2 -1
  156. package/src/classes/features/other/debugDisplay/DebugDisplayPoop.ts +2 -1
  157. package/src/classes/features/other/debugDisplay/DebugDisplayPressurePlate.ts +2 -1
  158. package/src/classes/features/other/debugDisplay/DebugDisplayProjectile.ts +2 -1
  159. package/src/classes/features/other/debugDisplay/DebugDisplayRock.ts +2 -1
  160. package/src/classes/features/other/debugDisplay/DebugDisplaySlot.ts +2 -1
  161. package/src/classes/features/other/debugDisplay/DebugDisplaySpikes.ts +2 -1
  162. package/src/classes/features/other/debugDisplay/DebugDisplayTNT.ts +2 -1
  163. package/src/classes/features/other/debugDisplay/DebugDisplayTear.ts +2 -1
  164. package/src/classes/features/other/debugDisplay/utils.ts +0 -13
  165. package/src/classes/features/other/saveDataManager/restoreDefaults.ts +1 -1
  166. package/src/functions/array.ts +8 -6
  167. package/src/functions/bitSet128.ts +9 -10
  168. package/src/functions/bitwise.ts +6 -3
  169. package/src/functions/color.ts +13 -15
  170. package/src/functions/deepCopy.ts +18 -24
  171. package/src/functions/deepCopyTests.ts +5 -6
  172. package/src/functions/entities.ts +22 -20
  173. package/src/functions/entitiesSpecific.ts +10 -27
  174. package/src/functions/enums.ts +29 -17
  175. package/src/functions/gridEntities.ts +14 -16
  176. package/src/functions/gridEntitiesSpecific.ts +15 -28
  177. package/src/functions/input.ts +3 -3
  178. package/src/functions/jsonRoom.ts +39 -27
  179. package/src/functions/kColor.ts +17 -20
  180. package/src/functions/map.ts +5 -5
  181. package/src/functions/minimap.ts +16 -15
  182. package/src/functions/players.ts +7 -10
  183. package/src/functions/render.ts +53 -0
  184. package/src/functions/rng.ts +5 -5
  185. package/src/functions/roomShapeWalls.ts +3 -4
  186. package/src/functions/roomTransition.ts +5 -5
  187. package/src/functions/rooms.ts +5 -6
  188. package/src/functions/serialization.ts +25 -30
  189. package/src/functions/table.ts +18 -20
  190. package/src/functions/tstlClass.ts +5 -5
  191. package/src/functions/utils.ts +27 -23
  192. package/src/functions/vector.ts +9 -10
  193. package/src/functions/weighted.ts +5 -5
  194. package/src/index.ts +2 -0
  195. package/src/sets/bossSets.ts +5 -5
  196. package/src/types/Expand.ts +5 -0
@@ -7,6 +7,7 @@ import { ReadonlySet } from "../types/ReadonlySet";
7
7
  import { getGridIndexesBetween } from "./gridIndex";
8
8
  import { getRoomShapeCorners, isLRoomShape } from "./roomShape";
9
9
  import { inBossRoomOf, inHomeCloset } from "./rooms";
10
+ import { assertDefined } from "./utils";
10
11
 
11
12
  const ROOM_SHAPE_TO_WALL_GRID_INDEX_SET: ReadonlyMap<
12
13
  RoomShape,
@@ -329,10 +330,8 @@ export function isVanillaWallGridIndex(gridIndex: int): boolean {
329
330
  wallGridIndexSet = MOTHER_ROOM_CORNERS_SET;
330
331
  } else {
331
332
  wallGridIndexSet = ROOM_SHAPE_TO_WALL_GRID_INDEX_SET.get(roomShape);
332
- }
333
-
334
- if (wallGridIndexSet === undefined) {
335
- error(
333
+ assertDefined(
334
+ wallGridIndexSet,
336
335
  `Failed to find the wall grid index set for: RoomShape.${RoomShape[roomShape]} (${roomShape})`,
337
336
  );
338
337
  }
@@ -5,6 +5,7 @@ import {
5
5
  } from "isaac-typescript-definitions";
6
6
  import { game } from "../core/cachedClasses";
7
7
  import { getRoomData, getRoomGridIndex } from "./roomData";
8
+ import { assertDefined } from "./utils";
8
9
 
9
10
  /**
10
11
  * Helper function to reload the current room using `Game.StartRoomTransition`.
@@ -40,11 +41,10 @@ export function teleport(
40
41
  const level = game.GetLevel();
41
42
 
42
43
  const roomData = getRoomData(roomGridIndex);
43
- if (roomData === undefined) {
44
- error(
45
- `Failed to change the room to grid index ${roomGridIndex} because that room does not exist.`,
46
- );
47
- }
44
+ assertDefined(
45
+ roomData,
46
+ `Failed to change the room to grid index ${roomGridIndex} because that room does not exist.`,
47
+ );
48
48
 
49
49
  // This must be set before every `Game.StartRoomTransition` method invocation or else the function
50
50
  // can send you to the wrong room.
@@ -48,7 +48,7 @@ import { isLRoomShape } from "./roomShape";
48
48
  import { reloadRoom } from "./roomTransition";
49
49
  import { getGotoCommand } from "./stage";
50
50
  import { asNumber } from "./types";
51
- import { iRange } from "./utils";
51
+ import { assertDefined, iRange } from "./utils";
52
52
 
53
53
  const SECRET_ROOM_TYPES = new ReadonlySet([
54
54
  RoomType.SECRET,
@@ -65,11 +65,10 @@ export function changeRoom(roomGridIndex: int): void {
65
65
  const level = game.GetLevel();
66
66
 
67
67
  const roomData = getRoomData(roomGridIndex);
68
- if (roomData === undefined) {
69
- error(
70
- `Failed to change the room to grid index ${roomGridIndex} because that room does not exist.`,
71
- );
72
- }
68
+ assertDefined(
69
+ roomData,
70
+ `Failed to change the room to grid index ${roomGridIndex} because that room does not exist.`,
71
+ );
73
72
 
74
73
  // LeaveDoor must be set before every `Game.ChangeRoom` invocation or else the function can send
75
74
  // you to the wrong room.
@@ -10,6 +10,7 @@ import type {
10
10
  import { ISAAC_API_CLASS_TYPE_TO_FUNCTIONS } from "../objects/isaacAPIClassTypeToFunctions";
11
11
  import { getIsaacAPIClassName } from "./isaacAPIClass";
12
12
  import { isTable, isUserdata } from "./types";
13
+ import { assertDefined } from "./utils";
13
14
 
14
15
  /**
15
16
  * Helper function to generically copy an Isaac API class without knowing what specific type of
@@ -27,11 +28,10 @@ export function copyIsaacAPIClass<T extends CopyableIsaacAPIClass>(
27
28
  }
28
29
 
29
30
  const isaacAPIClassType = getIsaacAPIClassName(isaacAPIClass);
30
- if (isaacAPIClassType === undefined) {
31
- error(
32
- "Failed to copy an Isaac API class since it does not have a class type.",
33
- );
34
- }
31
+ assertDefined(
32
+ isaacAPIClassType,
33
+ "Failed to copy an Isaac API class since it does not have a class type.",
34
+ );
35
35
 
36
36
  const copyableIsaacAPIClassType =
37
37
  isaacAPIClassType as CopyableIsaacAPIClassType;
@@ -48,11 +48,10 @@ export function copyIsaacAPIClass<T extends CopyableIsaacAPIClass>(
48
48
  ThisSerializedIsaacAPIClassType
49
49
  >
50
50
  | undefined;
51
- if (functions === undefined) {
52
- error(
53
- `Failed to copy an Isaac API class since the associated functions were not found for Isaac API class type: ${copyableIsaacAPIClassType}`,
54
- );
55
- }
51
+ assertDefined(
52
+ functions,
53
+ `Failed to copy an Isaac API class since the associated functions were not found for Isaac API class type: ${copyableIsaacAPIClassType}`,
54
+ );
56
55
 
57
56
  return functions.copy(isaacAPIClass);
58
57
  }
@@ -78,11 +77,10 @@ export function deserializeIsaacAPIClass<
78
77
  const copyableIsaacAPIClassType = getSerializedTableType(
79
78
  serializedIsaacAPIClass,
80
79
  );
81
- if (copyableIsaacAPIClassType === undefined) {
82
- error(
83
- "Failed to deserialize an Isaac API class since a valid class type brand was not found.",
84
- );
85
- }
80
+ assertDefined(
81
+ copyableIsaacAPIClassType,
82
+ "Failed to deserialize an Isaac API class since a valid class type brand was not found.",
83
+ );
86
84
 
87
85
  type ThisIsaacAPIClassType = IsaacAPIClassTypeToType[SerializedT["__kind"]];
88
86
  type ThisSerializedIsaacAPIClassType = SerializedT;
@@ -95,11 +93,10 @@ export function deserializeIsaacAPIClass<
95
93
  ThisSerializedIsaacAPIClassType
96
94
  >
97
95
  | undefined;
98
- if (functions === undefined) {
99
- error(
100
- `Failed to deserialize an Isaac API class since the associated functions were not found for class type: ${copyableIsaacAPIClassType}`,
101
- );
102
- }
96
+ assertDefined(
97
+ functions,
98
+ `Failed to deserialize an Isaac API class since the associated functions were not found for class type: ${copyableIsaacAPIClassType}`,
99
+ );
103
100
 
104
101
  return functions.deserialize(serializedIsaacAPIClass);
105
102
  }
@@ -170,11 +167,10 @@ export function serializeIsaacAPIClass<T extends CopyableIsaacAPIClass>(
170
167
  }
171
168
 
172
169
  const isaacAPIClassType = getIsaacAPIClassName(isaacAPIClass);
173
- if (isaacAPIClassType === undefined) {
174
- error(
175
- "Failed to serialize an Isaac API class since it does not have a class type.",
176
- );
177
- }
170
+ assertDefined(
171
+ isaacAPIClassType,
172
+ "Failed to serialize an Isaac API class since it does not have a class name.",
173
+ );
178
174
 
179
175
  const copyableIsaacAPIClassType =
180
176
  isaacAPIClassType as CopyableIsaacAPIClassType;
@@ -191,11 +187,10 @@ export function serializeIsaacAPIClass<T extends CopyableIsaacAPIClass>(
191
187
  ThisSerializedIsaacAPIClassType
192
188
  >
193
189
  | undefined;
194
- if (functions === undefined) {
195
- error(
196
- `Failed to serialize an Isaac API class since the associated functions were not found for class type: ${copyableIsaacAPIClassType}`,
197
- );
198
- }
190
+ assertDefined(
191
+ functions,
192
+ `Failed to serialize an Isaac API class since the associated functions were not found for class type: ${copyableIsaacAPIClassType}`,
193
+ );
199
194
 
200
195
  return functions.serialize(isaacAPIClass);
201
196
  }
@@ -1,4 +1,5 @@
1
1
  import { isBoolean, isNumber, isString, isUserdata } from "./types";
2
+ import { assertDefined } from "./utils";
2
3
 
3
4
  /**
4
5
  * In a `Map`, you can use the `clear` method to delete every element. However, in a `LuaMap`, the
@@ -47,11 +48,10 @@ export function getBooleansFromTable(
47
48
  const booleans: boolean[] = [];
48
49
  for (const key of keys) {
49
50
  const value = luaMap.get(key);
50
- if (value === undefined) {
51
- error(
52
- `Failed to find a value for "${key}" in a table representing a "${objectName}" object.`,
53
- );
54
- }
51
+ assertDefined(
52
+ value,
53
+ `Failed to find a value for "${key}" in a table representing a "${objectName}" object.`,
54
+ );
55
55
 
56
56
  if (isBoolean(value)) {
57
57
  booleans.push(value);
@@ -79,21 +79,20 @@ export function getNumbersFromTable(
79
79
  const numbers: number[] = [];
80
80
  for (const key of keys) {
81
81
  const value = luaMap.get(key);
82
- if (value === undefined) {
83
- error(
84
- `Failed to find a value for "${key}" in a table representing a "${objectName}" object.`,
85
- );
86
- }
82
+ assertDefined(
83
+ value,
84
+ `Failed to find a value for "${key}" in a table representing a "${objectName}" object.`,
85
+ );
87
86
 
88
87
  if (isNumber(value)) {
89
88
  numbers.push(value);
90
89
  } else if (isString(value)) {
91
90
  const number = tonumber(value);
92
- if (number === undefined) {
93
- error(
94
- `Failed to convert the "${key}" value of a table representing a "${objectName}" object to a number: ${value}`,
95
- );
96
- }
91
+ assertDefined(
92
+ number,
93
+ `Failed to convert the "${key}" value of a table representing a "${objectName}" object to a number: ${value}`,
94
+ );
95
+
97
96
  numbers.push(number);
98
97
  } else {
99
98
  error(
@@ -119,11 +118,10 @@ export function getStringsFromTable(
119
118
  const strings: string[] = [];
120
119
  for (const key of keys) {
121
120
  const value = luaMap.get(key);
122
- if (value === undefined) {
123
- error(
124
- `Failed to find a value for "${key}" in a table representing a "${objectName}" object.`,
125
- );
126
- }
121
+ assertDefined(
122
+ value,
123
+ `Failed to find a value for "${key}" in a table representing a "${objectName}" object.`,
124
+ );
127
125
 
128
126
  if (isString(value)) {
129
127
  strings.push(value);
@@ -2,6 +2,7 @@ import type { DefaultMap } from "../classes/DefaultMap";
2
2
  import type { TSTLClassMetatable } from "../interfaces/TSTLClassMetatable";
3
3
  import type { TSTLClass } from "../types/TSTLClass";
4
4
  import { isTable } from "./types";
5
+ import { assertDefined } from "./utils";
5
6
 
6
7
  /**
7
8
  * Helper function to get the constructor from an instantiated TypeScriptToLua class, which is
@@ -94,11 +95,10 @@ export function isTSTLSet(object: unknown): object is Set<AnyNotNil> {
94
95
  */
95
96
  export function newTSTLClass(oldClass: TSTLClass): TSTLClass {
96
97
  const constructor = getTSTLClassConstructor(oldClass);
97
- if (constructor === undefined) {
98
- error(
99
- "Failed to instantiate a new TypeScriptToLua class since the provided old class does not have a metatable/constructor.",
100
- );
101
- }
98
+ assertDefined(
99
+ constructor,
100
+ "Failed to instantiate a new TypeScriptToLua class since the provided old class does not have a metatable/constructor.",
101
+ );
102
102
 
103
103
  // We re-implement some of the logic from the transpiled "__TS__New" function.
104
104
  const newClass = new LuaMap<AnyNotNil, unknown>();
@@ -1,9 +1,26 @@
1
- import { RenderMode } from "isaac-typescript-definitions";
2
- import { game } from "../core/cachedClasses";
3
1
  import { ReadonlySet } from "../types/ReadonlySet";
4
2
  import { getAllPlayers } from "./playerIndex";
5
3
  import { isFunction } from "./types";
6
4
 
5
+ /**
6
+ * Helper function to throw an error (using the `error` Lua function) if the provided value is equal
7
+ * to `undefined`.
8
+ *
9
+ * This is useful to have TypeScript narrow a `T | undefined` value to `T` in a concise way.
10
+ */
11
+ export function assertDefined<T>(
12
+ value: T,
13
+ ...[msg]: [undefined] extends [T]
14
+ ? [string]
15
+ : [
16
+ "The assertion is useless because the provided value does not contain undefined.",
17
+ ]
18
+ ): asserts value is Exclude<T, undefined> {
19
+ if (value === undefined) {
20
+ error(msg);
21
+ }
22
+ }
23
+
7
24
  /**
8
25
  * Helper function to return an array of integers with the specified range, inclusive on the lower
9
26
  * end and exclusive on the high end. (The "e" in the function name stands for exclusive.) Thus,
@@ -123,21 +140,6 @@ export function isMultiplayer(): boolean {
123
140
  return controllerIndexesSet.size > 1;
124
141
  }
125
142
 
126
- /**
127
- * Helper function to see if the current render callback is rendering a water reflection.
128
- *
129
- * When the player is in a room with water, things will be rendered twice: once for the normal
130
- * rendering, and once for the reflecting rendering. Thus, any mod code in a render callback will
131
- * run twice per frame in these situations, which may be unexpected or cause bugs.
132
- *
133
- * This function is typically used to early return from a render function if it returns true.
134
- */
135
- export function isReflectionRender(): boolean {
136
- const room = game.GetRoom();
137
- const renderMode = room.GetRenderMode();
138
- return renderMode === RenderMode.WATER_REFLECT;
139
- }
140
-
141
143
  /**
142
144
  * Helper function to check if the player is using Afterbirth+ or Repentance.
143
145
  *
@@ -148,16 +150,18 @@ export function isReflectionRender(): boolean {
148
150
  */
149
151
  export function isRepentance(): boolean {
150
152
  const metatable = getmetatable(Sprite) as LuaMap<string, unknown> | undefined;
151
- if (metatable === undefined) {
152
- error("Failed to get the metatable of the Sprite global table.");
153
- }
153
+ assertDefined(
154
+ metatable,
155
+ "Failed to get the metatable of the Sprite global table.",
156
+ );
154
157
 
155
158
  const classTable = metatable.get("__class") as
156
159
  | LuaMap<string, unknown>
157
160
  | undefined;
158
- if (classTable === undefined) {
159
- error('Failed to get the "__class" key of the Sprite metatable.');
160
- }
161
+ assertDefined(
162
+ classTable,
163
+ 'Failed to get the "__class" key of the Sprite metatable.',
164
+ );
161
165
 
162
166
  const getAnimation = classTable.get("GetAnimation");
163
167
  return isFunction(getAnimation);
@@ -13,6 +13,7 @@ import {
13
13
  tableHasKeys,
14
14
  } from "./table";
15
15
  import { isTable } from "./types";
16
+ import { assertDefined } from "./utils";
16
17
 
17
18
  export type SerializedVector = LuaMap<string, unknown> & {
18
19
  readonly __serializedVectorBrand: symbol;
@@ -46,16 +47,14 @@ export function deserializeVector(vector: SerializedVector): Vector {
46
47
 
47
48
  const [x, y] = getNumbersFromTable(vector, OBJECT_NAME, ...KEYS);
48
49
 
49
- if (x === undefined) {
50
- error(
51
- `Failed to deserialize a ${OBJECT_NAME} object since the provided object did not have a value for: X`,
52
- );
53
- }
54
- if (y === undefined) {
55
- error(
56
- `Failed to deserialize a ${OBJECT_NAME} object since the provided object did not have a value for: Y`,
57
- );
58
- }
50
+ assertDefined(
51
+ x,
52
+ `Failed to deserialize a ${OBJECT_NAME} object since the provided object did not have a value for: X`,
53
+ );
54
+ assertDefined(
55
+ y,
56
+ `Failed to deserialize a ${OBJECT_NAME} object since the provided object did not have a value for: Y`,
57
+ );
59
58
 
60
59
  return Vector(x, y);
61
60
  }
@@ -2,6 +2,7 @@ import type { WeightedArray } from "../types/WeightedArray";
2
2
  import { sumArray } from "./array";
3
3
  import { getRandomFloat } from "./random";
4
4
  import { getRandomSeed } from "./rng";
5
+ import { assertDefined } from "./utils";
5
6
 
6
7
  /**
7
8
  * Get a random value from a `WeightedArray`. (A `WeightedArray` is an array of tuples, where the
@@ -15,11 +16,10 @@ export function getRandomFromWeightedArray<T>(
15
16
  const randomIndex = getRandomIndexFromWeightedArray(weightedArray, seedOrRNG);
16
17
 
17
18
  const randomElement = weightedArray[randomIndex];
18
- if (randomElement === undefined) {
19
- error(
20
- `Failed to get an element from a weighted array using a random index of: ${randomIndex}`,
21
- );
22
- }
19
+ assertDefined(
20
+ randomElement,
21
+ `Failed to get an element from a weighted array using a random index of: ${randomIndex}`,
22
+ );
23
23
 
24
24
  return randomElement[0];
25
25
  }
package/src/index.ts CHANGED
@@ -95,6 +95,7 @@ export * from "./functions/pressurePlate";
95
95
  export * from "./functions/projectiles";
96
96
  export * from "./functions/random";
97
97
  export * from "./functions/readOnly";
98
+ export * from "./functions/render";
98
99
  export * from "./functions/revive";
99
100
  export * from "./functions/rng";
100
101
  export * from "./functions/rockAlt";
@@ -157,6 +158,7 @@ export * from "./types/AnyGridEntity";
157
158
  export * from "./types/ConversionHeartSubType";
158
159
  export * from "./types/Decrement";
159
160
  export * from "./types/EntityID";
161
+ export * from "./types/Expand";
160
162
  export * from "./types/FunctionTuple";
161
163
  export * from "./types/GridEntityID";
162
164
  export * from "./types/HasFunction";
@@ -31,6 +31,7 @@ import {
31
31
  } from "isaac-typescript-definitions";
32
32
  import { parseEntityTypeVariantString } from "../functions/entities";
33
33
  import { copySet } from "../functions/set";
34
+ import { assertDefined } from "../functions/utils";
34
35
  import { ReadonlyMap } from "../types/ReadonlyMap";
35
36
  import { ReadonlySet } from "../types/ReadonlySet";
36
37
  import { STORY_BOSSES_SET } from "./storyBossesSet";
@@ -489,11 +490,10 @@ function getAllBossesExcludingStoryBossesSet(): ReadonlySet<string> {
489
490
  const allBosses = [...ALL_BOSSES_SET.values()];
490
491
  for (const entityTypeVariantString of allBosses) {
491
492
  const tuple = parseEntityTypeVariantString(entityTypeVariantString);
492
- if (tuple === undefined) {
493
- error(
494
- "Failed to parse a boss tuple when constructing the story boss set.",
495
- );
496
- }
493
+ assertDefined(
494
+ tuple,
495
+ "Failed to parse a boss tuple when constructing the story boss set.",
496
+ );
497
497
 
498
498
  const [entityType, _variant] = tuple;
499
499
  if (STORY_BOSSES_SET.has(entityType)) {
@@ -0,0 +1,5 @@
1
+ /**
2
+ * From:
3
+ * https://stackoverflow.com/questions/57683303/how-can-i-see-the-full-expanded-contract-of-a-typescript-type
4
+ */
5
+ export type Expand<T> = T extends infer O ? { [K in keyof O]: O[K] } : never;