isaacscript-common 8.4.4 → 8.5.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 (85) hide show
  1. package/dist/callbacks/postCursedTeleport.lua +4 -4
  2. package/dist/callbacks/postPlayerFatalDamage.lua +7 -7
  3. package/dist/callbacks/postSacrifice.lua +2 -2
  4. package/dist/callbacks/postTrinketBreak.lua +2 -2
  5. package/dist/callbacks/subscriptions/postPlayerFatalDamage.d.ts +2 -2
  6. package/dist/callbacks/subscriptions/postPlayerFatalDamage.d.ts.map +1 -1
  7. package/dist/callbacks/subscriptions/postPlayerFatalDamage.lua +4 -4
  8. package/dist/features/characterStats.d.ts.map +1 -1
  9. package/dist/features/characterStats.lua +1 -2
  10. package/dist/features/customGridEntity.d.ts.map +1 -1
  11. package/dist/features/customGridEntity.lua +3 -36
  12. package/dist/features/extraConsoleCommands/init.d.ts.map +1 -1
  13. package/dist/features/extraConsoleCommands/init.lua +1 -1
  14. package/dist/features/firstLast.d.ts +6 -3
  15. package/dist/features/firstLast.d.ts.map +1 -1
  16. package/dist/features/firstLast.lua +6 -3
  17. package/dist/functions/bosses.d.ts +5 -2
  18. package/dist/functions/bosses.d.ts.map +1 -1
  19. package/dist/functions/bosses.lua +11 -6
  20. package/dist/functions/collectibleCacheFlag.d.ts +1 -1
  21. package/dist/functions/collectibleCacheFlag.d.ts.map +1 -1
  22. package/dist/functions/collectibleCacheFlag.lua +1 -2
  23. package/dist/functions/collectibleSet.lua +32 -32
  24. package/dist/functions/collectibleTag.d.ts +1 -1
  25. package/dist/functions/collectibleTag.d.ts.map +1 -1
  26. package/dist/functions/collectibleTag.lua +1 -3
  27. package/dist/functions/eden.d.ts +1 -1
  28. package/dist/functions/eden.d.ts.map +1 -1
  29. package/dist/functions/eden.lua +1 -2
  30. package/dist/functions/flag.d.ts +1 -1
  31. package/dist/functions/flag.lua +1 -1
  32. package/dist/functions/flying.d.ts +1 -1
  33. package/dist/functions/flying.d.ts.map +1 -1
  34. package/dist/functions/flying.lua +5 -2
  35. package/dist/functions/input.d.ts +2 -2
  36. package/dist/functions/input.d.ts.map +1 -1
  37. package/dist/functions/input.lua +2 -4
  38. package/dist/functions/playerHealth.d.ts +93 -0
  39. package/dist/functions/playerHealth.d.ts.map +1 -1
  40. package/dist/functions/playerHealth.lua +216 -33
  41. package/dist/functions/players.d.ts +1 -111
  42. package/dist/functions/players.d.ts.map +1 -1
  43. package/dist/functions/players.lua +20 -279
  44. package/dist/functions/revive.d.ts +1 -1
  45. package/dist/functions/revive.d.ts.map +1 -1
  46. package/dist/functions/revive.lua +5 -4
  47. package/dist/functions/stats.d.ts +16 -0
  48. package/dist/functions/stats.d.ts.map +1 -1
  49. package/dist/functions/stats.lua +78 -0
  50. package/dist/functions/transformations.d.ts +1 -1
  51. package/dist/functions/transformations.d.ts.map +1 -1
  52. package/dist/functions/trinketCacheFlag.d.ts +1 -1
  53. package/dist/functions/trinketCacheFlag.d.ts.map +1 -1
  54. package/dist/functions/trinketCacheFlag.lua +1 -3
  55. package/dist/functions/trinketSet.lua +32 -32
  56. package/dist/index.d.ts +22 -33
  57. package/dist/sets/bossSets.d.ts +1 -0
  58. package/dist/sets/bossSets.d.ts.map +1 -1
  59. package/dist/sets/bossSets.lua +19 -0
  60. package/package.json +2 -2
  61. package/src/callbacks/postCursedTeleport.ts +7 -7
  62. package/src/callbacks/postPlayerFatalDamage.ts +9 -16
  63. package/src/callbacks/postSacrifice.ts +5 -5
  64. package/src/callbacks/postTrinketBreak.ts +5 -5
  65. package/src/callbacks/subscriptions/postPlayerFatalDamage.ts +9 -9
  66. package/src/features/characterStats.ts +1 -2
  67. package/src/features/customGridEntity.ts +0 -55
  68. package/src/features/extraConsoleCommands/init.ts +8 -1
  69. package/src/features/firstLast.ts +6 -3
  70. package/src/functions/bosses.ts +15 -6
  71. package/src/functions/collectibleCacheFlag.ts +3 -3
  72. package/src/functions/collectibleSet.ts +32 -32
  73. package/src/functions/collectibleTag.ts +2 -3
  74. package/src/functions/eden.ts +3 -3
  75. package/src/functions/flag.ts +1 -1
  76. package/src/functions/flying.ts +4 -4
  77. package/src/functions/input.ts +4 -5
  78. package/src/functions/playerHealth.ts +269 -7
  79. package/src/functions/players.ts +1 -348
  80. package/src/functions/revive.ts +6 -10
  81. package/src/functions/stats.ts +75 -0
  82. package/src/functions/transformations.ts +1 -1
  83. package/src/functions/trinketCacheFlag.ts +2 -3
  84. package/src/functions/trinketSet.ts +32 -32
  85. package/src/sets/bossSets.ts +24 -0
