isaacscript-common 7.4.2 → 7.5.1

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 (163) hide show
  1. package/dist/callbacks/postGridEntity.d.ts.map +1 -1
  2. package/dist/callbacks/postGridEntity.lua +53 -6
  3. package/dist/callbacks/postPlayerChangeStat.d.ts.map +1 -1
  4. package/dist/callbacks/postPlayerChangeStat.lua +9 -2
  5. package/dist/callbacks/subscriptions/postGridEntityCustomBroken.d.ts +1 -0
  6. package/dist/callbacks/subscriptions/postGridEntityCustomBroken.d.ts.map +1 -1
  7. package/dist/callbacks/subscriptions/postGridEntityCustomBroken.lua +5 -2
  8. package/dist/callbacks/subscriptions/postGridEntityCustomInit.d.ts +9 -0
  9. package/dist/callbacks/subscriptions/postGridEntityCustomInit.d.ts.map +1 -0
  10. package/dist/callbacks/subscriptions/postGridEntityCustomInit.lua +23 -0
  11. package/dist/callbacks/subscriptions/postGridEntityCustomRemove.d.ts +9 -0
  12. package/dist/callbacks/subscriptions/postGridEntityCustomRemove.d.ts.map +1 -0
  13. package/dist/callbacks/subscriptions/postGridEntityCustomRemove.lua +23 -0
  14. package/dist/callbacks/subscriptions/postGridEntityCustomStateChanged.d.ts +9 -0
  15. package/dist/callbacks/subscriptions/postGridEntityCustomStateChanged.d.ts.map +1 -0
  16. package/dist/callbacks/subscriptions/postGridEntityCustomStateChanged.lua +29 -0
  17. package/dist/callbacks/subscriptions/postPlayerChangeStat.d.ts +3 -2
  18. package/dist/callbacks/subscriptions/postPlayerChangeStat.d.ts.map +1 -1
  19. package/dist/classes/DefaultMap.d.ts +3 -2
  20. package/dist/classes/DefaultMap.d.ts.map +1 -1
  21. package/dist/classes/DefaultMap.lua +2 -1
  22. package/dist/enums/ModCallbackCustom.d.ts +131 -81
  23. package/dist/enums/ModCallbackCustom.d.ts.map +1 -1
  24. package/dist/enums/ModCallbackCustom.lua +67 -61
  25. package/dist/enums/StatType.d.ts +3 -1
  26. package/dist/enums/StatType.d.ts.map +1 -1
  27. package/dist/enums/StatType.lua +2 -0
  28. package/dist/features/customGridEntity.d.ts +30 -13
  29. package/dist/features/customGridEntity.d.ts.map +1 -1
  30. package/dist/features/customGridEntity.lua +67 -48
  31. package/dist/features/customStage/customStageGridEntities.d.ts.map +1 -1
  32. package/dist/features/customStage/customStageGridEntities.lua +37 -31
  33. package/dist/features/customStage/customStageUtils.d.ts +2 -1
  34. package/dist/features/customStage/customStageUtils.d.ts.map +1 -1
  35. package/dist/features/customStage/customStageUtils.lua +40 -1
  36. package/dist/features/customStage/exports.d.ts +1 -25
  37. package/dist/features/customStage/exports.d.ts.map +1 -1
  38. package/dist/features/customStage/exports.lua +28 -29
  39. package/dist/features/customStage/v.d.ts +0 -2
  40. package/dist/features/customStage/v.d.ts.map +1 -1
  41. package/dist/features/customStage/v.lua +0 -2
  42. package/dist/features/customStage/versusScreen.d.ts.map +1 -1
  43. package/dist/features/customStage/versusScreen.lua +74 -60
  44. package/dist/functions/dev.d.ts +20 -0
  45. package/dist/functions/dev.d.ts.map +1 -0
  46. package/dist/functions/dev.lua +34 -0
  47. package/dist/functions/doors.d.ts +6 -5
  48. package/dist/functions/doors.d.ts.map +1 -1
  49. package/dist/functions/doors.lua +25 -12
  50. package/dist/functions/enums.d.ts +3 -3
  51. package/dist/functions/enums.lua +3 -3
  52. package/dist/functions/gridEntities.d.ts +3 -0
  53. package/dist/functions/gridEntities.d.ts.map +1 -1
  54. package/dist/functions/gridEntities.lua +35 -4
  55. package/dist/functions/playerStats.d.ts.map +1 -1
  56. package/dist/functions/playerStats.lua +2 -1
  57. package/dist/functions/players.d.ts.map +1 -1
  58. package/dist/functions/players.lua +3 -2
  59. package/dist/functions/rooms.d.ts +5 -0
  60. package/dist/functions/rooms.d.ts.map +1 -1
  61. package/dist/functions/rooms.lua +12 -2
  62. package/dist/index.d.ts +312 -198
  63. package/dist/index.d.ts.map +1 -1
  64. package/dist/index.lua +1134 -8
  65. package/dist/interfaces/{CustomStageLua.d.ts → CustomStageTSConfig.d.ts} +86 -60
  66. package/dist/interfaces/CustomStageTSConfig.d.ts.map +1 -0
  67. package/dist/interfaces/{CustomStageLua.lua → CustomStageTSConfig.lua} +0 -0
  68. package/dist/interfaces/JSONRoomsFile.d.ts +6 -5
  69. package/dist/interfaces/JSONRoomsFile.d.ts.map +1 -1
  70. package/dist/interfaces/StatTypeType.d.ts +1 -0
  71. package/dist/interfaces/StatTypeType.d.ts.map +1 -1
  72. package/dist/interfaces/private/AddCallbackParameterCustom.d.ts +6 -0
  73. package/dist/interfaces/private/AddCallbackParameterCustom.d.ts.map +1 -1
  74. package/dist/interfaces/private/CustomStage.d.ts +1 -1
  75. package/dist/interfaces/private/CustomStage.d.ts.map +1 -1
  76. package/dist/objects/callbackRegisterFunctions.d.ts.map +1 -1
  77. package/dist/objects/callbackRegisterFunctions.lua +9 -0
  78. package/dist/types/PossibleStatType.d.ts +7 -0
  79. package/dist/types/PossibleStatType.d.ts.map +1 -0
  80. package/dist/{interfaces/index.lua → types/PossibleStatType.lua} +0 -0
  81. package/package.json +1 -1
  82. package/src/callbacks/postGridEntity.ts +75 -10
  83. package/src/callbacks/postPlayerChangeStat.ts +8 -4
  84. package/src/callbacks/subscriptions/postGridEntityCustomBroken.ts +4 -0
  85. package/src/callbacks/subscriptions/postGridEntityCustomInit.ts +38 -0
  86. package/src/callbacks/subscriptions/postGridEntityCustomRemove.ts +35 -0
  87. package/src/callbacks/subscriptions/postGridEntityCustomStateChanged.ts +42 -0
  88. package/src/callbacks/subscriptions/postPlayerChangeStat.ts +4 -7
  89. package/src/classes/DefaultMap.ts +3 -2
  90. package/src/enums/ModCallbackCustom.ts +73 -20
  91. package/src/enums/StatType.ts +3 -3
  92. package/src/features/customGridEntity.ts +87 -61
  93. package/src/features/customStage/customStageGridEntities.ts +16 -7
  94. package/src/features/customStage/customStageUtils.ts +52 -1
  95. package/src/features/customStage/exports.ts +33 -45
  96. package/src/features/customStage/init.ts +1 -1
  97. package/src/features/customStage/v.ts +0 -6
  98. package/src/features/customStage/versusScreen.ts +70 -55
  99. package/src/functions/dev.ts +31 -0
  100. package/src/functions/doors.ts +37 -21
  101. package/src/functions/enums.ts +3 -3
  102. package/src/functions/gridEntities.ts +33 -1
  103. package/src/functions/playerStats.ts +1 -0
  104. package/src/functions/players.ts +7 -3
  105. package/src/functions/rooms.ts +18 -0
  106. package/src/index.ts +208 -9
  107. package/src/interfaces/{CustomStageLua.ts → CustomStageTSConfig.ts} +107 -41
  108. package/src/interfaces/JSONRoomsFile.ts +6 -5
  109. package/src/interfaces/StatTypeType.ts +1 -0
  110. package/src/interfaces/private/AddCallbackParameterCustom.ts +6 -0
  111. package/src/interfaces/private/CustomStage.ts +4 -1
  112. package/src/objects/callbackRegisterFunctions.ts +9 -0
  113. package/src/types/PossibleStatType.ts +12 -0
  114. package/dist/classes/index.d.ts +0 -3
  115. package/dist/classes/index.d.ts.map +0 -1
  116. package/dist/classes/index.lua +0 -18
  117. package/dist/core/index.d.ts +0 -5
  118. package/dist/core/index.d.ts.map +0 -1
  119. package/dist/core/index.lua +0 -34
  120. package/dist/enums/DecorationVariant.d.ts +0 -10
  121. package/dist/enums/DecorationVariant.d.ts.map +0 -1
  122. package/dist/enums/DecorationVariant.lua +0 -7
  123. package/dist/enums/index.d.ts +0 -11
  124. package/dist/enums/index.d.ts.map +0 -1
  125. package/dist/enums/index.lua +0 -82
  126. package/dist/features/index.d.ts +0 -30
  127. package/dist/features/index.d.ts.map +0 -1
  128. package/dist/features/index.lua +0 -216
  129. package/dist/functions/index.d.ts +0 -100
  130. package/dist/functions/index.d.ts.map +0 -1
  131. package/dist/functions/index.lua +0 -794
  132. package/dist/interfaces/CustomStageLua.d.ts.map +0 -1
  133. package/dist/interfaces/index.d.ts +0 -12
  134. package/dist/interfaces/index.d.ts.map +0 -1
  135. package/dist/maps/index.d.ts +0 -5
  136. package/dist/maps/index.d.ts.map +0 -1
  137. package/dist/maps/index.lua +0 -34
  138. package/dist/objects/index.d.ts +0 -2
  139. package/dist/objects/index.d.ts.map +0 -1
  140. package/dist/objects/index.lua +0 -10
  141. package/dist/types/index.d.ts +0 -11
  142. package/dist/types/index.d.ts.map +0 -1
  143. package/dist/types/index.lua +0 -10
  144. package/src/classes/index.ts +0 -2
  145. package/src/classes/indexTypeDoc.ts +0 -2
  146. package/src/core/index.ts +0 -4
  147. package/src/core/indexTypeDoc.ts +0 -4
  148. package/src/enums/DecorationVariant.ts +0 -10
  149. package/src/enums/index.ts +0 -10
  150. package/src/enums/indexTypeDoc.ts +0 -10
  151. package/src/features/index.ts +0 -59
  152. package/src/features/indexTypeDoc.ts +0 -30
  153. package/src/functions/index.ts +0 -101
  154. package/src/functions/indexTypeDoc.ts +0 -101
  155. package/src/indexTypeDoc.ts +0 -13
  156. package/src/interfaces/index.ts +0 -11
  157. package/src/interfaces/indexTypeDoc.ts +0 -11
  158. package/src/maps/index.ts +0 -4
  159. package/src/maps/indexTypeDoc.ts +0 -4
  160. package/src/objects/index.ts +0 -1
  161. package/src/objects/indexTypeDoc.ts +0 -1
  162. package/src/types/index.ts +0 -10
  163. package/src/types/indexTypeDoc.ts +0 -10
