isaacscript-common 6.19.0 → 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.
Files changed (51) hide show
  1. package/dist/constants.d.ts +5 -0
  2. package/dist/constants.d.ts.map +1 -1
  3. package/dist/constants.lua +4 -0
  4. package/dist/features/customStage/exports.d.ts +6 -1
  5. package/dist/features/customStage/exports.d.ts.map +1 -1
  6. package/dist/features/customStage/exports.lua +14 -11
  7. package/dist/features/customTrapdoor/blackSprite.d.ts.map +1 -1
  8. package/dist/features/customTrapdoor/blackSprite.lua +1 -0
  9. package/dist/features/customTrapdoor/init.d.ts.map +1 -1
  10. package/dist/features/customTrapdoor/init.lua +10 -2
  11. package/dist/features/extraConsoleCommands/commandsSubroutines.d.ts.map +1 -1
  12. package/dist/features/extraConsoleCommands/commandsSubroutines.lua +2 -1
  13. package/dist/features/extraConsoleCommands/listCommands.d.ts.map +1 -1
  14. package/dist/features/extraConsoleCommands/listCommands.lua +2 -1
  15. package/dist/functions/curses.d.ts +3 -0
  16. package/dist/functions/curses.d.ts.map +1 -0
  17. package/dist/functions/curses.lua +11 -0
  18. package/dist/functions/dimensions.d.ts +12 -0
  19. package/dist/functions/dimensions.d.ts.map +1 -0
  20. package/dist/functions/dimensions.lua +35 -0
  21. package/dist/functions/level.d.ts.map +1 -1
  22. package/dist/functions/level.lua +8 -7
  23. package/dist/functions/levelGrid.d.ts +155 -0
  24. package/dist/functions/levelGrid.d.ts.map +1 -0
  25. package/dist/functions/levelGrid.lua +349 -0
  26. package/dist/functions/roomData.d.ts +6 -1
  27. package/dist/functions/roomData.d.ts.map +1 -1
  28. package/dist/functions/roomData.lua +6 -0
  29. package/dist/functions/roomGrid.d.ts +8 -0
  30. package/dist/functions/roomGrid.d.ts.map +1 -1
  31. package/dist/functions/rooms.d.ts +67 -68
  32. package/dist/functions/rooms.d.ts.map +1 -1
  33. package/dist/functions/rooms.lua +176 -203
  34. package/dist/index.d.ts +3 -0
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.lua +24 -0
  37. package/package.json +2 -2
  38. package/src/constants.ts +8 -0
  39. package/src/features/customStage/exports.ts +25 -14
  40. package/src/features/customTrapdoor/blackSprite.ts +1 -0
  41. package/src/features/customTrapdoor/init.ts +7 -3
  42. package/src/features/extraConsoleCommands/commandsSubroutines.ts +2 -1
  43. package/src/features/extraConsoleCommands/listCommands.ts +2 -1
  44. package/src/functions/curses.ts +9 -0
  45. package/src/functions/dimensions.ts +41 -0
  46. package/src/functions/level.ts +7 -10
  47. package/src/functions/levelGrid.ts +468 -0
  48. package/src/functions/roomData.ts +13 -1
  49. package/src/functions/roomGrid.ts +9 -0
  50. package/src/functions/rooms.ts +161 -219
  51. package/src/index.ts +3 -0
