isaacscript-common 6.11.2 → 6.14.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 (189) hide show
  1. package/dist/callbacks/postGridEntityCustomRender.d.ts +2 -0
  2. package/dist/callbacks/postGridEntityCustomRender.d.ts.map +1 -0
  3. package/dist/callbacks/postGridEntityCustomRender.lua +36 -0
  4. package/dist/callbacks/postGridEntityCustomUpdate.d.ts +2 -0
  5. package/dist/callbacks/postGridEntityCustomUpdate.d.ts.map +1 -0
  6. package/dist/callbacks/postGridEntityCustomUpdate.lua +36 -0
  7. package/dist/callbacks/postNewRoomEarly.lua +2 -2
  8. package/dist/callbacks/postPickupInitFirst.lua +1 -20
  9. package/dist/callbacks/reorderedCallbacks.d.ts +5 -5
  10. package/dist/callbacks/reorderedCallbacks.d.ts.map +1 -1
  11. package/dist/callbacks/reorderedCallbacks.lua +5 -5
  12. package/dist/callbacks/subscriptions/postGridEntityCustomRender.d.ts +6 -0
  13. package/dist/callbacks/subscriptions/postGridEntityCustomRender.d.ts.map +1 -0
  14. package/dist/callbacks/subscriptions/postGridEntityCustomRender.lua +29 -0
  15. package/dist/callbacks/subscriptions/postGridEntityCustomUpdate.d.ts +6 -0
  16. package/dist/callbacks/subscriptions/postGridEntityCustomUpdate.d.ts.map +1 -0
  17. package/dist/callbacks/subscriptions/postGridEntityCustomUpdate.lua +29 -0
  18. package/dist/constants.d.ts +1 -5
  19. package/dist/constants.d.ts.map +1 -1
  20. package/dist/constants.lua +0 -7
  21. package/dist/constantsFirstLast.d.ts +5 -1
  22. package/dist/constantsFirstLast.d.ts.map +1 -1
  23. package/dist/constantsFirstLast.lua +6 -0
  24. package/dist/enums/ModCallbackCustom.d.ts +89 -66
  25. package/dist/enums/ModCallbackCustom.d.ts.map +1 -1
  26. package/dist/enums/ModCallbackCustom.lua +62 -58
  27. package/dist/enums/private/SerializationBrand.d.ts +1 -1
  28. package/dist/enums/private/SerializationBrand.lua +1 -1
  29. package/dist/features/collectibleItemPoolType.d.ts +2 -2
  30. package/dist/features/collectibleItemPoolType.lua +2 -2
  31. package/dist/features/customGridEntity.d.ts +11 -2
  32. package/dist/features/customGridEntity.d.ts.map +1 -1
  33. package/dist/features/customGridEntity.lua +22 -2
  34. package/dist/features/customTrapdoor/blackSprite.d.ts.map +1 -1
  35. package/dist/features/customTrapdoor/blackSprite.lua +6 -6
  36. package/dist/features/customTrapdoor/customTrapdoorConstants.d.ts +2 -2
  37. package/dist/features/customTrapdoor/customTrapdoorConstants.d.ts.map +1 -1
  38. package/dist/features/customTrapdoor/customTrapdoorConstants.lua +2 -2
  39. package/dist/features/customTrapdoor/init.d.ts.map +1 -1
  40. package/dist/features/customTrapdoor/init.lua +4 -3
  41. package/dist/features/customTrapdoor/touched.d.ts.map +1 -1
  42. package/dist/features/customTrapdoor/touched.lua +51 -33
  43. package/dist/features/deployJSONRoom.d.ts +2 -2
  44. package/dist/features/deployJSONRoom.lua +2 -2
  45. package/dist/features/extraConsoleCommands/exports.d.ts +4 -3
  46. package/dist/features/extraConsoleCommands/exports.d.ts.map +1 -1
  47. package/dist/features/extraConsoleCommands/exports.lua +4 -3
  48. package/dist/features/extraConsoleCommands/init.lua +12 -14
  49. package/dist/features/extraConsoleCommands/listCommands.d.ts +15 -19
  50. package/dist/features/extraConsoleCommands/listCommands.d.ts.map +1 -1
  51. package/dist/features/extraConsoleCommands/listCommands.lua +34 -42
  52. package/dist/features/pause.d.ts +1 -1
  53. package/dist/features/pause.d.ts.map +1 -1
  54. package/dist/features/pause.lua +87 -8
  55. package/dist/features/persistentEntities.d.ts.map +1 -1
  56. package/dist/features/persistentEntities.lua +7 -7
  57. package/dist/features/pickupIndex.d.ts +19 -0
  58. package/dist/features/pickupIndex.d.ts.map +1 -0
  59. package/dist/features/pickupIndex.lua +197 -0
  60. package/dist/features/roomHistory.d.ts +24 -0
  61. package/dist/features/roomHistory.d.ts.map +1 -0
  62. package/dist/features/roomHistory.lua +89 -0
  63. package/dist/functions/collectibles.d.ts +26 -13
  64. package/dist/functions/collectibles.d.ts.map +1 -1
  65. package/dist/functions/collectibles.lua +26 -13
  66. package/dist/functions/color.d.ts +10 -0
  67. package/dist/functions/color.d.ts.map +1 -1
  68. package/dist/functions/color.lua +24 -0
  69. package/dist/functions/entities.d.ts +3 -3
  70. package/dist/functions/entities.d.ts.map +1 -1
  71. package/dist/functions/entities.lua +8 -3
  72. package/dist/functions/gridEntities.d.ts +4 -22
  73. package/dist/functions/gridEntities.d.ts.map +1 -1
  74. package/dist/functions/gridEntities.lua +4 -61
  75. package/dist/functions/isaacAPIClass.d.ts +64 -0
  76. package/dist/functions/isaacAPIClass.d.ts.map +1 -1
  77. package/dist/functions/isaacAPIClass.lua +84 -1
  78. package/dist/functions/kColor.d.ts +10 -0
  79. package/dist/functions/kColor.d.ts.map +1 -1
  80. package/dist/functions/kColor.lua +24 -0
  81. package/dist/functions/map.d.ts +2 -0
  82. package/dist/functions/map.d.ts.map +1 -1
  83. package/dist/functions/map.lua +7 -0
  84. package/dist/functions/npcs.d.ts +2 -2
  85. package/dist/functions/npcs.lua +2 -2
  86. package/dist/functions/pickupVariants.d.ts +2 -2
  87. package/dist/functions/pickupVariants.d.ts.map +1 -1
  88. package/dist/functions/pickupVariants.lua +2 -2
  89. package/dist/functions/playerCenter.lua +2 -2
  90. package/dist/functions/playerIndex.d.ts +0 -3
  91. package/dist/functions/playerIndex.d.ts.map +1 -1
  92. package/dist/functions/playerIndex.lua +4 -23
  93. package/dist/functions/random.d.ts +1 -1
  94. package/dist/functions/random.lua +1 -1
  95. package/dist/functions/rockAlt.d.ts +28 -0
  96. package/dist/functions/rockAlt.d.ts.map +1 -0
  97. package/dist/functions/rockAlt.lua +140 -0
  98. package/dist/functions/roomData.d.ts +3 -2
  99. package/dist/functions/roomData.d.ts.map +1 -1
  100. package/dist/functions/roomData.lua +3 -2
  101. package/dist/functions/rooms.d.ts +6 -6
  102. package/dist/functions/rooms.lua +6 -6
  103. package/dist/functions/set.d.ts +2 -0
  104. package/dist/functions/set.d.ts.map +1 -1
  105. package/dist/functions/set.lua +6 -0
  106. package/dist/functions/stage.d.ts +1 -0
  107. package/dist/functions/stage.d.ts.map +1 -1
  108. package/dist/functions/stage.lua +4 -0
  109. package/dist/functions/vector.d.ts +11 -0
  110. package/dist/functions/vector.d.ts.map +1 -1
  111. package/dist/functions/vector.lua +23 -0
  112. package/dist/index.d.ts +4 -0
  113. package/dist/index.d.ts.map +1 -1
  114. package/dist/index.lua +31 -0
  115. package/dist/initCustomCallbacks.d.ts.map +1 -1
  116. package/dist/initCustomCallbacks.lua +6 -0
  117. package/dist/initFeatures.d.ts.map +1 -1
  118. package/dist/initFeatures.lua +6 -0
  119. package/dist/interfaces/AddCallbackParameterCustom.d.ts +4 -0
  120. package/dist/interfaces/AddCallbackParameterCustom.d.ts.map +1 -1
  121. package/dist/interfaces/RoomDescription.d.ts +14 -0
  122. package/dist/interfaces/RoomDescription.d.ts.map +1 -0
  123. package/dist/interfaces/RoomDescription.lua +2 -0
  124. package/dist/objects/callbackRegisterFunctions.d.ts.map +1 -1
  125. package/dist/objects/callbackRegisterFunctions.lua +6 -0
  126. package/dist/types/CollectibleIndex.d.ts +1 -1
  127. package/dist/types/PickupIndex.d.ts +17 -0
  128. package/dist/types/PickupIndex.d.ts.map +1 -0
  129. package/dist/types/PickupIndex.lua +2 -0
  130. package/dist/types/PlayerIndex.d.ts +1 -1
  131. package/dist/upgradeMod.d.ts.map +1 -1
  132. package/package.json +2 -2
  133. package/src/callbacks/postGridEntityCustomRender.ts +44 -0
  134. package/src/callbacks/postGridEntityCustomUpdate.ts +44 -0
  135. package/src/callbacks/postNewRoomEarly.ts +2 -2
  136. package/src/callbacks/postPickupInitFirst.ts +3 -32
  137. package/src/callbacks/postPlayerReorderedCallbacks.ts +3 -3
  138. package/src/callbacks/reorderedCallbacks.ts +9 -8
  139. package/src/callbacks/subscriptions/postGridEntityCustomRender.ts +41 -0
  140. package/src/callbacks/subscriptions/postGridEntityCustomUpdate.ts +41 -0
  141. package/src/constants.ts +1 -9
  142. package/src/constantsFirstLast.ts +16 -0
  143. package/src/enums/ModCallbackCustom.ts +33 -8
  144. package/src/enums/private/SerializationBrand.ts +1 -1
  145. package/src/features/collectibleItemPoolType.ts +3 -3
  146. package/src/features/customGridEntity.ts +27 -2
  147. package/src/features/customTrapdoor/blackSprite.ts +11 -5
  148. package/src/features/customTrapdoor/customTrapdoorConstants.ts +2 -2
  149. package/src/features/customTrapdoor/init.ts +7 -5
  150. package/src/features/customTrapdoor/touched.ts +59 -39
  151. package/src/features/deployJSONRoom.ts +4 -4
  152. package/src/features/extraConsoleCommands/exports.ts +4 -3
  153. package/src/features/extraConsoleCommands/init.ts +18 -14
  154. package/src/features/extraConsoleCommands/listCommands.ts +38 -43
  155. package/src/features/pause.ts +97 -7
  156. package/src/features/persistentEntities.ts +9 -8
  157. package/src/features/pickupIndex.ts +257 -0
  158. package/src/features/playerInventory.ts +2 -2
  159. package/src/features/roomHistory.ts +113 -0
  160. package/src/features/saveDataManager/main.ts +2 -2
  161. package/src/features/taintedLazarusPlayers.ts +5 -5
  162. package/src/functions/collectibles.ts +26 -13
  163. package/src/functions/color.ts +22 -0
  164. package/src/functions/entities.ts +6 -3
  165. package/src/functions/gridEntities.ts +4 -56
  166. package/src/functions/isaacAPIClass.ts +106 -1
  167. package/src/functions/kColor.ts +22 -0
  168. package/src/functions/map.ts +10 -0
  169. package/src/functions/npcs.ts +2 -2
  170. package/src/functions/pickupVariants.ts +2 -2
  171. package/src/functions/playerCenter.ts +2 -2
  172. package/src/functions/playerIndex.ts +8 -21
  173. package/src/functions/random.ts +1 -1
  174. package/src/functions/rockAlt.ts +117 -0
  175. package/src/functions/roomData.ts +3 -2
  176. package/src/functions/rooms.ts +6 -6
  177. package/src/functions/set.ts +7 -1
  178. package/src/functions/stage.ts +10 -1
  179. package/src/functions/vector.ts +23 -0
  180. package/src/index.ts +4 -0
  181. package/src/initCustomCallbacks.ts +4 -0
  182. package/src/initFeatures.ts +4 -0
  183. package/src/interfaces/AddCallbackParameterCustom.ts +4 -0
  184. package/src/interfaces/RoomDescription.ts +19 -0
  185. package/src/objects/callbackRegisterFunctions.ts +6 -0
  186. package/src/types/CollectibleIndex.ts +1 -1
  187. package/src/types/PickupIndex.ts +15 -0
  188. package/src/types/PlayerIndex.ts +1 -1
  189. package/src/upgradeMod.ts +2 -1