@@ -9,7 +9,7 @@ import {
9
9
  import { game, sfxManager } from "../../core/cachedClasses";
10
10
  import { arrayRemove } from "../../functions/array";
11
11
  import { getBosses } from "../../functions/bosses";
12
- import { getEntityID } from "../../functions/entities";
12
+ import { getRoomSubType } from "../../functions/roomData";
13
13
  import { erange } from "../../functions/utils";
14
14
  import { CustomStage } from "../../interfaces/private/CustomStage";
15
15
  import { BOSS_NAME_PNG_FILE_NAMES } from "../../objects/bossNamePNGFileNames";
@@ -26,7 +26,7 @@ import {
26
26
  DEFAULT_BASE_STAGE_TYPE,
27
27
  INVALID_STAGE_VALUE,
28
28
  } from "./exports";
29
- import v, { customBossPNGPaths } from "./v";
29
+ import v from "./v";
30
30
 
31
31
  const DEFAULT_CHARACTER = PlayerType.ISAAC;
32
32
  const DEFAULT_STAGE_ID = StageID.BASEMENT;
@@ -137,22 +137,25 @@ export function playVersusScreenAnimation(customStage: CustomStage): void {
137
137
  pause();
138
138
  hud.SetVisible(false);
139
139
 
140
- const [playerNamePNGPath, playerPortraitPNGPath] = getPlayerPNGPaths();
141
- versusScreenSprite.ReplaceSpritesheet(
142
- PLAYER_NAME_ANM2_LAYER,
143
- playerNamePNGPath,
144
- );
145
- versusScreenSprite.ReplaceSpritesheet(
146
- PLAYER_PORTRAIT_ANM2_LAYER,
147
- playerPortraitPNGPath,
148
- );
140
+ // Player
141
+ {
142
+ const { namePNGPath, portraitPNGPath } = getPlayerPNGPaths();
143
+ versusScreenSprite.ReplaceSpritesheet(PLAYER_NAME_ANM2_LAYER, namePNGPath);
144
+ versusScreenSprite.ReplaceSpritesheet(
145
+ PLAYER_PORTRAIT_ANM2_LAYER,
146
+ portraitPNGPath,
147
+ );
148
+ }
149
149
 
150
- const [bossNamePNGPath, bossPortraitPNGPath] = getBossPNGPaths();
151
- versusScreenSprite.ReplaceSpritesheet(BOSS_NAME_ANM2_LAYER, bossNamePNGPath);
152
- versusScreenSprite.ReplaceSpritesheet(
153
- BOSS_PORTRAIT_ANM2_LAYER,
154
- bossPortraitPNGPath,
155
- );
150
+ // Boss
151
+ {
152
+ const { namePNGPath, portraitPNGPath } = getBossPNGPaths(customStage);
153
+ versusScreenSprite.ReplaceSpritesheet(BOSS_NAME_ANM2_LAYER, namePNGPath);
154
+ versusScreenSprite.ReplaceSpritesheet(
155
+ BOSS_PORTRAIT_ANM2_LAYER,
156
+ portraitPNGPath,
157
+ );
158
+ }
156
159
 
157
160
  versusScreenSprite.LoadGraphics();
158
161
 
@@ -186,67 +189,81 @@ function willVanillaVersusScreenPlay() {
186
189
  }
187
190
 
188
191
  /** Use the character of the 0th player. */
189
- function getPlayerPNGPaths(): [
190
- playerNamePNGPath: string,
191
- playerPortraitPNGPath: string,
192
- ] {
192
+ function getPlayerPNGPaths(): {
193
+ namePNGPath: string;
194
+ portraitPNGPath: string;
195
+ } {
193
196
  const player = Isaac.GetPlayer();
194
197
  const character = player.GetPlayerType();
195
198
 
196
- let playerNamePNGFileName = PLAYER_NAME_PNG_FILE_NAMES[character];
197
- if (playerNamePNGFileName === undefined) {
198
- playerNamePNGFileName = PLAYER_NAME_PNG_FILE_NAMES[DEFAULT_CHARACTER];
199
+ let namePNGFileName = PLAYER_NAME_PNG_FILE_NAMES[character];
200
+ if (namePNGFileName === undefined) {
201
+ namePNGFileName = PLAYER_NAME_PNG_FILE_NAMES[DEFAULT_CHARACTER];
199
202
  }
200
203
 
201
- const playerNamePNGPath = `${PNG_PATH_PREFIX}/${playerNamePNGFileName}`;
204
+ const namePNGPath = `${PNG_PATH_PREFIX}/${namePNGFileName}`;
202
205
 
203
- let playerPortraitFileName = PLAYER_PORTRAIT_PNG_FILE_NAMES[character];
204
- if (playerNamePNGFileName === undefined) {
205
- playerPortraitFileName = PLAYER_PORTRAIT_PNG_FILE_NAMES[DEFAULT_CHARACTER];
206
+ let portraitFileName = PLAYER_PORTRAIT_PNG_FILE_NAMES[character];
207
+ if (namePNGFileName === undefined) {
208
+ portraitFileName = PLAYER_PORTRAIT_PNG_FILE_NAMES[DEFAULT_CHARACTER];
206
209
  }
207
210
 
208
- const playerPortraitPNGPath = `${PLAYER_PORTRAIT_PNG_PATH_PREFIX}/${playerPortraitFileName}`;
211
+ const portraitPNGPath = `${PLAYER_PORTRAIT_PNG_PATH_PREFIX}/${portraitFileName}`;
209
212
 
210
- return [playerNamePNGPath, playerPortraitPNGPath];
213
+ return { namePNGPath, portraitPNGPath };
211
214
  }
212
215
 
213
216
  /** Use the boss of the first boss found. */
214
- function getBossPNGPaths(): [
215
- bossNamePNGPath: string,
216
- bossPortraitPNGPath: string,
217
- ] {
218
- const bosses = getBosses();
219
- const firstBoss = bosses[0];
220
-
217
+ function getBossPNGPaths(customStage: CustomStage): {
218
+ namePNGPath: string;
219
+ portraitPNGPath: string;
220
+ } {
221
221
  // Prefer the PNG paths specified by the end-user, if any.
222
- if (firstBoss !== undefined) {
223
- const entityID = getEntityID(firstBoss);
224
- const pngPaths = customBossPNGPaths.get(entityID);
225
- if (pngPaths !== undefined) {
226
- return pngPaths;
227
- }
222
+ const paths = getBossPNGPathsCustom(customStage);
223
+ if (paths !== undefined) {
224
+ return paths;
228
225
  }
229
226
 
230
227
  // If this is not a vanilla boss, default to showing question marks.
228
+ const bosses = getBosses();
229
+ const firstBoss = bosses[0];
231
230
  const bossID = firstBoss === undefined ? 0 : firstBoss.GetBossID();
232
231
  if (bossID === 0) {
233
232
  const questionMarkSprite = `${PNG_PATH_PREFIX}/${
234
233
  BOSS_NAME_PNG_FILE_NAMES[BossID.BLUE_BABY]
235
234
  }`;
236
- const bossNamePNGPath = questionMarkSprite;
237
- const bossPortraitPNGPath = questionMarkSprite;
238
- return [bossNamePNGPath, bossPortraitPNGPath];
235
+ const namePNGPath = questionMarkSprite;
236
+ const portraitPNGPath = questionMarkSprite;
237
+ return { namePNGPath, portraitPNGPath };
239
238
  }
240
239
 
241
240
  // If this is a vanilla boss, it will have a boss ID, and we can use the corresponding vanilla
242
241
  // files.
243
- const bossNamePNGFileName = BOSS_NAME_PNG_FILE_NAMES[bossID];
244
- const bossNamePNGPath = `${PNG_PATH_PREFIX}/${bossNamePNGFileName}`;
242
+ const namePNGFileName = BOSS_NAME_PNG_FILE_NAMES[bossID];
243
+ const namePNGPath = `${PNG_PATH_PREFIX}/${namePNGFileName}`;
245
244
 
246
- const bossPortraitPNGFileName = BOSS_PORTRAIT_PNG_FILE_NAMES[bossID];
247
- const bossPortraitPNGPath = `${PNG_PATH_PREFIX}/${bossPortraitPNGFileName}`;
245
+ const portraitPNGFileName = BOSS_PORTRAIT_PNG_FILE_NAMES[bossID];
246
+ const portraitPNGPath = `${PNG_PATH_PREFIX}/${portraitPNGFileName}`;
248
247
 
249
- return [bossNamePNGPath, bossPortraitPNGPath];
248
+ return { namePNGPath, portraitPNGPath };
249
+ }
250
+
251
+ function getBossPNGPathsCustom(
252
+ customStage: CustomStage,
253
+ ): { namePNGPath: string; portraitPNGPath: string } | undefined {
254
+ if (customStage.bossPool === undefined) {
255
+ return undefined;
256
+ }
257
+
258
+ const roomSubType = getRoomSubType();
259
+ const matchingBossEntry = customStage.bossPool.find(
260
+ (bossEntry) => bossEntry.subType === roomSubType,
261
+ );
262
+ if (matchingBossEntry === undefined) {
263
+ return undefined;
264
+ }
265
+
266
+ return matchingBossEntry.versusScreen;
250
267
  }
251
268
 
252
269
  function finishVersusScreenAnimation() {
@@ -267,10 +284,8 @@ export function versusScreenPostRender(): void {
267
284
  return;
268
285
  }
269
286
 
270
- const isPaused = game.IsPaused();
271
- if (isPaused) {
272
- return;
273
- }
287
+ // We do not want to early return when the game is paused because we need to start displaying the
288
+ // black screen as soon as the slide animation starts.
274
289
 
275
290
  if (versusScreenSprite.IsFinished(VERSUS_SCREEN_ANIMATION_NAME)) {
276
291
  finishVersusScreenAnimation();
@@ -0,0 +1,31 @@
1
+ import { ModUpgraded } from "../classes/ModUpgraded";
2
+ import { enableExtraConsoleCommands } from "../features/extraConsoleCommands/exports";
3
+ import { removeFadeIn } from "../features/fadeInRemover";
4
+ import { enableFastReset } from "../features/fastReset";
5
+ import { saveDataManagerSetGlobal } from "../features/saveDataManager/exports";
6
+ import { setLogFunctionsGlobal } from "./log";
7
+
8
+ /**
9
+ * Helper function to enable some IsaacScript features that are useful when developing a mod. They
10
+ * shouldn't be enabled when your mod goes to production (i.e. it is uploaded to the Steam
11
+ * Workshop).
12
+ *
13
+ * The list of development features that are enabled are as follows:
14
+ *
15
+ * - `saveDataManagerSetGlobal` - Sets your local variables registered with the save data manager as
16
+ * global variables so you can access them from the in-game console.
17
+ * - `setLogFunctionsGlobal` - Sets the various log functions global so that you can access them
18
+ * from the in-game console.
19
+ * - `enableExtraConsoleCommands` - Enables many extra in-game console commands that make warping
20
+ * around easier (like e.g. `angel` to warp to the Angel Room).
21
+ * - `enableFastReset` - Makes it so that the r key resets the game instantaneously.
22
+ * - `removeFadeIn` - Removes the slow fade in that occurs at the beginning of the run, so that you
23
+ * can immediately start playing or testing.
24
+ */
25
+ export function enableDevFeatures(mod: ModUpgraded): void {
26
+ saveDataManagerSetGlobal();
27
+ setLogFunctionsGlobal();
28
+ enableExtraConsoleCommands(mod);
29
+ enableFastReset();
30
+ removeFadeIn();
31
+ }
@@ -21,6 +21,7 @@ import { ROOM_SHAPE_TO_DOOR_SLOTS } from "../objects/roomShapeToDoorSlots";
21
21
  import { arrayToBitFlags } from "./bitwise";
22
22
  import { directionToVector } from "./direction";
23
23
  import { getEnumValues } from "./enums";
24
+ import { hasFlag } from "./flag";
24
25
  import { isTSTLSet } from "./tstlClass";
25
26
  import { asNumber } from "./types";
26
27
 
@@ -53,6 +54,21 @@ export function doorSlotFlagToDoorSlot(doorSlotFlag: DoorSlotFlag): DoorSlot {
53
54
  return doorSlot === undefined ? DEFAULT_DOOR_SLOT : doorSlot;
54
55
  }
55
56
 
57
+ export function doorSlotFlagsToDoorSlots(
58
+ doorSlotFlags: BitFlags<DoorSlotFlag>,
59
+ ): DoorSlot[] {
60
+ const doorSlots: DoorSlot[] = [];
61
+
62
+ for (const doorSlotFlag of getEnumValues(DoorSlotFlag)) {
63
+ if (hasFlag(doorSlotFlags, doorSlotFlag)) {
64
+ const doorSlot = doorSlotFlagToDoorSlot(doorSlotFlag);
65
+ doorSlots.push(doorSlot);
66
+ }
67
+ }
68
+
69
+ return doorSlots;
70
+ }
71
+
56
72
  export function doorSlotToDirection(doorSlot: DoorSlot): Direction {
57
73
  return DOOR_SLOT_TO_DIRECTION[doorSlot];
58
74
  }
@@ -61,6 +77,27 @@ export function doorSlotToDoorSlotFlag(doorSlot: DoorSlot): DoorSlotFlag {
61
77
  return DOOR_SLOT_TO_DOOR_SLOT_FLAG[doorSlot];
62
78
  }
63
79
 
80
+ /**
81
+ * Helper function to convert an array of door slots or a set of door slots to the resulting bit
82
+ * flag number.
83
+ */
84
+ export function doorSlotsToDoorSlotFlags(
85
+ doorSlots:
86
+ | DoorSlot[]
87
+ | readonly DoorSlot[]
88
+ | Set<DoorSlot>
89
+ | ReadonlySet<DoorSlot>,
90
+ ): BitFlags<DoorSlotFlag> {
91
+ const doorSlotArray = isTSTLSet(doorSlots)
92
+ ? [...doorSlots.values()]
93
+ : (doorSlots as DoorSlot[]);
94
+ const doorSlotFlagArray = doorSlotArray.map((doorSlot) =>
95
+ doorSlotToDoorSlotFlag(doorSlot),
96
+ );
97
+
98
+ return arrayToBitFlags(doorSlotFlagArray);
99
+ }
100
+
64
101
  export function getAngelRoomDoor(): GridEntityDoor | undefined {
65
102
  const angelRoomDoors = getDoors(RoomType.ANGEL);
66
103
  return angelRoomDoors.length === 0 ? undefined : angelRoomDoors[0];
@@ -113,27 +150,6 @@ export function getDoorSlotEnterPositionOffset(
113
150
  return oppositeVector.mul(ROOM_ENTRY_OFFSET_FROM_DOOR);
114
151
  }
115
152
 
116
- /**
117
- * Helper function to convert an array of door slots or a set of door slots to the resulting bit
118
- * flag number.
119
- */
120
- export function getDoorSlotFlags(
121
- doorSlots:
122
- | DoorSlot[]
123
- | readonly DoorSlot[]
124
- | Set<DoorSlot>
125
- | ReadonlySet<DoorSlot>,
126
- ): BitFlags<DoorSlotFlag> {
127
- const doorSlotArray = isTSTLSet(doorSlots)
128
- ? [...doorSlots.values()]
129
- : (doorSlots as DoorSlot[]);
130
- const doorSlotFlagArray = doorSlotArray.map((doorSlot) =>
131
- doorSlotToDoorSlotFlag(doorSlot),
132
- );
133
-
134
- return arrayToBitFlags(doorSlotFlagArray);
135
- }
136
-
137
153
  /** Helper function to get the possible door slots that can exist for a given room shape. */
138
154
  export function getDoorSlotsForRoomShape(
139
155
  roomShape: RoomShape,
@@ -18,7 +18,7 @@ import { irange } from "./utils";
18
18
  * Also see the `getEnumKeys` and `getEnumValues` helper functions.
19
19
  *
20
20
  * For a more in depth explanation, see:
21
- * https://isaacscript.github.io/gotchas#iterating-over-enums
21
+ * https://isaacscript.github.io/main/gotchas#iterating-over-enums
22
22
  */
23
23
  export function getEnumEntries<T>(
24
24
  transpiledEnum: T,
@@ -57,7 +57,7 @@ export function getEnumEntries<T>(
57
57
  * Also see the `getEnumEntries` and `getEnumValues` helper functions.
58
58
  *
59
59
  * For a more in depth explanation, see:
60
- * https://isaacscript.github.io/gotchas#iterating-over-enums
60
+ * https://isaacscript.github.io/main/gotchas#iterating-over-enums
61
61
  */
62
62
  export function getEnumKeys<T>(transpiledEnum: T): string[] {
63
63
  const enumEntries = getEnumEntries(transpiledEnum);
@@ -84,7 +84,7 @@ export function getEnumLength<T>(transpiledEnum: T): int {
84
84
  * Also see the `getEnumEntries` and `getEnumKeys` helper functions.
85
85
  *
86
86
  * For a more in depth explanation, see:
87
- * https://isaacscript.github.io/gotchas#iterating-over-enums
87
+ * https://isaacscript.github.io/main/gotchas#iterating-over-enums
88
88
  */
89
89
  export function getEnumValues<T>(transpiledEnum: T): Array<T[keyof T]> {
90
90
  const enumEntries = getEnumEntries(transpiledEnum);
@@ -1,5 +1,6 @@
1
1
  import {
2
2
  CrawlSpaceVariant,
3
+ EffectVariant,
3
4
  GridCollisionClass,
4
5
  GridEntityType,
5
6
  GridEntityXMLType,
@@ -16,12 +17,14 @@ import {
16
17
  ROOM_SHAPE_TO_TOP_LEFT_WALL_GRID_INDEX_MAP,
17
18
  } from "../maps/roomShapeToTopLeftWallGridIndexMap";
18
19
  import { AnyGridEntity } from "../types/AnyGridEntity";
20
+ import { removeEntities } from "./entities";
21
+ import { getEffects } from "./entitiesSpecific";
19
22
  import { isCircleIntersectingRectangle } from "./math";
20
23
  import { roomUpdateSafe } from "./rooms";
21
24
  import { clearSprite } from "./sprites";
22
25
  import { asNumber, isNumber } from "./types";
23
26
  import { erange } from "./utils";
24
- import { isVector } from "./vector";
27
+ import { isVector, vectorEquals } from "./vector";
25
28
 
26
29
  const BREAKABLE_GRID_ENTITY_TYPES_BY_EXPLOSIONS: ReadonlySet<GridEntityType> =
27
30
  new Set([
@@ -498,6 +501,9 @@ export function removeGridEntities<T extends AnyGridEntity>(
498
501
  * Helper function to remove a grid entity by providing the grid entity object or the grid index
499
502
  * inside of the room.
500
503
  *
504
+ * If removing a Devil Statue or an Angel Statue, this will also remove the associated effect
505
+ * (`EffectVariant.DEVIL` (6) or `EffectVariant.ANGEL` (9), respectively.)
506
+ *
501
507
  * @param gridEntityOrGridIndex The grid entity or grid index to remove.
502
508
  * @param updateRoom Whether or not to update the room after the grid entity is removed. This is
503
509
  * generally a good idea because if the room is not updated, you will be unable to
@@ -511,6 +517,18 @@ export function removeGridEntity(
511
517
  ): void {
512
518
  const room = game.GetRoom();
513
519
 
520
+ const gridEntity = isNumber(gridEntityOrGridIndex)
521
+ ? room.GetGridEntity(gridEntityOrGridIndex)
522
+ : gridEntityOrGridIndex;
523
+ if (gridEntity === undefined) {
524
+ // There is no grid entity to remove.
525
+ return;
526
+ }
527
+
528
+ const gridEntityType = gridEntity.GetType();
529
+ const variant = gridEntity.GetVariant();
530
+ const position = gridEntity.Position;
531
+
514
532
  const gridIndex = isNumber(gridEntityOrGridIndex)
515
533
  ? gridEntityOrGridIndex
516
534
  : gridEntityOrGridIndex.GetGridIndex();
@@ -519,6 +537,20 @@ export function removeGridEntity(
519
537
  if (updateRoom) {
520
538
  roomUpdateSafe();
521
539
  }
540
+
541
+ // In the special case of removing a Devil Statue or Angel Statue, we also need to delete the
542
+ // corresponding effect.
543
+ if (gridEntityType === GridEntityType.STATUE) {
544
+ const effectVariant =
545
+ variant === asNumber(StatueVariant.DEVIL)
546
+ ? EffectVariant.DEVIL
547
+ : EffectVariant.ANGEL;
548
+ const effects = getEffects(effectVariant);
549
+ const effectsOnTile = effects.filter((effect) =>
550
+ vectorEquals(effect.Position, position),
551
+ );
552
+ removeEntities(effectsOnTile);
553
+ }
522
554
  }
523
555
 
524
556
  /**
@@ -21,5 +21,6 @@ export function getPlayerStat<T extends StatType>(
21
21
  [StatType.TEAR_COLOR]: player.TearColor, // 1 << 6
22
22
  [StatType.FLYING]: player.CanFly, // 1 << 7
23
23
  [StatType.LUCK]: player.Luck, // 1 << 10
24
+ [StatType.SIZE]: player.SpriteScale, // 1 << 11
24
25
  }[statType];
25
26
  }
@@ -21,7 +21,11 @@ import {
21
21
  import { getCollectibleMaxCharges } from "./collectibles";
22
22
  import { getCollectibleArray } from "./collectibleSet";
23
23
  import { getEnumValues } from "./enums";
24
- import { getPlayerIndexVanilla, getPlayers } from "./playerIndex";
24
+ import {
25
+ getAllPlayers,
26
+ getPlayerIndexVanilla,
27
+ getPlayers,
28
+ } from "./playerIndex";
25
29
  import { addTearsStat } from "./tears";
26
30
  import { isNumber } from "./types";
27
31
  import { repeat } from "./utils";
@@ -127,12 +131,12 @@ export function addTrinketCostume(
127
131
  export function anyPlayerHasCollectible(
128
132
  collectibleType: CollectibleType,
129
133
  ): boolean {
130
- const players = getPlayers();
134
+ const players = getAllPlayers();
131
135
  return players.some((player) => player.HasCollectible(collectibleType));
132
136
  }
133
137
 
134
138
  export function anyPlayerHasTrinket(trinketType: TrinketType): boolean {
135
- const players = getPlayers();
139
+ const players = getAllPlayers();
136
140
  return players.some((player) => player.HasTrinket(trinketType));
137
141
  }
138
142
 
@@ -4,6 +4,7 @@ import {
4
4
  BossID,
5
5
  Dimension,
6
6
  DoorSlot,
7
+ DownpourRoomSubType,
7
8
  DungeonSubType,
8
9
  GridRoom,
9
10
  HomeRoomSubType,
@@ -425,6 +426,23 @@ export function inMinibossRoomOf(minibossID: MinibossID): boolean {
425
426
  );
426
427
  }
427
428
 
429
+ /**
430
+ * Helper function to check if the current room is a "mirror room" in Downpour or Dross. (These
431
+ * rooms are marked with a specific sub-type.)
432
+ */
433
+ export function inMirrorRoom(): boolean {
434
+ const room = game.GetRoom();
435
+ const roomType = room.GetType();
436
+ const roomStageID = getRoomStageID();
437
+ const roomSubType = getRoomSubType();
438
+
439
+ return (
440
+ roomType === RoomType.DEFAULT &&
441
+ (roomStageID === StageID.DOWNPOUR || roomStageID === StageID.DROSS) &&
442
+ roomSubType === asNumber(DownpourRoomSubType.MIRROR)
443
+ );
444
+ }
445
+
428
446
  /**
429
447
  * Helper function for checking if the room is a secret shop (from the Member Card collectible).
430
448
  *