isaacscript-common 7.4.3 → 7.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 (183) 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 +46 -36
  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/features/customTrapdoor/exports.d.ts +28 -16
  45. package/dist/features/customTrapdoor/exports.d.ts.map +1 -1
  46. package/dist/features/customTrapdoor/exports.lua +45 -61
  47. package/dist/features/customTrapdoor/init.d.ts.map +1 -1
  48. package/dist/features/customTrapdoor/init.lua +12 -10
  49. package/dist/features/customTrapdoor/spawn.d.ts +6 -0
  50. package/dist/features/customTrapdoor/spawn.d.ts.map +1 -0
  51. package/dist/features/customTrapdoor/spawn.lua +52 -0
  52. package/dist/features/customTrapdoor/v.d.ts +2 -2
  53. package/dist/features/customTrapdoor/v.d.ts.map +1 -1
  54. package/dist/functions/dev.d.ts +20 -0
  55. package/dist/functions/dev.d.ts.map +1 -0
  56. package/dist/functions/dev.lua +34 -0
  57. package/dist/functions/doors.d.ts +6 -5
  58. package/dist/functions/doors.d.ts.map +1 -1
  59. package/dist/functions/doors.lua +25 -12
  60. package/dist/functions/enums.d.ts +3 -3
  61. package/dist/functions/enums.lua +3 -3
  62. package/dist/functions/playerStats.d.ts.map +1 -1
  63. package/dist/functions/playerStats.lua +2 -1
  64. package/dist/functions/players.d.ts.map +1 -1
  65. package/dist/functions/players.lua +3 -2
  66. package/dist/functions/rooms.d.ts +5 -0
  67. package/dist/functions/rooms.d.ts.map +1 -1
  68. package/dist/functions/rooms.lua +12 -2
  69. package/dist/index.d.ts +172 -11037
  70. package/dist/index.d.ts.map +1 -1
  71. package/dist/index.lua +1134 -8
  72. package/dist/interfaces/{CustomStageLua.d.ts → CustomStageTSConfig.d.ts} +86 -60
  73. package/dist/interfaces/CustomStageTSConfig.d.ts.map +1 -0
  74. package/dist/interfaces/{CustomStageLua.lua → CustomStageTSConfig.lua} +0 -0
  75. package/dist/interfaces/JSONRoomsFile.d.ts +6 -5
  76. package/dist/interfaces/JSONRoomsFile.d.ts.map +1 -1
  77. package/dist/interfaces/StatTypeType.d.ts +1 -0
  78. package/dist/interfaces/StatTypeType.d.ts.map +1 -1
  79. package/dist/interfaces/private/AddCallbackParameterCustom.d.ts +6 -0
  80. package/dist/interfaces/private/AddCallbackParameterCustom.d.ts.map +1 -1
  81. package/dist/interfaces/private/CustomStage.d.ts +1 -1
  82. package/dist/interfaces/private/CustomStage.d.ts.map +1 -1
  83. package/dist/interfaces/private/CustomTrapdoorDescription.d.ts +2 -2
  84. package/dist/interfaces/private/CustomTrapdoorDescription.d.ts.map +1 -1
  85. package/dist/interfaces/private/CustomTrapdoorDestination.d.ts +14 -0
  86. package/dist/interfaces/private/CustomTrapdoorDestination.d.ts.map +1 -0
  87. package/dist/interfaces/{index.lua → private/CustomTrapdoorDestination.lua} +0 -0
  88. package/dist/objects/callbackRegisterFunctions.d.ts.map +1 -1
  89. package/dist/objects/callbackRegisterFunctions.lua +9 -0
  90. package/dist/types/PossibleStatType.d.ts +7 -0
  91. package/dist/types/PossibleStatType.d.ts.map +1 -0
  92. package/dist/types/{TrapdoorDestination.lua → PossibleStatType.lua} +0 -0
  93. package/package.json +1 -1
  94. package/src/callbacks/postGridEntity.ts +75 -10
  95. package/src/callbacks/postPlayerChangeStat.ts +8 -4
  96. package/src/callbacks/subscriptions/postGridEntityCustomBroken.ts +4 -0
  97. package/src/callbacks/subscriptions/postGridEntityCustomInit.ts +38 -0
  98. package/src/callbacks/subscriptions/postGridEntityCustomRemove.ts +35 -0
  99. package/src/callbacks/subscriptions/postGridEntityCustomStateChanged.ts +42 -0
  100. package/src/callbacks/subscriptions/postPlayerChangeStat.ts +4 -7
  101. package/src/classes/DefaultMap.ts +3 -2
  102. package/src/enums/ModCallbackCustom.ts +73 -20
  103. package/src/enums/StatType.ts +3 -3
  104. package/src/features/customGridEntity.ts +87 -61
  105. package/src/features/customStage/customStageGridEntities.ts +36 -23
  106. package/src/features/customStage/customStageUtils.ts +52 -1
  107. package/src/features/customStage/exports.ts +33 -45
  108. package/src/features/customStage/init.ts +1 -1
  109. package/src/features/customStage/v.ts +0 -6
  110. package/src/features/customStage/versusScreen.ts +70 -55
  111. package/src/features/customTrapdoor/exports.ts +60 -66
  112. package/src/features/customTrapdoor/init.ts +12 -11
  113. package/src/features/customTrapdoor/spawn.ts +54 -0
  114. package/src/features/customTrapdoor/v.ts +2 -2
  115. package/src/functions/dev.ts +31 -0
  116. package/src/functions/doors.ts +37 -21
  117. package/src/functions/enums.ts +3 -3
  118. package/src/functions/playerStats.ts +1 -0
  119. package/src/functions/players.ts +7 -3
  120. package/src/functions/rooms.ts +18 -0
  121. package/src/index.ts +207 -9
  122. package/src/interfaces/{CustomStageLua.ts → CustomStageTSConfig.ts} +107 -41
  123. package/src/interfaces/JSONRoomsFile.ts +6 -5
  124. package/src/interfaces/StatTypeType.ts +1 -0
  125. package/src/interfaces/private/AddCallbackParameterCustom.ts +6 -0
  126. package/src/interfaces/private/CustomStage.ts +4 -1
  127. package/src/interfaces/private/CustomTrapdoorDescription.ts +2 -2
  128. package/src/interfaces/private/CustomTrapdoorDestination.ts +14 -0
  129. package/src/objects/callbackRegisterFunctions.ts +9 -0
  130. package/src/types/PossibleStatType.ts +12 -0
  131. package/dist/classes/index.d.ts +0 -3
  132. package/dist/classes/index.d.ts.map +0 -1
  133. package/dist/classes/index.lua +0 -18
  134. package/dist/core/index.d.ts +0 -5
  135. package/dist/core/index.d.ts.map +0 -1
  136. package/dist/core/index.lua +0 -34
  137. package/dist/enums/DecorationVariant.d.ts +0 -10
  138. package/dist/enums/DecorationVariant.d.ts.map +0 -1
  139. package/dist/enums/DecorationVariant.lua +0 -7
  140. package/dist/enums/index.d.ts +0 -11
  141. package/dist/enums/index.d.ts.map +0 -1
  142. package/dist/enums/index.lua +0 -82
  143. package/dist/features/index.d.ts +0 -30
  144. package/dist/features/index.d.ts.map +0 -1
  145. package/dist/features/index.lua +0 -216
  146. package/dist/functions/index.d.ts +0 -100
  147. package/dist/functions/index.d.ts.map +0 -1
  148. package/dist/functions/index.lua +0 -794
  149. package/dist/interfaces/CustomStageLua.d.ts.map +0 -1
  150. package/dist/interfaces/index.d.ts +0 -12
  151. package/dist/interfaces/index.d.ts.map +0 -1
  152. package/dist/maps/index.d.ts +0 -5
  153. package/dist/maps/index.d.ts.map +0 -1
  154. package/dist/maps/index.lua +0 -34
  155. package/dist/objects/index.d.ts +0 -2
  156. package/dist/objects/index.d.ts.map +0 -1
  157. package/dist/objects/index.lua +0 -10
  158. package/dist/types/TrapdoorDestination.d.ts +0 -6
  159. package/dist/types/TrapdoorDestination.d.ts.map +0 -1
  160. package/dist/types/index.d.ts +0 -11
  161. package/dist/types/index.d.ts.map +0 -1
  162. package/dist/types/index.lua +0 -10
  163. package/src/classes/index.ts +0 -2
  164. package/src/classes/indexTypeDoc.ts +0 -2
  165. package/src/core/index.ts +0 -4
  166. package/src/core/indexTypeDoc.ts +0 -4
  167. package/src/enums/DecorationVariant.ts +0 -10
  168. package/src/enums/index.ts +0 -10
  169. package/src/enums/indexTypeDoc.ts +0 -10
  170. package/src/features/index.ts +0 -59
  171. package/src/features/indexTypeDoc.ts +0 -30
  172. package/src/functions/index.ts +0 -101
  173. package/src/functions/indexTypeDoc.ts +0 -101
  174. package/src/indexTypeDoc.ts +0 -13
  175. package/src/interfaces/index.ts +0 -11
  176. package/src/interfaces/indexTypeDoc.ts +0 -11
  177. package/src/maps/index.ts +0 -4
  178. package/src/maps/indexTypeDoc.ts +0 -4
  179. package/src/objects/index.ts +0 -1
  180. package/src/objects/indexTypeDoc.ts +0 -1
  181. package/src/types/TrapdoorDestination.ts +0 -8
  182. package/src/types/index.ts +0 -10
  183. 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();