@@ -1,6 +1,8 @@
1
1
  import { SerializationBrand } from "../enums/private/SerializationBrand";
2
2
  import { SerializationType } from "../enums/SerializationType";
3
3
  import { isaacAPIClassEquals, isIsaacAPIClassOfType } from "./isaacAPIClass";
4
+ import { getRandom } from "./random";
5
+ import { getRandomSeed, isRNG, newRNG } from "./rng";
4
6
  import { copyValuesToTable, getNumbersFromTable, tableHasKeys } from "./table";
5
7
  import { isTable } from "./types";
6
8
 
@@ -105,6 +107,26 @@ export function copyColor(
105
107
  }
106
108
  }
107
109
 
110
+ /**
111
+ * Helper function to get a random color.
112
+ *
113
+ * @param seedOrRNG Optional. The `Seed` or `RNG` object to use. If an `RNG` object is provided, the
114
+ * `RNG.Next` method will be called. Default is `getRandomSeed()`.
115
+ * @param alpha Optional. The alpha value to use. Default is 1.
116
+ */
117
+ export function getRandomColor(
118
+ seedOrRNG: Seed | RNG = getRandomSeed(),
119
+ alpha = 1,
120
+ ): Color {
121
+ const rng = isRNG(seedOrRNG) ? seedOrRNG : newRNG(seedOrRNG);
122
+
123
+ const r = getRandom(rng);
124
+ const g = getRandom(rng);
125
+ const b = getRandom(rng);
126
+
127
+ return Color(r, g, b, alpha);
128
+ }
129
+
108
130
  /** Helper function to check if something is an instantiated Color object. */
