isaacscript-common 6.20.1 → 6.20.2

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.
@@ -4,8 +4,13 @@ import { EntityType } from "isaac-typescript-definitions";
4
4
  *
5
5
  * Custom stages/levels must first be defined in the "tsconfig.json" file. See the documentation for
6
6
  * more details: https://isaacscript.github.io/main/custom-stages/
7
+ *
8
+ * @param name The name of the custom stage, corresponding to what is in the "tsconfig.json" file.
9
+ * @param _firstFloor Whether to go to the first floor or the second floor. For example, if you have
10
+ * a custom stage emulating Caves, then the first floor would be Caves 1, and the
11
+ * second floor would be Caves 2.
7
12
  */
8
- export declare function setCustomStage(name: string, verbose?: boolean): void;
13
+ export declare function setCustomStage(name: string, _firstFloor?: boolean, verbose?: boolean): void;
9
14
  export declare function setCustomStageDebug(): void;
10
15
  /**
11
16
  * By default, unknown bosses will be drawn on the boss "versus" screen as "???". If your custom
@@ -1 +1 @@
1
- {"version":3,"file":"exports.d.ts","sourceRoot":"","sources":["../../../src/features/customStage/exports.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EAKX,MAAM,8BAA8B,CAAC;AAmBtC;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,UAAQ,GAAG,IAAI,CAyGlE;AAED,wBAAgB,mBAAmB,IAAI,IAAI,CAQ1C;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,UAAU,EACtB,OAAO,EAAE,GAAG,EACZ,OAAO,EAAE,GAAG,EACZ,WAAW,EAAE,MAAM,EACnB,eAAe,EAAE,MAAM,GACtB,IAAI,CAGN"}
1
+ {"version":3,"file":"exports.d.ts","sourceRoot":"","sources":["../../../src/features/customStage/exports.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EAKX,MAAM,8BAA8B,CAAC;AAsBtC;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,WAAW,UAAO,EAClB,OAAO,UAAQ,GACd,IAAI,CAyGN;AAED,wBAAgB,mBAAmB,IAAI,IAAI,CAQ1C;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,UAAU,EACtB,OAAO,EAAE,GAAG,EACZ,OAAO,EAAE,GAAG,EACZ,WAAW,EAAE,MAAM,EACnB,eAAe,EAAE,MAAM,GACtB,IAAI,CAGN"}
@@ -19,7 +19,7 @@ local ____rng = require("functions.rng")
19
19
  local newRNG = ____rng.newRNG
20
20
  local ____rooms = require("functions.rooms")
21
21
  local getRoomDataForTypeVariant = ____rooms.getRoomDataForTypeVariant
22
- local getRooms = ____rooms.getRooms
22
+ local getRoomsInGrid = ____rooms.getRoomsInGrid
23
23
  local ____stage = require("functions.stage")
24
24
  local setStage = ____stage.setStage
25
25
  local ____customStageUtils = require("features.customStage.customStageUtils")
@@ -37,13 +37,21 @@ local DEFAULT_BASE_STAGE_TYPE = StageType.ORIGINAL
37
37
  --
38
38
  -- Custom stages/levels must first be defined in the "tsconfig.json" file. See the documentation for
39
39
  -- more details: https://isaacscript.github.io/main/custom-stages/
40
- function ____exports.setCustomStage(self, name, verbose)
40
+ --
41
+ -- @param name The name of the custom stage, corresponding to what is in the "tsconfig.json" file.
42
+ -- @param _firstFloor Whether to go to the first floor or the second floor. For example, if you have
43
+ -- a custom stage emulating Caves, then the first floor would be Caves 1, and the
44
+ -- second floor would be Caves 2.
45
+ function ____exports.setCustomStage(self, name, _firstFloor, verbose)
46
+ if _firstFloor == nil then
47
+ _firstFloor = true
48
+ end
41
49
  if verbose == nil then
42
50
  verbose = false
43
51
  end
44
52
  local customStage = customStagesMap:get(name)
45
53
  if customStage == nil then
46
- error(("Failed to set the custom stage of \"" .. name) .. "\" because it was not found in the custom stages map. (Try restarting IsaacScript / recompiling the mod, and try again. If that does not work, you probably forgot to define it in your \"tsconfig.json\" file.) See the website for more details on how to set up custom stages.")
54
+ error(("Failed to set the custom stage of \"" .. name) .. "\" because it was not found in the custom stages map. (Try restarting IsaacScript / recompiling the mod / restarting the game, and try again. If that does not work, you probably forgot to define it in your \"tsconfig.json\" file.) See the website for more details on how to set up custom stages.")
47
55
  end
48
56
  local level = game:GetLevel()
49
57
  local startingRoomGridIndex = level:GetStartingRoomIndex()
@@ -54,7 +62,7 @@ function ____exports.setCustomStage(self, name, verbose)
54
62
  local baseStage = customStage.baseStage == nil and DEFAULT_BASE_STAGE or customStage.baseStage
55
63
  local baseStageType = customStage.baseStageType == nil and DEFAULT_BASE_STAGE_TYPE or customStage.baseStageType
56
64
  setStage(nil, baseStage, baseStageType)
57
- for ____, room in ipairs(getRooms(nil)) do
65
+ for ____, room in ipairs(getRoomsInGrid(nil)) do
58
66
  do
59
67
  if room.SafeGridIndex == startingRoomGridIndex then
60
68
  goto __continue4
@@ -1 +1 @@
1
- {"version":3,"file":"blackSprite.d.ts","sourceRoot":"","sources":["../../../src/features/customTrapdoor/blackSprite.ts"],"names":[],"mappings":"AAUA,wBAAgB,eAAe,IAAI,IAAI,CAWtC"}
1
+ {"version":3,"file":"blackSprite.d.ts","sourceRoot":"","sources":["../../../src/features/customTrapdoor/blackSprite.ts"],"names":[],"mappings":"AAUA,wBAAgB,eAAe,IAAI,IAAI,CAYtC"}
@@ -13,6 +13,7 @@ function ____exports.drawBlackSprite(self)
13
13
  if not blackSprite:IsLoaded() then
14
14
  blackSprite:Load("gfx/ui/boss/versusscreen.anm2", true)
15
15
  blackSprite:SetFrame("Scene", 0)
16
+ blackSprite.Scale = Vector(100, 100)
16
17
  end
17
18
  blackSprite:RenderLayer(0, VectorZero)
18
19
  end
@@ -229,7 +229,7 @@ end
229
229
  -- indexes for N room types.
230
230
  function ____exports.getRoomGridIndexesForType(self, ...)
231
231
  local roomTypesSet = __TS__New(Set, {...})
232
- local rooms = getRooms(nil)
232
+ local rooms = getRoomsInGrid(nil)
233
233
  local matchingRooms = __TS__ArrayFilter(
234
234
  rooms,
235
235
  function(____, roomDescriptor) return roomDescriptor.Data ~= nil and roomTypesSet:has(roomDescriptor.Data.Type) end
@@ -20,7 +20,7 @@ export declare function getRoomDescriptor(roomGridIndex?: int): RoomDescriptor;
20
20
  * Alias for the `Level.GetCurrentRoomDesc` method. Use this to make it more clear what type of
21
21
  * `RoomDescriptor` object that you are retrieving.
22
22
  */