@@ -1,45 +1,28 @@
1
- import {
2
- GridCollisionClass,
3
- LevelStage,
4
- StageType,
5
- } from "isaac-typescript-definitions";
6
- import { game } from "../../core/cachedClasses";
7
- import { TrapdoorAnimation } from "../../enums/private/TrapdoorAnimation";
1
+ import { LevelStage, StageType } from "isaac-typescript-definitions";
8
2
  import { errorIfFeaturesNotInitialized } from "../../featuresInitialized";
9
3
  import { getNextStage, getNextStageType } from "../../functions/nextStage";
10
- import { getRoomListIndex } from "../../functions/roomData";
11
- import { isVector } from "../../functions/vector";
12
- import { CustomTrapdoorDescription } from "../../interfaces/private/CustomTrapdoorDescription";
13
- import { TrapdoorDestination } from "../../types/TrapdoorDestination";
14
- import { spawnCustomGridEntity } from "../customGridEntity";
15
- import {
16
- CUSTOM_TRAPDOOR_FEATURE_NAME,
17
- GridEntityTypeCustom,
18
- } from "./customTrapdoorConstants";
19
- import { shouldTrapdoorSpawnOpen } from "./openClose";
20
- import v from "./v";
4
+ import { CustomTrapdoorDestination } from "../../interfaces/private/CustomTrapdoorDestination";
5
+ import { CUSTOM_TRAPDOOR_FEATURE_NAME } from "./customTrapdoorConstants";
6
+ import { spawnCustomTrapdoorToDestination } from "./spawn";
21
7
 