109
131
  export function isColor(object: unknown): object is Color {
110
132
  return isIsaacAPIClassOfType(object, OBJECT_NAME);
@@ -7,6 +7,7 @@ import { getIsaacAPIClassName } from "./isaacAPIClass";
7
7
  import { getRandom } from "./random";
8
8
  import { isRNG, newRNG } from "./rng";
9
9
  import { isPrimitive } from "./types";
10
+ import { isVector, vectorToString } from "./vector";
10
11
 
11
12
  /**
12
13
  * Helper function to count the number of entities in room. Use this over the vanilla
@@ -130,10 +131,10 @@ export function getEntities(
130
131
 
131
132
  /**
132
133
  * Helper function to get all the fields on an entity. For example, this is useful for comparing it
133
- * to another entity later.
134
+ * to another entity later. (One option is to use the `logTableDifferences` function for this.)
134
135
  *
135
- * This function will only get fields that are equal to booleans, numbers, or strings, as comparing
136
- * other types is non-trivial.
136
+ * This function will only get fields that are equal to booleans, numbers, or strings, or Vectors,
137
+ * as comparing other types is non-trivial.
137
138
  */
138
139
  export function getEntityFields(
139
140
  entity: Entity,
@@ -187,6 +188,8 @@ function setPrimitiveEntityFields(
187
188
  const value = entity[indexKey];
188
189
  if (isPrimitive(value)) {
189
190
  entityFields.set(indexKey, value);
191
+ } else if (isVector(value)) {
192
+ entityFields.set(indexKey, vectorToString(value));
190
193
  }
191
194
  }
192
195
  }
@@ -19,7 +19,6 @@ import {
19
19
  import { BACKDROP_TYPE_TO_ROCK_ALT_TYPE } from "../objects/backdropTypeToRockAltType";
20
20
  import { AnyGridEntity } from "../types/AnyGridEntity";
21
21
  import { isCircleIntersectingRectangle } from "./math";
22
- import { getRandomSeed } from "./rng";
23
22
  import { roomUpdateSafe } from "./rooms";
24
23
  import { clearSprite } from "./sprites";
25
24
  import { isNumber } from "./types";
@@ -95,8 +94,8 @@ export function getAllGridIndexes(): int[] {
95
94
  * Gets the entities that have a hitbox that overlaps with any part of the square that the grid
96
95
  * entity is on.
97
96
  *
98
- * Note that this function will not work properly in the PostNewRoom callback, since entities do not
99
- * have collision yet in that callback.
97
+ * Note that this function will not work properly in the `POST_NEW_ROOM` callback, since entities do
98
+ * not have collision yet in that callback.
100
99
  */
101
100
  export function getCollidingEntitiesWithGridEntity(
102
101
  gridEntity: GridEntity,
@@ -488,7 +487,7 @@ export function removeAllMatchingGridEntities(
488
487
  * generally a good idea because if the room is not updated, you will be unable to
489
488
  * spawn another grid entity on the same tile until a frame has passed. However,
490
489
  * 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.
490
+ * so set this to false if you need to run this function multiple times.
492
491
  * @param cap Optional. If specified, will only remove the given amount of entities.
493
492
  * @returns An array of the entities that were removed.
494
493
  */
@@ -527,7 +526,7 @@ export function removeGridEntities<T extends AnyGridEntity>(
527
526
  * generally a good idea because if the room is not updated, you will be unable to
528
527
  * spawn another grid entity on the same tile until a frame has passed. However,
529
528
  * 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.
529
+ * so set this to false if you need to run this function multiple times.
531
530
  */
532
531
  export function removeGridEntity(
533
532
  gridEntityOrGridIndex: GridEntity | int,
@@ -654,57 +653,6 @@ export function spawnGridEntityWithVariant(
654
653
  return gridEntity;
655
654
  }
656
655
 
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
656
  /**
709
657
  * Helper function to spawn a Void Portal. This is more complicated than simply spawning a trapdoor
710
658
  * with the appropriate variant, as the game does not give it the correct sprite automatically.
@@ -1,4 +1,5 @@
1
1
  import { IsaacAPIClass } from "../types/private/IsaacAPIClass";
2
+ import { trimPrefix } from "./string";
2
3
  import { isString, isUserdata } from "./types";
3
4
 
4
5
  /**
@@ -9,6 +10,10 @@ import { isString, isUserdata } from "./types";
9
10
  *
10
11
  * Returns undefined if the object is not of type `userdata` or if the "__type" metatable key does
11
12
  * not exist.
13
+ *
14
+ * In some cases, Isaac classes can be a read-only. If this is the case, the "__type" field will be
15
+ * prepended with "const ". This function will always strip this prefix, if it exists. For example,
16
+ * the class name returned for "const Vector" will be "Vector".
12
17
  */
13
18
  export function getIsaacAPIClassName(object: unknown): string | undefined {
14
19
  if (!isUserdata(object)) {
@@ -27,7 +32,40 @@ export function getIsaacAPIClassName(object: unknown): string | undefined {
27
32
  return undefined;
28
33
  }
29
34
 
30
- return classType;
35
+ return trimPrefix(classType, "const ");
36
+ }
37
+
38
+ /** Helper function to detect if a variable is of type `EntityBomb`. */
39
+ export function isBomb(variable: unknown): variable is EntityBomb {
40
+ return getIsaacAPIClassName(variable) === "EntityBomb";
41
+ }
42
+
43
+ /** Helper function to detect if a variable is of type `GridEntityDoor`. */
44
+ export function isDoor(variable: unknown): variable is GridEntityDoor {
45
+ return getIsaacAPIClassName(variable) === "GridEntityDoor";
46
+ }
47
+
48
+ /** Helper function to detect if a variable is of type `EntityEffect`. */
49
+ export function isEffect(variable: unknown): variable is EntityEffect {
50
+ return getIsaacAPIClassName(variable) === "EntityEffect";
51
+ }
52
+
53
+ /**
54
+ * Helper function to detect if a variable is of type `Entity`. This will return false for child
55
+ * classes such as `EntityPlayer` or `EntityTear`.
56
+ */
57
+ export function isEntity(variable: unknown): variable is Entity {
58
+ return getIsaacAPIClassName(variable) === "Entity";
59
+ }
60
+
61
+ /** Helper function to detect if a variable is of type `EntityEffect`. */
62
+ export function isFamiliar(variable: unknown): variable is EntityFamiliar {
63
+ return getIsaacAPIClassName(variable) === "EntityEffect";
64
+ }
65
+
66
+ /** Helper function to detect if a variable is of type `GridEntity`. */
67
+ export function isGridEntity(variable: unknown): variable is GridEntity {
68
+ return getIsaacAPIClassName(variable) === "GridEntity";
31
69
  }
32
70
 
33
71
  /**
@@ -51,6 +89,73 @@ export function isIsaacAPIClassOfType(
51
89
  );
52
90
  }
53
91
 
92
+ /** Helper function to detect if a variable is of type `EntityKnife`. */
93
+ export function isKnife(variable: unknown): variable is EntityKnife {
94
+ return getIsaacAPIClassName(variable) === "EntityKnife";
95
+ }
96
+
97
+ /** Helper function to detect if a variable is of type `EntityLaser`. */
98
+ export function isLaser(variable: unknown): variable is EntityLaser {
99
+ return getIsaacAPIClassName(variable) === "EntityLaser";
100
+ }
101
+
102
+ /** Helper function to detect if a variable is of type `EntityNPC`. */
103
+ export function isNPC(variable: unknown): variable is EntityNPC {
104
+ return getIsaacAPIClassName(variable) === "EntityNPC";
105
+ }
106
+
107
+ /** Helper function to detect if a variable is of type `EntityPickup`. */
108
+ export function isPickup(variable: unknown): variable is EntityPickup {
109
+ return getIsaacAPIClassName(variable) === "EntityPickup";
110
+ }
111
+
112
+ /** Helper function to detect if a variable is of type `GridEntityPit`. */
113
+ export function isPit(variable: unknown): variable is GridEntityPit {
114
+ return getIsaacAPIClassName(variable) === "GridEntityPit";
115
+ }
116
+
117
+ /** Helper function to detect if a variable is of type `EntityPlayer`. */
118
+ export function isPlayer(variable: unknown): variable is EntityPlayer {
119
+ return getIsaacAPIClassName(variable) === "EntityPlayer";
120
+ }
121
+
122
+ /** Helper function to detect if a variable is of type `GridEntityPoop`. */
123
+ export function isPoop(variable: unknown): variable is GridEntityPoop {
124
+ return getIsaacAPIClassName(variable) === "GridEntityPoop";
125
+ }
126
+
127
+ /** Helper function to detect if a variable is of type `GridEntityPressurePlate`. */
128
+ export function isPressurePlate(
129
+ variable: unknown,
130
+ ): variable is GridEntityPressurePlate {
131
+ return getIsaacAPIClassName(variable) === "GridEntityPressurePlate";
132
+ }
133
+
134
+ /** Helper function to detect if a variable is of type `EntityProjectile`. */
135
+ export function isProjectile(variable: unknown): variable is EntityProjectile {
136
+ return getIsaacAPIClassName(variable) === "EntityProjectile";
137
+ }
138
+
139
+ /** Helper function to detect if a variable is of type `GridEntityRock`. */
140
+ export function isRock(variable: unknown): variable is GridEntityRock {
141
+ return getIsaacAPIClassName(variable) === "GridEntityRock";
142
+ }
143
+
144
+ /** Helper function to detect if a variable is of type `GridEntitySpikes`. */
145
+ export function isSpikes(variable: unknown): variable is GridEntitySpikes {
146
+ return getIsaacAPIClassName(variable) === "GridEntitySpikes";
147
+ }
148
+
149
+ /** Helper function to detect if a variable is of type `GridEntityTNT`. */
150
+ export function isTNT(variable: unknown): variable is GridEntityTNT {
151
+ return getIsaacAPIClassName(variable) === "GridEntityTNT";
152
+ }
153
+
154
+ /** Helper function to detect if a variable is of type `EntityTear`. */
155
+ export function isTear(variable: unknown): variable is EntityTear {
156
+ return getIsaacAPIClassName(variable) === "EntityTear";
157
+ }
158
+
54
159
  /**
55
160
  * Helper function to check if an instantiated Isaac API class is equal to another one of the same
56
161
  * type. You must provide the list of keys to check for.
@@ -1,6 +1,8 @@
1
1
  import { SerializationBrand } from "../enums/private/SerializationBrand";
2
2
  import { SerializationType } from "../enums/SerializationType";
3
3
  import { isaacAPIClassEquals, isIsaacAPIClassOfType } from "./isaacAPIClass";
4
+ import { getRandom } from "./random";
5
+ import { getRandomSeed, isRNG, newRNG } from "./rng";
4
6
  import { copyValuesToTable, getNumbersFromTable, tableHasKeys } from "./table";
5
7
  import { isTable } from "./types";
6
8
 
@@ -98,6 +100,26 @@ export function copyKColor(
98
100
  }
99
101
  }
100
102
 
103
+ /**
104
+ * Helper function to get a random color.
105
+ *
106
+ * @param seedOrRNG Optional. The `Seed` or `RNG` object to use. If an `RNG` object is provided, the
107
+ * `RNG.Next` method will be called. Default is `getRandomSeed()`.
108
+ * @param alpha Optional. The alpha value to use. Default is 1.
109
+ */
110
+ export function getRandomKColor(
111
+ seedOrRNG: Seed | RNG = getRandomSeed(),
112
+ alpha = 1,
113
+ ): KColor {
114
+ const rng = isRNG(seedOrRNG) ? seedOrRNG : newRNG(seedOrRNG);
115
+
116
+ const r = getRandom(rng);
117
+ const g = getRandom(rng);
118
+ const b = getRandom(rng);
119
+
120
+ return KColor(r, g, b, alpha);
121
+ }
122
+
101
123
  /** Helper function to check if something is an instantiated KColor object. */
102
124
  export function isKColor(object: unknown): object is KColor {
103
125
  return isIsaacAPIClassOfType(object, OBJECT_NAME);
@@ -1,3 +1,5 @@
1
+ import { sumArray } from "./array";
2
+
1
3
  /** Helper function to copy a map. (You can also use a Map constructor to accomplish this task.) */
2
4
  export function copyMap<K, V>(oldMap: Map<K, V>): Map<K, V> {
3
5
  const newMap = new Map<K, V>();
@@ -54,3 +56,11 @@ export function getMapPartialMatch<T>(
54
56
 
55
57
  return [matchingKey, value];
56
58
  }
59
+
60
+ /** Helper function to sum every value in a map together. */
61
+ export function sumMap(
62
+ map: Map<unknown, number> | ReadonlyMap<unknown, number>,
63
+ ): number {
64
+ const values = [...map.values()];
65
+ return sumArray(values);
66
+ }
@@ -152,8 +152,8 @@ export function isRaglingDeathPatch(npc: EntityNPC): boolean {
152
152
 
153
153
  /**
154
154
  * The base game `EntityNPC.FireProjectiles` method does not return anything, which is a problem in
155
- * situations where you need to work with the fired projectiles. This function invokes that method,
156
- * and then returns the projectiles that were spawned.
155
+ * situations where you need to work with the fired projectiles. This function runs that method, and
156
+ * then returns the projectiles that were spawned.
157
157
  *
158
158
  * @param npc The EntityNPC firing projectiles.
159
159
  * @param position The starting position of the projectiles.
@@ -18,12 +18,12 @@ export function isKey(pickup: EntityPickup): pickup is EntityPickupKey {
18
18
  }
19
19
 
20
20
  /** For `PickupVariant.BOMB` (40) */
21
- export function isBomb(pickup: EntityPickup): pickup is EntityPickupBomb {
21
+ export function isBombPickup(pickup: EntityPickup): pickup is EntityPickupBomb {
22
22
  return pickup.Variant === PickupVariant.BOMB;
23
23
  }
24
24
 
25
25
  /** For `PickupVariant.POOP` (42) */
26
- export function isPoop(pickup: EntityPickup): pickup is EntityPickupPoop {
26
+ export function isPoopPickup(pickup: EntityPickup): pickup is EntityPickupPoop {
27
27
  return pickup.Variant === PickupVariant.POOP;
28
28
  }
29
29
 
@@ -6,7 +6,7 @@ import {
6
6
  } from "../constants";
7
7
  import { getPlayerFamiliars } from "./familiars";
8
8
  import { getCircleDiscretizedPoints } from "./math";
9
- import { getPlayers } from "./playerIndex";
9
+ import { getAllPlayers } from "./playerIndex";
10
10
 
11
11
  const CIRCLE_RADIUS_BETWEEN_PLAYERS = 50;
12
12
 
@@ -25,7 +25,7 @@ export function movePlayersToCenter(): void {
25
25
  ? NEW_FLOOR_STARTING_POSITION_GREED_MODE
26
26
  : NEW_FLOOR_STARTING_POSITION_NORMAL_MODE;
27
27
 
28
- const players = getPlayers();
28
+ const players = getAllPlayers();
29
29
  const firstPlayer = players[0];
30
30
  if (firstPlayer === undefined) {
31
31
  return;
@@ -72,9 +72,6 @@ export function getPlayerFromIndex(
72
72
  * Instead, we use the `EntityPlayer.GetCollectibleRNG` method with an arbitrary value of Sad Onion
73
73
  * (1). This works even if the player does not have any Sad Onions.
74
74
  *
75
- * Since the RNG value is the same for both Tainted Lazarus and Dead Tainted Lazarus, we revert to
76
- * using the RNG of The Inner Eye (2) for Dead Tainted Lazarus.
77
- *
78
75
  * Note that by default, this returns the same index for both The Forgotten and The Soul. (Even
79
76
  * though they are technically different characters, they share the same inventory and InitSeed.) If
80
77
  * this is not desired, pass true for the `differentiateForgottenAndSoul` argument, and the RNG of
@@ -94,13 +91,13 @@ export function getPlayerIndex(
94
91
  // We can safely ignore the player's character because regardless of whether the main player ends
95
92
  // up being The Forgotten or The Soul, the collectible RNG values will be the same. The
96
93
  // `EntityPlayer.IsSubPlayer` method can return true for Dead Tainted Lazarus during the
97
- // PostPlayerInit callback, but since we fall back to the player in the case of
94
+ // `POST_PLAYER_INIT` callback, but since we fall back to the player in the case of
98
95
  // "getSubPlayerParent" returning undefined, we do not need to explicitly check for this case.
99
96
  let playerToUse = player;
100
97
  const isSubPlayer = player.IsSubPlayer();
101
98
  if (isSubPlayer) {
102
99
  // The "getSubPlayerParent" function will return undefined in the situation where we are on Dead
103
- // Tainted Lazarus in the PostPlayerInit callback.
100
+ // Tainted Lazarus in the `POST_PLAYER_INIT` callback.
104
101
  const playerParent = getSubPlayerParent(player as EntitySubPlayer);
105
102
  if (playerParent !== undefined) {
106
103
  playerToUse = playerParent;
@@ -123,23 +120,13 @@ function getPlayerIndexCollectibleType(
123
120
  ) {
124
121
  const character = player.GetPlayerType();
125
122
 
126
- switch (character) {
127
- // 17
128
- case PlayerType.THE_SOUL: {
129
- return differentiateForgottenAndSoul
130
- ? CollectibleType.SPOON_BENDER
131
- : DEFAULT_COLLECTIBLE_TYPE;
132
- }
133
-
134
- // 38
135
- case PlayerType.LAZARUS_2_B: {
136
- return CollectibleType.INNER_EYE;
137
- }
138
-
139
- default: {
140
- return DEFAULT_COLLECTIBLE_TYPE;
141
- }
123
+ if (character === PlayerType.THE_SOUL) {
124
+ return differentiateForgottenAndSoul
125
+ ? CollectibleType.INNER_EYE
126
+ : DEFAULT_COLLECTIBLE_TYPE;
142
127
  }
128
+
129
+ return DEFAULT_COLLECTIBLE_TYPE;
143
130
  }
144
131
 
145
132
  /**
@@ -45,7 +45,7 @@ export function getRandomFloat(
45
45
  /**
46
46
  * This returns a random integer between min and max. It is inclusive on both ends.
47
47
  *
48
- * Note that this function will invoke the `Next` method on the `RNG` object before returning the
48
+ * Note that this function will run the `Next` method on the `RNG` object before returning the
49
49
  * random number.
50
50
  *
51
51
  * For example:
@@ -0,0 +1,117 @@
1
+ import {
2
+ CoinSubType,
3
+ CollectibleType,
4
+ TrinketType,
5
+ } from "isaac-typescript-definitions";
6
+ import { DISTANCE_OF_GRID_TILE } from "../constants";
7
+ import { RockAltType } from "../enums/RockAltType";
8
+ import { spawnCoinWithSeed, spawnTrinketWithSeed } from "./pickupsSpecific";
9
+ import { getRandom } from "./random";
10
+ import { getRandomSeed, isRNG, newRNG } from "./rng";
11
+ import { spawnCollectible } from "./spawnCollectible";
12
+ import { repeat } from "./utils";
13
+ import { getRandomVector } from "./vector";
14
+
15
+ /**
16
+ * Helper function for emulating what happens when a vanilla `GridEntityType.ROCK_ALT` grid entity
17
+ * breaks.
18
+ *
19
+ * Note that most of the time, this function will do nothing, similar to how most of the time, when
20
+ * an individual urn is destroyed, nothing will spawn.
21
+ *
22
+ * For the purposes of spawning collectibles, this function assumes that the player has not seen the
23
+ * collectible yet in the current run. In vanilla, it is only possible to get a e.g. Quarter if the
24
+ * collectible still exists in the Treasure Room pool.
25
+ *
26
+ * The logic in this function is based on the rewards listed on the wiki:
27
+ * https://bindingofisaacrebirth.fandom.com/wiki/Rocks
28
+ *
29
+ * @param position The place to spawn the reward.
30
+ * @param rockAltType The type of reward to spawn. For example, `RockAltType.URN` will have a chance
31
+ * at spawning coins and spiders.
32
+ * @param seedOrRNG Optional. The `Seed` or `RNG` object to use. If an `RNG` object is provided, the
33
+ * `RNG.Next` method will be called. Default is `getRandomSeed()`. Normally, you
34
+ * should pass the `InitSeed` of the grid entity that was broken.
35
+ * @returns Whether or not this function spawned something.
36
+ */
37
+ export function spawnRockAltReward(
38
+ position: Vector,
39
+ rockAltType: RockAltType,
40
+ seedOrRNG: Seed | RNG = getRandomSeed(),
41
+ ): boolean {
42
+ const rng = isRNG(seedOrRNG) ? seedOrRNG : newRNG(seedOrRNG);
43
+ const chance = getRandom(rng);
44
+
45
+ switch (rockAltType) {
46
+ case RockAltType.URN: {
47
+ let totalChance = 0;
48
+
49
+ // Nothing. (68.00%)
50
+ totalChance += 0.68;
51
+ if (chance < totalChance) {
52
+ return false;
53
+ }
54
+
55
+ // One or two random coins. (9.44%)
56
+ totalChance += 0.0944;
57
+ if (chance < totalChance) {
58
+ const numCoinsChance = getRandom(rng);
59
+ const numCoins = numCoinsChance < 0.5 ? 1 : 2;
60
+ repeat(numCoins, () => {
61
+ const velocity = getRandomVector(rng);
62
+ spawnCoinWithSeed(CoinSubType.NULL, position, rng, velocity);
63
+ });
64
+ return true;
65
+ }
66
+
67
+ // Swallowed Penny. (2.50%)
68
+ totalChance += 0.025;
69
+ if (chance < totalChance) {
70
+ spawnTrinketWithSeed(TrinketType.SWALLOWED_PENNY, position, rng);
71
+ }
72
+
73
+ // A Quarter. (0.50%)
74
+ totalChance += 0.005;
75
+ if (chance < totalChance) {
76
+ spawnCollectible(CollectibleType.QUARTER, position, rng);
77
+ }
78
+
79
+ // One or two spiders. (19.48%)
80
+ totalChance += 0.1948;
81
+ if (chance < totalChance) {
82
+ const numSpidersChance = getRandom(rng);
83
+ const numSpiders = numSpidersChance < 0.5 ? 1 : 2;
84
+ repeat(numSpiders, () => {
85
+ const randomVector = getRandomVector(rng);
86
+ const length = DISTANCE_OF_GRID_TILE * 3;
87
+ const offset = randomVector.mul(length);
88
+ const targetPos = position.add(offset);
89
+ EntityNPC.ThrowSpider(position, undefined, targetPos, false, 0);
90
+ });
91
+ }
92
+
93
+ // TODO
94
+ return false;
95
+ }
96
+
97
+ case RockAltType.MUSHROOM: {
98
+ // TODO
99
+ return false;
100
+ }
101
+
102
+ case RockAltType.SKULL: {
103
+ // TODO
104
+ return false;
105
+ }
106
+
107
+ case RockAltType.POLYP: {
108
+ // TODO
109
+ return false;
110
+ }
111
+
112
+ case RockAltType.BUCKET: {
113
+ // TODO
114
+ return false;
115
+ }
116
+ }
117
+ }
@@ -187,9 +187,10 @@ export function getRoomVariant(roomGridIndex?: int): int {
187
187
  }
188
188
 
189
189
  /**
190
- * Note that the room visited count will be inaccurate during the period before the PostNewRoom
190
+ * Note that the room visited count will be inaccurate during the period before the `POST_NEW_ROOM`
191
191
  * callback has fired (i.e. when entities are initializing and performing their first update). This
192
- * is because the variable is only incremented immediately before the PostNewRoom callback fires.
192
+ * is because the variable is only incremented immediately before the `POST_NEW_ROOM` callback
193
+ * fires.
193
194
  *
194
195
  * @param roomGridIndex Optional. Default is the current room index.
195
196
  */
@@ -566,9 +566,9 @@ export function roomGridIndexToXY(roomGridIndex: int): [x: int, y: int] {
566
566
  }
567
567
 
568
568
  /**
569
- * If the `Room.Update` method is called in a PostNewRoom callback, then some entities will slide
570
- * around (such as the player). Since those entity velocities are already at zero, setting them to
571
- * zero will have no effect. Thus, a generic solution is to record all of the entity
569
+ * If the `Room.Update` method is called in a `POST_NEW_ROOM` callback, then some entities will
570
+ * slide around (such as the player). Since those entity velocities are already at zero, setting
571
+ * them to zero will have no effect. Thus, a generic solution is to record all of the entity
572
572
  * positions/velocities before updating the room, and then restore those positions/velocities.
573
573
  */
574
574
  export function roomUpdateSafe(): void {
@@ -585,9 +585,9 @@ export function roomUpdateSafe(): void {
585
585
  }
586
586
 
587
587
  /**
588
- * Helper function to convert an uncleared room to a cleared room in the PostNewRoom callback. This
589
- * is useful because if enemies are removed in this callback, a room drop will be awarded and the
590
- * doors will start closed and then open.
588
+ * Helper function to convert an uncleared room to a cleared room in the `POST_NEW_ROOM` callback.
589
+ * This is useful because if enemies are removed in this callback, a room drop will be awarded and
590
+ * the doors will start closed and then open.
591
591
  */
592
592
  export function setRoomCleared(): void {
593
593
  const room = game.GetRoom();
@@ -1,4 +1,4 @@
1
- import { getArrayCombinations, getRandomArrayElement } from "./array";
1
+ import { getArrayCombinations, getRandomArrayElement, sumArray } from "./array";
2
2
  import { getRandomSeed } from "./rng";
3
3
 
4
4
  /**
@@ -122,3 +122,9 @@ export function getSortedSetValues<T>(set: Set<T> | ReadonlySet<T>): T[] {
122
122
 
123
123
  return array;
124
124
  }
125
+
126
+ /** Helper function to sum every value in a set together. */
127
+ export function sumSet(set: Set<number> | ReadonlySet<number>): number {
128
+ const values = [...set.values()];
129
+ return sumArray(values);
130
+ }
@@ -1,4 +1,9 @@
1
- import { LevelStage, RoomType, StageType } from "isaac-typescript-definitions";
1
+ import {
2
+ GameStateFlag,
3
+ LevelStage,
4
+ RoomType,
5
+ StageType,
6
+ } from "isaac-typescript-definitions";
2
7
  import { game } from "../cachedClasses";
3
8
  import { ROOM_TYPE_GOTO_PREFIXES } from "../objects/roomTypeGotoPrefixes";
4
9
  import { STAGE_TYPE_SUFFIXES } from "../objects/stageTypeSuffixes";
@@ -116,6 +121,10 @@ export function isRepentanceStage(stageType: StageType): boolean {
116
121
  );
117
122
  }
118
123
 
124
+ export function onAscent(): boolean {
125
+ return game.GetStateFlag(GameStateFlag.BACKWARDS_PATH);
126
+ }
127
+
119
128
  export function onCathedral(): boolean {
120
129
  const level = game.GetLevel();
121
130
  const stage = level.GetStage();