23
- export declare function getRoomDescriptorReadOnly(): ReadonlyRoomDescriptor;
23
+ export declare function getRoomDescriptorReadOnly(): Readonly<RoomDescriptor>;
24
24
  /**
25
25
  * Helper function to get the grid index of the current room.
26
26
  *
@@ -1 +1 @@
1
- {"version":3,"file":"roomData.d.ts","sourceRoot":"","sources":["../../src/functions/roomData.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,EAER,SAAS,EACT,QAAQ,EACR,OAAO,EACR,MAAM,8BAA8B,CAAC;AAMtC;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,aAAa,CAAC,EAAE,GAAG,GAAG,GAAG,CAAC,QAAQ,CAAC,CAiBtE;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,aAAa,CAAC,EAAE,GAAG,GAAG,UAAU,GAAG,SAAS,CAGvE;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,aAAa,CAAC,EAAE,GAAG,GAAG,cAAc,CAQrE;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,IAAI,sBAAsB,CAGlE;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,gBAAgB,IAAI,GAAG,CAatC;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,aAAa,CAAC,EAAE,GAAG,GAAG,GAAG,CAGzD;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,aAAa,CAAC,EAAE,GAAG,GAAG,MAAM,CAGvD;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,aAAa,CAAC,EAAE,GAAG,GAAG,SAAS,GAAG,SAAS,CAGvE;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,aAAa,CAAC,EAAE,GAAG,GAAG,OAAO,CAG3D;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,aAAa,CAAC,EAAE,GAAG,GAAG,GAAG,CAGvD;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,aAAa,CAAC,EAAE,GAAG,GAAG,QAAQ,CAGzD;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,aAAa,CAAC,EAAE,GAAG,GAAG,GAAG,CAGvD;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,aAAa,CAAC,EAAE,GAAG,GAAG,GAAG,CAG5D;AAED;;;GAGG;AACH,wBAAgB,WAAW,CACzB,aAAa,EAAE,GAAG,EAClB,QAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,GAC7B,IAAI,CAGN"}
1
+ {"version":3,"file":"roomData.d.ts","sourceRoot":"","sources":["../../src/functions/roomData.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,EAER,SAAS,EACT,QAAQ,EACR,OAAO,EACR,MAAM,8BAA8B,CAAC;AAMtC;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,aAAa,CAAC,EAAE,GAAG,GAAG,GAAG,CAAC,QAAQ,CAAC,CAiBtE;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,aAAa,CAAC,EAAE,GAAG,GAAG,UAAU,GAAG,SAAS,CAGvE;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,aAAa,CAAC,EAAE,GAAG,GAAG,cAAc,CAQrE;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,IAAI,QAAQ,CAAC,cAAc,CAAC,CAGpE;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,gBAAgB,IAAI,GAAG,CAatC;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,aAAa,CAAC,EAAE,GAAG,GAAG,GAAG,CAGzD;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,aAAa,CAAC,EAAE,GAAG,GAAG,MAAM,CAGvD;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,aAAa,CAAC,EAAE,GAAG,GAAG,SAAS,GAAG,SAAS,CAGvE;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,aAAa,CAAC,EAAE,GAAG,GAAG,OAAO,CAG3D;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,aAAa,CAAC,EAAE,GAAG,GAAG,GAAG,CAGvD;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,aAAa,CAAC,EAAE,GAAG,GAAG,QAAQ,CAGzD;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,aAAa,CAAC,EAAE,GAAG,GAAG,GAAG,CAGvD;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,aAAa,CAAC,EAAE,GAAG,GAAG,GAAG,CAG5D;AAED;;;GAGG;AACH,wBAAgB,WAAW,CACzB,aAAa,EAAE,GAAG,EAClB,QAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,GAC7B,IAAI,CAGN"}
@@ -1,4 +1,4 @@
1
- import { BossID, Dimension, Direction, ItemPoolType, MinibossID, RoomTransitionAnim, RoomType } from "isaac-typescript-definitions";
1
+ import { BackdropType, BossID, Dimension, Direction, ItemPoolType, MinibossID, RoomTransitionAnim, RoomType } from "isaac-typescript-definitions";
2
2
  /**
3
3
  * Helper function for quickly switching to a new room without playing a particular animation. Use
4
4
  * this helper function over invoking the `Game.ChangeRoom` method directly to ensure that you do
@@ -10,6 +10,18 @@ export declare function changeRoom(roomGridIndex: int): void;
10
10
  * include off-grid rooms, like the Devil Room.
11
11
  */
12
12
  export declare function getNumRooms(): int;
13
+ /**
14
+ * Helper function to get a read-only copy of the room descriptor for every room on the level. This
15
+ * includes off-grid rooms, such as the Devil Room, and extra-dimensional rooms, if they are
16
+ * generated and exist.
17
+ *
18
+ * Room descriptors without any data are assumed to be non-existent and are not included.
19
+ *
20
+ * Under the hood, this is performed by iterating over the `RoomList` from the `Level.GetRooms`
21
+ * method. This is the best way to see if off-grid rooms have been initialized, since it is possible
22
+ * for mods to insert room data at non-official negative room grid indexes.
23
+ */
24
+ export declare function getReadOnlyRooms(): Array<Readonly<RoomDescriptor>>;
13
25
  /**
14
26
  * Helper function to get the room data for a specific room type and variant combination. This is
15
27
  * accomplished by using the "goto" console command to load the specified room into the
@@ -45,39 +57,43 @@ export declare function getRoomItemPoolType(): ItemPoolType;
45
57
  export declare function getRoomTypeName(roomType: RoomType): string;
46
58
  /**
47
59
  * Helper function to get the room descriptor for every room on the level. This includes off-grid
48
- * rooms, such as the Devil Room. (Off-grid rooms will only be included if they the data exists,
49
- * which only usually happens once they have been visited at least once.)
60
+ * rooms, such as the Devil Room.
61
+ *
62
+ * Room descriptors without any data are assumed to be non-existent and are not included.
50
63
  *
51
- * Under the hood, this function uses the `Level.GetRooms` method to accomplish this. Rooms without
52
- * data are assumed to be non-existent and are not added to the list.
64
+ * - If you want just the rooms inside of the grid, use the `getRoomsInGrid` helper function.
65
+ * - If you want just the rooms outside of the grid, use the `getRoomsOutsideGrid` helper function.
53
66
  *
54
67
  * @param includeExtraDimensionalRooms Optional. On some floors (e.g. Downpour 2, Mines 2),
55
- * extra-dimensional rooms are automatically generated and can be
56
- * seen when you iterate over the `RoomList`. Default is false.
68
+ * extra-dimensional rooms are automatically generated. Default is
69
+ * false.
57
70
  */