22
8
  /**
23
- * Helper function to spawn a trapdoor grid entity that will have one or more of the following
24
- * attributes:
9
+ * Helper function to spawn a trapdoor grid entity that will take a player to a custom stage. If you
10
+ * want to create a custom trapdoor that goes to a vanilla stage instead, use the
11
+ * `spawnCustomTrapdoorToVanilla` helper function.
12
+ *
13
+ * Custom trapdoors can have one or more of the following attributes:
25
14
  *
26
15
  * - custom destination (or custom logic for after the player enters)
27
16
  * - custom graphics
28
17
  * - custom logic for opening/closing
29
18
  *
30
- * You can use this function to take the player to your custom stage.
31
- *
32
19
  * Under the hood, the custom trapdoor is represented by a decoration grid entity and is manually
33
20
  * respawned every time the player re-enters the room.
34
21
  *
35
22
  * @param gridIndexOrPosition The location in the room to spawn the trapdoor.
36
- * @param destination Optional. Used to specify where the player will go after jumping into the
37
- * trapdoor. Can either be a vanilla stage tuple, a custom stage tuple, or
38
- * undefined. For example, a destination of `[LevelStage.CAVES_1,
39
- * StageType.ORIGINAL]` corresponds to Caves 1, and a destination of
40
- * `["Slaughterhouse", 1]` corresponds to a custom stage of Slaughterhouse 1. If
41
- * the destination is undefined, then the "normal" destination corresponding to
42
- * the current stage and room will be used (e.g. the next floor, in most cases).
23
+ * @param customStageName The name of the custom stage.
24
+ * @param customStageFloorNum The floor of the custom stage. For most purposes, you should use 1 or
25
+ * 2.
43
26
  * @param anm2Path Optional. The path to the anm2 file to use. By default, the vanilla trapdoor anm2
44
27
  * of "gfx/grid/door_11_trapdoor.anm2" will be used. The specified anm2 file must
45
28
  * have animations called "Opened", "Closed", and "Open Animation".
@@ -48,54 +31,65 @@ import v from "./v";
48
31
  */
