isaacscript-common 6.13.0 → 6.16.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 (144) hide show
  1. package/dist/callbacks/postGridEntityCustomCollision.d.ts +2 -0
  2. package/dist/callbacks/postGridEntityCustomCollision.d.ts.map +1 -0
  3. package/dist/callbacks/postGridEntityCustomCollision.lua +71 -0
  4. package/dist/callbacks/postGridEntityCustomRender.lua +0 -7
  5. package/dist/callbacks/postGridEntityCustomUpdate.lua +0 -7
  6. package/dist/callbacks/subscriptions/postGridEntityCustomBroken.d.ts +6 -0
  7. package/dist/callbacks/subscriptions/postGridEntityCustomBroken.d.ts.map +1 -0
  8. package/dist/callbacks/subscriptions/postGridEntityCustomBroken.lua +29 -0
  9. package/dist/callbacks/subscriptions/postGridEntityCustomCollision.d.ts +6 -0
  10. package/dist/callbacks/subscriptions/postGridEntityCustomCollision.d.ts.map +1 -0
  11. package/dist/callbacks/subscriptions/postGridEntityCustomCollision.lua +29 -0
  12. package/dist/enums/ModCallbackCustom.d.ts +96 -62
  13. package/dist/enums/ModCallbackCustom.d.ts.map +1 -1
  14. package/dist/enums/ModCallbackCustom.lua +64 -60
  15. package/dist/enums/private/SerializationBrand.d.ts +1 -1
  16. package/dist/enums/private/SerializationBrand.lua +1 -1
  17. package/dist/features/customGridEntity.d.ts +7 -3
  18. package/dist/features/customGridEntity.d.ts.map +1 -1
  19. package/dist/features/customGridEntity.lua +67 -7
  20. package/dist/features/extraConsoleCommands/exports.d.ts +4 -3
  21. package/dist/features/extraConsoleCommands/exports.d.ts.map +1 -1
  22. package/dist/features/extraConsoleCommands/exports.lua +4 -3
  23. package/dist/features/extraConsoleCommands/init.lua +1 -0
  24. package/dist/functions/collectibles.d.ts +6 -2
  25. package/dist/functions/collectibles.d.ts.map +1 -1
  26. package/dist/functions/collectibles.lua +4 -2
  27. package/dist/functions/color.d.ts +20 -14
  28. package/dist/functions/color.d.ts.map +1 -1
  29. package/dist/functions/color.lua +78 -73
  30. package/dist/functions/deepCopy.d.ts.map +1 -1
  31. package/dist/functions/deepCopy.lua +22 -1
  32. package/dist/functions/gridEntities.d.ts +2 -36
  33. package/dist/functions/gridEntities.d.ts.map +1 -1
  34. package/dist/functions/gridEntities.lua +2 -78
  35. package/dist/functions/isaacAPIClass.d.ts +1 -1
  36. package/dist/functions/isaacAPIClass.d.ts.map +1 -1
  37. package/dist/functions/itemPool.d.ts +10 -0
  38. package/dist/functions/itemPool.d.ts.map +1 -0
  39. package/dist/functions/itemPool.lua +116 -0
  40. package/dist/functions/kColor.d.ts +20 -14
  41. package/dist/functions/kColor.d.ts.map +1 -1
  42. package/dist/functions/kColor.lua +65 -60
  43. package/dist/functions/mergeTests.lua +2 -2
  44. package/dist/functions/npcs.d.ts +1 -29
  45. package/dist/functions/npcs.d.ts.map +1 -1
  46. package/dist/functions/npcs.lua +0 -45
  47. package/dist/functions/projectiles.d.ts +32 -0
  48. package/dist/functions/projectiles.d.ts.map +1 -0
  49. package/dist/functions/projectiles.lua +73 -0
  50. package/dist/functions/random.d.ts +1 -1
  51. package/dist/functions/random.lua +1 -1
  52. package/dist/functions/rng.d.ts +11 -15
  53. package/dist/functions/rng.d.ts.map +1 -1
  54. package/dist/functions/rng.lua +32 -52
  55. package/dist/functions/rockAlt.d.ts +48 -0
  56. package/dist/functions/rockAlt.d.ts.map +1 -0
  57. package/dist/functions/rockAlt.lua +365 -0
  58. package/dist/functions/saveFile.d.ts +8 -7
  59. package/dist/functions/saveFile.d.ts.map +1 -1
  60. package/dist/functions/saveFile.lua +10 -96
  61. package/dist/functions/serialization.d.ts +26 -7
  62. package/dist/functions/serialization.d.ts.map +1 -1
  63. package/dist/functions/serialization.lua +51 -19
  64. package/dist/functions/table.d.ts +2 -2
  65. package/dist/functions/table.lua +2 -2
  66. package/dist/functions/trinketGive.d.ts +13 -0
  67. package/dist/functions/trinketGive.d.ts.map +1 -1
  68. package/dist/functions/trinketGive.lua +16 -0
  69. package/dist/functions/tstlClass.d.ts +1 -1
  70. package/dist/functions/tstlClass.d.ts.map +1 -1
  71. package/dist/functions/vector.d.ts +21 -14
  72. package/dist/functions/vector.d.ts.map +1 -1
  73. package/dist/functions/vector.lua +58 -54
  74. package/dist/index.d.ts +2 -0
  75. package/dist/index.d.ts.map +1 -1
  76. package/dist/index.lua +16 -0
  77. package/dist/initCustomCallbacks.d.ts.map +1 -1
  78. package/dist/initCustomCallbacks.lua +3 -0
  79. package/dist/interfaces/AddCallbackParameterCustom.d.ts +4 -0
  80. package/dist/interfaces/AddCallbackParameterCustom.d.ts.map +1 -1
  81. package/dist/objects/callbackRegisterFunctions.d.ts.map +1 -1
  82. package/dist/objects/callbackRegisterFunctions.lua +6 -0
  83. package/dist/objects/isaacAPIClassTypeToFunctions.d.ts +12 -0
  84. package/dist/objects/isaacAPIClassTypeToFunctions.d.ts.map +1 -0
  85. package/dist/objects/isaacAPIClassTypeToFunctions.lua +25 -0
  86. package/dist/types/{private/IsaacAPIClass.d.ts → IsaacAPIClass.d.ts} +0 -0
  87. package/dist/types/IsaacAPIClass.d.ts.map +1 -0
  88. package/dist/types/{private/IsaacAPIClass.lua → IsaacAPIClass.lua} +0 -0
  89. package/dist/types/{private/SerializedIsaacAPIClass.d.ts → SerializedIsaacAPIClass.d.ts} +0 -0
  90. package/dist/types/SerializedIsaacAPIClass.d.ts.map +1 -0
  91. package/dist/types/{private/SerializedIsaacAPIClass.lua → SerializedIsaacAPIClass.lua} +0 -0
  92. package/dist/types/{private/TSTLClass.d.ts → TSTLClass.d.ts} +0 -0
  93. package/dist/types/TSTLClass.d.ts.map +1 -0
  94. package/dist/types/{private/TSTLClass.lua → TSTLClass.lua} +0 -0
  95. package/package.json +2 -2
  96. package/src/callbacks/postGridEntityCustomCollision.ts +74 -0
  97. package/src/callbacks/postGridEntityCustomRender.ts +1 -17
  98. package/src/callbacks/postGridEntityCustomUpdate.ts +1 -17
  99. package/src/callbacks/subscriptions/postGridEntityCustomBroken.ts +41 -0
  100. package/src/callbacks/subscriptions/postGridEntityCustomCollision.ts +43 -0
  101. package/src/enums/ModCallbackCustom.ts +38 -2
  102. package/src/enums/private/SerializationBrand.ts +1 -1
  103. package/src/features/customGridEntity.ts +78 -2
  104. package/src/features/extraConsoleCommands/exports.ts +4 -3
  105. package/src/features/extraConsoleCommands/init.ts +1 -0
  106. package/src/features/extraConsoleCommands/listCommands.ts +2 -2
  107. package/src/functions/collectibles.ts +6 -2
  108. package/src/functions/color.ts +89 -87
  109. package/src/functions/deepCopy.ts +15 -2
  110. package/src/functions/gridEntities.ts +2 -77
  111. package/src/functions/isaacAPIClass.ts +1 -1
  112. package/src/functions/itemPool.ts +153 -0
  113. package/src/functions/kColor.ts +87 -84
  114. package/src/functions/mergeTests.ts +2 -2
  115. package/src/functions/npcs.ts +1 -58
  116. package/src/functions/projectiles.ts +78 -0
  117. package/src/functions/random.ts +1 -1
  118. package/src/functions/rng.ts +45 -65
  119. package/src/functions/rockAlt.ts +396 -0
  120. package/src/functions/saveFile.ts +13 -119
  121. package/src/functions/serialization.ts +81 -25
  122. package/src/functions/table.ts +2 -2
  123. package/src/functions/trinketGive.ts +21 -0
  124. package/src/functions/tstlClass.ts +1 -1
  125. package/src/functions/vector.ts +78 -74
  126. package/src/index.ts +2 -0
  127. package/src/initCustomCallbacks.ts +2 -0
  128. package/src/interfaces/AddCallbackParameterCustom.ts +4 -0
  129. package/src/objects/callbackRegisterFunctions.ts +6 -0
  130. package/src/objects/isaacAPIClassTypeToFunctions.ts +63 -0
  131. package/src/types/{private/IsaacAPIClass.ts → IsaacAPIClass.ts} +0 -0
  132. package/src/types/{private/SerializedIsaacAPIClass.ts → SerializedIsaacAPIClass.ts} +0 -0
  133. package/src/types/{private/TSTLClass.ts → TSTLClass.ts} +0 -0
  134. package/dist/objects/isaacAPIClassTypeToCopyFunction.d.ts +0 -6
  135. package/dist/objects/isaacAPIClassTypeToCopyFunction.d.ts.map +0 -1
  136. package/dist/objects/isaacAPIClassTypeToCopyFunction.lua +0 -13
  137. package/dist/objects/serializedIsaacAPIClassTypeToIdentityFunction.d.ts +0 -5
  138. package/dist/objects/serializedIsaacAPIClassTypeToIdentityFunction.d.ts.map +0 -1
  139. package/dist/objects/serializedIsaacAPIClassTypeToIdentityFunction.lua +0 -13
  140. package/dist/types/private/IsaacAPIClass.d.ts.map +0 -1
  141. package/dist/types/private/SerializedIsaacAPIClass.d.ts.map +0 -1
  142. package/dist/types/private/TSTLClass.d.ts.map +0 -1
  143. package/src/objects/isaacAPIClassTypeToCopyFunction.ts +0 -18
  144. package/src/objects/serializedIsaacAPIClassTypeToIdentityFunction.ts +0 -14
