isaacscript-common 75.2.1 → 76.1.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 (43) hide show
  1. package/dist/classes/features/other/DeployJSONRoom.d.ts +0 -1
  2. package/dist/classes/features/other/DeployJSONRoom.d.ts.map +1 -1
  3. package/dist/classes/features/other/DeployJSONRoom.lua +6 -4
  4. package/dist/classes/features/other/SpawnRockAltRewards.lua +14 -14
  5. package/dist/classes/features/other/extraConsoleCommands/commands.lua +3 -3
  6. package/dist/enums/ISCFeature.d.ts +12 -14
  7. package/dist/enums/ISCFeature.d.ts.map +1 -1
  8. package/dist/enums/ISCFeature.lua +12 -16
  9. package/dist/features.d.ts +12 -18
  10. package/dist/features.d.ts.map +1 -1
  11. package/dist/features.lua +1 -9
  12. package/dist/functions/cards.d.ts +8 -0
  13. package/dist/functions/cards.d.ts.map +1 -1
  14. package/dist/functions/cards.lua +22 -0
  15. package/dist/functions/collectibles.d.ts +8 -0
  16. package/dist/functions/collectibles.d.ts.map +1 -1
  17. package/dist/functions/collectibles.lua +19 -0
  18. package/dist/functions/spawnCollectible.d.ts +28 -6
  19. package/dist/functions/spawnCollectible.d.ts.map +1 -1
  20. package/dist/functions/spawnCollectible.lua +50 -7
  21. package/dist/functions/tears.d.ts +6 -2
  22. package/dist/functions/tears.d.ts.map +1 -1
  23. package/dist/functions/tears.lua +6 -2
  24. package/dist/index.rollup.d.ts +63 -106
  25. package/dist/isaacscript-common.lua +225 -331
  26. package/package.json +1 -1
  27. package/src/classes/features/other/DeployJSONRoom.ts +4 -12
  28. package/src/classes/features/other/SpawnRockAltRewards.ts +14 -14
  29. package/src/classes/features/other/extraConsoleCommands/commands.ts +3 -3
  30. package/src/enums/ISCFeature.ts +0 -2
  31. package/src/features.ts +1 -15
  32. package/src/functions/cards.ts +19 -0
  33. package/src/functions/collectibles.ts +25 -0
  34. package/src/functions/spawnCollectible.ts +58 -8
  35. package/src/functions/tears.ts +6 -2
  36. package/dist/classes/features/other/PreventCollectibleRotation.d.ts +0 -28
  37. package/dist/classes/features/other/PreventCollectibleRotation.d.ts.map +0 -1
  38. package/dist/classes/features/other/PreventCollectibleRotation.lua +0 -112
  39. package/dist/classes/features/other/SpawnCollectible.d.ts +0 -58
  40. package/dist/classes/features/other/SpawnCollectible.d.ts.map +0 -1
  41. package/dist/classes/features/other/SpawnCollectible.lua +0 -68
  42. package/src/classes/features/other/PreventCollectibleRotation.ts +0 -205
  43. package/src/classes/features/other/SpawnCollectible.ts +0 -124
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "isaacscript-common",
3
- "version": "75.2.1",
3
+ "version": "76.1.0",
4
4
  "description": "Helper functions and features for IsaacScript mods.",