58
71
  export declare function getRooms(includeExtraDimensionalRooms?: boolean): RoomDescriptor[];
59
72
  /**
60
- * Helper function to get the room descriptor for every room on the level except for rooms that are
61
- * not on the grid.
73
+ * Helper function to get the room descriptor for every room on the level that is on the grid. (For
74
+ * example, Devil Rooms are excluded.)
62
75
  *
63
- * Under the hood, this function uses the `Level.GetRooms` method to accomplish this. Rooms without
64
- * data are assumed to be non-existent and are not added to the list.
76
+ * Room descriptors without any data are assumed to be non-existent and are not included.
65
77
  *
66
78
  * @param includeExtraDimensionalRooms Optional. On some floors (e.g. Downpour 2, Mines 2),
67
- * extra-dimensional rooms are automatically be generated and can be
68
- * seen when you iterate over the `RoomList`. Default is false.
79
+ * extra-dimensional rooms are automatically be generated. Default
80
+ * is false.
69
81
  */
70
82
  export declare function getRoomsInGrid(includeExtraDimensionalRooms?: boolean): RoomDescriptor[];
71
83
  /**
72
84
  * Helper function to get the room descriptor for every room on the level in a specific dimension.
73
85
  * This will not include any off-grid rooms, such as the Devil Room.
74
86
  *
75
- * Under the hood, this function uses the `Level.GetRooms` method to accomplish this. Rooms without
76
- * data are assumed to be non-existent and are not added to the list.
77
- *
78
- * @returns A map of room ListIndex to RoomDescriptor.
87
+ * Room descriptors without any data are assumed to be non-existent and are not included.
79
88
  */
80
89
  export declare function getRoomsOfDimension(dimension: Dimension): RoomDescriptor[];
90
+ /**
91
+ * Helper function to get the room descriptor for every room on the level that is outside of the
92
+ * grid (like a Devil Room).
93
+ *
94
+ * Room descriptors without any data are assumed to be non-existent and are not included.
95
+ */
96
+ export declare function getRoomsOutsideGrid(): RoomDescriptor[];
81
97
  /**
82
98
  * Helper function to determine if the current room shape is equal to `RoomShape.1x2` or
83
99
  * `RoomShape.2x1`.
@@ -139,7 +155,7 @@ export declare function inStartingRoom(): boolean;
139
155
  /**
140
156
  * Helper function to loop through every room on the floor and see if it has been cleared.
141
157
  *
142
- * This function will only check rooms in the current dimension.
158
+ * This function will only check rooms inside the gird and inside the current dimension.
143
159
  *
144
160
  * @param onlyCheckRoomTypes Optional. A whitelist of room types. If specified, room types not in
145
161
  * the array will be ignored. If not specified, then all rooms will be
@@ -153,6 +169,8 @@ export declare function isAllRoomsClear(onlyCheckRoomTypes?: RoomType[]): boolea
153
169
  * positions/velocities before updating the room, and then restore those positions/velocities.
154
170
  */
155
171
  export declare function roomUpdateSafe(): void;