@@ -1,6 +1,5 @@
1
1
  import {
2
2
  ActiveSlot,
3
- CacheFlag,
4
3
  Challenge,
5
4
  CollectibleType,
6
5
  FamiliarVariant,
@@ -11,14 +10,8 @@ import {
11
10
  TrinketType,
12
11
  } from "isaac-typescript-definitions";
13
12
  import { game, itemConfig } from "../core/cachedClasses";
14
- import { HealthType } from "../enums/HealthType";
15
13
  import { getLastElement, sumArray } from "./array";
16
- import { countSetBits, getKBitOfN, getNumBitsOfN } from "./bitwise";
17
- import {
18
- getCharacterMaxHeartContainers,
19
- getCharacterName,
20
- isVanillaCharacter,
21
- } from "./characters";
14
+ import { getCharacterName, isVanillaCharacter } from "./characters";
22
15
  import { getCollectibleMaxCharges } from "./collectibles";
23
16
  import { getCollectibleArray } from "./collectibleSet";
24
17
  import { getEnumValues } from "./enums";
@@ -27,19 +20,9 @@ import {
27
20
  getPlayerIndexVanilla,
28
21
  getPlayers,
29
22
  } from "./playerIndex";
30
- import { addTearsStat } from "./tears";
31
23
  import { isNumber } from "./types";
32
24
  import { repeat } from "./utils";
33
25
 
34
- const STAT_CACHE_FLAGS_SET: ReadonlySet<CacheFlag> = new Set([
35
- CacheFlag.DAMAGE, // 1 << 0
36
- CacheFlag.FIRE_DELAY, // 1 << 1
37
- CacheFlag.SHOT_SPEED, // 1 << 2
38
- CacheFlag.RANGE, // 1 << 3
39
- CacheFlag.SPEED, // 1 << 4
40
- CacheFlag.LUCK, // 1 << 10
41
- ]);
42
-
43
26
  export function addCollectibleCostume(
44
27
  player: EntityPlayer,
45
28
  collectibleType: CollectibleType,
@@ -52,71 +35,6 @@ export function addCollectibleCostume(
52
35
  player.AddCostume(itemConfigItem, false);
53
36
  }
54
37
 
55
- /**
56
- * Helper function to add a stat to a player based on the `CacheFlag` provided. Call this function
57
- * from the `EVALUATE_CACHE` callback.
58
- *
59
- * Note that for `CacheFlag.FIRE_DELAY`, the "amount" argument will be interpreted as the tear stat
60
- * to add (and not the amount to mutate `EntityPlayer.MaxFireDelay` by).
61
- *
62
- * This function supports the following cache flags:
63
- * - CacheFlag.DAMAGE (1 << 0)
64
- * - CacheFlag.FIRE_DELAY (1 << 1)
65
- * - CacheFlag.SHOT_SPEED (1 << 2)
66
- * - CacheFlag.RANGE (1 << 3)
67
- * - CacheFlag.SPEED (1 << 4)
68
- * - CacheFlag.LUCK (1 << 10)
69
- */
70
- export function addStat(
71
- player: EntityPlayer,
72
- cacheFlag: CacheFlag,
73
- amount: number,
74
- ): void {
75
- if (!STAT_CACHE_FLAGS_SET.has(cacheFlag)) {
76
- error(
77
- `You cannot add a stat to a player with the cache flag of: ${cacheFlag}`,
78
- );
79
- }
80
-
81
- switch (cacheFlag) {
82
- // 1 << 0
83
- case CacheFlag.DAMAGE: {
84
- player.Damage += amount;
85
- break;
86
- }
87
-
88
- // 1 << 1
89
- case CacheFlag.FIRE_DELAY: {
90
- addTearsStat(player, amount);
91
- break;
92
- }
93
-
94
- // 1 << 2
95
- case CacheFlag.SHOT_SPEED: {
96
- player.ShotSpeed += amount;
97
- break;
98
- }
99
-
100
- // 1 << 3
101
- case CacheFlag.RANGE: {
102
- player.TearHeight += amount;
103
- break;
104
- }
105
-
106
- // 1 << 4
107
- case CacheFlag.SPEED: {
108
- player.MoveSpeed += amount;
109
- break;
110
- }
111
-
112
- // 1 << 10
113
- case CacheFlag.LUCK: {
114
- player.Luck += amount;
115
- break;
116
- }
117
- }
118
- }
119
-
120
38
  export function addTrinketCostume(
121
39
  player: EntityPlayer,
122
40
  trinketType: TrinketType,
@@ -173,45 +91,6 @@ export function canPlayerCrushRocks(player: EntityPlayer): boolean {
173
91
  );
174
92
  }
175
93
 
176
- /**
177
- * Returns whether or not all of the player's soul-heart-type hearts are black hearts.
178
- *
179
- * Note that this function does not consider red heart containers.
180
- *
181
- * For example:
182
- *
183
- * - If the player has one black heart, this function would return true.
184
- * - If the player has one soul heart and two black hearts, this function would return false.
185
- * - If the player has no black hearts, this function will return false.
186
- * - If the player has one red heart container and three black hearts, this function would return
187
- * true.
188
- */
189
- export function doesPlayerHaveAllBlackHearts(player: EntityPlayer): boolean {
190
- const soulHearts = getPlayerSoulHearts(player);
191
- const blackHearts = getPlayerBlackHearts(player);
192
-
193
- return blackHearts > 0 && soulHearts === 0;
194
- }
195
-
196
- /**
197
- * Returns whether or not all of the player's soul-heart-type hearts are soul hearts.
198
- *
199
- * Note that this function does not consider red heart containers.
200
- *
201
- * For example:
202
- *
203
- * - If the player has two soul hearts and one black heart, this function would return false.
204
- * - If the player has no soul hearts, this function will return false.
205
- * - If the player has one red heart container and three soul hearts, this function would return
206
- * true.
207
- */
208
- export function doesPlayerHaveAllSoulHearts(player: EntityPlayer): boolean {
209
- const soulHearts = getPlayerSoulHearts(player);
210
- const blackHearts = getPlayerBlackHearts(player);
211
-
212
- return soulHearts > 0 && blackHearts === 0;
213
- }
214
-
215
94
  /**
216
95
  * Helper function to find the active slot that the player has the corresponding collectible type
217
96
  * in. Returns undefined if the player does not have the collectible in any active slot.
@@ -324,39 +203,6 @@ export function getNewestPlayer(): EntityPlayer {
324
203
  return newestPlayer;
325
204
  }
326
205
 
327
- /**
328
- * Returns the number of slots that the player has remaining for new heart containers, accounting
329
- * for broken hearts. For example, if the player is Judas and has 1 red heart containers and 2 full
330
- * soul hearts and 3 broken hearts, then this function would return 6 (i.e. 12 - 1 - 2 - 3).
331
- */
332
- export function getPlayerAvailableHeartSlots(player: EntityPlayer): int {
333
- const maxHeartContainers = getPlayerMaxHeartContainers(player);
334
- const effectiveMaxHearts = player.GetEffectiveMaxHearts();
335
- const normalAndBoneHeartContainers = effectiveMaxHearts / 2;
336
- const soulHearts = player.GetSoulHearts();
337
- const soulHeartContainers = math.ceil(soulHearts / 2);
338
- const totalHeartContainers =
339
- normalAndBoneHeartContainers + soulHeartContainers;
340
- const brokenHearts = player.GetBrokenHearts();
341
- const totalOccupiedHeartSlots = totalHeartContainers + brokenHearts;
342
-
343
- return maxHeartContainers - totalOccupiedHeartSlots;
344
- }
345
-
346
- /**
347
- * Returns the number of black hearts that the player has, excluding any soul hearts. For example,
348
- * if the player has one full black heart, one full soul heart, and one half black heart, this
349
- * function returns 3.
350
- *
351
- * This is different from the `EntityPlayer.GetBlackHearts` method, since that returns a bitmask.
352
- */
353
- export function getPlayerBlackHearts(player: EntityPlayer): int {
354
- const blackHeartsBitmask = player.GetBlackHearts();
355
- const blackHeartBits = countSetBits(blackHeartsBitmask);
356
-
357
- return blackHeartBits * 2;
358
- }
359
-
360
206
  /**
361
207
  * Iterates over all players and checks if any are close enough to the specified position.
362
208
  *
@@ -445,124 +291,6 @@ export function getPlayerFromTear(entity: Entity): EntityPlayer | undefined {
445
291
  return undefined;
446
292
  }
447
293
 
448
- /**
449
- * Returns the number of red hearts that the player has, excluding any rotten hearts. For example,
450
- * if the player has one full black heart, one full soul heart, and one half black heart, this
451
- * function returns 3.
452
- *
453
- * This is different from the `EntityPlayer.GetHearts` method, since that returns a value that
454
- * includes rotten hearts.
455
- */
456
- export function getPlayerHearts(player: EntityPlayer): int {
457
- const rottenHearts = player.GetRottenHearts();
458
- const hearts = player.GetHearts();
459
-
460
- return hearts - rottenHearts * 2;
461
- }
462
-
463
- /**
464
- * Helper function that returns the type of the rightmost heart. This does not including golden
465
- * hearts or broken hearts, since they cannot be damaged directly.
466
- */
467
- export function getPlayerLastHeart(player: EntityPlayer): HealthType {
468
- const hearts = player.GetHearts();
469
- const effectiveMaxHearts = player.GetEffectiveMaxHearts();
470
- const soulHearts = player.GetSoulHearts();
471
- const blackHearts = player.GetBlackHearts();
472
- const eternalHearts = player.GetEternalHearts();
473
- const boneHearts = player.GetBoneHearts();
474
- const rottenHearts = player.GetRottenHearts();
475
-
476
- const soulHeartSlots = soulHearts / 2;
477
- const lastHeartIndex = boneHearts + soulHeartSlots - 1;
478
- const isLastHeartBone = player.IsBoneHeart(lastHeartIndex);
479
-
480
- if (isLastHeartBone) {
481
- const isLastContainerEmpty = hearts <= effectiveMaxHearts - 2;
482
- if (isLastContainerEmpty) {
483
- return HealthType.BONE;
484
- }
485
-
486
- if (rottenHearts > 0) {
487
- return HealthType.ROTTEN;
488
- }
489
-
490
- if (eternalHearts > 0) {
491
- return HealthType.ETERNAL;
492
- }
493
-
494
- return HealthType.RED;
495
- }
496
-
497
- if (soulHearts > 0) {
498
- const numBits = getNumBitsOfN(blackHearts);
499
- const finalBit = getKBitOfN(numBits - 1, blackHearts);
500
- const isBlack = finalBit === 1;
501
-
502
- if (isBlack) {
503
- return HealthType.BLACK;
504
- }
505
-
506
- // If it is not a black heart, it must be a soul heart.
507
- return HealthType.SOUL;
508
- }
509
-
510
- if (eternalHearts > 0) {
511
- return HealthType.ETERNAL;
512
- }
513
-
514
- if (rottenHearts > 0) {
515
- return HealthType.ROTTEN;
516
- }
517
-
518
- return HealthType.RED;
519
- }
520
-
521
- /**
522
- * Returns the maximum heart containers that the provided player can have. Normally, this is 12, but
523
- * it can change depending on the character (e.g. Keeper) and other things (e.g. Mother's Kiss).
524
- * This function does not account for Broken Hearts; use the `getPlayerAvailableHeartSlots` helper
525
- * function for that.
526
- */
527
- export function getPlayerMaxHeartContainers(player: EntityPlayer): int {
528
- const character = player.GetPlayerType();
529
- const characterMaxHeartContainers = getCharacterMaxHeartContainers(character);
530
-
531
- // 1
532
- // Magdalene can increase her maximum heart containers with Birthright.
533
- if (
534
- character === PlayerType.MAGDALENE &&
535
- player.HasCollectible(CollectibleType.BIRTHRIGHT)
536
- ) {
537
- const extraMaxHeartContainersFromBirthright = 6;
538
- return characterMaxHeartContainers + extraMaxHeartContainersFromBirthright;
539
- }
540
-
541
- // 14, 33
542
- // Keeper and Tainted Keeper can increase their coin containers with Mother's Kiss and Greed's
543
- // Gullet.
544
- if (isKeeper(player)) {
545
- const numMothersKisses = player.GetTrinketMultiplier(
546
- TrinketType.MOTHERS_KISS,
547
- );
548
- const hasGreedsGullet = player.HasCollectible(
549
- CollectibleType.GREEDS_GULLET,
550
- );
551
- const coins = player.GetNumCoins();
552
- const greedsGulletCoinContainers = hasGreedsGullet
553
- ? Math.floor(coins / 25)
554
- : 0;
555
-
556
- return (
557
- characterMaxHeartContainers +
558
- numMothersKisses +
559
- greedsGulletCoinContainers
560
- );
561
- }
562
-
563
- return characterMaxHeartContainers;
564
- }
565
-
566
294
  /**
567
295
  * Helper function to get the proper name of the player. Use this instead of the
568
296
  * `EntityPlayer.GetName` method because it accounts for Blue Baby, Lazarus II, and Tainted
@@ -596,21 +324,6 @@ export function getPlayerNumHitsRemaining(player: EntityPlayer): int {
596
324
  return hearts + soulHearts + boneHearts + eternalHearts - rottenHearts;
597
325
  }
598
326
 
599
- /**
600
- * Returns the number of soul hearts that the player has, excluding any black hearts. For example,
601
- * if the player has one full black heart, one full soul heart, and one half black heart, this
602
- * function returns 2.
603
- *
604
- * This is different from the `EntityPlayer.GetSoulHearts` method, since that returns the combined
605
- * number of soul hearts and black hearts.
606
- */
607
- export function getPlayerSoulHearts(player: EntityPlayer): int {
608
- const soulHearts = player.GetSoulHearts();
609
- const blackHearts = getPlayerBlackHearts(player);
610
-
611
- return soulHearts - blackHearts;
612
- }
613
-
614
327
  /**
615
328
  * Helper function to get all of the players that are a certain character.
616
329
  *
@@ -658,26 +371,6 @@ export function getPlayersWithTrinket(
658
371
  );
659
372
  }
660
373
 
661
- /**
662
- * Helper function to determine how many heart containers that Tainted Magdalene has that will not
663
- * be automatically depleted over time. By default, this is 2, but this function will return 4 so
664
- * that it is consistent with the `player.GetHearts` and `player.GetMaxHearts` methods.
665
- *
666
- * If Tainted Magdalene has Birthright, she will gained an additional non-temporary heart container.
667
- *
668
- * This function does not validate whether or not the provided player is Tainted Magdalene; that
669
- * should be accomplished before invoking this function.
670
- */
671
- export function getTaintedMagdaleneNonTemporaryMaxHearts(
672
- player: EntityPlayer,
673
- ): int {
674
- const maxHearts = player.GetMaxHearts();
675
- const hasBirthright = player.HasCollectible(CollectibleType.BIRTHRIGHT);
676
- const maxNonTemporaryMaxHearts = hasBirthright ? 6 : 4;
677
-
678
- return Math.min(maxHearts, maxNonTemporaryMaxHearts);
679
- }
680
-
681
374
  /**
682
375
  * Returns the total number of collectibles amongst all players. For example, if player 1 has 1 Sad
683
376
  * Onion and player 2 has 2 Sad Onions, then this function would return 3.
@@ -1099,43 +792,3 @@ export function useActiveItemTemp(
1099
792
  ): void {
1100
793
  player.UseActiveItem(collectibleType, false, false, true, false, -1);
1101
794
  }
1102
-
1103
- /**
1104
- * Helper function to see if a certain damage amount would deal "permanent" damage to Tainted
1105
- * Magdalene.
1106
- *
1107
- * Tainted Magdalene has "permanent" health and "temporary" health. When standing still and doing
1108
- * nothing, all of Tainted Magdalene's temporary health will eventually go away.
1109
- *
1110
- * Before using this function, it is expected that you check to see if the player is Tainted
1111
- * Magdalene first, or else it will give a nonsensical result.
1112
- */
1113
- export function wouldDamageTaintedMagdaleneNonTemporaryHeartContainers(
1114
- player: EntityPlayer,
1115
- damageAmount: float,
1116
- ): boolean {
1117
- // Regardless of the damage amount, damage to a player cannot remove a soul heart and a red heart
1118
- // at the same time.
1119
- const soulHearts = player.GetSoulHearts();
1120
- if (soulHearts > 0) {
1121
- return false;
1122
- }
1123
-
1124
- // Regardless of the damage amount, damage to a player cannot remove a bone heart and a red heart
1125
- // at the same time.
1126
- const boneHearts = player.GetBoneHearts();
1127
- if (boneHearts > 0) {
1128
- return false;
1129
- }
1130
-
1131
- // Account for rotten hearts eating away at more red hearts than usual.
1132
- const hearts = player.GetHearts();
1133
- const rottenHearts = player.GetRottenHearts();
1134
- const effectiveDamageAmount =
1135
- damageAmount + Math.min(rottenHearts, damageAmount);
1136
-
1137
- const heartsAfterDamage = hearts - effectiveDamageAmount;
1138
- const nonTemporaryMaxHearts =
1139
- getTaintedMagdaleneNonTemporaryMaxHearts(player);
1140
- return heartsAfterDamage < nonTemporaryMaxHearts;
1141
- }
@@ -11,12 +11,8 @@ import {
11
11
  TAINTED_SAMSON_BERSERK_CHARGE_FROM_TAKING_DAMAGE,
12
12
  } from "../core/constants";
13
13
  import { getCharacterDeathAnimationName } from "./characters";
14
- import {
15
- getPlayerMaxHeartContainers,
16
- getPlayerNumHitsRemaining,
17
- hasLostCurse,
18
- isKeeper,
19
- } from "./players";
14
+ import { getPlayerMaxHeartContainers } from "./playerHealth";
15
+ import { getPlayerNumHitsRemaining, hasLostCurse, isKeeper } from "./players";
20
16
  import { getLastFrameOfAnimation } from "./sprites";
21
17
  import { giveTrinketsBack, temporarilyRemoveTrinket } from "./trinketGive";
22
18
 
@@ -26,8 +22,8 @@ import { giveTrinketsBack, temporarilyRemoveTrinket } from "./trinketGive";
26
22
  */
27
23
  export function isDamageToPlayerFatal(
28
24
  player: EntityPlayer,
29
- damageAmount: int,
30
- damageSource: EntityRef,
25
+ amount: int,
26
+ source: EntityRef,
31
27
  lastDamageGameFrame: int | undefined,
32
28
  ): boolean {
33
29
  const gameFrameCount = game.GetFrameCount();
@@ -39,7 +35,7 @@ export function isDamageToPlayerFatal(
39
35
  // (because we will transform into Tainted Jacob's lost form).
40
36
  if (
41
37
  character === PlayerType.JACOB_B &&
42
- damageSource.Type === EntityType.DARK_ESAU
38
+ source.Type === EntityType.DARK_ESAU
43
39
  ) {
44
40
  return false;
45
41
  }
@@ -79,7 +75,7 @@ export function isDamageToPlayerFatal(
79
75
  }
80
76
 
81
77
  const playerNumAllHearts = getPlayerNumHitsRemaining(player);
82
- if (damageAmount < playerNumAllHearts) {
78
+ if (amount < playerNumAllHearts) {
83
79
  return false;
84
80
  }
85
81
 
@@ -1,5 +1,80 @@
1
1
  import { CacheFlag } from "isaac-typescript-definitions";
2
2
  import { DEFAULT_PLAYER_STAT_MAP } from "../maps/defaultPlayerStatMap";
3
+ import { addTearsStat } from "./tears";
4
+
5
+ const STAT_CACHE_FLAGS_SET: ReadonlySet<CacheFlag> = new Set([
6
+ CacheFlag.DAMAGE, // 1 << 0
7
+ CacheFlag.FIRE_DELAY, // 1 << 1
8
+ CacheFlag.SHOT_SPEED, // 1 << 2
9
+ CacheFlag.RANGE, // 1 << 3
10
+ CacheFlag.SPEED, // 1 << 4
11
+ CacheFlag.LUCK, // 1 << 10
12
+ ]);
13
+
14
+ /**
15
+ * Helper function to add a stat to a player based on the `CacheFlag` provided. Call this function
16
+ * from the `EVALUATE_CACHE` callback.
17
+ *
18
+ * Note that for `CacheFlag.FIRE_DELAY`, the "amount" argument will be interpreted as the tear stat
19
+ * to add (and not the amount to mutate `EntityPlayer.MaxFireDelay` by).
20
+ *
21
+ * This function supports the following cache flags:
22
+ * - CacheFlag.DAMAGE (1 << 0)
23
+ * - CacheFlag.FIRE_DELAY (1 << 1)
24
+ * - CacheFlag.SHOT_SPEED (1 << 2)
25
+ * - CacheFlag.RANGE (1 << 3)
26
+ * - CacheFlag.SPEED (1 << 4)
27
+ * - CacheFlag.LUCK (1 << 10)
28
+ */
29
+ export function addStat(
30
+ player: EntityPlayer,
31
+ cacheFlag: CacheFlag,
32
+ amount: number,
33
+ ): void {
34
+ if (!STAT_CACHE_FLAGS_SET.has(cacheFlag)) {
35
+ error(
36
+ `You cannot add a stat to a player with the cache flag of: ${cacheFlag}`,
37
+ );
38
+ }
39
+
40
+ switch (cacheFlag) {
41
+ // 1 << 0
42
+ case CacheFlag.DAMAGE: {
43
+ player.Damage += amount;
44
+ break;
45
+ }
46
+
47
+ // 1 << 1
48
+ case CacheFlag.FIRE_DELAY: {
49
+ addTearsStat(player, amount);
50
+ break;
51
+ }
52
+
53
+ // 1 << 2
54
+ case CacheFlag.SHOT_SPEED: {
55
+ player.ShotSpeed += amount;
56
+ break;
57
+ }
58
+
59
+ // 1 << 3
60
+ case CacheFlag.RANGE: {
61
+ player.TearHeight += amount;
62
+ break;
63
+ }
64
+
65
+ // 1 << 4
66
+ case CacheFlag.SPEED: {
67
+ player.MoveSpeed += amount;
68
+ break;
69
+ }
70
+
71
+ // 1 << 10
72
+ case CacheFlag.LUCK: {
73
+ player.Luck += amount;
74
+ break;
75
+ }
76
+ }
77
+ }
3
78
 
4
79
  /**
5
80
  * Returns the starting stat that Isaac (the default character) starts with. For example, if you
@@ -47,7 +47,7 @@ const TRANSFORMATIONS_THAT_GRANT_FLYING: ReadonlySet<PlayerForm> = new Set([
47
47
  */
48
48
  export function getCollectibleTypesForTransformation(
49
49
  playerForm: PlayerForm,
50
- ): Set<CollectibleType> {
50
+ ): ReadonlySet<CollectibleType> {
51
51
  const itemConfigTag = TRANSFORMATION_TO_TAG_MAP.get(playerForm);
52
52
  if (itemConfigTag === undefined) {
53
53
  error(
@@ -3,7 +3,6 @@ import { itemConfig } from "../core/cachedClasses";
3
3
  import { getTrinketTypes } from "../features/firstLast";
4
4
  import { getEnumValues } from "./enums";
5
5
  import { hasFlag } from "./flag";
6
- import { copySet } from "./set";
7
6
 
8
7
  const CACHE_FLAG_TO_TRINKETS_MAP = new Map<CacheFlag, Set<TrinketType>>();
9
8
 
@@ -57,7 +56,7 @@ export function getPlayerTrinketsForCacheFlag(
57
56
  */
58
57
  export function getTrinketsForCacheFlag(
59
58
  cacheFlag: CacheFlag,
60
- ): Set<TrinketType> {
59
+ ): ReadonlySet<TrinketType> {
61
60
  lazyInitCacheFlagMap();
62
61
 
63
62
  const trinketsSet = CACHE_FLAG_TO_TRINKETS_MAP.get(cacheFlag);
@@ -65,7 +64,7 @@ export function getTrinketsForCacheFlag(
65
64
  return new Set();
66
65
  }
67
66
 
68
- return copySet(trinketsSet);
67
+ return trinketsSet;
69
68
  }
70
69
 
71
70
  /** Helper function to check in the item config if a given trinket has a given cache flag. */