49
32
  export function spawnCustomTrapdoor(
50
33
  gridIndexOrPosition: int | Vector,
51
- destination?: TrapdoorDestination,
34
+ customStageName: string,
35
+ customStageFloorNum: int,
52
36
  anm2Path = "gfx/grid/door_11_trapdoor.anm2",
53
37
  spawnOpen?: boolean,
54
38
  ): GridEntity {
55
39
  errorIfFeaturesNotInitialized(CUSTOM_TRAPDOOR_FEATURE_NAME);
56
40
 
57
- const room = game.GetRoom();
58
- const roomFrameCount = room.GetFrameCount();
59
- const roomListIndex = getRoomListIndex();
60
- const gridIndex = isVector(gridIndexOrPosition)
61
- ? room.GetGridIndex(gridIndexOrPosition)
62
- : gridIndexOrPosition;
41
+ const destination: CustomTrapdoorDestination = {
42
+ customStageName,
43
+ customStageFloorNum,
44
+ };
63
45
 
64
- const gridEntity = spawnCustomGridEntity(
65
- GridEntityTypeCustom.TRAPDOOR_CUSTOM,
46
+ return spawnCustomTrapdoorToDestination(
66
47
  gridIndexOrPosition,
67
- GridCollisionClass.NONE,
48
+ destination,
68
49
  anm2Path,
69
- TrapdoorAnimation.OPENED,
50
+ spawnOpen,
70
51
  );
52
+ }
71
53
 
72
- const firstSpawn = roomFrameCount !== 0;
73
- const open =
74
- spawnOpen === undefined
75
- ? shouldTrapdoorSpawnOpen(gridEntity, firstSpawn)
76
- : spawnOpen;
77
- const destinationToUse =
78
- destination === undefined ? getDefaultDestination() : destination;
79
-
80
- const roomTrapdoorMap = v.level.trapdoors.getAndSetDefault(roomListIndex);
81
- const customTrapdoorDescription: CustomTrapdoorDescription = {
82
- open,
83
- destination: destinationToUse,
84
- firstSpawn,
85
- };
86
- roomTrapdoorMap.set(gridIndex, customTrapdoorDescription);
87
-
88
- if (!open) {
89
- const sprite = gridEntity.GetSprite();
90
- sprite.Play(TrapdoorAnimation.CLOSED, true);
91
- }
54
+ /**
55
+ * This is the same thing as the `spawnCustomTrapdoor` function, but instead of having a destination
56
+ * of a custom stage, it has a destination of a vanilla stage.
57
+ *
58
+ * For more information, see the `spawnCustomTrapdoor` function.
59
+ *
60
+ * @param gridIndexOrPosition The location in the room to spawn the trapdoor.
61
+ * @param stage Optional. The number of the vanilla stage to go to. If not provided, the "normal"
62
+ * next stage will be selected.
63
+ * @param stageType The stage type of the vanilla stage to go to. If not provided, the "normal" next
64
+ * stage type will be selected.
65
+ * @param anm2Path Optional. The path to the anm2 file to use. By default, the vanilla trapdoor anm2
66
+ * of "gfx/grid/door_11_trapdoor.anm2" will be used. The specified anm2 file must
67
+ * have animations called "Opened", "Closed", and "Open Animation".
68
+ * @param spawnOpen Optional. Whether or not to spawn the trapdoor in an open state. By default,
69
+ * behavior will be used that emulates a vanilla trapdoor.
70
+ */
71
+ export function spawnCustomTrapdoorToVanilla(
72
+ gridIndexOrPosition: int | Vector,
73
+ stage?: LevelStage,
74
+ stageType?: StageType,
75
+ anm2Path = "gfx/grid/door_11_trapdoor.anm2",
76
+ spawnOpen?: boolean,
77
+ ): GridEntity {
78
+ errorIfFeaturesNotInitialized(CUSTOM_TRAPDOOR_FEATURE_NAME);
92
79
 
93
- return gridEntity;
94
- }
80
+ const vanillaStage = stage === undefined ? getNextStage() : stage;
81
+ const vanillaStageType =
82
+ stageType === undefined ? getNextStageType() : stageType;
95
83
 
96
- function getDefaultDestination(): [stage: LevelStage, stageType: StageType] {
97
- const nextStage = getNextStage();
98
- const nextStageType = getNextStageType();
84
+ const destination: CustomTrapdoorDestination = {
85
+ vanillaStage,
86
+ vanillaStageType,
87
+ };
99
88
 
100
- return [nextStage, nextStageType];
89
+ return spawnCustomTrapdoorToDestination(
90
+ gridIndexOrPosition,
91
+ destination,
92
+ anm2Path,
93
+ spawnOpen,
94
+ );
101
95
  }
@@ -4,7 +4,6 @@ import {
4
4
  EntityGridCollisionClass,
5
5
  ModCallback,
6
6
  RoomTransitionAnim,
7
- StageType,
8
7
  } from "isaac-typescript-definitions";
9
8
  import { ModUpgraded } from "../../classes/ModUpgraded";
10
9
  import { game } from "../../core/cachedClasses";
@@ -15,7 +14,6 @@ import { getAllPlayers } from "../../functions/playerIndex";
15
14
  import { getRoomGridIndex, getRoomListIndex } from "../../functions/roomData";
16
15
  import { teleport } from "../../functions/roomTransition";
17
16
  import { setStage } from "../../functions/stage";
18
- import { isString } from "../../functions/types";
19
17
  import { disableCustomStage, setCustomStage } from "../customStage/exports";
20
18
  import { topStreakTextStart } from "../customStage/streakText";
21
19
  import { enableAllInputs } from "../disableInputs";
@@ -119,7 +117,7 @@ function checkPixelationToBlackComplete() {
119
117
  StageTravelState.WAITING_FOR_SECOND_PIXELATION_TO_GET_HALF_WAY;
120
118
  v.run.stateRenderFrame = futureRenderFrameCount;
121
119
 
122
- goToCustomDestination();
120
+ goToCustomTrapdoorDestination();
123
121
 
124
122
  // Start another pixelation effect. This time, we will keep the screen black with the sprite,
125
123
  // and then remove the black sprite once the pixelation effect is halfway complete.
@@ -193,21 +191,24 @@ function checkAllPlayersLayingDownComplete() {
193
191
  enableAllInputs(CUSTOM_TRAPDOOR_FEATURE_NAME);
194
192
  }
195
193
 
196
- function goToCustomDestination() {
194
+ function goToCustomTrapdoorDestination() {
197
195
  if (v.run.destination === null) {
198
196
  return;
199
197
  }
200
198
 
201
- const [arg1, arg2] = v.run.destination;
199
+ const {
200
+ customStageName,
201
+ customStageFloorNum,
202
+ vanillaStage,
203
+ vanillaStageType,
204
+ } = v.run.destination;
202
205
 
203
- if (isString(arg1)) {
204
- // A string represents a custom stage.
205
- const firstFloor = arg2 === 1;
206
+ if (customStageName !== undefined && customStageFloorNum !== undefined) {
207
+ const firstFloor = customStageFloorNum === 1;
206
208
  setCustomStage("Slaughterhouse", firstFloor);
207
- } else {
208
- // A number represents a vanilla `LevelStage`.
209
+ } else if (vanillaStage !== undefined && vanillaStageType !== undefined) {
209
210
  disableCustomStage();
210
- setStage(arg1, arg2 as StageType);
211
+ setStage(vanillaStage, vanillaStageType);
211
212
  }
212
213
  }
213
214
 
@@ -0,0 +1,54 @@
1
+ import { GridCollisionClass } from "isaac-typescript-definitions";
2
+ import { game } from "../../core/cachedClasses";
3
+ import { TrapdoorAnimation } from "../../enums/private/TrapdoorAnimation";
4
+ import { getRoomListIndex } from "../../functions/roomData";
5
+ import { isVector } from "../../functions/vector";
6
+ import { CustomTrapdoorDescription } from "../../interfaces/private/CustomTrapdoorDescription";
7
+ import { CustomTrapdoorDestination } from "../../interfaces/private/CustomTrapdoorDestination";
8
+ import { spawnCustomGridEntity } from "../customGridEntity";
9
+ import { GridEntityTypeCustom } from "./customTrapdoorConstants";
10
+ import { shouldTrapdoorSpawnOpen } from "./openClose";
11
+ import v from "./v";
12
+
13
+ export function spawnCustomTrapdoorToDestination(
14
+ gridIndexOrPosition: int | Vector,
15
+ destination: CustomTrapdoorDestination,
16
+ anm2Path: string,
17
+ spawnOpen?: boolean,
18
+ ): GridEntity {
19
+ const room = game.GetRoom();
20
+ const roomFrameCount = room.GetFrameCount();
21
+ const roomListIndex = getRoomListIndex();
22
+ const gridIndex = isVector(gridIndexOrPosition)
23
+ ? room.GetGridIndex(gridIndexOrPosition)
24
+ : gridIndexOrPosition;
25
+
26
+ const gridEntity = spawnCustomGridEntity(
27
+ GridEntityTypeCustom.TRAPDOOR_CUSTOM,
28
+ gridIndexOrPosition,
29
+ GridCollisionClass.NONE,
30
+ anm2Path,
31
+ TrapdoorAnimation.OPENED,
32
+ );
33
+
34
+ const firstSpawn = roomFrameCount !== 0;
35
+ const open =
36
+ spawnOpen === undefined
37
+ ? shouldTrapdoorSpawnOpen(gridEntity, firstSpawn)
38
+ : spawnOpen;
39
+
40
+ const roomTrapdoorMap = v.level.trapdoors.getAndSetDefault(roomListIndex);
41
+ const customTrapdoorDescription: CustomTrapdoorDescription = {
42
+ open,
43
+ destination,
44
+ firstSpawn,
45
+ };
46
+ roomTrapdoorMap.set(gridIndex, customTrapdoorDescription);
47
+
48
+ if (!open) {
49
+ const sprite = gridEntity.GetSprite();
50
+ sprite.Play(TrapdoorAnimation.CLOSED, true);
51
+ }
52
+
53
+ return gridEntity;
54
+ }
@@ -1,7 +1,7 @@
1
1
  import { DefaultMap } from "../../classes/DefaultMap";
2
2
  import { StageTravelState } from "../../enums/private/StageTravelState";
3
3
  import { CustomTrapdoorDescription } from "../../interfaces/private/CustomTrapdoorDescription";
4
- import { TrapdoorDestination } from "../../types/TrapdoorDestination";
4
+ import { CustomTrapdoorDestination } from "../../interfaces/private/CustomTrapdoorDestination";
5
5
 
6
6
  const v = {
7
7
  run: {
@@ -10,7 +10,7 @@ const v = {
10
10
  /** The render frame that this state was reached. */
11
11
  stateRenderFrame: null as int | null,
12
12
 
13
- destination: null as TrapdoorDestination | null,
13
+ destination: null as CustomTrapdoorDestination | null,
14
14
  },
15
15
 
16
16
  level: {
@@ -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);
@@ -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