172
+ /** Helper function to set the backdrop of the current room. */
173
+ export declare function setBackdrop(backdropType: BackdropType): void;
156
174
  /**
157
175
  * Helper function to convert an uncleared room to a cleared room in the `POST_NEW_ROOM` callback.
158
176
  * This is useful because if enemies are removed in this callback, a room drop will be awarded and
@@ -1 +1 @@
1
- {"version":3,"file":"rooms.d.ts","sourceRoot":"","sources":["../../src/functions/rooms.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,MAAM,EACN,SAAS,EACT,SAAS,EAKT,YAAY,EAEZ,UAAU,EAGV,kBAAkB,EAClB,QAAQ,EAGT,MAAM,8BAA8B,CAAC;AAgCtC;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,aAAa,EAAE,GAAG,GAAG,IAAI,CAenD;AAED;;;GAGG;AACH,wBAAgB,WAAW,IAAI,GAAG,CAGjC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,QAAQ,EAClB,WAAW,EAAE,GAAG,EAChB,oBAAoB,UAAO,GAC1B,QAAQ,CAAC,UAAU,CAAC,GAAG,SAAS,CAgBlC;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,IAAI,YAAY,CAOlD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAE1D;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,QAAQ,CACtB,4BAA4B,UAAQ,GACnC,cAAc,EAAE,CAwBlB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAC5B,4BAA4B,UAAQ,GACnC,cAAc,EAAE,CAGlB;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,SAAS,GAAG,cAAc,EAAE,CAc1E;AAED;;;GAGG;AACH,wBAAgB,SAAS,IAAI,OAAO,CAKnC;AAED,wBAAgB,WAAW,IAAI,OAAO,CAOrC;AAED,wBAAgB,WAAW,IAAI,OAAO,CASrC;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAWpD;AAED;;;;GAIG;AACH,wBAAgB,YAAY,IAAI,OAAO,CAOtC;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,OAAO,CAWhD;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,IAAI,OAAO,CAGnD;AAED,wBAAgB,eAAe,IAAI,OAAO,CAMzC;AAED,wBAAgB,aAAa,IAAI,OAAO,CAKvC;AAED,+FAA+F;AAC/F,wBAAgB,OAAO,IAAI,OAAO,CAUjC;AAED,wBAAgB,eAAe,IAAI,OAAO,CAKzC;AAED;;;GAGG;AACH,wBAAgB,WAAW,IAAI,OAAO,CASrC;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAWhE;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,IAAI,OAAO,CAKtC;AAED;;;;GAIG;AACH,wBAAgB,cAAc,IAAI,OAAO,CAMxC;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,kBAAkB,CAAC,EAAE,QAAQ,EAAE,GAAG,OAAO,CAcxE;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,IAAI,IAAI,CAWrC;AAED;;;;GAIG;AACH,wBAAgB,cAAc,IAAI,IAAI,CA8BrC;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CAKvC;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,QAAQ,CACtB,aAAa,EAAE,GAAG,EAClB,SAAS,YAAyB,EAClC,kBAAkB,qBAA8B,EAChD,KAAK,UAAQ,GACZ,IAAI,CA0BN"}
1
+ {"version":3,"file":"rooms.d.ts","sourceRoot":"","sources":["../../src/functions/rooms.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,YAAY,EACZ,MAAM,EACN,SAAS,EACT,SAAS,EAKT,YAAY,EAEZ,UAAU,EAGV,kBAAkB,EAClB,QAAQ,EAGT,MAAM,8BAA8B,CAAC;AAiCtC;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,aAAa,EAAE,GAAG,GAAG,IAAI,CAenD;AAED;;;GAGG;AACH,wBAAgB,WAAW,IAAI,GAAG,CAGjC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,IAAI,KAAK,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,CAiBlE;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,QAAQ,EAClB,WAAW,EAAE,GAAG,EAChB,oBAAoB,UAAO,GAC1B,QAAQ,CAAC,UAAU,CAAC,GAAG,SAAS,CAgBlC;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,IAAI,YAAY,CAOlD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAE1D;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,QAAQ,CACtB,4BAA4B,UAAQ,GACnC,cAAc,EAAE,CAOlB;AAED;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAC5B,4BAA4B,UAAQ,GACnC,cAAc,EAAE,CAqBlB;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,SAAS,GAAG,cAAc,EAAE,CAe1E;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,IAAI,cAAc,EAAE,CAWtD;AAED;;;GAGG;AACH,wBAAgB,SAAS,IAAI,OAAO,CAKnC;AAED,wBAAgB,WAAW,IAAI,OAAO,CAOrC;AAED,wBAAgB,WAAW,IAAI,OAAO,CASrC;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAWpD;AAED;;;;GAIG;AACH,wBAAgB,YAAY,IAAI,OAAO,CAOtC;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,OAAO,CAWhD;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,IAAI,OAAO,CAGnD;AAED,wBAAgB,eAAe,IAAI,OAAO,CAMzC;AAED,wBAAgB,aAAa,IAAI,OAAO,CAKvC;AAED,+FAA+F;AAC/F,wBAAgB,OAAO,IAAI,OAAO,CAUjC;AAED,wBAAgB,eAAe,IAAI,OAAO,CAKzC;AAED;;;GAGG;AACH,wBAAgB,WAAW,IAAI,OAAO,CASrC;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAWhE;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,IAAI,OAAO,CAKtC;AAED;;;;GAIG;AACH,wBAAgB,cAAc,IAAI,OAAO,CAMxC;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,kBAAkB,CAAC,EAAE,QAAQ,EAAE,GAAG,OAAO,CAcxE;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,IAAI,IAAI,CAWrC;AAED,+DAA+D;AAC/D,wBAAgB,WAAW,CAAC,YAAY,EAAE,YAAY,GAAG,IAAI,CAE5D;AAED;;;;GAIG;AACH,wBAAgB,cAAc,IAAI,IAAI,CA8BrC;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CAKvC;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,QAAQ,CACtB,aAAa,EAAE,GAAG,EAClB,SAAS,YAAyB,EAClC,kBAAkB,qBAA8B,EAChD,KAAK,UAAQ,GACZ,IAAI,CA0BN"}
@@ -1,8 +1,12 @@
1
1
  local ____lualib = require("lualib_bundle")
2
+ local __TS__SparseArrayNew = ____lualib.__TS__SparseArrayNew
3
+ local __TS__SparseArrayPush = ____lualib.__TS__SparseArrayPush
4
+ local __TS__SparseArraySpread = ____lualib.__TS__SparseArraySpread
2
5
  local Map = ____lualib.Map
3
6
  local __TS__New = ____lualib.__TS__New
4
7
  local __TS__Spread = ____lualib.__TS__Spread
5
8
  local __TS__ArrayFilter = ____lualib.__TS__ArrayFilter
9
+ local __TS__ArrayMap = ____lualib.__TS__ArrayMap
6
10
  local __TS__StringIncludes = ____lualib.__TS__StringIncludes
7
11
  local Set = ____lualib.Set
8
12
  local __TS__ArrayEvery = ____lualib.__TS__ArrayEvery
@@ -27,6 +31,7 @@ local game = ____cachedClasses.game
27
31
  local sfxManager = ____cachedClasses.sfxManager
28
32
  local ____constants = require("constants")
29
33
  local MAX_LEVEL_GRID_INDEX = ____constants.MAX_LEVEL_GRID_INDEX
34
+ local NUM_DIMENSIONS = ____constants.NUM_DIMENSIONS
30
35
  local ____roomTypeNames = require("objects.roomTypeNames")
31
36
  local ROOM_TYPE_NAMES = ____roomTypeNames.ROOM_TYPE_NAMES
32
37
  local ____mineShaftRoomSubTypesSet = require("sets.mineShaftRoomSubTypesSet")
@@ -51,6 +56,7 @@ local setEntityPositions = ____positionVelocity.setEntityPositions
51
56
  local setEntityVelocities = ____positionVelocity.setEntityVelocities
52
57
  local ____roomData = require("functions.roomData")
53
58
  local getRoomData = ____roomData.getRoomData
59
+ local getRoomDescriptor = ____roomData.getRoomDescriptor
54
60
  local getRoomDescriptorReadOnly = ____roomData.getRoomDescriptorReadOnly
55
61
  local getRoomGridIndex = ____roomData.getRoomGridIndex
56
62
  local getRoomName = ____roomData.getRoomName
@@ -59,61 +65,73 @@ local getRoomSubType = ____roomData.getRoomSubType
59
65
  local ____stage = require("functions.stage")
60
66
  local getGotoCommand = ____stage.getGotoCommand
61
67
  local ____utils = require("functions.utils")
68
+ local erange = ____utils.erange
62
69
  local irange = ____utils.irange
63
- --- Helper function to get the room descriptor for every room on the level. This includes off-grid
64
- -- rooms, such as the Devil Room. (Off-grid rooms will only be included if they the data exists,
65
- -- which only usually happens once they have been visited at least once.)
70
+ --- Helper function to get a read-only copy of the room descriptor for every room on the level. This
71
+ -- includes off-grid rooms, such as the Devil Room, and extra-dimensional rooms, if they are
72
+ -- generated and exist.
66
73
  --
67
- -- Under the hood, this function uses the `Level.GetRooms` method to accomplish this. Rooms without
68
- -- data are assumed to be non-existent and are not added to the list.
74
+ -- Room descriptors without any data are assumed to be non-existent and are not included.
69
75
  --
70
- -- @param includeExtraDimensionalRooms Optional. On some floors (e.g. Downpour 2, Mines 2),
71
- -- extra-dimensional rooms are automatically generated and can be
72
- -- seen when you iterate over the `RoomList`. Default is false.
73
- function ____exports.getRooms(self, includeExtraDimensionalRooms)
74
- if includeExtraDimensionalRooms == nil then
75
- includeExtraDimensionalRooms = false
76
- end
76
+ -- Under the hood, this is performed by iterating over the `RoomList` from the `Level.GetRooms`
77
+ -- method. This is the best way to see if off-grid rooms have been initialized, since it is possible
78
+ -- for mods to insert room data at non-official negative room grid indexes.
79
+ function ____exports.getReadOnlyRooms(self)
77
80
  local level = game:GetLevel()
78
81
  local roomList = level:GetRooms()
79
- --- Indexed by room safe grid index. We use a map to avoid adding extra dimensional rooms.
80
- local roomsMap = __TS__New(Map)
82
+ local readOnlyRoomDescriptors = {}
81
83
  do
82
84
  local i = 0
83
85
  while i < roomList.Size do
84
- do
85
- local roomDescriptor = roomList:Get(i)
86
- if roomDescriptor == nil or roomDescriptor.Data == nil then
87
- goto __continue10
88
- end
89
- if not includeExtraDimensionalRooms and roomsMap:has(roomDescriptor.SafeGridIndex) then
90
- goto __continue10
91
- end
92
- roomsMap:set(roomDescriptor.SafeGridIndex, roomDescriptor)
86
+ local readOnlyRoomDescriptor = roomList:Get(i)
87
+ if readOnlyRoomDescriptor ~= nil and readOnlyRoomDescriptor.Data ~= nil then
88
+ readOnlyRoomDescriptors[#readOnlyRoomDescriptors + 1] = readOnlyRoomDescriptor
93
89
  end
94
- ::__continue10::
95
90
  i = i + 1
96
91
  end
97
92
  end
98
- return {__TS__Spread(roomsMap:values())}
93
+ return readOnlyRoomDescriptors
99
94
  end
100
- --- Helper function to get the room descriptor for every room on the level except for rooms that are
101
- -- not on the grid.
95
+ --- Helper function to get the room descriptor for every room on the level that is on the grid. (For
96
+ -- example, Devil Rooms are excluded.)
102
97
  --
103
- -- Under the hood, this function uses the `Level.GetRooms` method to accomplish this. Rooms without
104
- -- data are assumed to be non-existent and are not added to the list.
98
+ -- Room descriptors without any data are assumed to be non-existent and are not included.
105
99
  --
106
100
  -- @param includeExtraDimensionalRooms Optional. On some floors (e.g. Downpour 2, Mines 2),
107
- -- extra-dimensional rooms are automatically be generated and can be
108
- -- seen when you iterate over the `RoomList`. Default is false.
101
+ -- extra-dimensional rooms are automatically be generated. Default
102
+ -- is false.
109
103
  function ____exports.getRoomsInGrid(self, includeExtraDimensionalRooms)
110
104
  if includeExtraDimensionalRooms == nil then
111
105
  includeExtraDimensionalRooms = false
112
106
  end
113
- local rooms = ____exports.getRooms(nil, includeExtraDimensionalRooms)
114
- return __TS__ArrayFilter(
115
- rooms,
116
- function(____, roomDescriptor) return roomDescriptor.SafeGridIndex >= 0 end
107
+ local level = game:GetLevel()
108
+ local dimensions = includeExtraDimensionalRooms and erange(nil, NUM_DIMENSIONS) or ({Dimension.CURRENT})
109
+ --- We use a map instead of an array because room shapes occupy more than one room grid index.
110
+ local roomDescriptorMap = __TS__New(Map)
111
+ for ____, dimension in ipairs(dimensions) do
112
+ for ____, roomGridIndex in ipairs(irange(nil, MAX_LEVEL_GRID_INDEX)) do
113
+ local roomDescriptor = level:GetRoomByIdx(roomGridIndex, dimension)
114
+ if roomDescriptor.Data ~= nil then
115
+ local ptrHash = GetPtrHash(roomDescriptor)
116
+ roomDescriptorMap:set(ptrHash, roomDescriptor)
117
+ end
118
+ end
119
+ end
120
+ return {__TS__Spread(roomDescriptorMap:values())}
121
+ end
122
+ --- Helper function to get the room descriptor for every room on the level that is outside of the
123
+ -- grid (like a Devil Room).
124
+ --
125
+ -- Room descriptors without any data are assumed to be non-existent and are not included.
126
+ function ____exports.getRoomsOutsideGrid(self)
127
+ local readOnlyRooms = ____exports.getReadOnlyRooms(nil)
128
+ local readOnlyRoomsOffGrid = __TS__ArrayFilter(
129
+ readOnlyRooms,
130
+ function(____, readOnlyRoomDescriptor) return readOnlyRoomDescriptor.SafeGridIndex < 0 end
131
+ )
132
+ return __TS__ArrayMap(
133
+ readOnlyRoomsOffGrid,
134
+ function(____, readOnlyRoomDescriptor) return getRoomDescriptor(nil, readOnlyRoomDescriptor.SafeGridIndex) end
117
135
  )
118
136
  end
119
137
  --- Helper function to change the current room. It can be used for both teleportation and "normal"
@@ -226,13 +244,34 @@ end
226
244
  function ____exports.getRoomTypeName(self, roomType)
227
245
  return ROOM_TYPE_NAMES[roomType]
228
246
  end
247
+ --- Helper function to get the room descriptor for every room on the level. This includes off-grid
248
+ -- rooms, such as the Devil Room.
249
+ --
250
+ -- Room descriptors without any data are assumed to be non-existent and are not included.
251
+ --
252
+ -- - If you want just the rooms inside of the grid, use the `getRoomsInGrid` helper function.
253
+ -- - If you want just the rooms outside of the grid, use the `getRoomsOutsideGrid` helper function.
254
+ --
255
+ -- @param includeExtraDimensionalRooms Optional. On some floors (e.g. Downpour 2, Mines 2),
256
+ -- extra-dimensional rooms are automatically generated. Default is
257
+ -- false.
258
+ function ____exports.getRooms(self, includeExtraDimensionalRooms)
259
+ if includeExtraDimensionalRooms == nil then
260
+ includeExtraDimensionalRooms = false
261
+ end
262
+ local roomsInGrid = ____exports.getRoomsInGrid(nil, includeExtraDimensionalRooms)
263
+ local roomsOutsideGrid = ____exports.getRoomsOutsideGrid(nil)
264
+ local ____array_0 = __TS__SparseArrayNew(table.unpack(roomsInGrid))
265
+ __TS__SparseArrayPush(
266
+ ____array_0,
267
+ table.unpack(roomsOutsideGrid)
268
+ )
269
+ return {__TS__SparseArraySpread(____array_0)}
270
+ end
229
271
  --- Helper function to get the room descriptor for every room on the level in a specific dimension.
230
272
  -- This will not include any off-grid rooms, such as the Devil Room.
231
273
  --
232
- -- Under the hood, this function uses the `Level.GetRooms` method to accomplish this. Rooms without
233
- -- data are assumed to be non-existent and are not added to the list.
234
- --
235
- -- @returns A map of room ListIndex to RoomDescriptor.
274
+ -- Room descriptors without any data are assumed to be non-existent and are not included.
236
275
  function ____exports.getRoomsOfDimension(self, dimension)
237
276
  local level = game:GetLevel()
238
277
  --- We use a map instead of an array because room shapes occupy more than one room grid index.
@@ -240,7 +279,8 @@ function ____exports.getRoomsOfDimension(self, dimension)
240
279
  for ____, roomGridIndex in ipairs(irange(nil, MAX_LEVEL_GRID_INDEX)) do
241
280
  local roomDescriptor = level:GetRoomByIdx(roomGridIndex, dimension)
242
281
  if roomDescriptor.Data ~= nil then
243
- roomsMap:set(roomDescriptor.ListIndex, roomDescriptor)
282
+ local ptrHash = GetPtrHash(roomDescriptor)
283
+ roomsMap:set(ptrHash, roomDescriptor)
244
284
  end
245
285
  end
246
286
  return {__TS__Spread(roomsMap:values())}
@@ -352,20 +392,20 @@ function ____exports.inStartingRoom(self)
352
392
  end
353
393
  --- Helper function to loop through every room on the floor and see if it has been cleared.
354
394
  --
355
- -- This function will only check rooms in the current dimension.
395
+ -- This function will only check rooms inside the gird and inside the current dimension.
356
396
  --
357
397
  -- @param onlyCheckRoomTypes Optional. A whitelist of room types. If specified, room types not in
358
398
  -- the array will be ignored. If not specified, then all rooms will be
359
399
  -- checked. Undefined by default.
360
400
  function ____exports.isAllRoomsClear(self, onlyCheckRoomTypes)
361
- local ____temp_0
401
+ local ____temp_1
362
402
  if onlyCheckRoomTypes == nil then
363
- ____temp_0 = nil
403
+ ____temp_1 = nil
364
404
  else
365
- ____temp_0 = __TS__New(Set, onlyCheckRoomTypes)
405
+ ____temp_1 = __TS__New(Set, onlyCheckRoomTypes)
366
406
  end
367
- local roomTypeWhitelist = ____temp_0
368
- local rooms = ____exports.getRooms(nil)
407
+ local roomTypeWhitelist = ____temp_1
408
+ local rooms = ____exports.getRoomsInGrid(nil)
369
409
  local matchingRooms = roomTypeWhitelist == nil and rooms or __TS__ArrayFilter(
370
410
  rooms,
371
411
  function(____, roomDescriptor) return roomDescriptor.Data ~= nil and roomTypeWhitelist:has(roomDescriptor.Data.Type) end
@@ -388,6 +428,10 @@ function ____exports.roomUpdateSafe(self)
388
428
  setEntityPositions(nil, entityPositions, entities)
389
429
  setEntityVelocities(nil, entityVelocities, entities)
390
430
  end
431
+ --- Helper function to set the backdrop of the current room.
432
+ function ____exports.setBackdrop(self, backdropType)
433
+ game:ShowHallucination(0, backdropType)
434
+ end
391
435
  --- Helper function to convert an uncleared room to a cleared room in the `POST_NEW_ROOM` callback.
392
436
  -- This is useful because if enemies are removed in this callback, a room drop will be awarded and
393
437
  -- the doors will start closed and then open.
@@ -401,12 +445,12 @@ function ____exports.setRoomCleared(self)
401
445
  for ____, door in ipairs(getDoors(nil)) do
402
446
  do
403
447
  if isHiddenSecretRoomDoor(nil, door) then
404
- goto __continue40
448
+ goto __continue48
405
449
  end
406
450
  openDoorFast(nil, door)
407
451
  door.ExtraVisible = false
408
452
  end
409
- ::__continue40::
453
+ ::__continue48::
410
454
  end
411
455
  sfxManager:Stop(SoundEffect.DOOR_HEAVY_OPEN)
412
456
  game:ShakeScreen(0)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "isaacscript-common",
3
- "version": "6.20.1",
3
+ "version": "6.20.2",
4
4
  "description": "Helper functions and features for IsaacScript mods.",
5
5
  "keywords": [
6
6
  "isaac",
@@ -22,6 +22,6 @@
22
22
  "main": "dist/index",
23
23
  "types": "dist/index.d.ts",
24
24
  "dependencies": {
25
- "isaac-typescript-definitions": "^3.1.1"
25
+ "isaac-typescript-definitions": "^3.1.3"
26
26
  }
27
27
  }
@@ -10,7 +10,10 @@ import { reorderedCallbacksSetStage } from "../../callbacks/reorderedCallbacks";
10
10
  import { getEntityIDFromConstituents } from "../../functions/entities";
11
11
  import { log, logError } from "../../functions/log";
12
12
  import { newRNG } from "../../functions/rng";
13
- import { getRoomDataForTypeVariant, getRooms } from "../../functions/rooms";
13
+ import {
14
+ getRoomDataForTypeVariant,
15
+ getRoomsInGrid,
16
+ } from "../../functions/rooms";
14
17
  import { setStage } from "../../functions/stage";
15
18
  import { getRandomCustomStageRoom } from "./customStageUtils";
16
19
  import { topStreakTextStart } from "./streakText";
@@ -28,12 +31,21 @@ const DEFAULT_BASE_STAGE_TYPE = StageType.ORIGINAL;
28
31
  *
29
32
  * Custom stages/levels must first be defined in the "tsconfig.json" file. See the documentation for
30
33
  * more details: https://isaacscript.github.io/main/custom-stages/
34
+ *
35
+ * @param name The name of the custom stage, corresponding to what is in the "tsconfig.json" file.
36
+ * @param _firstFloor Whether to go to the first floor or the second floor. For example, if you have
37
+ * a custom stage emulating Caves, then the first floor would be Caves 1, and the
38
+ * second floor would be Caves 2.
31
39
  */