@@ -1,5 +1,6 @@
1
1
  import {
2
2
  AngelRoomSubType,
3
+ BackdropType,
3
4
  BossID,
4
5
  Dimension,
5
6
  Direction,
@@ -8,6 +9,7 @@ import {
8
9
  GridRoom,
9
10
  HomeRoomSubType,
10
11
  ItemPoolType,
12
+ LevelCurse,
11
13
  MinibossID,
12
14
  RoomDescriptorFlag,
13
15
  RoomShape,
@@ -17,14 +19,11 @@ import {
17
19
  StageID,
18
20
  } from "isaac-typescript-definitions";
19
21
  import { game, sfxManager } from "../cachedClasses";
20
- import {
21
- LEVEL_GRID_ROW_WIDTH,
22
- MAX_LEVEL_GRID_INDEX,
23
- NUM_DIMENSIONS,
24
- } from "../constants";
25
- import { ROOM_SHAPE_TO_DOOR_SLOTS_TO_GRID_INDEX_DELTA } from "../objects/roomShapeToDoorSlotsToGridIndexDelta";
22
+ import { MAX_LEVEL_GRID_INDEX, NUM_DIMENSIONS } from "../constants";
26
23
  import { ROOM_TYPE_NAMES } from "../objects/roomTypeNames";
27
24
  import { MINE_SHAFT_ROOM_SUB_TYPE_SET } from "../sets/mineShaftRoomSubTypesSet";
25
+ import { hasCurse } from "./curses";
26
+ import { inDimension } from "./dimensions";
28
27
  import {
29
28
  closeAllDoors,
30
29
  getDoors,
@@ -40,17 +39,15 @@ import {
40
39
  setEntityVelocities,
41
40
  } from "./positionVelocity";
42
41
  import {
43
- getRoomAllowedDoors,
44
42
  getRoomData,
45
43
  getRoomDescriptor,
46
44
  getRoomDescriptorReadOnly,
47
45
  getRoomGridIndex,
48
46
  getRoomName,
49
- getRoomShape,
50
47
  getRoomStageID,
51
48
  getRoomSubType,
52
49
  } from "./roomData";
53
- import { getGridIndexDelta } from "./roomShape";
50
+ import { getGotoCommand } from "./stage";
54
51
  import { erange, irange } from "./utils";
55
52
 
56
53
  /**
@@ -76,72 +73,85 @@ export function changeRoom(roomGridIndex: int): void {
76
73
  }
77
74
 
78
75
  /**
79
- * Helper function to get an array with every valid `Dimension` (not including `Dimension.CURRENT`).
76
+ * Helper function to get the number of rooms that are currently on the floor layout. This does not
77
+ * include off-grid rooms, like the Devil Room.
80
78
  */
81
- export function getAllDimensions(): Dimension[] {
82
- return erange(NUM_DIMENSIONS) as Dimension[];
83
- }
84
-
85
- /** Helper function to get the grid index for every room on the entire floor. */
86
- export function getAllRoomGridIndexes(): int[] {
87
- const rooms = getRooms();
88
- return rooms.map((roomDescriptor) => roomDescriptor.SafeGridIndex);
79
+ export function getNumRooms(): int {
80
+ const rooms = getRoomsInGrid();
81
+ return rooms.length;
89
82
  }
90
83
 
91
84
  /**
92
- * Helper function to get the current dimension. Most of the time, this will be `Dimension.MAIN`,
93
- * but it can change if e.g. the player is in the mirror world of Downpour/Dross.
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
94
  */
95
- export function getDimension(): Dimension {
95
+ export function getReadOnlyRooms(): Array<Readonly<RoomDescriptor>> {
96
96
  const level = game.GetLevel();
97
- const roomGridIndex = getRoomGridIndex();
98
- const roomDescription = level.GetRoomByIdx(roomGridIndex, Dimension.CURRENT);
99
- const currentRoomHash = GetPtrHash(roomDescription);
97
+ const roomList = level.GetRooms();
100
98
 
101
- for (const dimension of getAllDimensions()) {
102
- const dimensionRoomDescription = level.GetRoomByIdx(
103
- roomGridIndex,
104
- dimension,
105
- );
106
- const dimensionRoomHash = GetPtrHash(dimensionRoomDescription);
99
+ const readOnlyRoomDescriptors: Array<Readonly<RoomDescriptor>> = [];
107
100
 
108
- if (dimensionRoomHash === currentRoomHash) {
109
- return dimension;
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);
110
108
  }
111
109
  }
112
110
 
113
- error("Failed to get the current dimension.");
114
- }
115
-
116
- /**
117
- * Helper function to get the number of rooms that are currently on the floor layout. This does not
118
- * include off-grid rooms, like the Devil Room.
119
- */
120
- export function getNumRooms(): int {
121
- const rooms = getRooms();
122
- return rooms.length;
111
+ return readOnlyRoomDescriptors;
123
112
  }
124
113
 
125
114
  /**
126
- * Helper function to get an array of all of the safe grid indexes for rooms that match the
127
- * specified room type.
115
+ * Helper function to get the room data for a specific room type and variant combination. This is
116
+ * accomplished by using the "goto" console command to load the specified room into the
117
+ * `GridRoom.DEBUG` slot.
128
118
  *
129
- * This function only searches through rooms in the current dimension.
119
+ * Returns undefined if the provided room type and variant combination were not found. (A warning
120
+ * message will also appear on the console, since the "goto" command will fail.)
130
121
  *
131
- * This function is variadic, meaning that you can specify N arguments to get the combined grid
132
- * indexes for N room types.
122
+ * Note that the side effect of using the "goto" console command is that it will trigger a room
123
+ * transition after a short delay. By default, this function cancels the incoming room transition by
124
+ * using the `Game.StartRoomTransition` method to travel to the same room.
125
+ *
126
+ * @param roomType The type of room to retrieve.
127
+ * @param roomVariant The room variant to retrieve. (The room variant is the "ID" of the room in
128
+ * Basement Renovator.)
129
+ * @param cancelRoomTransition Optional. Whether to cancel the room transition by using the
130
+ * `Game.StartRoomTransition` method to travel to the same room. Default
131
+ * is true. Set this to false if you are getting the data for many rooms
132
+ * at the same time, and then use the `teleport` helper function when
133
+ * you are finished.
133
134
  */
134
- export function getRoomGridIndexesForType(...roomTypes: RoomType[]): int[] {
135
- const roomTypesSet = new Set<RoomType>([...roomTypes]);
136
-
137
- const rooms = getRooms();
138
- const matchingRooms = rooms.filter(
139
- (roomDescriptor) =>
140
- roomDescriptor.Data !== undefined &&
141
- roomTypesSet.has(roomDescriptor.Data.Type),
142
- );
135
+ export function getRoomDataForTypeVariant(
136
+ roomType: RoomType,
137
+ roomVariant: int,
138
+ cancelRoomTransition = true,
139
+ ): Readonly<RoomConfig> | undefined {
140
+ const command = getGotoCommand(roomType, roomVariant);
141
+ Isaac.ExecuteCommand(command);
142
+ const newRoomData = getRoomData(GridRoom.DEBUG);
143
+
144
+ if (cancelRoomTransition) {
145
+ const roomGridIndex = getRoomGridIndex();
146
+ teleport(
147
+ roomGridIndex,
148
+ Direction.NO_DIRECTION,
149
+ RoomTransitionAnim.FADE,
150
+ true,
151
+ );
152
+ }
143
153
 
144
- return matchingRooms.map((roomDescriptor) => roomDescriptor.SafeGridIndex);
154
+ return newRoomData;
145
155
  }
146
156
 
147
157
  /**
@@ -157,40 +167,6 @@ export function getRoomItemPoolType(): ItemPoolType {
157
167
  return itemPool.GetPoolForRoom(roomType, roomSeed);
158
168
  }
159
169
 
160
- /**
161
- * Helper function to get the grid indexes of all the rooms connected to the given room index.
162
- *
163
- * @param roomGridIndex Optional. Default is the current room index.
164
- */
165
- export function getRoomNeighbors(roomGridIndex?: int): int[] {
166
- const roomDescriptor = getRoomDescriptor(roomGridIndex);
167
-
168
- if (
169
- roomDescriptor.SafeGridIndex < 0 ||
170
- roomDescriptor.SafeGridIndex > MAX_LEVEL_GRID_INDEX
171
- ) {
172
- return [];
173
- }
174
-
175
- const roomData = roomDescriptor.Data;
176
- if (roomData === undefined) {
177
- return [];
178
- }
179
-
180
- const roomShape = roomData.Shape;
181
- const gridIndexDeltas = getRoomShapeNeighborGridIndexDeltas(roomShape);
182
- const gridIndexes = gridIndexDeltas.map(
183
- (gridIndexDelta) => roomDescriptor.SafeGridIndex + gridIndexDelta,
184
- );
185
- return gridIndexes.filter((gridIndex) => roomExists(gridIndex));
186
- }
187
-
188
- export function getRoomShapeNeighborGridIndexDeltas(
189
- roomShape: RoomShape,
190
- ): int[] {
191
- return [...ROOM_SHAPE_TO_DOOR_SLOTS_TO_GRID_INDEX_DELTA[roomShape].values()];
192
- }
193
-
194
170
  /**
195
171
  * Helper function to get the proper name of a room type.
196
172
  *
@@ -201,77 +177,106 @@ export function getRoomTypeName(roomType: RoomType): string {
201
177
  }
202
178
 
203
179
  /**
204
- * Helper function to get the room descriptor for every room on the level, including off-grid rooms.
205
- * Uses the `Level.GetRooms` method to accomplish this. Rooms without data are assumed to be
206
- * non-existent and are not added to the list.
180
+ * Helper function to get the room descriptor for every room on the level. This includes off-grid
181
+ * rooms, such as the Devil Room.
182
+ *
183
+ * Room descriptors without any data are assumed to be non-existent and are not included.
184
+ *
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.
207
187
  *
208
188
  * @param includeExtraDimensionalRooms Optional. On some floors (e.g. Downpour 2, Mines 2),
209
- * extra-dimensional rooms are automatically generated and can be
210
- * seen when you iterate over the `RoomList`. Default is false.
189
+ * extra-dimensional rooms are automatically generated. Default is
190
+ * false.
211
191
  */
212
192
  export function getRooms(
213
193
  includeExtraDimensionalRooms = false,
214
194
  ): RoomDescriptor[] {
215
- const level = game.GetLevel();
216
- const roomList = level.GetRooms();
217
-
218
- const roomsMap = new Map<int, RoomDescriptor>();
219
- if (includeExtraDimensionalRooms) {
220
- for (let i = 0; i < roomList.Size; i++) {
221
- const roomDescriptor = roomList.Get(i);
222
- if (roomDescriptor !== undefined && roomDescriptor.Data !== undefined) {
223
- roomsMap.set(roomDescriptor.ListIndex, roomDescriptor);
224
- }
225
- }
226
- } else {
227
- for (const roomGridIndex of irange(MAX_LEVEL_GRID_INDEX)) {
228
- const roomDescriptor = level.GetRoomByIdx(roomGridIndex);
229
- if (roomDescriptor.Data !== undefined) {
230
- roomsMap.set(roomDescriptor.ListIndex, roomDescriptor);
231
- }
232
- }
233
- }
234
-
235
- 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];
236
201
  }
237
202
 
238
203
  /**
239
- * Helper function to get the room descriptor for every room on the level except for rooms that are
240
- * not on the grid. Uses the `Level.GetRooms` method to accomplish this. Rooms without data are
241
- * assumed to be non-existent and are not added to the list.
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.)
206
+ *
207
+ * Room descriptors without any data are assumed to be non-existent and are not included.
242
208
  *
243
209
  * @param includeExtraDimensionalRooms Optional. On some floors (e.g. Downpour 2, Mines 2),
244
- * extra-dimensional rooms are automatically be generated and can be
245
- * seen when you iterate over the `RoomList`. Default is false.
210
+ * extra-dimensional rooms are automatically be generated. Default
211
+ * is false.
246
212
  */
247
213
  export function getRoomsInGrid(
248
214
  includeExtraDimensionalRooms = false,
249
215
  ): RoomDescriptor[] {
250
- const rooms = getRooms(includeExtraDimensionalRooms);
251
- 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()];
252
236
  }
253
237
 
254
238
  /**
255
239
  * Helper function to get the room descriptor for every room on the level in a specific dimension.
256
- * Uses the `Level.GetRooms` method to accomplish this. Rooms without data are assumed to be
257
- * non-existent and are not added to the list.
240
+ * This will not include any off-grid rooms, such as the Devil Room.
258
241
  *
259
- * @returns A map of room ListIndex to RoomDescriptor.
242
+ * Room descriptors without any data are assumed to be non-existent and are not included.
260
243
  */
261
244
  export function getRoomsOfDimension(dimension: Dimension): RoomDescriptor[] {
262
245
  const level = game.GetLevel();
263
246
 
264
- const roomsMap = new Map<int, RoomDescriptor>();
247
+ /** We use a map instead of an array because room shapes occupy more than one room grid index. */
248
+ const roomsMap = new Map<PtrHash, RoomDescriptor>();
249
+
265
250
  for (const roomGridIndex of irange(MAX_LEVEL_GRID_INDEX)) {
266
251
  const roomDescriptor = level.GetRoomByIdx(roomGridIndex, dimension);
267
252
  if (roomDescriptor.Data !== undefined) {
268
- roomsMap.set(roomDescriptor.ListIndex, roomDescriptor);
253
+ const ptrHash = GetPtrHash(roomDescriptor);
254
+ roomsMap.set(ptrHash, roomDescriptor);
269
255
  }
270
256
  }
271
257
 
272
258
  return [...roomsMap.values()];
273
259
  }
274
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
+
275
280
  /**
276
281
  * Helper function to determine if the current room shape is equal to `RoomShape.1x2` or
277
282
  * `RoomShape.2x1`.
@@ -361,10 +366,6 @@ export function inDevilsCrownTreasureRoom(): boolean {
361
366
  return hasFlag(roomDescriptor.Flags, RoomDescriptorFlag.DEVIL_TREASURE);
362
367
  }
363
368
 
364
- export function inDimension(dimension: Dimension): boolean {
365
- return dimension === getDimension();
366
- }
367
-
368
369
  export function inDoubleTrouble(): boolean {
369
370
  const room = game.GetRoom();
370
371
  const roomType = room.GetType();
@@ -462,7 +463,7 @@ export function inStartingRoom(): boolean {
462
463
  /**
463
464
  * Helper function to loop through every room on the floor and see if it has been cleared.
464
465
  *
465
- * 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.
466
467
  *
467
468
  * @param onlyCheckRoomTypes Optional. A whitelist of room types. If specified, room types not in
468
469
  * the array will be ignored. If not specified, then all rooms will be
@@ -471,7 +472,7 @@ export function inStartingRoom(): boolean {
471
472
  export function isAllRoomsClear(onlyCheckRoomTypes?: RoomType[]): boolean {
472
473
  const roomTypeWhitelist =
473
474
  onlyCheckRoomTypes === undefined ? null : new Set(onlyCheckRoomTypes);
474
- const rooms = getRooms();
475
+ const rooms = getRoomsInGrid();
475
476
  const matchingRooms =
476
477
  roomTypeWhitelist === null
477
478
  ? rooms
@@ -484,87 +485,6 @@ export function isAllRoomsClear(onlyCheckRoomTypes?: RoomType[]): boolean {
484
485
  return matchingRooms.every((roomDescriptor) => roomDescriptor.Clear);
485
486
  }
486
487
 
487
- export function isDoorSlotValidAtGridIndex(
488
- doorSlot: DoorSlot,
489
- roomGridIndex: int,
490
- ): boolean {
491
- const allowedDoors = getRoomAllowedDoors(roomGridIndex);
492
- return allowedDoors.has(doorSlot);
493
- }
494
-
495
- export function isDoorSlotValidAtGridIndexForRedRoom(
496
- doorSlot: DoorSlot,
497
- roomGridIndex: int,
498
- ): boolean {
499
- const doorSlotValidAtGridIndex = isDoorSlotValidAtGridIndex(
500
- doorSlot,
501
- roomGridIndex,
502
- );
503
- if (!doorSlotValidAtGridIndex) {
504
- return false;
505
- }
506
-
507
- const roomShape = getRoomShape(roomGridIndex);
508
- if (roomShape === undefined) {
509
- return false;
510
- }
511
-
512
- const delta = getGridIndexDelta(roomShape, doorSlot);
513
- if (delta === undefined) {
514
- return false;
515
- }
516
-
517
- const redRoomGridIndex = roomGridIndex + delta;
518
- return (
519
- !roomExists(redRoomGridIndex) &&
520
- redRoomGridIndex >= 0 &&
521
- redRoomGridIndex <= MAX_LEVEL_GRID_INDEX
522
- );
523
- }
524
-
525
- /**
526
- * Helper function to detect if the provided room was created by the Red Key item. Under the hood,
527
- * this checks for the `RoomDescriptorFlag.FLAG_RED_ROOM` flag.
528
- *
529
- * @param roomGridIndex Optional. Default is the current room index.
530
- */
531
- export function isRedKeyRoom(roomGridIndex?: int): boolean {
532
- const roomDescriptor = getRoomDescriptor(roomGridIndex);
533
- return hasFlag(roomDescriptor.Flags, RoomDescriptorFlag.RED_ROOM);
534
- }
535
-
536
- /**
537
- * Helper function to determine if the provided room is part of the floor layout. For example, Devil
538
- * Rooms and the Mega Satan room are not considered to be inside the map.
539
- *
540
- * @param roomGridIndex Optional. Default is the current room index.
541
- */
542
- export function isRoomInsideMap(roomGridIndex?: int): boolean {
543
- if (roomGridIndex === undefined) {
544
- roomGridIndex = getRoomGridIndex();
545
- }
546
-
547
- return roomGridIndex >= 0;
548
- }
549
-
550
- /** Helper function to check if a room exists at the given room grid index. */
551
- export function roomExists(roomGridIndex: int): boolean {
552
- const roomData = getRoomData(roomGridIndex);
553
- return roomData !== undefined;
554
- }
555
-
556
- /**
557
- * Helper function to get the coordinates of a given grid index. The floor is represented by a 13x13
558
- * grid. For example, since the starting room is in the center, the starting room grid index of 84
559
- * be equal to coordinates of (?, ?).
560
- */
561
- export function roomGridIndexToXY(roomGridIndex: int): [x: int, y: int] {
562
- const x = roomGridIndex % LEVEL_GRID_ROW_WIDTH;
563
- const y = Math.floor(roomGridIndex / LEVEL_GRID_ROW_WIDTH);
564
-
565
- return [x, y];
566
- }
567
-
568
488
  /**
569
489
  * If the `Room.Update` method is called in a `POST_NEW_ROOM` callback, then some entities will
570
490
  * slide around (such as the player). Since those entity velocities are already at zero, setting
@@ -584,6 +504,11 @@ export function roomUpdateSafe(): void {
584
504
  setEntityVelocities(entityVelocities, entities);
585
505
  }
586
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
+
587
512
  /**
588
513
  * Helper function to convert an uncleared room to a cleared room in the `POST_NEW_ROOM` callback.
589
514
  * This is useful because if enemies are removed in this callback, a room drop will be awarded and
@@ -635,21 +560,34 @@ export function setRoomUncleared(): void {
635
560
  /**
636
561
  * Helper function to change the current room. It can be used for both teleportation and "normal"
637
562
  * room transitions, depending on what is passed for the `direction` and `roomTransitionAnim`
638
- * arguments. Use this function instead of invoking the `Game.StartRoomTransition` method directly
639
- * so that you do not forget to set `Level.LeaveDoor` property and to prevent crashing on invalid
640
- * room grid indexes.
563
+ * arguments.
564
+ *
565
+ * Use this function instead of invoking the `Game.StartRoomTransition` method directly so that:
566
+ * - you do not forget to set `Level.LeaveDoor` property
567
+ * - to prevent crashing on invalid room grid indexes
568
+ * - to automatically handle Curse of the Maze
641
569
  *
642
570
  * @param roomGridIndex The room grid index of the destination room.
643
571
  * @param direction Optional. Default is `Direction.NO_DIRECTION`.
644
572
  * @param roomTransitionAnim Optional. Default is `RoomTransitionAnim.TELEPORT`.
573
+ * @param force Optional. Whether to temporarily disable Curse of the Maze. Default is false. If set
574
+ * to false, then this function may not go to the provided room grid index.
645
575
  */
646
576
  export function teleport(
647
577
  roomGridIndex: int,
648
578
  direction = Direction.NO_DIRECTION,
649
579
  roomTransitionAnim = RoomTransitionAnim.TELEPORT,
580
+ force = false,
650
581
  ): void {
651
582
  const level = game.GetLevel();
652
583
 
584
+ // Before starting a room transition, we must ensure that Curse of the Maze is not in effect, or
585
+ // else the room transition might send us to the wrong room.
586
+ const shouldTempDisableCurse = force && hasCurse(LevelCurse.MAZE);
587
+ if (shouldTempDisableCurse) {
588
+ level.RemoveCurses(LevelCurse.MAZE);
589
+ }
590
+
653
591
  const roomData = getRoomData(roomGridIndex);
654
592
  if (roomData === undefined) {
655
593
  error(
@@ -662,4 +600,8 @@ export function teleport(
662
600
  level.LeaveDoor = DoorSlot.NO_DOOR_SLOT;
663
601
 
664
602
  game.StartRoomTransition(roomGridIndex, direction, roomTransitionAnim);
603
+
604
+ if (shouldTempDisableCurse) {
605
+ level.AddCurse(LevelCurse.MAZE, false);
606
+ }
665
607
  }
package/src/index.ts CHANGED
@@ -97,9 +97,11 @@ export * from "./functions/collectibles";
97
97
  export * from "./functions/collectibleSet";
98
98
  export * from "./functions/collectibleTag";
99
99
  export * from "./functions/color";
100
+ export * from "./functions/curses";
100
101
  export * from "./functions/debug";
101
102
  export * from "./functions/deepCopy";
102
103
  export * from "./functions/deepCopyTests";
104
+ export * from "./functions/dimensions";
103
105
  export * from "./functions/direction";
104
106
  export * from "./functions/doors";
105
107
  export * from "./functions/easing";
@@ -123,6 +125,7 @@ export * from "./functions/jsonRoom";
123
125
  export * from "./functions/kColor";
124
126
  export * from "./functions/language";
125
127
  export * from "./functions/level";
128
+ export * from "./functions/levelGrid";
126
129
  export * from "./functions/log";
127
130
  export * from "./functions/map";
128
131
  export * from "./functions/math";