@@ -1,19 +1,14 @@
1
1
  import { SerializationBrand } from "../enums/private/SerializationBrand";
2
- import { SerializationType } from "../enums/SerializationType";
3
2
  import { isaacAPIClassEquals, isIsaacAPIClassOfType } from "./isaacAPIClass";
3
+ import { getRandom } from "./random";
4
+ import { getRandomSeed, isRNG, newRNG } from "./rng";
4
5
  import { copyValuesToTable, getNumbersFromTable, tableHasKeys } from "./table";
5
6
  import { isTable } from "./types";
6
7
 
7
- type SerializedColor = LuaMap<string, unknown> & {
8
+ export type SerializedColor = LuaMap<string, unknown> & {
8
9
  readonly __serializedColorBrand: symbol;
9
10
  };
10
11
 
11
- interface CopyColorReturn {
12
- [SerializationType.NONE]: Color;
13
- [SerializationType.SERIALIZE]: SerializedColor;
14
- [SerializationType.DESERIALIZE]: Color;
15
- }
16
-
17
12
  const KEYS = ["R", "G", "B", "A", "RO", "GO", "BO"];
18
13
  const OBJECT_NAME = "Color";
19
14
 
@@ -21,88 +16,79 @@ export function colorEquals(color1: Color, color2: Color): boolean {
21
16
  return isaacAPIClassEquals(color1, color2, KEYS);
22
17
  }
23
18
 
19
+ /** Helper function to copy a `Color` Isaac API class. */
20
+ export function copyColor(color: Color): Color {
21
+ if (!isColor(color)) {
22
+ error(
23
+ `Failed to copy a ${OBJECT_NAME} object since the provided object was not a userdata ${OBJECT_NAME} class.`,
24
+ );
25
+ }
26
+
27
+ return Color(
28
+ color.R,
29
+ color.G,
30
+ color.B,
31
+ color.A,
32
+ color.RO,
33
+ color.GO,
34
+ color.BO,
35
+ );
36
+ }
37
+
24
38
  /**
25
- * Helper function to copy a `Color` object.
26
- *
27
- * @param color The Color object to copy. In the case of deserialization, this will actually be a
28
- * Lua table instead of an instantiated Color class.
29
- * @param serializationType Default is `SerializationType.NONE`.
39
+ * Helper function to convert a `SerializedColor` object to a normal `Color` object. (This is used
40
+ * by the save data manager when reading data from the "save#.dat" file.)
30
41
  */
31
- export function copyColor<
32
- C extends Color | SerializedColor,
33
- S extends SerializationType,
34
- >(color: C, serializationType: S): CopyColorReturn[S];
35
- export function copyColor<C extends Color | SerializedColor>(
36
- color: C,
37
- ): CopyColorReturn[SerializationType.NONE];
38
- export function copyColor(
39
- color: Color | SerializedColor,
40
- serializationType = SerializationType.NONE,
41
- ): CopyColorReturn[keyof CopyColorReturn] {
42
- switch (serializationType) {
43
- case SerializationType.NONE: {
44
- if (!isColor(color)) {
45
- error(
46
- `Failed to copy a ${OBJECT_NAME} object since the provided object was not a userdata ${OBJECT_NAME} class.`,
47
- );
48
- }
49
-
50
- return Color(
51
- color.R,
52
- color.G,
53
- color.B,
54
- color.A,
55
- color.RO,
56
- color.GO,
57
- color.BO,
58
- );
59
- }
60
-
61
- case SerializationType.SERIALIZE: {
62
- if (!isColor(color)) {
63
- error(
64
- `Failed to serialize a ${OBJECT_NAME} object since the provided object was not a userdata ${OBJECT_NAME} class.`,
65
- );
66
- }
67
-
68
- const colorTable = new LuaMap<string, unknown>();
69
- copyValuesToTable(color, KEYS, colorTable);
70
- colorTable.set(SerializationBrand.COLOR, "");
71
- return colorTable as SerializedColor;
72
- }
73
-
74
- case SerializationType.DESERIALIZE: {
75
- if (!isTable(color)) {
76
- error(
77
- `Failed to deserialize a ${OBJECT_NAME} object since the provided object was not a Lua table.`,
78
- );
79
- }
80
-
81
- const [r, g, b, a, ro, go, bo] = getNumbersFromTable(
82
- color as LuaMap<string, unknown>,
83
- OBJECT_NAME,
84
- ...KEYS,
85
- );
86
-
87
- if (r === undefined) {
88
- error(
89
- `Failed to deserialize a ${OBJECT_NAME} object since the provided object did not have a value for: r`,
90
- );
91
- }
92
- if (g === undefined) {
93
- error(
94
- `Failed to deserialize a ${OBJECT_NAME} object since the provided object did not have a value for: g`,
95
- );
96
- }
97
- if (b === undefined) {
98
- error(
99
- `Failed to deserialize a ${OBJECT_NAME} object since the provided object did not have a value for: b`,
100
- );
101
- }
102
-
103
- return Color(r, g, b, a, ro, go, bo);
104
- }
42
+ export function deserializeColor(color: SerializedColor): Color {
43
+ if (!isTable(color)) {
44
+ error(
45
+ `Failed to deserialize a ${OBJECT_NAME} object since the provided object was not a Lua table.`,
46
+ );
105
47
  }
48
+
49
+ const [r, g, b, a, ro, go, bo] = getNumbersFromTable(
50
+ color as LuaMap<string, unknown>,
51
+ OBJECT_NAME,
52
+ ...KEYS,
53
+ );
54
+
55
+ if (r === undefined) {
56
+ error(
57
+ `Failed to deserialize a ${OBJECT_NAME} object since the provided object did not have a value for: R`,
58
+ );
59
+ }
60
+ if (g === undefined) {
61
+ error(
62
+ `Failed to deserialize a ${OBJECT_NAME} object since the provided object did not have a value for: G`,
63
+ );
64
+ }
65
+ if (b === undefined) {
66
+ error(
67
+ `Failed to deserialize a ${OBJECT_NAME} object since the provided object did not have a value for: B`,
68
+ );
69
+ }
70
+
71
+ return Color(r, g, b, a, ro, go, bo);
72
+ }
73
+
74
+ /**
75
+ * Helper function to get a random color.
76
+ *
77
+ * @param seedOrRNG Optional. The `Seed` or `RNG` object to use. If an `RNG` object is provided, the
78
+ * `RNG.Next` method will be called. Default is `getRandomSeed()`.
79
+ * @param alpha Optional. The alpha value to use. Default is 1.
80
+ */
81
+ export function getRandomColor(
82
+ seedOrRNG: Seed | RNG = getRandomSeed(),
83
+ alpha = 1,
84
+ ): Color {
85
+ const rng = isRNG(seedOrRNG) ? seedOrRNG : newRNG(seedOrRNG);
86
+
87
+ const r = getRandom(rng);
88
+ const g = getRandom(rng);
89
+ const b = getRandom(rng);
90
+
91
+ return Color(r, g, b, alpha);
106
92
  }
107
93
 
108
94
  /** Helper function to check if something is an instantiated Color object. */
@@ -121,3 +107,19 @@ export function isSerializedColor(object: unknown): object is SerializedColor {
121
107
 
122
108
  return tableHasKeys(object, ...KEYS) && object.has(SerializationBrand.COLOR);
123
109
  }
110
+ /**
111
+ * Helper function to convert a `Color` object to a `SerializedColor` object. (This is used by the
112
+ * save data manager when writing data from the "save#.dat" file.)
113
+ */
114
+ export function serializeColor(color: Color): SerializedColor {
115
+ if (!isColor(color)) {
116
+ error(
117
+ `Failed to serialize a ${OBJECT_NAME} object since the provided object was not a userdata ${OBJECT_NAME} class.`,
118
+ );
119
+ }
120
+
121
+ const colorTable = new LuaMap<string, unknown>();
122
+ copyValuesToTable(color, KEYS, colorTable);
123
+ colorTable.set(SerializationBrand.COLOR, "");
124
+ return colorTable as SerializedColor;
125
+ }
@@ -4,7 +4,7 @@ import { SerializationBrand } from "../enums/private/SerializationBrand";
4
4
  import { SerializationType } from "../enums/SerializationType";
5
5
  import { SAVE_DATA_MANAGER_DEBUG } from "../features/saveDataManager/saveDataManagerConstants";
6
6
  import { isSerializationBrand } from "../features/saveDataManager/serializationBrands";
7
- import { TSTLClass } from "../types/private/TSTLClass";
7
+ import { TSTLClass } from "../types/TSTLClass";
8
8
  import { isArray } from "./array";
9
9
  import { getEnumValues } from "./enums";
10
10
  import { getIsaacAPIClassName } from "./isaacAPIClass";
@@ -13,6 +13,7 @@ import {
13
13
  copyIsaacAPIClass,
14
14
  deserializeIsaacAPIClass,
15
15
  isSerializedIsaacAPIClass,
16
+ serializeIsaacAPIClass,
16
17
  } from "./serialization";
17
18
  import {
18
19
  getTSTLClassName,
@@ -664,5 +665,17 @@ function deepCopyUserdata(
664
665
  );
665
666
  }
666
667
 
667
- return copyIsaacAPIClass(value, serializationType);
668
+ switch (serializationType) {
669
+ case SerializationType.NONE: {
670
+ return copyIsaacAPIClass(value);
671
+ }
672
+
673
+ case SerializationType.SERIALIZE: {
674
+ return serializeIsaacAPIClass(value);
675
+ }
676
+
677
+ case SerializationType.DESERIALIZE: {
678
+ return deserializeIsaacAPIClass(value);
679
+ }
680
+ }
668
681
  }
@@ -9,17 +9,14 @@ import {
9
9
  } from "isaac-typescript-definitions";
10
10
  import { game } from "../cachedClasses";
11
11
  import { DISTANCE_OF_GRID_TILE } from "../constants";
12
- import { RockAltType } from "../enums/RockAltType";
13
12
  import { GRID_ENTITY_TYPE_TO_BROKEN_STATE_MAP } from "../maps/gridEntityTypeToBrokenStateMap";
14
13
  import { GRID_ENTITY_XML_MAP } from "../maps/gridEntityXMLMap";
15
14
  import {
16
15
  DEFAULT_TOP_LEFT_WALL_GRID_INDEX,
17
16
  ROOM_SHAPE_TO_TOP_LEFT_WALL_GRID_INDEX_MAP,
18
17
  } from "../maps/roomShapeToTopLeftWallGridIndexMap";
19
- import { BACKDROP_TYPE_TO_ROCK_ALT_TYPE } from "../objects/backdropTypeToRockAltType";
20
18
  import { AnyGridEntity } from "../types/AnyGridEntity";
21
19
  import { isCircleIntersectingRectangle } from "./math";
22
- import { getRandomSeed } from "./rng";
23
20
  import { roomUpdateSafe } from "./rooms";
24
21
  import { clearSprite } from "./sprites";
25
22
  import { isNumber } from "./types";
@@ -277,27 +274,6 @@ export function getMatchingGridEntities(
277
274
  );
278
275
  }
279
276
 
280
- /**
281
- * Helper function to get the alternate rock type (i.e. urn, mushroom, etc.) that the current room
282
- * will have.
283
- *
284
- * The rock type is based on the backdrop of the room.
285
- *
286
- * For example, if you change the backdrop of the starting room of the run to `BackdropType.CAVES`,
287
- * and then spawn `GridEntityType.ROCK_ALT`, it will be a mushroom instead of an urn. Additionally,
288
- * if it is destroyed, it will generate mushroom-appropriate rewards.
289
- *
290
- * On the other hand, if an urn is spawned first before the backdrop is changed to
291
- * `BackdropType.CAVES`, the graphic of the urn will not switch to a mushroom. However, when
292
- * destroyed, the urn will still generate mushroom-appropriate rewards.
293
- */
294
- export function getRockAltType(): RockAltType {
295
- const room = game.GetRoom();
296
- const backdropType = room.GetBackdropType();
297
-
298
- return BACKDROP_TYPE_TO_ROCK_ALT_TYPE[backdropType];
299
- }
300
-
301
277
  export function getSurroundingGridEntities(
302
278
  gridEntity: GridEntity,
303
279
  ): GridEntity[] {
@@ -488,7 +464,7 @@ export function removeAllMatchingGridEntities(
488
464
  * generally a good idea because if the room is not updated, you will be unable to
489
465
  * spawn another grid entity on the same tile until a frame has passed. However,
490
466
  * doing this is expensive, since it involves a call to `Isaac.GetRoomEntities`,
491
- * so set this to false if you need to invoke this function multiple times.
467
+ * so set this to false if you need to run this function multiple times.
492
468
  * @param cap Optional. If specified, will only remove the given amount of entities.
493
469
  * @returns An array of the entities that were removed.
494
470
  */
@@ -527,7 +503,7 @@ export function removeGridEntities<T extends AnyGridEntity>(
527
503
  * generally a good idea because if the room is not updated, you will be unable to
528
504
  * spawn another grid entity on the same tile until a frame has passed. However,
529
505
  * doing this is expensive, since it involves a call to `Isaac.GetRoomEntities`,
530
- * so set this to false if you need to invoke this function multiple times.
506
+ * so set this to false if you need to run this function multiple times.
531
507
  */
532
508
  export function removeGridEntity(
533
509
  gridEntityOrGridIndex: GridEntity | int,
@@ -654,57 +630,6 @@ export function spawnGridEntityWithVariant(
654
630
  return gridEntity;
655
631
  }
656
632
 
657
- /**
658
- * Helper function for emulating what happens when a vanilla `GridEntityType.ROCK_ALT` grid entity
659
- * breaks.
660
- *
661
- * Note that most of the time, this function will do nothing, similar to how most of the time, when
662
- * an individual urn is destroyed, nothing will spawn.
663
- *
664
- * The logic in this function is based on the rewards listed on the wiki:
665
- * https://bindingofisaacrebirth.fandom.com/wiki/Rocks
666
- *
667
- * @param rockAltType The type of reward to spawn. For example, `RockAltType.URN` will have a chance
668
- * at spawning coins and spiders.
669
- * @param _seedOrRNG Optional. The `Seed` or `RNG` object to use. If an `RNG` object is provided,
670
- * the `RNG.Next` method will be called. Default is `getRandomSeed()`. Normally,
671
- * you should pass the `InitSeed` of the grid entity that was broken.
672
- * @returns Whether or not this function spawned something.
673
- */
674
- export function spawnRockAltReward(
675
- rockAltType: RockAltType,
676
- _seedOrRNG: Seed | RNG = getRandomSeed(),
677
- ): boolean {
678
- /// const chance = getRandom(seedOrRNG);
679
-
680
- switch (rockAltType) {
681
- case RockAltType.URN: {
682
- // TODO
683
- return false;
684
- }
685
-
686
- case RockAltType.MUSHROOM: {
687
- // TODO
688
- return false;
689
- }
690
-
691
- case RockAltType.SKULL: {
692
- // TODO
693
- return false;
694
- }
695
-
696
- case RockAltType.POLYP: {
697
- // TODO
698
- return false;
699
- }
700
-
701
- case RockAltType.BUCKET: {
702
- // TODO
703
- return false;
704
- }
705
- }
706
- }
707
-
708
633
  /**
709
634
  * Helper function to spawn a Void Portal. This is more complicated than simply spawning a trapdoor
710
635
  * with the appropriate variant, as the game does not give it the correct sprite automatically.
@@ -1,4 +1,4 @@
1
- import { IsaacAPIClass } from "../types/private/IsaacAPIClass";
1
+ import { IsaacAPIClass } from "../types/IsaacAPIClass";
2
2
  import { trimPrefix } from "./string";
3
3
  import { isString, isUserdata } from "./types";
4
4
 
@@ -0,0 +1,153 @@
1
+ import {
2
+ CollectibleType,
3
+ ItemConfigTag,
4
+ ItemPoolType,
5
+ PlayerType,
6
+ TrinketType,
7
+ } from "isaac-typescript-definitions";
8
+ import { game } from "../cachedClasses";
9
+ import { PlayerIndex } from "../types/PlayerIndex";
10
+ import { getCollectibleSet } from "./collectibleSet";
11
+ import { collectibleHasTag } from "./collectibleTag";
12
+ import { mapGetPlayer, mapSetPlayer } from "./playerDataStructures";
13
+ import { getPlayers } from "./playerIndex";
14
+ import { getPlayersOfType } from "./players";
15
+ import { repeat } from "./utils";
16
+
17
+ const COLLECTIBLES_THAT_AFFECT_ITEM_POOLS: readonly CollectibleType[] = [
18
+ CollectibleType.CHAOS, // 402
19
+ CollectibleType.SACRED_ORB, // 691
20
+ CollectibleType.TMTRAINER, // 721
21
+ ];
22
+
23
+ const TRINKETS_THAT_AFFECT_ITEM_POOLS: readonly TrinketType[] = [
24
+ TrinketType.NO,
25
+ ];
26
+
27
+ /**
28
+ * Helper function to see if the given collectible is still present in the given item pool.
29
+ *
30
+ * If the collectible is non-offensive, any Tainted Losts will be temporarily changed to Isaac and
31
+ * then changed back. (This is because Tainted Lost is not able to retrieve non-offensive
32
+ * collectibles from item pools).
33
+ */
34
+ export function isCollectibleInItemPool(
35
+ collectibleType: CollectibleType,
36
+ itemPoolType: ItemPoolType,
37
+ ): boolean {
38
+ // On Tainted Lost, it is impossible to retrieve non-offensive collectibles from pools, so we
39
+ // temporarily change the character to Isaac.
40
+ const taintedLosts = getPlayersOfType(PlayerType.THE_LOST_B);
41
+ const isOffensive = collectibleHasTag(
42
+ collectibleType,
43
+ ItemConfigTag.OFFENSIVE,
44
+ );
45
+ let changedPlayerTypes = false;
46
+ if (!isOffensive) {
47
+ changedPlayerTypes = true;
48
+ for (const player of taintedLosts) {
49
+ player.ChangePlayerType(PlayerType.ISAAC);
50
+ }
51
+ }
52
+
53
+ const [removedItemsMap, removedTrinketsMap] =
54
+ removeItemsAndTrinketsThatAffectItemPools();
55
+
56
+ // Blacklist every collectible in the game except for the provided collectible.
57
+ const itemPool = game.GetItemPool();
58
+ const collectibleSet = getCollectibleSet();
59
+ for (const collectibleTypeInSet of collectibleSet.values()) {
60
+ if (collectibleTypeInSet !== collectibleType) {
61
+ itemPool.AddRoomBlacklist(collectibleTypeInSet);
62
+ }
63
+ }
64
+
65
+ // Get a collectible from the pool and see if it is the intended collectible. (We can use any
66
+ // arbitrary value as the seed since it should not influence the result.)
67
+ const retrievedCollectibleType = itemPool.GetCollectible(
68
+ itemPoolType,
69
+ false,
70
+ 1 as Seed,
71
+ );
72
+
73
+ const collectibleUnlocked = retrievedCollectibleType === collectibleType;
74
+
75
+ // Reset the blacklist
76
+ itemPool.ResetRoomBlacklist();
77
+
78
+ restoreItemsAndTrinketsThatAffectItemPools(
79
+ removedItemsMap,
80
+ removedTrinketsMap,
81
+ );
82
+
83
+ // Change any players back to Tainted Lost, if necessary.
84
+ if (changedPlayerTypes) {
85
+ for (const player of taintedLosts) {
86
+ player.ChangePlayerType(PlayerType.THE_LOST_B);
87
+ }
88
+ }
89
+
90
+ return collectibleUnlocked;
91
+ }
92
+
93
+ /**
94
+ * Before checking the item pools, remove any collectibles or trinkets that would affect the
95
+ * retrieved collectible types.
96
+ */
97
+ function removeItemsAndTrinketsThatAffectItemPools(): [
98
+ removedItemsMap: Map<PlayerIndex, CollectibleType[]>,
99
+ removedTrinketsMap: Map<PlayerIndex, TrinketType[]>,
100
+ ] {
101
+ const removedItemsMap = new Map<PlayerIndex, CollectibleType[]>();
102
+ const removedTrinketsMap = new Map<PlayerIndex, TrinketType[]>();
103
+ for (const player of getPlayers()) {
104
+ const removedItems: CollectibleType[] = [];
105
+ for (const itemToRemove of COLLECTIBLES_THAT_AFFECT_ITEM_POOLS) {
106
+ if (player.HasCollectible(itemToRemove)) {
107
+ const numCollectibles = player.GetCollectibleNum(itemToRemove);
108
+ repeat(numCollectibles, () => {
109
+ player.RemoveCollectible(itemToRemove);
110
+ removedItems.push(itemToRemove);
111
+ });
112
+ }
113
+ }
114
+
115
+ mapSetPlayer(removedItemsMap, player, removedItems);
116
+
117
+ const removedTrinkets: TrinketType[] = [];
118
+ for (const trinketToRemove of TRINKETS_THAT_AFFECT_ITEM_POOLS) {
119
+ if (player.HasTrinket(trinketToRemove)) {
120
+ const numTrinkets = player.GetTrinketMultiplier(trinketToRemove);
121
+ repeat(numTrinkets, () => {
122
+ player.TryRemoveTrinket(trinketToRemove);
123
+ removedTrinkets.push(trinketToRemove);
124
+ });
125
+ }
126
+ }
127
+
128
+ mapSetPlayer(removedTrinketsMap, player, removedTrinkets);
129
+ }
130
+
131
+ return [removedItemsMap, removedTrinketsMap];
132
+ }
133
+
134
+ function restoreItemsAndTrinketsThatAffectItemPools(
135
+ removedItemsMap: Map<PlayerIndex, CollectibleType[]>,
136
+ removedTrinketsMap: Map<PlayerIndex, TrinketType[]>,
137
+ ) {
138
+ for (const player of getPlayers()) {
139
+ const removedItems = mapGetPlayer(removedItemsMap, player);
140
+ if (removedItems !== undefined) {
141
+ for (const collectibleType of removedItems) {
142
+ player.AddCollectible(collectibleType, 0, false); // Prevent Chaos from spawning pickups
143
+ }
144
+ }
145
+
146
+ const removedTrinkets = mapGetPlayer(removedTrinketsMap, player);
147
+ if (removedTrinkets !== undefined) {
148
+ for (const trinketType of removedTrinkets) {
149
+ player.AddTrinket(trinketType, false);
150
+ }
151
+ }
152
+ }
153
+ }