32
- export function setCustomStage(name: string, verbose = false): void {
40
+ export function setCustomStage(
41
+ name: string,
42
+ _firstFloor = true,
43
+ verbose = false,
44
+ ): void {
33
45
  const customStage = customStagesMap.get(name);
34
46
  if (customStage === undefined) {
35
47
  error(
36
- `Failed to set the custom stage of "${name}" because it was not found in the custom stages map. (Try restarting IsaacScript / recompiling the mod, and try again. If that does not work, you probably forgot to define it in your "tsconfig.json" file.) See the website for more details on how to set up custom stages.`,
48
+ `Failed to set the custom stage of "${name}" because it was not found in the custom stages map. (Try restarting IsaacScript / recompiling the mod / restarting the game, and try again. If that does not work, you probably forgot to define it in your "tsconfig.json" file.) See the website for more details on how to set up custom stages.`,
37
49
  );
38
50
  }
39
51
 
@@ -56,7 +68,7 @@ export function setCustomStage(name: string, verbose = false): void {
56
68
  setStage(baseStage, baseStageType);
57
69
 
58
70
  // Now, we need to pick a custom room for each vanilla room.
59
- for (const room of getRooms()) {
71
+ for (const room of getRoomsInGrid()) {
60
72
  // The starting floor of each room should stay empty.
61
73
  if (room.SafeGridIndex === startingRoomGridIndex) {
62
74
  continue;
@@ -16,6 +16,7 @@ export function drawBlackSprite(): void {
16
16
  if (!blackSprite.IsLoaded()) {
17
17
  blackSprite.Load("gfx/ui/boss/versusscreen.anm2", true);
18
18
  blackSprite.SetFrame("Scene", 0);
19
+ blackSprite.Scale = Vector(100, 100);
19
20
  }
20
21
 
21
22
  blackSprite.RenderLayer(0, VectorZero);
@@ -207,7 +207,7 @@ export function getNewRoomCandidatesForLevel(): Array<
207
207
  export function getRoomGridIndexesForType(...roomTypes: RoomType[]): int[] {
208
208
  const roomTypesSet = new Set<RoomType>([...roomTypes]);
209
209
 
210
- const rooms = getRooms();
210
+ const rooms = getRoomsInGrid();
211
211
  const matchingRooms = rooms.filter(
212
212
  (roomDescriptor) =>
213
213
  roomDescriptor.Data !== undefined &&
@@ -62,7 +62,7 @@ export function getRoomDescriptor(roomGridIndex?: int): RoomDescriptor {
62
62
  * Alias for the `Level.GetCurrentRoomDesc` method. Use this to make it more clear what type of
63
63
  * `RoomDescriptor` object that you are retrieving.
64
64
  */
65
- export function getRoomDescriptorReadOnly(): ReadonlyRoomDescriptor {
65
+ export function getRoomDescriptorReadOnly(): Readonly<RoomDescriptor> {
66
66
  const level = game.GetLevel();
67
67
  return level.GetCurrentRoomDesc();
68
68
  }
@@ -1,5 +1,6 @@
1
1
  import {
2
2
  AngelRoomSubType,
3
+ BackdropType,
3
4
  BossID,
4
5
  Dimension,
5
6
  Direction,
@@ -18,7 +19,7 @@ import {
18
19
  StageID,
19
20
  } from "isaac-typescript-definitions";
20
21
  import { game, sfxManager } from "../cachedClasses";
21
- import { MAX_LEVEL_GRID_INDEX } from "../constants";
22
+ import { MAX_LEVEL_GRID_INDEX, NUM_DIMENSIONS } from "../constants";
22
23
  import { ROOM_TYPE_NAMES } from "../objects/roomTypeNames";
23
24
  import { MINE_SHAFT_ROOM_SUB_TYPE_SET } from "../sets/mineShaftRoomSubTypesSet";
24
25
  import { hasCurse } from "./curses";
@@ -39,6 +40,7 @@ import {
39
40
  } from "./positionVelocity";
40
41
  import {
41
42
  getRoomData,
43
+ getRoomDescriptor,
42
44
  getRoomDescriptorReadOnly,
43
45
  getRoomGridIndex,
44
46
  getRoomName,
@@ -46,7 +48,7 @@ import {
46
48
  getRoomSubType,
47
49
  } from "./roomData";
48
50
  import { getGotoCommand } from "./stage";
49
- import { irange } from "./utils";
51
+ import { erange, irange } from "./utils";
50
52
 
51
53
  /**
52
54
  * Helper function for quickly switching to a new room without playing a particular animation. Use
@@ -79,6 +81,36 @@ export function getNumRooms(): int {
79
81
  return rooms.length;
80
82
  }
81
83
 
84
+ /**
85
+ * Helper function to get a read-only copy of the room descriptor for every room on the level. This
86
+ * includes off-grid rooms, such as the Devil Room, and extra-dimensional rooms, if they are
87
+ * generated and exist.
88
+ *
89
+ * Room descriptors without any data are assumed to be non-existent and are not included.
90
+ *
91
+ * Under the hood, this is performed by iterating over the `RoomList` from the `Level.GetRooms`
92
+ * method. This is the best way to see if off-grid rooms have been initialized, since it is possible
93
+ * for mods to insert room data at non-official negative room grid indexes.
94
+ */
95
+ export function getReadOnlyRooms(): Array<Readonly<RoomDescriptor>> {
96
+ const level = game.GetLevel();
97
+ const roomList = level.GetRooms();
98
+
99
+ const readOnlyRoomDescriptors: Array<Readonly<RoomDescriptor>> = [];
100
+
101
+ for (let i = 0; i < roomList.Size; i++) {
102
+ const readOnlyRoomDescriptor = roomList.Get(i);
103
+ if (
104
+ readOnlyRoomDescriptor !== undefined &&
105
+ readOnlyRoomDescriptor.Data !== undefined
106
+ ) {
107
+ readOnlyRoomDescriptors.push(readOnlyRoomDescriptor);
108
+ }
109
+ }
110
+
111
+ return readOnlyRoomDescriptors;
112
+ }
113
+
82
114
  /**
83
115
  * Helper function to get the room data for a specific room type and variant combination. This is
84
116
  * accomplished by using the "goto" console command to load the specified room into the
@@ -146,87 +178,105 @@ export function getRoomTypeName(roomType: RoomType): string {
146
178
 
147
179
  /**
148
180
  * Helper function to get the room descriptor for every room on the level. This includes off-grid
149
- * rooms, such as the Devil Room. (Off-grid rooms will only be included if they the data exists,
150
- * which only usually happens once they have been visited at least once.)
181
+ * rooms, such as the Devil Room.
182
+ *
183
+ * Room descriptors without any data are assumed to be non-existent and are not included.
151
184
  *
152
- * Under the hood, this function uses the `Level.GetRooms` method to accomplish this. Rooms without
153
- * data are assumed to be non-existent and are not added to the list.
185
+ * - If you want just the rooms inside of the grid, use the `getRoomsInGrid` helper function.
186
+ * - If you want just the rooms outside of the grid, use the `getRoomsOutsideGrid` helper function.
154
187
  *
155
188
  * @param includeExtraDimensionalRooms Optional. On some floors (e.g. Downpour 2, Mines 2),
156
- * extra-dimensional rooms are automatically generated and can be
157
- * seen when you iterate over the `RoomList`. Default is false.
189
+ * extra-dimensional rooms are automatically generated. Default is
190
+ * false.
158
191
  */
159
192
  export function getRooms(
160
193
  includeExtraDimensionalRooms = false,
161
194
  ): RoomDescriptor[] {
162
- const level = game.GetLevel();
163
- const roomList = level.GetRooms();
164
-
165
- /** Indexed by room safe grid index. We use a map to avoid adding extra dimensional rooms. */
166
- const roomsMap = new Map<int, RoomDescriptor>();
167
-
168
- for (let i = 0; i < roomList.Size; i++) {
169
- const roomDescriptor = roomList.Get(i);
170
- if (roomDescriptor === undefined || roomDescriptor.Data === undefined) {
171
- continue;
172
- }
173
-
174
- if (
175
- !includeExtraDimensionalRooms &&
176
- roomsMap.has(roomDescriptor.SafeGridIndex)
177
- ) {
178
- continue;
179
- }
180
-
181
- roomsMap.set(roomDescriptor.SafeGridIndex, roomDescriptor);
182
- }
183
-
184
- return [...roomsMap.values()];
195
+ // The obvious way to get all of the rooms would be to iterate over the `RoomList` from the
196
+ // `Level.GetRooms` method. However, this results in read-only data, and we want to return a
197
+ // writable object. Instead, we let the heavy lifting be handled by other functions.
198
+ const roomsInGrid = getRoomsInGrid(includeExtraDimensionalRooms);
199
+ const roomsOutsideGrid = getRoomsOutsideGrid();
200
+ return [...roomsInGrid, ...roomsOutsideGrid];
185
201
  }
186
202
 
187
203
  /**
188
- * Helper function to get the room descriptor for every room on the level except for rooms that are
189
- * not on the grid.
204
+ * Helper function to get the room descriptor for every room on the level that is on the grid. (For
205
+ * example, Devil Rooms are excluded.)
190
206
  *
191
- * Under the hood, this function uses the `Level.GetRooms` method to accomplish this. Rooms without
192
- * data are assumed to be non-existent and are not added to the list.
207
+ * Room descriptors without any data are assumed to be non-existent and are not included.
193
208
  *
194
209
  * @param includeExtraDimensionalRooms Optional. On some floors (e.g. Downpour 2, Mines 2),
195
- * extra-dimensional rooms are automatically be generated and can be
196
- * seen when you iterate over the `RoomList`. Default is false.
210
+ * extra-dimensional rooms are automatically be generated. Default
211
+ * is false.
197
212
  */
198
213
  export function getRoomsInGrid(
199
214
  includeExtraDimensionalRooms = false,
200
215
  ): RoomDescriptor[] {
201
- const rooms = getRooms(includeExtraDimensionalRooms);
202
- return rooms.filter((roomDescriptor) => roomDescriptor.SafeGridIndex >= 0);
216
+ const level = game.GetLevel();
217
+
218
+ const dimensions = includeExtraDimensionalRooms
219
+ ? (erange(NUM_DIMENSIONS) as Dimension[])
220
+ : [Dimension.CURRENT];
221
+
222
+ /** We use a map instead of an array because room shapes occupy more than one room grid index. */
223
+ const roomDescriptorMap = new Map<PtrHash, RoomDescriptor>();
224
+
225
+ for (const dimension of dimensions) {
226
+ for (const roomGridIndex of irange(MAX_LEVEL_GRID_INDEX)) {
227
+ const roomDescriptor = level.GetRoomByIdx(roomGridIndex, dimension);
228
+ if (roomDescriptor.Data !== undefined) {
229
+ const ptrHash = GetPtrHash(roomDescriptor);
230
+ roomDescriptorMap.set(ptrHash, roomDescriptor);
231
+ }
232
+ }
233
+ }
234
+
235
+ return [...roomDescriptorMap.values()];
203
236
  }
204
237
 
205
238
  /**
206
239
  * Helper function to get the room descriptor for every room on the level in a specific dimension.
207
240
  * This will not include any off-grid rooms, such as the Devil Room.
208
241
  *
209
- * Under the hood, this function uses the `Level.GetRooms` method to accomplish this. Rooms without
210
- * data are assumed to be non-existent and are not added to the list.
211
- *
212
- * @returns A map of room ListIndex to RoomDescriptor.
242
+ * Room descriptors without any data are assumed to be non-existent and are not included.
213
243
  */
214
244
  export function getRoomsOfDimension(dimension: Dimension): RoomDescriptor[] {
215
245
  const level = game.GetLevel();
216
246
 
217
247
  /** We use a map instead of an array because room shapes occupy more than one room grid index. */
218
- const roomsMap = new Map<int, RoomDescriptor>();
248
+ const roomsMap = new Map<PtrHash, RoomDescriptor>();
219
249
 
220
250
  for (const roomGridIndex of irange(MAX_LEVEL_GRID_INDEX)) {
221
251
  const roomDescriptor = level.GetRoomByIdx(roomGridIndex, dimension);
222
252
  if (roomDescriptor.Data !== undefined) {
223
- roomsMap.set(roomDescriptor.ListIndex, roomDescriptor);
253
+ const ptrHash = GetPtrHash(roomDescriptor);
254
+ roomsMap.set(ptrHash, roomDescriptor);
224
255
  }
225
256
  }
226
257
 
227
258
  return [...roomsMap.values()];
228
259
  }
229
260
 
261
+ /**
262
+ * Helper function to get the room descriptor for every room on the level that is outside of the
263
+ * grid (like a Devil Room).
264
+ *
265
+ * Room descriptors without any data are assumed to be non-existent and are not included.
266
+ */
267
+ export function getRoomsOutsideGrid(): RoomDescriptor[] {
268
+ // We filter an array of all rooms instead of iterating over the `GridRoom` enum because it is
269
+ // possible for mods to insert data at arbitrary negative room grid indexes.
270
+ const readOnlyRooms = getReadOnlyRooms();
271
+ const readOnlyRoomsOffGrid = readOnlyRooms.filter(
272
+ (readOnlyRoomDescriptor) => readOnlyRoomDescriptor.SafeGridIndex < 0,
273
+ );
274
+
275
+ return readOnlyRoomsOffGrid.map((readOnlyRoomDescriptor) =>
276
+ getRoomDescriptor(readOnlyRoomDescriptor.SafeGridIndex),
277
+ );
278
+ }
279
+
230
280
  /**
231
281
  * Helper function to determine if the current room shape is equal to `RoomShape.1x2` or
232
282
  * `RoomShape.2x1`.
@@ -413,7 +463,7 @@ export function inStartingRoom(): boolean {
413
463
  /**
414
464
  * Helper function to loop through every room on the floor and see if it has been cleared.
415
465
  *
416
- * This function will only check rooms in the current dimension.
466
+ * This function will only check rooms inside the gird and inside the current dimension.
417
467
  *
418
468
  * @param onlyCheckRoomTypes Optional. A whitelist of room types. If specified, room types not in
419
469
  * the array will be ignored. If not specified, then all rooms will be
@@ -422,7 +472,7 @@ export function inStartingRoom(): boolean {
422
472
  export function isAllRoomsClear(onlyCheckRoomTypes?: RoomType[]): boolean {
423
473
  const roomTypeWhitelist =
424
474
  onlyCheckRoomTypes === undefined ? null : new Set(onlyCheckRoomTypes);
425
- const rooms = getRooms();
475
+ const rooms = getRoomsInGrid();
426
476
  const matchingRooms =
427
477
  roomTypeWhitelist === null
428
478
  ? rooms
@@ -454,6 +504,11 @@ export function roomUpdateSafe(): void {
454
504
  setEntityVelocities(entityVelocities, entities);
455
505
  }
456
506
 
507
+ /** Helper function to set the backdrop of the current room. */
508
+ export function setBackdrop(backdropType: BackdropType): void {
509
+ game.ShowHallucination(0, backdropType);
510
+ }
511
+
457
512
  /**
458
513
  * Helper function to convert an uncleared room to a cleared room in the `POST_NEW_ROOM` callback.
459
514
  * This is useful because if enemies are removed in this callback, a room drop will be awarded and