5
5
  "keywords": [
6
6
  "isaac",
@@ -27,13 +27,13 @@ import { log } from "../../../functions/log";
27
27
  import { isRNG, newRNG } from "../../../functions/rng";
28
28
  import { gridCoordinatesToWorldPosition } from "../../../functions/roomGrid";
29
29
  import { setRoomCleared, setRoomUncleared } from "../../../functions/rooms";
30
+ import { spawnCollectible } from "../../../functions/spawnCollectible";
30
31
  import { asCollectibleType, asNumber } from "../../../functions/types";
31
32
  import { assertDefined } from "../../../functions/utils";
32
33
  import type { JSONRoom } from "../../../interfaces/JSONRoomsFile";
33
34
  import { ReadonlySet } from "../../../types/ReadonlySet";
34
35
  import { Feature } from "../../private/Feature";
35
36
  import type { PreventGridEntityRespawn } from "./PreventGridEntityRespawn";
36
- import type { SpawnCollectible } from "./SpawnCollectible";
37
37
 
38
38
  const GRID_ENTITY_XML_TYPE_SET = new ReadonlySet<GridEntityXMLType>(
39
39
  GRID_ENTITY_XML_TYPE_VALUES,
@@ -41,22 +41,14 @@ const GRID_ENTITY_XML_TYPE_SET = new ReadonlySet<GridEntityXMLType>(
41
41
 
42
42
  export class DeployJSONRoom extends Feature {
43
43
  private readonly preventGridEntityRespawn: PreventGridEntityRespawn;
44
- private readonly spawnCollectible: SpawnCollectible;
45
44
 
46
45
  /** @internal */
47
- constructor(
48
- preventGridEntityRespawn: PreventGridEntityRespawn,
49
- spawnCollectible: SpawnCollectible,
50
- ) {
46
+ constructor(preventGridEntityRespawn: PreventGridEntityRespawn) {
51
47
  super();
52
48
 
53
- this.featuresUsed = [
54
- ISCFeature.PREVENT_GRID_ENTITY_RESPAWN,
55
- ISCFeature.SPAWN_COLLECTIBLE,
56
- ];
49
+ this.featuresUsed = [ISCFeature.PREVENT_GRID_ENTITY_RESPAWN];
57
50
 
58
51
  this.preventGridEntityRespawn = preventGridEntityRespawn;
59
- this.spawnCollectible = spawnCollectible;
60
52
  }
61
53
 
62
54
  private spawnAllEntities(
@@ -173,7 +165,7 @@ export class DeployJSONRoom extends Feature {
173
165
  variant === asNumber(PickupVariant.COLLECTIBLE)
174
166
  ) {
175
167
  const options = roomType === RoomType.ANGEL;
176
- entity = this.spawnCollectible.spawnCollectible(
168
+ entity = spawnCollectible(
177
169
  asCollectibleType(subType),
178
170
  position,
179
171
  seed,
@@ -29,7 +29,7 @@ import {
29
29
  import { fireProjectilesInCircle } from "../../../functions/projectiles";
30
30
  import { getRandom } from "../../../functions/random";
31
31
  import { isRNG, newRNG } from "../../../functions/rng";
32
- import { spawnCollectibleUnsafe } from "../../../functions/spawnCollectible";
32
+ import { spawnCollectible } from "../../../functions/spawnCollectible";
33
33
  import { repeat } from "../../../functions/utils";
34
34
  import { getRandomVector, isVector } from "../../../functions/vector";
35
35
  import { Feature } from "../../private/Feature";
@@ -189,7 +189,7 @@ export class SpawnRockAltRewards extends Feature {
189
189
  ItemPoolType.DEVIL,
190
190
  );
191
191
  if (stillInPools) {
192
- spawnCollectibleUnsafe(CollectibleType.QUARTER, position, rng);
192
+ spawnCollectible(CollectibleType.QUARTER, position, rng);
193
193
  return true;
194
194
  }
195
195
 
@@ -253,7 +253,7 @@ export class SpawnRockAltRewards extends Feature {
253
253
  ItemPoolType.SECRET,
254
254
  );
255
255
  if (stillInPools) {
256
- spawnCollectibleUnsafe(CollectibleType.WAVY_CAP, position, rng);
256
+ spawnCollectible(CollectibleType.WAVY_CAP, position, rng);
257
257
  return true;
258
258
  }
259
259
  }
@@ -275,17 +275,17 @@ export class SpawnRockAltRewards extends Feature {
275
275
  collectibleChance < 0.5
276
276
  ? CollectibleType.MAGIC_MUSHROOM // 12
277
277
  : CollectibleType.MINI_MUSH; // 71
278
- spawnCollectibleUnsafe(collectibleType, position, rng);
278
+ spawnCollectible(collectibleType, position, rng);
279
279
  return true;
280
280
  }
281
281
 
282
282
  if (magicMushroomStillInPools) {
283
- spawnCollectibleUnsafe(CollectibleType.MINI_MUSH, position, rng);
283
+ spawnCollectible(CollectibleType.MINI_MUSH, position, rng);
284
284
  return true;
285
285
  }
286
286
 
287
287
  if (miniMushStillInPools) {
288
- spawnCollectibleUnsafe(CollectibleType.MAGIC_MUSHROOM, position, rng);
288
+ spawnCollectible(CollectibleType.MAGIC_MUSHROOM, position, rng);
289
289
  return true;
290
290
  }
291
291
 
@@ -347,17 +347,17 @@ export class SpawnRockAltRewards extends Feature {
347
347
  collectibleChance < 0.5
348
348
  ? CollectibleType.GHOST_BABY // 163
349
349
  : CollectibleType.DRY_BABY; // 265
350
- spawnCollectibleUnsafe(collectibleType, position, rng);
350
+ spawnCollectible(collectibleType, position, rng);
351
351
  return true;
352
352
  }
353
353
 
354
354
  if (ghostBabyStillInPools) {
355
- spawnCollectibleUnsafe(CollectibleType.DRY_BABY, position, rng);
355
+ spawnCollectible(CollectibleType.DRY_BABY, position, rng);
356
356
  return true;
357
357
  }
358
358
 
359
359
  if (dryBabyStillInPools) {
360
- spawnCollectibleUnsafe(CollectibleType.GHOST_BABY, position, rng);
360
+ spawnCollectible(CollectibleType.GHOST_BABY, position, rng);
361
361
  return true;
362
362
  }
363
363
 
@@ -418,17 +418,17 @@ export class SpawnRockAltRewards extends Feature {
418
418
  collectibleChance < 0.5
419
419
  ? CollectibleType.PLACENTA // 218
420
420
  : CollectibleType.BLOOD_CLOT; // 254
421
- spawnCollectibleUnsafe(collectibleType, position, rng);
421
+ spawnCollectible(collectibleType, position, rng);
422
422
  return true;
423
423
  }
424
424
 
425
425
  if (placentaStillInPools) {
426
- spawnCollectibleUnsafe(CollectibleType.PLACENTA, position, rng);
426
+ spawnCollectible(CollectibleType.PLACENTA, position, rng);
427
427
  return true;
428
428
  }
429
429
 
430
430
  if (bloodClotStillInPools) {
431
- spawnCollectibleUnsafe(CollectibleType.BLOOD_CLOT, position, rng);
431
+ spawnCollectible(CollectibleType.BLOOD_CLOT, position, rng);
432
432
  return true;
433
433
  }
434
434
 
@@ -493,7 +493,7 @@ export class SpawnRockAltRewards extends Feature {
493
493
  ItemPoolType.TREASURE,
494
494
  );
495
495
  if (stillInPools) {
496
- spawnCollectibleUnsafe(CollectibleType.LEECH, position, rng);
496
+ spawnCollectible(CollectibleType.LEECH, position, rng);
497
497
  return true;
498
498
  }
499
499
 
@@ -578,7 +578,7 @@ export class SpawnRockAltRewards extends Feature {
578
578
  ItemPoolType.TREASURE,
579
579
  );
580
580
  if (stillInPools) {
581
- spawnCollectibleUnsafe(CollectibleType.POOP, position, rng);
581
+ spawnCollectible(CollectibleType.POOP, position, rng);
582
582
  return true;
583
583
  }
584
584
 
@@ -120,7 +120,7 @@ import { gridCoordinatesToWorldPosition } from "../../../../functions/roomGrid";
120
120
  import { reloadRoom as reloadRoomFunction } from "../../../../functions/roomTransition";
121
121
  import { changeRoom } from "../../../../functions/rooms";
122
122
  import { onSetSeed, restart, setUnseeded } from "../../../../functions/run";
123
- import { spawnCollectibleUnsafe } from "../../../../functions/spawnCollectible";
123
+ import { spawnCollectible as spawnCollectibleFunc } from "../../../../functions/spawnCollectible";
124
124
  import { onStage, setStage } from "../../../../functions/stage";
125
125
  import { getMapPartialMatch } from "../../../../functions/string";
126
126
  import { getGoldenTrinketType } from "../../../../functions/trinkets";
@@ -1493,7 +1493,7 @@ export function spawnCollectible(params: string): void {
1493
1493
 
1494
1494
  const roomClass = game.GetRoom();
1495
1495
  const centerPos = roomClass.GetCenterPos();
1496
- spawnCollectibleUnsafe(collectibleType, centerPos, undefined);
1496
+ spawnCollectibleFunc(collectibleType, centerPos, undefined);
1497
1497
  }
1498
1498
 
1499
1499
  /**
@@ -1538,7 +1538,7 @@ export function spawnCollectibleAt(params: string): void {
1538
1538
  }
1539
1539
 
1540
1540
  const collectibleType = asCollectibleType(collectibleTypeNumber);
1541
- spawnCollectibleUnsafe(collectibleType, gridIndex, undefined);
1541
+ spawnCollectibleFunc(collectibleType, gridIndex, undefined);
1542
1542
  }
1543
1543
 
1544
1544
  /** Alias for the `spawnGoldenTrinket` command. */
@@ -46,7 +46,6 @@ export enum ISCFeature {
46
46
  PONY_DETECTION,
47
47
  PRESS_INPUT,
48
48
  PREVENT_CHILD_ENTITIES,
49
- PREVENT_COLLECTIBLE_ROTATION,
50
49
  PREVENT_GRID_ENTITY_RESPAWN,
51
50
  ROOM_CLEAR_FRAME,
52
51
  ROOM_HISTORY,
@@ -55,7 +54,6 @@ export enum ISCFeature {
55
54
  RUN_NEXT_RUN,
56
55
  SAVE_DATA_MANAGER,
57
56
  SPAWN_ALT_ROCK_REWARDS,
58
- SPAWN_COLLECTIBLE,
59
57
  STAGE_HISTORY,
60
58
  START_AMBUSH,
61
59
  TAINTED_LAZARUS_PLAYERS,
package/src/features.ts CHANGED
@@ -43,7 +43,6 @@ import { PlayerCollectibleTracking } from "./classes/features/other/PlayerCollec
43
43
  import { PonyDetection } from "./classes/features/other/PonyDetection";
44
44
  import { PressInput } from "./classes/features/other/PressInput";
45
45
  import { PreventChildEntities } from "./classes/features/other/PreventChildEntities";
46
- import { PreventCollectibleRotation } from "./classes/features/other/PreventCollectibleRotation";
47
46
  import { PreventGridEntityRespawn } from "./classes/features/other/PreventGridEntityRespawn";
48
47
  import { RoomClearFrame } from "./classes/features/other/RoomClearFrame";
49
48
  import { RoomHistory } from "./classes/features/other/RoomHistory";
@@ -51,7 +50,6 @@ import { RunInNFrames } from "./classes/features/other/RunInNFrames";
51
50
  import { RunNextRoom } from "./classes/features/other/RunNextRoom";
52
51
  import { RunNextRun } from "./classes/features/other/RunNextRun";
53
52
  import { SaveDataManager } from "./classes/features/other/SaveDataManager";
54
- import { SpawnCollectible } from "./classes/features/other/SpawnCollectible";
55
53
  import { SpawnRockAltRewards } from "./classes/features/other/SpawnRockAltRewards";
56
54
  import { StageHistory } from "./classes/features/other/StageHistory";
57
55
  import { StartAmbush } from "./classes/features/other/StartAmbush";
@@ -111,7 +109,6 @@ export interface ISCFeatureToClass {
111
109
  [ISCFeature.PONY_DETECTION]: PonyDetection;
112
110
  [ISCFeature.PRESS_INPUT]: PressInput;
113
111
  [ISCFeature.PREVENT_CHILD_ENTITIES]: PreventChildEntities;
114
- [ISCFeature.PREVENT_COLLECTIBLE_ROTATION]: PreventCollectibleRotation;
115
112
  [ISCFeature.PREVENT_GRID_ENTITY_RESPAWN]: PreventGridEntityRespawn;
116
113
  [ISCFeature.ROOM_CLEAR_FRAME]: RoomClearFrame;
117
114
  [ISCFeature.ROOM_HISTORY]: RoomHistory;
@@ -120,7 +117,6 @@ export interface ISCFeatureToClass {
120
117
  [ISCFeature.RUN_NEXT_RUN]: RunNextRun;
121
118
  [ISCFeature.SAVE_DATA_MANAGER]: SaveDataManager;
122
119
  [ISCFeature.SPAWN_ALT_ROCK_REWARDS]: SpawnRockAltRewards;
123
- [ISCFeature.SPAWN_COLLECTIBLE]: SpawnCollectible;
124
120
  [ISCFeature.STAGE_HISTORY]: StageHistory;
125
121
  [ISCFeature.START_AMBUSH]: StartAmbush;
126
122
  [ISCFeature.TAINTED_LAZARUS_PLAYERS]: TaintedLazarusPlayers;
@@ -158,17 +154,12 @@ export function getFeatures(
158
154
  roomHistory,
159
155
  saveDataManager,
160
156
  );
161
- const preventCollectibleRotation = new PreventCollectibleRotation(
162
- pickupIndexCreation,
163
- runInNFrames,
164
- );
165
157
 
166
158
  const customGridEntities = new CustomGridEntities(runInNFrames);
167
159
  const moddedElementSets = new ModdedElementSets(moddedElementDetection);
168
160
  const itemPoolDetection = new ItemPoolDetection(moddedElementSets);
169
161
  const pause = new Pause(disableInputs);
170
162
  const preventGridEntityRespawn = new PreventGridEntityRespawn(runInNFrames);
171
- const spawnCollectible = new SpawnCollectible(preventCollectibleRotation);
172
163
 
173
164
  const customTrapdoors = new CustomTrapdoors(
174
165
  customGridEntities,
@@ -272,10 +263,7 @@ export function getFeatures(
272
263
  ),
273
264
  [ISCFeature.CUSTOM_TRAPDOORS]: customTrapdoors,
274
265
  [ISCFeature.DEBUG_DISPLAY]: new DebugDisplay(mod),
275
- [ISCFeature.DEPLOY_JSON_ROOM]: new DeployJSONRoom(
276
- preventGridEntityRespawn,
277
- spawnCollectible,
278
- ),
266
+ [ISCFeature.DEPLOY_JSON_ROOM]: new DeployJSONRoom(preventGridEntityRespawn),
279
267
  [ISCFeature.DISABLE_ALL_SOUND]: disableAllSound,
280
268
  [ISCFeature.DISABLE_INPUTS]: disableInputs,
281
269
  [ISCFeature.EDEN_STARTING_STATS_HEALTH]: new EdenStartingStatsHealth(),
@@ -295,7 +283,6 @@ export function getFeatures(
295
283
  [ISCFeature.PONY_DETECTION]: ponyDetection,
296
284
  [ISCFeature.PRESS_INPUT]: pressInput,
297
285
  [ISCFeature.PREVENT_CHILD_ENTITIES]: new PreventChildEntities(),
298
- [ISCFeature.PREVENT_COLLECTIBLE_ROTATION]: preventCollectibleRotation,
299
286
  [ISCFeature.PREVENT_GRID_ENTITY_RESPAWN]: preventGridEntityRespawn,
300
287
  [ISCFeature.ROOM_CLEAR_FRAME]: roomClearFrame,
301
288
  [ISCFeature.ROOM_HISTORY]: roomHistory,
@@ -306,7 +293,6 @@ export function getFeatures(
306
293
  [ISCFeature.SPAWN_ALT_ROCK_REWARDS]: new SpawnRockAltRewards(
307
294
  itemPoolDetection,
308
295
  ),
309
- [ISCFeature.SPAWN_COLLECTIBLE]: spawnCollectible,
310
296
  [ISCFeature.STAGE_HISTORY]: stageHistory,
311
297
  [ISCFeature.START_AMBUSH]: new StartAmbush(runInNFrames),
312
298
  [ISCFeature.TAINTED_LAZARUS_PLAYERS]: new TaintedLazarusPlayers(),
@@ -1,5 +1,6 @@
1
1
  import type { CardType } from "isaac-typescript-definitions";
2
2
  import { ItemConfigCardType, UseFlag } from "isaac-typescript-definitions";
3
+ import { POCKET_ITEM_SLOT_VALUES } from "../arrays/cachedEnumValues";
3
4
  import { itemConfig } from "../core/cachedClasses";
4
5
  import { LAST_VANILLA_CARD_TYPE } from "../core/constantsFirstLast";
5
6
  import {
@@ -79,6 +80,24 @@ export function getItemConfigCardType(
79
80
  return itemConfigCard.CardType;
80
81
  }
81
82
 
83
+ /**
84
+ * Helper function to check if a player is holding a specific card in one of their pocket item
85
+ * slots.
86
+ *
87
+ * This function is variadic, meaning that you can pass as many cards as you want to check for. The
88
+ * function will return true if the player has any of the cards.
89
+ */
90
+ export function hasCard(
91
+ player: EntityPlayer,
92
+ ...cardTypes: CardType[]
93
+ ): boolean {
94
+ const cardTypesSet = new Set(cardTypes);
95
+ return POCKET_ITEM_SLOT_VALUES.some((pocketItemSlot) => {
96
+ const cardType = player.GetCard(pocketItemSlot);
97
+ return cardTypesSet.has(cardType);
98
+ });
99
+ }
100
+
82
101
  /**
83
102
  * Returns true for card types that have the following item config card type:
84
103
  *
@@ -608,6 +608,31 @@ export function newCollectibleSprite(
608
608
  return sprite;
609
609
  }
610
610
 
611
+ /**
612
+ * Helper function to remove the rotation behavior from a collectible. This will happen by default
613
+ * when collectibles are spawned when playing as Tainted Isaac or when having Binge Eater.
614
+ *
615
+ * Under the hood, this is accomplished by morphing the collectible with the `ignoreModifiers`
616
+ * argument set to true.
617
+ */
618
+ export function preventCollectibleRotation(collectible: EntityPickup): void {
619
+ if (!isCollectible(collectible)) {
620
+ const entityID = getEntityID(collectible);
621
+ error(
622
+ `The "preventCollectibleRotation" function was given a non-collectible: ${entityID}`,
623
+ );
624
+ }
625
+
626
+ collectible.Morph(
627
+ collectible.Type,
628
+ collectible.Variant,
629
+ collectible.SubType,
630
+ true,
631
+ true,
632
+ true,
633
+ );
634
+ }
635
+
611
636
  /**
612
637
  * Helper function to remove all pickup delay on a collectible. By default, collectibles have a 20
613
638
  * frame delay before they can be picked up by a player.
@@ -1,11 +1,16 @@
1
+ import type { ItemPoolType } from "isaac-typescript-definitions";
1
2
  import {
2
3
  CollectibleType,
3
4
  PickupVariant,
4
5
  PlayerType,
5
6
  } from "isaac-typescript-definitions";
7
+ import { game } from "../core/cachedClasses";
6
8
  import { VectorZero } from "../core/constants";
7
9
  import { isQuestCollectible } from "./collectibleTag";
8
- import { setCollectibleEmpty } from "./collectibles";
10
+ import {
11
+ preventCollectibleRotation,
12
+ setCollectibleEmpty,
13
+ } from "./collectibles";
9
14
  import { spawnPickupWithSeed } from "./entitiesSpecific";
10
15
  import { anyPlayerIs } from "./players";
11
16
  import { getRandomSeed, isRNG } from "./rng";
@@ -14,11 +19,8 @@ import { getRandomSeed, isRNG } from "./rng";
14
19
  * Helper function to spawn a collectible.
15
20
  *
16
21
  * Use this instead of the `Game.Spawn` method because it handles the cases of Tainted Keeper
17
- * collectibles costing coins.
18
- *
19
- * This function is unsafe because it will not correctly handle quest items being rotated by Tainted
20
- * Isaac's rotation mechanic. To handle that, use the `spawnCollectible` helper function instead
21
- * (which is provided by `ISCFeature.SPAWN_COLLECTIBLE`).
22
+ * collectibles costing coins and prevents quest items from being rotated by Tainted Isaac's
23
+ * rotation mechanic.
22
24
  *
23
25
  * If you want to spawn an unseeded collectible, you must explicitly pass `undefined` to the
24
26
  * `seedOrRNG` parameter.
@@ -34,7 +36,7 @@ import { getRandomSeed, isRNG } from "./rng";
34
36
  * Tainted Keeper. Default is false.
35
37
  * @param spawner Optional.
36
38
  */
37
- export function spawnCollectibleUnsafe(
39
+ export function spawnCollectible(
38
40
  collectibleType: CollectibleType,
39
41
  positionOrGridIndex: Vector | int,
40
42
  seedOrRNG: Seed | RNG | undefined,
@@ -56,6 +58,10 @@ export function spawnCollectibleUnsafe(
56
58
  spawner,
57
59
  ) as EntityPickupCollectible;
58
60
 
61
+ if (isQuestCollectible(collectible)) {
62
+ preventCollectibleRotation(collectible);
63
+ }
64
+
59
65
  if (options) {
60
66
  collectible.OptionsPickupIndex = 1;
61
67
  }
@@ -80,6 +86,50 @@ export function spawnCollectibleUnsafe(
80
86
  return collectible;
81
87
  }
82
88
 
89
+ /**
90
+ * Helper function to spawn a collectible from a specific item pool.
91
+ *
92
+ * Use this instead of the `Game.Spawn` method because it handles the cases of Tainted Keeper
93
+ * collectibles costing coins and prevents quest items from being rotated by Tainted Isaac's
94
+ * rotation mechanic.
95
+ *
96
+ * If you want to spawn an unseeded collectible, you must explicitly pass `undefined` to the
97
+ * `seedOrRNG` parameter.
98
+ *
99
+ * In order to use this function, you must upgrade your mod with `ISCFeature.SPAWN_COLLECTIBLE`.
100
+ *
101
+ * @param itemPoolType The item pool to draw the collectible type from.
102
+ * @param positionOrGridIndex The position or grid index to spawn the collectible at.
103
+ * @param seedOrRNG The `Seed` or `RNG` object to use. If an `RNG` object is provided, the
104
+ * `RNG.Next` method will be called. If `undefined` is provided, it will default to
105
+ * a random seed.
106
+ * @param options Optional. Set to true to make the collectible a "There's Options" style
107
+ * collectible. Default is false.
108
+ * @param forceFreeItem Optional. Set to true to disable the logic that gives the item a price for
109
+ * Tainted Keeper. Default is false.
110
+ * @param spawner Optional.
111
+ */
112
+ export function spawnCollectibleFromPool(
113
+ itemPoolType: ItemPoolType,
114
+ positionOrGridIndex: Vector | int,
115
+ seedOrRNG: Seed | RNG | undefined,
116
+ options = false,
117
+ forceFreeItem = false,
118
+ spawner?: Entity,
119
+ ): EntityPickupCollectible {
120
+ const itemPool = game.GetItemPool();
121
+ const collectibleType = itemPool.GetCollectible(itemPoolType);
122
+
123
+ return spawnCollectible(
124
+ collectibleType,
125
+ positionOrGridIndex,
126
+ seedOrRNG,
127
+ options,
128
+ forceFreeItem,
129
+ spawner,
130
+ );
131
+ }
132
+
83
133
  /**
84
134
  * Helper function to spawn an empty collectible. Doing this is tricky since spawning a collectible
85
135
  * with `CollectibleType.NULL` will result in spawning a collectible with a random type from the
@@ -102,7 +152,7 @@ export function spawnEmptyCollectible(
102
152
  positionOrGridIndex: Vector | int,
103
153
  seedOrRNG: Seed | RNG | undefined,
104
154
  ): EntityPickup {
105
- const collectible = spawnCollectibleUnsafe(
155
+ const collectible = spawnCollectible(
106
156
  CollectibleType.BROKEN_SHOVEL_1,
107
157
  positionOrGridIndex,
108
158
  seedOrRNG,
@@ -48,8 +48,12 @@ export function getTearsStat(fireDelay: float): float {
48
48
  * Helper function to check if a tear hit an enemy. A tear is considered to be missed if it hit the
49
49
  * ground, a wall, or a grid entity.
50
50
  *
51
- * Under the hood, this function uses the `Entity.IsDead` method to determine this. (Tears will not
52
- * die if they hit an enemy, but they will die if they hit a wall or object.)
51
+ * Note that tears are still considered to be missed if they hit a poop or fire, so you may want to
52
+ * handle those separately using the `POST_GRID_ENTITY_COLLISION` and `POST_ENTITY_COLLISION`
53
+ * callbacks, respectively.
54
+ *
55
+ * Under the hood, this function uses the `Entity.IsDead` method. (Tears will not die if they hit an
56
+ * enemy, but they will die if they hit a wall or object.)
53
57
  */
54
58
  export function isMissedTear(tear: EntityTear): boolean {
55
59
  return tear.IsDead();
@@ -1,28 +0,0 @@
1
- import { CollectibleType } from "isaac-typescript-definitions";
2
- import { Feature } from "../../private/Feature";
3
- export declare class PreventCollectibleRotation extends Feature {
4
- private readonly pickupIndexCreation;
5
- private readonly runInNFrames;
6
- private readonly preUseItem;
7
- /**
8
- * Soul of Isaac causes items to flip. We assume that the player deliberately wants to roll a
9
- * quest item, so we delete all tracked items in the current room.
10
- */
11
- private readonly postUseCardSoulOfIsaac;
12
- private readonly postDiceRoomActivated;
13
- private readonly postPickupChanged;
14
- /**
15
- * Helper function to prevent a collectible from being affected by Tainted Isaac's rotation
16
- * mechanic. (This mechanic also happens from Glitched Crown and Binge Eater.) This is useful
17
- * because quest items that are manually spawned by mods will be automatically be affected by this
18
- * mechanic.
19
- *
20
- * It is required to pass the intended collectible type to this function since it is possible for
21
- * collectibles to rotate on the first frame that they are spawned.
22
- *
23
- * In order to use this function, you must upgrade your mod with
24
- * `ISCFeature.PREVENT_COLLECTIBLE_ROTATION`.
25
- */
26
- preventCollectibleRotation(collectible: EntityPickup, collectibleType: CollectibleType): void;
27
- }
28
- //# sourceMappingURL=PreventCollectibleRotation.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"PreventCollectibleRotation.d.ts","sourceRoot":"","sources":["../../../../src/classes/features/other/PreventCollectibleRotation.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,eAAe,EAIhB,MAAM,8BAA8B,CAAC;AAatC,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAwBhD,qBAAa,0BAA2B,SAAQ,OAAO;IAIrD,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAsB;IAC1D,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAe;IAmC5C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAQzB;IAEF;;;OAGG;IAGH,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAMrC;IAGF,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAOpC;IAGF,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAuChC;IAEF;;;;;;;;;;;OAWG;IAEI,0BAA0B,CAC/B,WAAW,EAAE,YAAY,EACzB,eAAe,EAAE,eAAe,GAC/B,IAAI;CA6BR"}
@@ -1,112 +0,0 @@
1
- local ____lualib = require("lualib_bundle")
2
- local __TS__New = ____lualib.__TS__New
3
- local Map = ____lualib.Map
4
- local __TS__Class = ____lualib.__TS__Class
5
- local __TS__ClassExtends = ____lualib.__TS__ClassExtends
6
- local __TS__DecorateLegacy = ____lualib.__TS__DecorateLegacy
7
- local ____exports = {}
8
- local ____isaac_2Dtypescript_2Ddefinitions = require("isaac-typescript-definitions")
9
- local CardType = ____isaac_2Dtypescript_2Ddefinitions.CardType
10
- local CollectibleType = ____isaac_2Dtypescript_2Ddefinitions.CollectibleType
11
- local DiceFloorSubType = ____isaac_2Dtypescript_2Ddefinitions.DiceFloorSubType
12
- local ModCallback = ____isaac_2Dtypescript_2Ddefinitions.ModCallback
13
- local PickupVariant = ____isaac_2Dtypescript_2Ddefinitions.PickupVariant
14
- local ____cachedClasses = require("core.cachedClasses")
15
- local game = ____cachedClasses.game
16
- local ____decorators = require("decorators")
17
- local Exported = ____decorators.Exported
18
- local ____ISCFeature = require("enums.ISCFeature")
19
- local ISCFeature = ____ISCFeature.ISCFeature
20
- local ____ModCallbackCustom = require("enums.ModCallbackCustom")
21
- local ModCallbackCustom = ____ModCallbackCustom.ModCallbackCustom
22
- local ____collectibles = require("functions.collectibles")
23
- local setCollectibleSubType = ____collectibles.setCollectibleSubType
24
- local ____entities = require("functions.entities")
25
- local getEntityID = ____entities.getEntityID
26
- local ____frames = require("functions.frames")
27
- local onGameFrame = ____frames.onGameFrame
28
- local ____pickupVariants = require("functions.pickupVariants")
29
- local isCollectible = ____pickupVariants.isCollectible
30
- local ____pickupsSpecific = require("functions.pickupsSpecific")
31
- local getCollectibles = ____pickupsSpecific.getCollectibles
32
- local ____types = require("functions.types")
33
- local asCollectibleType = ____types.asCollectibleType
34
- local ____ReadonlySet = require("types.ReadonlySet")
35
- local ReadonlySet = ____ReadonlySet.ReadonlySet
36
- local ____Feature = require("classes.private.Feature")
37
- local Feature = ____Feature.Feature
38
- local ROLL_COLLECTIBLE_TYPES = __TS__New(ReadonlySet, {CollectibleType.D6, CollectibleType.ETERNAL_D6, CollectibleType.SPINDOWN_DICE})
39
- local ROLL_FLOOR_DICE_FLOOR_SUB_TYPES = __TS__New(ReadonlySet, {DiceFloorSubType.FOUR_PIP, DiceFloorSubType.SIX_PIP})
40
- local v = {run = {
41
- trackedCollectibles = __TS__New(Map),
42
- rollGameFrame = nil
43
- }}
44
- ____exports.PreventCollectibleRotation = __TS__Class()
45
- local PreventCollectibleRotation = ____exports.PreventCollectibleRotation
46
- PreventCollectibleRotation.name = "PreventCollectibleRotation"
47
- __TS__ClassExtends(PreventCollectibleRotation, Feature)
48
- function PreventCollectibleRotation.prototype.____constructor(self, pickupIndexCreation, runInNFrames)
49
- Feature.prototype.____constructor(self)
50
- self.v = v
51
- self.preUseItem = function(____, collectibleType)
52
- if ROLL_COLLECTIBLE_TYPES:has(collectibleType) then
53
- v.run.rollGameFrame = game:GetFrameCount()
54
- end
55
- return nil
56
- end
57
- self.postUseCardSoulOfIsaac = function()
58
- local collectibles = getCollectibles(nil)
59
- for ____, collectible in ipairs(collectibles) do
60
- local pickupIndex = self.pickupIndexCreation:getPickupIndex(collectible)
61
- v.run.trackedCollectibles:delete(pickupIndex)
62
- end
63
- end
64
- self.postDiceRoomActivated = function(____, _player, diceFloorSubType)
65
- if ROLL_FLOOR_DICE_FLOOR_SUB_TYPES:has(diceFloorSubType) then
66
- v.run.trackedCollectibles:clear()
67
- end
68
- end
69
- self.postPickupChanged = function(____, pickup, oldVariant, _oldSubType, newVariant, newSubType)
70
- if oldVariant ~= PickupVariant.COLLECTIBLE or newVariant ~= PickupVariant.COLLECTIBLE then
71
- return
72
- end
73
- if asCollectibleType(nil, newSubType) == CollectibleType.NULL then
74
- return
75
- end
76
- local pickupIndex = self.pickupIndexCreation:getPickupIndex(pickup)
77
- local trackedCollectibleType = v.run.trackedCollectibles:get(pickupIndex)
78
- if trackedCollectibleType == nil then
79
- return
80
- end
81
- if v.run.rollGameFrame ~= nil and (onGameFrame(nil, v.run.rollGameFrame) or onGameFrame(nil, v.run.rollGameFrame + 1)) then
82
- v.run.trackedCollectibles:delete(pickupIndex)
83
- return
84
- end
85
- if trackedCollectibleType ~= asCollectibleType(nil, newSubType) then
86
- setCollectibleSubType(nil, pickup, trackedCollectibleType)
87
- end
88
- end
89
- self.featuresUsed = {ISCFeature.PICKUP_INDEX_CREATION, ISCFeature.RUN_IN_N_FRAMES}
90
- self.callbacksUsed = {{ModCallback.POST_USE_CARD, self.postUseCardSoulOfIsaac, {CardType.SOUL_OF_ISAAC}}, {ModCallback.PRE_USE_ITEM, self.preUseItem}}
91
- self.customCallbacksUsed = {{ModCallbackCustom.POST_DICE_ROOM_ACTIVATED, self.postDiceRoomActivated}, {ModCallbackCustom.POST_PICKUP_CHANGED, self.postPickupChanged}}
92
- self.pickupIndexCreation = pickupIndexCreation
93
- self.runInNFrames = runInNFrames
94
- end
95
- function PreventCollectibleRotation.prototype.preventCollectibleRotation(self, collectible, collectibleType)
96
- if not isCollectible(nil, collectible) then
97
- local entityID = getEntityID(nil, collectible)
98
- error("The \"preventCollectibleRotation\" function was given a non-collectible: " .. entityID)
99
- end
100
- local pickupIndex = self.pickupIndexCreation:getPickupIndex(collectible)
101
- v.run.trackedCollectibles:set(pickupIndex, collectibleType)
102
- if collectible.SubType ~= collectibleType then
103
- setCollectibleSubType(nil, collectible, collectibleType)
104
- end
105
- self.runInNFrames:runNextGameFrame(function()
106
- if collectible:Exists() and collectible.SubType ~= collectibleType then
107
- setCollectibleSubType(nil, collectible, collectibleType)
108
- end
109
- end)
110
- end
111
- __TS__DecorateLegacy({Exported}, PreventCollectibleRotation.prototype, "preventCollectibleRotation", true)
112
- return ____exports