isaacscript-common 6.10.2 → 6.11.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (169) hide show
  1. package/dist/callbacks/postFlip.lua +2 -2
  2. package/dist/callbacks/postPlayerFatalDamage.lua +1 -1
  3. package/dist/callbacks/postPlayerInitFirst.d.ts +2 -0
  4. package/dist/callbacks/postPlayerInitFirst.d.ts.map +1 -0
  5. package/dist/callbacks/postPlayerInitFirst.lua +42 -0
  6. package/dist/callbacks/postPlayerInitLate.lua +5 -5
  7. package/dist/callbacks/postPlayerReorderedCallbacks.d.ts +2 -0
  8. package/dist/callbacks/postPlayerReorderedCallbacks.d.ts.map +1 -0
  9. package/dist/callbacks/{postPlayerReordered.lua → postPlayerReorderedCallbacks.lua} +11 -37
  10. package/dist/callbacks/subscriptions/postFirstFlip.d.ts +1 -1
  11. package/dist/callbacks/subscriptions/postFirstFlip.d.ts.map +1 -1
  12. package/dist/callbacks/subscriptions/postFirstFlip.lua +2 -2
  13. package/dist/callbacks/subscriptions/postFlip.d.ts +1 -1
  14. package/dist/callbacks/subscriptions/postFlip.d.ts.map +1 -1
  15. package/dist/callbacks/subscriptions/postFlip.lua +2 -2
  16. package/dist/callbacks/subscriptions/{postPlayerInitReordered.d.ts → postPlayerInitFirst.d.ts} +2 -2
  17. package/dist/callbacks/subscriptions/postPlayerInitFirst.d.ts.map +1 -0
  18. package/dist/callbacks/subscriptions/{postPlayerInitReordered.lua → postPlayerInitFirst.lua} +3 -3
  19. package/dist/enums/ModCallbackCustom.d.ts +19 -17
  20. package/dist/enums/ModCallbackCustom.d.ts.map +1 -1
  21. package/dist/enums/ModCallbackCustom.lua +3 -3
  22. package/dist/enums/private/StageTravelState.d.ts +9 -0
  23. package/dist/enums/private/StageTravelState.d.ts.map +1 -0
  24. package/dist/enums/private/StageTravelState.lua +15 -0
  25. package/dist/enums/private/TrapdoorAnimation.d.ts +6 -0
  26. package/dist/enums/private/TrapdoorAnimation.d.ts.map +1 -0
  27. package/dist/enums/private/TrapdoorAnimation.lua +6 -0
  28. package/dist/features/customGridEntity.d.ts +8 -5
  29. package/dist/features/customGridEntity.d.ts.map +1 -1
  30. package/dist/features/customGridEntity.lua +66 -17
  31. package/dist/features/customStage/exports.d.ts.map +1 -1
  32. package/dist/features/customStage/exports.lua +0 -13
  33. package/dist/features/customStage/init.d.ts.map +1 -1
  34. package/dist/features/customStage/init.lua +24 -2
  35. package/dist/features/customStage/streakText.d.ts +6 -0
  36. package/dist/features/customStage/streakText.d.ts.map +1 -1
  37. package/dist/features/customStage/streakText.lua +16 -12
  38. package/dist/features/customStage/versusScreen.d.ts +6 -0
  39. package/dist/features/customStage/versusScreen.d.ts.map +1 -1
  40. package/dist/features/customStage/versusScreen.lua +10 -5
  41. package/dist/features/customTrapdoor/blackSprite.d.ts +2 -0
  42. package/dist/features/customTrapdoor/blackSprite.d.ts.map +1 -0
  43. package/dist/features/customTrapdoor/blackSprite.lua +19 -0
  44. package/dist/features/customTrapdoor/customTrapdoorConstants.d.ts +15 -0
  45. package/dist/features/customTrapdoor/customTrapdoorConstants.d.ts.map +1 -0
  46. package/dist/features/customTrapdoor/customTrapdoorConstants.lua +16 -0
  47. package/dist/features/customTrapdoor/exports.d.ts +29 -0
  48. package/dist/features/customTrapdoor/exports.d.ts.map +1 -0
  49. package/dist/features/customTrapdoor/exports.lua +93 -0
  50. package/dist/features/customTrapdoor/init.d.ts +3 -0
  51. package/dist/features/customTrapdoor/init.d.ts.map +1 -0
  52. package/dist/features/customTrapdoor/init.lua +173 -0
  53. package/dist/features/customTrapdoor/openClose.d.ts +5 -0
  54. package/dist/features/customTrapdoor/openClose.d.ts.map +1 -0
  55. package/dist/features/customTrapdoor/openClose.lua +60 -0
  56. package/dist/features/customTrapdoor/touched.d.ts +4 -0
  57. package/dist/features/customTrapdoor/touched.d.ts.map +1 -0
  58. package/dist/features/customTrapdoor/touched.lua +141 -0
  59. package/dist/features/customTrapdoor/v.d.ts +18 -0
  60. package/dist/features/customTrapdoor/v.d.ts.map +1 -0
  61. package/dist/features/customTrapdoor/v.lua +17 -0
  62. package/dist/features/deployJSONRoom.d.ts.map +1 -1
  63. package/dist/features/deployJSONRoom.lua +1 -1
  64. package/dist/features/extraConsoleCommands/init.d.ts.map +1 -1
  65. package/dist/features/extraConsoleCommands/init.lua +3 -1
  66. package/dist/features/extraConsoleCommands/listCommands.lua +2 -2
  67. package/dist/features/taintedLazarusPlayers.d.ts.map +1 -1
  68. package/dist/features/taintedLazarusPlayers.lua +13 -21
  69. package/dist/functions/{character.d.ts → characters.d.ts} +3 -1
  70. package/dist/functions/characters.d.ts.map +1 -0
  71. package/dist/functions/{character.lua → characters.lua} +12 -0
  72. package/dist/functions/deepCopyTests.lua +35 -45
  73. package/dist/functions/jsonHelpers.d.ts +6 -0
  74. package/dist/functions/jsonHelpers.d.ts.map +1 -1
  75. package/dist/functions/jsonHelpers.lua +9 -3
  76. package/dist/functions/log.lua +3 -3
  77. package/dist/functions/playerIndex.d.ts +11 -2
  78. package/dist/functions/playerIndex.d.ts.map +1 -1
  79. package/dist/functions/playerIndex.lua +20 -8
  80. package/dist/functions/players.lua +4 -4
  81. package/dist/functions/revive.lua +2 -2
  82. package/dist/functions/table.d.ts +1 -1
  83. package/dist/functions/table.d.ts.map +1 -1
  84. package/dist/index.d.ts +3 -2
  85. package/dist/index.d.ts.map +1 -1
  86. package/dist/index.lua +10 -2
  87. package/dist/initCustomCallbacks.d.ts.map +1 -1
  88. package/dist/initCustomCallbacks.lua +5 -2
  89. package/dist/initFeatures.d.ts +1 -2
  90. package/dist/initFeatures.d.ts.map +1 -1
  91. package/dist/initFeatures.lua +10 -2
  92. package/dist/interfaces/AddCallbackParameterCustom.d.ts +2 -2
  93. package/dist/interfaces/AddCallbackParameterCustom.d.ts.map +1 -1
  94. package/dist/interfaces/CustomGridEntityData.d.ts +6 -2
  95. package/dist/interfaces/CustomGridEntityData.d.ts.map +1 -1
  96. package/dist/interfaces/private/CustomTrapdoorDescription.d.ts +7 -0
  97. package/dist/interfaces/private/CustomTrapdoorDescription.d.ts.map +1 -0
  98. package/dist/interfaces/private/CustomTrapdoorDescription.lua +2 -0
  99. package/dist/lib/jsonLua.lua +390 -0
  100. package/dist/objects/callbackRegisterFunctions.d.ts.map +1 -1
  101. package/dist/objects/callbackRegisterFunctions.lua +3 -3
  102. package/dist/objects/characterDamageMultipliers.d.ts +6 -0
  103. package/dist/objects/characterDamageMultipliers.d.ts.map +1 -0
  104. package/dist/objects/characterDamageMultipliers.lua +49 -0
  105. package/dist/upgradeMod.d.ts.map +1 -1
  106. package/dist/upgradeMod.lua +2 -4
  107. package/package.json +2 -2
  108. package/src/callbacks/customRevive.ts +3 -3
  109. package/src/callbacks/itemPickup.ts +3 -3
  110. package/src/callbacks/postAmbush.ts +3 -3
  111. package/src/callbacks/postEsauJr.ts +3 -3
  112. package/src/callbacks/postFlip.ts +6 -5
  113. package/src/callbacks/postGridEntity.ts +5 -5
  114. package/src/callbacks/postPlayerCollectible.ts +2 -2
  115. package/src/callbacks/postPlayerFatalDamage.ts +5 -0
  116. package/src/callbacks/postPlayerInitFirst.ts +57 -0
  117. package/src/callbacks/postPlayerInitLate.ts +9 -5
  118. package/src/callbacks/{postPlayerReordered.ts → postPlayerReorderedCallbacks.ts} +9 -29
  119. package/src/callbacks/postSlotInitUpdate.ts +5 -2
  120. package/src/callbacks/postSlotRender.ts +2 -2
  121. package/src/callbacks/reorderedCallbacks.ts +1 -1
  122. package/src/callbacks/subscriptions/postFirstFlip.ts +6 -3
  123. package/src/callbacks/subscriptions/postFlip.ts +6 -3
  124. package/src/callbacks/subscriptions/{postPlayerInitReordered.ts → postPlayerInitFirst.ts} +6 -6
  125. package/src/enums/ModCallbackCustom.ts +19 -17
  126. package/src/enums/private/StageTravelState.ts +8 -0
  127. package/src/enums/private/TrapdoorAnimation.ts +5 -0
  128. package/src/features/customGridEntity.ts +93 -12
  129. package/src/features/customStage/exports.ts +3 -22
  130. package/src/features/customStage/init.ts +30 -1
  131. package/src/features/customStage/streakText.ts +13 -5
  132. package/src/features/customStage/versusScreen.ts +20 -12
  133. package/src/features/customTrapdoor/blackSprite.ts +16 -0
  134. package/src/features/customTrapdoor/customTrapdoorConstants.ts +23 -0
  135. package/src/features/customTrapdoor/exports.ts +99 -0
  136. package/src/features/customTrapdoor/init.ts +215 -0
  137. package/src/features/customTrapdoor/openClose.ts +103 -0
  138. package/src/features/customTrapdoor/touched.ts +175 -0
  139. package/src/features/customTrapdoor/v.ts +26 -0
  140. package/src/features/deployJSONRoom.ts +6 -1
  141. package/src/features/extraConsoleCommands/init.ts +5 -2
  142. package/src/features/extraConsoleCommands/listCommands.ts +1 -1
  143. package/src/features/saveDataManager/main.ts +1 -1
  144. package/src/features/taintedLazarusPlayers.ts +32 -31
  145. package/src/functions/{character.ts → characters.ts} +13 -0
  146. package/src/functions/deepCopy.ts +2 -2
  147. package/src/functions/deepCopyTests.ts +44 -48
  148. package/src/functions/entities.ts +1 -1
  149. package/src/functions/jsonHelpers.ts +9 -3
  150. package/src/functions/playerIndex.ts +18 -2
  151. package/src/functions/players.ts +1 -1
  152. package/src/functions/revive.ts +1 -1
  153. package/src/functions/rng.ts +1 -1
  154. package/src/functions/table.ts +2 -2
  155. package/src/index.ts +6 -2
  156. package/src/initCustomCallbacks.ts +3 -1
  157. package/src/initFeatures.ts +9 -2
  158. package/src/interfaces/AddCallbackParameterCustom.ts +2 -2
  159. package/src/interfaces/CustomGridEntityData.ts +7 -2
  160. package/src/interfaces/private/CustomTrapdoorDescription.ts +7 -0
  161. package/src/lib/jsonLua.d.ts +10 -0
  162. package/src/lib/jsonLua.lua +390 -0
  163. package/src/objects/callbackRegisterFunctions.ts +2 -3
  164. package/src/objects/characterDamageMultipliers.ts +49 -0
  165. package/src/upgradeMod.ts +2 -3
  166. package/dist/callbacks/postPlayerReordered.d.ts +0 -2
  167. package/dist/callbacks/postPlayerReordered.d.ts.map +0 -1
  168. package/dist/callbacks/subscriptions/postPlayerInitReordered.d.ts.map +0 -1
  169. package/dist/functions/character.d.ts.map +0 -1
@@ -0,0 +1,57 @@
1
+ import { ModUpgraded } from "../classes/ModUpgraded";
2
+ import { ModCallbackCustom } from "../enums/ModCallbackCustom";
3
+ import { getPlayers, isChildPlayer } from "../functions/playerIndex";
4
+ import { inGenesisRoom } from "../functions/rooms";
5
+ import {
6
+ postPlayerInitFirstFire,
7
+ postPlayerInitFirstHasSubscriptions,
8
+ } from "./subscriptions/postPlayerInitFirst";
9
+
10
+ /** @internal */
11
+ export function postPlayerInitFirstInit(mod: ModUpgraded): void {
12
+ mod.AddCallbackCustom(
13
+ ModCallbackCustom.POST_NEW_ROOM_REORDERED,
14
+ postNewRoomReordered,
15
+ );
16
+ mod.AddCallbackCustom(
17
+ ModCallbackCustom.POST_PLAYER_INIT_LATE,
18
+ postPlayerInitLate,
19
+ );
20
+ }
21
+
22
+ function hasSubscriptions() {
23
+ return postPlayerInitFirstHasSubscriptions();
24
+ }
25
+
26
+ // ModCallbackCustom.POST_NEW_ROOM_REORDERED
27
+ function postNewRoomReordered() {
28
+ if (!hasSubscriptions()) {
29
+ return;
30
+ }
31
+
32
+ // When a player uses the Genesis collectible, they will lose all of their collectibles, trinkets,
33
+ // pocket items, and stats, so they will need to be re-initialized like they would be at the
34
+ // beginning of a run. However, in this case, the `POST_PLAYER_INIT_FIRST` callback will not fire,
35
+ // because that only fires once per run. Thus, we explicitly handle this special case.
36
+ if (!inGenesisRoom()) {
37
+ return;
38
+ }
39
+
40
+ for (const player of getPlayers()) {
41
+ postPlayerInitFirstFire(player);
42
+ }
43
+ }
44
+
45
+ // ModCallback.POST_PEFFECT_UPDATE (4)
46
+ function postPlayerInitLate(player: EntityPlayer) {
47
+ if (!hasSubscriptions()) {
48
+ return;
49
+ }
50
+
51
+ // We want to exclude non-real players like the Strawman keeper.
52
+ if (isChildPlayer(player)) {
53
+ return;
54
+ }
55
+
56
+ postPlayerInitFirstFire(player);
57
+ }
@@ -1,4 +1,5 @@
1
- import { ModCallback } from "isaac-typescript-definitions";
1
+ import { ModUpgraded } from "../classes/ModUpgraded";
2
+ import { ModCallbackCustom } from "../enums/ModCallbackCustom";
2
3
  import { saveDataManager } from "../features/saveDataManager/exports";
3
4
  import { setAddPlayer, setHasPlayer } from "../functions/playerDataStructures";
4
5
  import { PlayerIndex } from "../types/PlayerIndex";
@@ -14,18 +15,21 @@ const v = {
14
15
  };
15
16
 
16
17
  /** @internal */
17
- export function postPlayerInitLateInit(mod: Mod): void {
18
+ export function postPlayerInitLateInit(mod: ModUpgraded): void {
18
19
  saveDataManager("postPlayerInitLate", v, hasSubscriptions);
19
20
 
20
- mod.AddCallback(ModCallback.POST_PLAYER_UPDATE, postPlayerUpdate); // 31
21
+ mod.AddCallbackCustom(
22
+ ModCallbackCustom.POST_PEFFECT_UPDATE_REORDERED,
23
+ postPEffectUpdateReordered,
24
+ );
21
25
  }
22
26
 
23
27
  function hasSubscriptions() {
24
28
  return postPlayerInitLateHasSubscriptions();
25
29
  }
26
30
 
27
- // ModCallback.POST_PLAYER_UPDATE (31)
28
- function postPlayerUpdate(player: EntityPlayer) {
31
+ // ModCallbackCustom.POST_PEFFECT_UPDATE_REORDERED
32
+ function postPEffectUpdateReordered(player: EntityPlayer) {
29
33
  if (!hasSubscriptions()) {
30
34
  return;
31
35
  }
@@ -1,3 +1,8 @@
1
+ // This handles logic for the following callbacks:
2
+ // - POST_PEFFECT_UPDATE_REORDERED
3
+ // - POST_PLAYER_RENDER_REORDERED
4
+ // - POST_PLAYER_UPDATE_REORDERED
5
+
1
6
  import { ModCallback } from "isaac-typescript-definitions";
2
7
  import { saveDataManager } from "../features/saveDataManager/exports";
3
8
  import { emptyArray } from "../functions/array";
@@ -7,10 +12,6 @@ import {
7
12
  postPEffectUpdateReorderedFire,
8
13
  postPEffectUpdateReorderedHasSubscriptions,
9
14
  } from "./subscriptions/postPEffectUpdateReordered";
10
- import {
11
- postPlayerInitReorderedFire,
12
- postPlayerInitReorderedHasSubscriptions,
13
- } from "./subscriptions/postPlayerInitReordered";
14
15
  import {
15
16
  postPlayerRenderReorderedFire,
16
17
  postPlayerRenderReorderedHasSubscriptions,
@@ -24,7 +25,6 @@ const v = {
24
25
  run: {
25
26
  postGameStartedFiredOnThisRun: false,
26
27
 
27
- postPlayerInitQueue: [] as PlayerIndex[],
28
28
  postPEffectUpdateQueue: [] as PlayerIndex[],
29
29
  postPlayerUpdateQueue: [] as PlayerIndex[],
30
30
  postPlayerRenderQueue: [] as PlayerIndex[],
@@ -36,16 +36,13 @@ export function postPlayerReorderedCallbacksInit(mod: Mod): void {
36
36
  saveDataManager("postPlayerReordered", v, hasSubscriptions);
37
37
 
38
38
  mod.AddCallback(ModCallback.POST_PEFFECT_UPDATE, postPEffectUpdate); // 4
39
- mod.AddCallback(ModCallback.POST_PLAYER_INIT, postPlayerInit); // 9
39
+ mod.AddCallback(ModCallback.POST_GAME_STARTED, postGameStarted); // 15
40
40
  mod.AddCallback(ModCallback.POST_PLAYER_UPDATE, postPlayerUpdate); // 31
41
41
  mod.AddCallback(ModCallback.POST_PLAYER_RENDER, postPlayerRender); // 32
42
-
43
- mod.AddCallback(ModCallback.POST_GAME_STARTED, postGameStarted); // 15
44
42
  }
45
43
 
46
44
  function hasSubscriptions() {
47
45
  return (
48
- postPlayerInitReorderedHasSubscriptions() ||
49
46
  postPEffectUpdateReorderedHasSubscriptions() ||
50
47
  postPlayerUpdateReorderedHasSubscriptions() ||
51
48
  postPlayerRenderReorderedHasSubscriptions()
@@ -67,21 +64,6 @@ function postPEffectUpdate(player: EntityPlayer) {
67
64
  }
68
65
  }
69
66
 
70
- // ModCallback.POST_PLAYER_INIT (9)
71
- function postPlayerInit(player: EntityPlayer) {
72
- if (!hasSubscriptions()) {
73
- return;
74
- }
75
-
76
- if (v.run.postGameStartedFiredOnThisRun) {
77
- postPlayerInitReorderedFire(player);
78
- } else {
79
- // Defer callback execution until the PostGameStarted callback fires.
80
- const playerIndex = getPlayerIndex(player);
81
- v.run.postPlayerInitQueue.push(playerIndex);
82
- }
83
- }
84
-
85
67
  // ModCallback.POST_PLAYER_UPDATE (31)
86
68
  function postPlayerUpdate(player: EntityPlayer) {
87
69
  if (!hasSubscriptions()) {
@@ -120,7 +102,7 @@ function postGameStarted() {
120
102
 
121
103
  v.run.postGameStartedFiredOnThisRun = true;
122
104
 
123
- dequeue(v.run.postPlayerInitQueue, postPlayerInitReorderedFire);
105
+ dequeue(v.run.postPEffectUpdateQueue, postPEffectUpdateReorderedFire);
124
106
  dequeue(v.run.postPlayerUpdateQueue, postPlayerUpdateReorderedFire);
125
107
  dequeue(v.run.postPlayerRenderQueue, postPlayerRenderReorderedFire);
126
108
  }
@@ -131,11 +113,9 @@ function dequeue(
131
113
  ) {
132
114
  for (const playerIndex of playerIndexes) {
133
115
  const player = getPlayerFromIndex(playerIndex);
134
- if (player === undefined) {
135
- continue;
116
+ if (player !== undefined) {
117
+ fireFunction(player);
136
118
  }
137
-
138
- fireFunction(player);
139
119
  }
140
120
 
141
121
  emptyArray(playerIndexes);
@@ -1,5 +1,8 @@
1
- // This provides the logic for the PostSlotInit and PostSlotUpdate callbacks. (The other slot
2
- // callbacks are handled in a different file.)
1
+ // This provides the logic for the following callbacks:
2
+ // - `POST_SLOT_INIT`
3
+ // - `POST_SLOT_UPDATE`
4
+
5
+ // (The other slot callbacks are handled in a different file.)
3
6
 
4
7
  import { ModCallback } from "isaac-typescript-definitions";
5
8
  import { ModUpgraded } from "../classes/ModUpgraded";
@@ -1,6 +1,6 @@
1
1
  // This provides the logic for the following callbacks:
2
- // - PostSlotRender
3
- // - PostSlotAnimationChanged
2
+ // - `POST_SLOT_RENDER`
3
+ // - `POST_SLOT_ANIMATION_CHANGED`
4
4
 
5
5
  import { ModCallback } from "isaac-typescript-definitions";
6
6
  import { DefaultMap } from "../classes/DefaultMap";
@@ -1,4 +1,4 @@
1
- // This provides the logic for:
1
+ // This provides the logic for the following callbacks:
2
2
  // - `POST_GAME_STARTED_REORDERED`
3
3
  // - `POST_NEW_LEVEL_REORDERED`
4
4
  // - `POST_NEW_ROOM_REORDERED`
@@ -1,5 +1,5 @@
1
1
  export type PostFirstFlipRegisterParameters = [
2
- callback: (player: EntityPlayer) => void,
2
+ callback: (newLazarus: EntityPlayer, oldLazarus: EntityPlayer) => void,
3
3
  ];
4
4
 
5
5
  const subscriptions: PostFirstFlipRegisterParameters[] = [];
@@ -17,8 +17,11 @@ export function postFirstFlipRegister(
17
17
  }
18
18
 
19
19
  /** @internal */
20
- export function postFirstFlipFire(player: EntityPlayer): void {
20
+ export function postFirstFlipFire(
21
+ newLazarus: EntityPlayer,
22
+ oldLazarus: EntityPlayer,
23
+ ): void {
21
24
  for (const [callback] of subscriptions) {
22
- callback(player);
25
+ callback(newLazarus, oldLazarus);
23
26
  }
24
27
  }
@@ -1,5 +1,5 @@
1
1
  export type PostFlipRegisterParameters = [
2
- callback: (player: EntityPlayer) => void,
2
+ callback: (newLazarus: EntityPlayer, oldLazarus: EntityPlayer) => void,
3
3
  ];
4
4
 
5
5
  const subscriptions: PostFlipRegisterParameters[] = [];
@@ -15,8 +15,11 @@ export function postFlipRegister(...args: PostFlipRegisterParameters): void {
15
15
  }
16
16
 
17
17
  /** @internal */
18
- export function postFlipFire(player: EntityPlayer): void {
18
+ export function postFlipFire(
19
+ newLazarus: EntityPlayer,
20
+ oldLazarus: EntityPlayer,
21
+ ): void {
19
22
  for (const [callback] of subscriptions) {
20
- callback(player);
23
+ callback(newLazarus, oldLazarus);
21
24
  }
22
25
  }
@@ -1,27 +1,27 @@
1
1
  import { PlayerType, PlayerVariant } from "isaac-typescript-definitions";
2
2
 
3
- export type PostPlayerInitReorderedRegisterParameters = [
3
+ export type PostPlayerInitFirstRegisterParameters = [
4
4
  callback: (player: EntityPlayer) => void,
5
5
  playerVariant?: PlayerVariant,
6
6
  character?: PlayerType,
7
7
  ];
8
8
 
9
- const subscriptions: PostPlayerInitReorderedRegisterParameters[] = [];
9
+ const subscriptions: PostPlayerInitFirstRegisterParameters[] = [];
10
10
 
11
11
  /** @internal */
12
- export function postPlayerInitReorderedHasSubscriptions(): boolean {
12
+ export function postPlayerInitFirstHasSubscriptions(): boolean {
13
13
  return subscriptions.length > 0;
14
14
  }
15
15
 
16
16
  /** @internal */
17
- export function postPlayerInitReorderedRegister(
18
- ...args: PostPlayerInitReorderedRegisterParameters
17
+ export function postPlayerInitFirstRegister(
18
+ ...args: PostPlayerInitFirstRegisterParameters
19
19
  ): void {
20
20
  subscriptions.push(args);
21
21
  }
22
22
 
23
23
  /** @internal */
24
- export function postPlayerInitReorderedFire(player: EntityPlayer): void {
24
+ export function postPlayerInitFirstFire(player: EntityPlayer): void {
25
25
  const character = player.GetPlayerType();
26
26
 
27
27
  for (const [callback, playerVariant, callbackCharacter] of subscriptions) {
@@ -295,7 +295,7 @@ export enum ModCallbackCustom {
295
295
  * before the player has actually used the Flip item.
296
296
  *
297
297
  * ```ts
298
- * function postFirstFlip(player: EntityPlayer): void {}
298
+ * function postFirstFlip(newLazarus: EntityPlayer, oldLazarus: EntityPlayer): void {}
299
299
  * ```
300
300
  */
301
301
  POST_FIRST_FLIP,
@@ -309,7 +309,7 @@ export enum ModCallbackCustom {
309
309
  * before the player has actually used the Flip item.
310
310
  *
311
311
  * ```ts
312
- * function postFlip(player: EntityPlayer): void {}
312
+ * function postFlip(newLazarus: EntityPlayer, oldLazarus: EntityPlayer): void {}
313
313
  * ```
314
314
  */
315
315
  POST_FLIP,
@@ -825,10 +825,15 @@ export enum ModCallbackCustom {
825
825
  POST_PLAYER_FATAL_DAMAGE,
826
826
 
827
827
  /**
828
- * Fires on the first `POST_PLAYER_UPDATE` frame for each player.
828
+ * Fires on the first `POST_PEFFECT_UPDATE_REORDERED` frame for each player, similar to the
829
+ * `POST_PLAYER_INIT_LATE` callback, with two changes:
829
830
  *
830
- * This callback is useful because many attributes cannot be set or retrieved properly in the
831
- * normal `POST_PLAYER_INIT` callback.
831
+ * - This will not fire for "child" players (e.g. non-real players like the Strawman Keeper).
832
+ * - This will fire when the player enters a Genesis room and all of their items are taken away.
833
+ *
834
+ * You should use this callback for any player-related initialization logic, like giving the
835
+ * character their starting items for the run. (You do not want to use the vanilla
836
+ * `POST_PLAYER_INIT` callback for this because it fires when a run is continued.)
832
837
  *
833
838
  * - When registering the callback, takes an optional second argument that will make the callback
834
839
  * only fire if the player matches the `PlayerVariant` provided.
@@ -836,22 +841,19 @@ export enum ModCallbackCustom {
836
841
  * only fire if the player matches the `PlayerType` provided.
837
842
  *
838
843
  * ```ts
839
- * function postPlayerInitLate(pickup: EntityPickup): void {}
844
+ * function postPlayerInitFirst(player: EntityPlayer): void {}
840
845
  * ```
841
846
  */
842
- POST_PLAYER_INIT_LATE,
847
+ POST_PLAYER_INIT_FIRST,
843
848
 
844
849
  /**
845
- * Similar to the vanilla callback of the same name, but fires after the `POST_GAME_STARTED`
846
- * callback fires (if the player is spawning on the 0th game frame of the run).
850
+ * Fires on the first `POST_PEFFECT_UPDATE_REORDERED` frame for each player.
847
851
  *
848
- * This callback is useful for two reasons:
852
+ * This callback is useful because many attributes cannot be set or retrieved properly in the
853
+ * normal `POST_PLAYER_INIT` callback.
849
854
  *
850
- * 1. Normally, `POST_PLAYER_INIT` fires before `POST_GAME_STARTED`. Since mod variables are often
851
- * initialized at the beginning of the `POST_GAME_STARTED` callback, this can cause problems.
852
- * 1. Some functions do not work (or crash the game) when called before the `POST_NEW_ROOM`
853
- * callback. For example, since the level is not generated yet, you will not be able to access
854
- * any rooms.
855
+ * For initializing a player with custom items and so forth, use the `POST_PLAYER_INIT_FIRST`
856
+ * callback instead to handle the case of a Genesis room.
855
857
  *
856
858
  * - When registering the callback, takes an optional second argument that will make the callback
857
859
  * only fire if the player matches the `PlayerVariant` provided.
@@ -859,10 +861,10 @@ export enum ModCallbackCustom {
859
861
  * only fire if the player matches the `PlayerType` provided.
860
862
  *
861
863
  * ```ts
862
- * function postPlayerInitReordered(player: EntityPlayer): void {}
864
+ * function postPlayerInitLate(pickup: EntityPickup): void {}
863
865
  * ```
864
866
  */
865
- POST_PLAYER_INIT_REORDERED,
867
+ POST_PLAYER_INIT_LATE,
866
868
 
867
869
  /**
868
870
  * Similar to the vanilla callback of the same name, but fires after the `POST_GAME_STARTED`
@@ -0,0 +1,8 @@
1
+ export enum StageTravelState {
2
+ NONE,
3
+ PLAYERS_JUMPING_DOWN,
4
+ PIXELATION_TO_BLACK,
5
+ PAUSING_ON_BLACK,
6
+ PIXELATION_TO_ROOM,
7
+ PLAYERS_LAYING_DOWN,
8
+ }
@@ -0,0 +1,5 @@
1
+ export enum TrapdoorAnimation {
2
+ OPENED = "Opened",
3
+ CLOSED = "Closed",
4
+ OPEN_ANIMATION = "Open Animation",
5
+ }
@@ -1,6 +1,10 @@
1
1
  import {
2
+ ActiveSlot,
3
+ CollectibleType,
2
4
  GridCollisionClass,
3
5
  GridEntityType,
6
+ ModCallback,
7
+ UseFlag,
4
8
  } from "isaac-typescript-definitions";
5
9
  import { game } from "../cachedClasses";
6
10
  import { DefaultMap } from "../classes/DefaultMap";
@@ -15,6 +19,7 @@ import {
15
19
  import { getRoomListIndex } from "../functions/roomData";
16
20
  import { isVector } from "../functions/vector";
17
21
  import { CustomGridEntityData } from "../interfaces/CustomGridEntityData";
22
+ import { runNextGameFrame } from "./runInNFrames";
18
23
  import { saveDataManager } from "./saveDataManager/exports";
19
24
 
20
25
  const FEATURE_NAME = "customGridEntity";
@@ -26,18 +31,83 @@ const v = {
26
31
  () => new Map(),
27
32
  ),
28
33
  },
34
+
35
+ room: {
36
+ manuallyUsingShovel: false,
37
+ },
29
38
  };
30
39
 
31
40
  /** @internal */
32
41
  export function customGridEntityInit(mod: ModUpgraded): void {
33
42
  saveDataManager(FEATURE_NAME, v);
34
43
 
44
+ mod.AddCallback(
45
+ ModCallback.PRE_USE_ITEM,
46
+ preUseItemWeNeedToGoDeeper,
47
+ CollectibleType.WE_NEED_TO_GO_DEEPER,
48
+ ); // 23
49
+
35
50
  mod.AddCallbackCustom(
36
51
  ModCallbackCustom.POST_NEW_ROOM_REORDERED,
37
52
  postNewRoomReordered,
38
53
  );
39
54
  }
40
55
 
56
+ // ModCallback.PRE_USE_ITEM (23)
57
+ // CollectibleType.WE_NEED_TO_GO_DEEPER (84)
58
+ function preUseItemWeNeedToGoDeeper(
59
+ _collectibleType: CollectibleType,
60
+ _rng: RNG,
61
+ player: EntityPlayer,
62
+ _useFlags: BitFlags<UseFlag>,
63
+ _activeSlot: ActiveSlot,
64
+ _customVarData: int,
65
+ ): boolean | undefined {
66
+ // If a player uses We Need to Go Deeper on top of a custom grid entity, then they will always get
67
+ // a crawlspace, due to how custom grids are implemented with decorations. Thus, remove the custom
68
+ // grid entity to prevent this from happening if needed.
69
+ const room = game.GetRoom();
70
+ const roomListIndex = getRoomListIndex();
71
+ const roomCustomGridEntities = v.level.customGridEntities.get(roomListIndex);
72
+ if (roomCustomGridEntities === undefined) {
73
+ return undefined;
74
+ }
75
+
76
+ const gridIndex = room.GetGridIndex(player.Position);
77
+ const customGridEntity = roomCustomGridEntities.get(gridIndex);
78
+ if (customGridEntity === undefined) {
79
+ return undefined;
80
+ }
81
+
82
+ // If the custom grid entity has collision, then the player should not be able to be standing on
83
+ // top of it.
84
+ if (customGridEntity.gridCollisionClass !== GridCollisionClass.NONE) {
85
+ return undefined;
86
+ }
87
+
88
+ removeGridEntity(customGridEntity.gridIndex, false);
89
+
90
+ const playerPtr = EntityPtr(player);
91
+ runNextGameFrame(() => {
92
+ const futureEntity = playerPtr.Ref;
93
+ if (futureEntity === undefined) {
94
+ return;
95
+ }
96
+
97
+ const futurePlayer = futureEntity.ToPlayer();
98
+ if (futurePlayer === undefined) {
99
+ return;
100
+ }
101
+
102
+ v.room.manuallyUsingShovel = true;
103
+ futurePlayer.UseActiveItem(CollectibleType.WE_NEED_TO_GO_DEEPER);
104
+ v.room.manuallyUsingShovel = false;
105
+ });
106
+
107
+ // Cancel the original effect.
108
+ return true;
109
+ }
110
+
41
111
  // ModCallbackCustom.POST_NEW_ROOM_REORDERED
42
112
  function postNewRoomReordered() {
43
113
  // When we re-enter a room, the graphics for any custom entities will be reverted back to that of
@@ -57,13 +127,19 @@ function postNewRoomReordered() {
57
127
  }
58
128
 
59
129
  const sprite = decoration.GetSprite();
60
- sprite.Load(data.anm2, true);
61
- sprite.Play(data.defaultAnimation, true);
130
+ sprite.Load(data.anm2Path, true);
131
+ const animationToPlay =
132
+ data.defaultAnimation === undefined
133
+ ? sprite.GetDefaultAnimation()
134
+ : data.defaultAnimation;
135
+ sprite.Play(animationToPlay, true);
62
136
  }
63
137
  }
64
138
 
65
139
  /**
66
- * Helper function to spawn a custom grid entity.
140
+ * Helper function to spawn a custom grid entity. Custom grid entities are persistent in that they
141
+ * will reappear if the player leaves and re-enters the room. (It will be manually respawned in the
142
+ * `POST_NEW_ROOM` callback.)
67
143
  *
68
144
  * This is an IsaacScript feature because the vanilla game does not support any custom grid
69
145
  * entities. Under the hood, IsaacScript accomplishes this by using decorations with an arbitrary
@@ -80,17 +156,18 @@ function postNewRoomReordered() {
80
156
  * @param gridIndexOrPosition The grid index or position in the room that you want to spawn the grid
81
157
  * entity at. If a position is specified, the closest grid index will be
82
158
  * used.
83
- * @param anm2 The path to the ANM2 file to use for the sprite.
84
- * @param defaultAnimation The name of the animation to play after the sprite is initialized and
85
- * after the player re-enters a room with this grid entity in it.
86
159
  * @param gridCollisionClass The collision class that you want the custom grid entity to have.
160
+ * @param anm2Path The path to the ANM2 file to use for the sprite.
161
+ * @param defaultAnimation Optional. The name of the animation to play after the sprite is
162
+ * initialized and after the player re-enters a room with this grid entity
163
+ * in it. If not specified, the default animation in the anm2 will be used.
87
164
  */
88
- export function spawnCustomGrid(
165
+ export function spawnCustomGridEntity(
89
166
  gridEntityTypeCustom: GridEntityType,
90
167
  gridIndexOrPosition: int | Vector,
91
- anm2: string,
92
- defaultAnimation: string,
93
168
  gridCollisionClass: GridCollisionClass,
169
+ anm2Path: string,
170
+ defaultAnimation?: string,
94
171
  ): GridEntity {
95
172
  errorIfFeaturesNotInitialized(FEATURE_NAME);
96
173
 
@@ -118,14 +195,18 @@ export function spawnCustomGrid(
118
195
  }
119
196
 
120
197
  const sprite = decoration.GetSprite();
121
- sprite.Load(anm2, true);
122
- sprite.Play(defaultAnimation, true);
198
+ sprite.Load(anm2Path, true);
199
+ const animationToPlay =
200
+ defaultAnimation === undefined
201
+ ? sprite.GetDefaultAnimation()
202
+ : defaultAnimation;
203
+ sprite.Play(animationToPlay, true);
123
204
 
124
205
  const customGridEntityData: CustomGridEntityData = {
125
206
  gridEntityTypeCustom,
126
207
  roomListIndex,
127
208
  gridIndex,
128
- anm2,
209
+ anm2Path,
129
210
  defaultAnimation,
130
211
  gridCollisionClass,
131
212
  };
@@ -1,10 +1,8 @@
1
1
  import {
2
- Direction,
3
2
  EntityType,
4
3
  GridRoom,
5
4
  LevelStage,
6
5
  RoomShape,
7
- RoomTransitionAnim,
8
6
  RoomType,
9
7
  StageType,
10
8
  } from "isaac-typescript-definitions";
@@ -12,12 +10,10 @@ import { game } from "../../cachedClasses";
12
10
  import { reorderedCallbacksSetStage } from "../../callbacks/reorderedCallbacks";
13
11
  import { getEntityIDFromConstituents } from "../../functions/entities";
14
12
  import { log, logError } from "../../functions/log";
15
- import { movePlayersToCenter } from "../../functions/playerCenter";
16
13
  import { newRNG } from "../../functions/rng";
17
14
  import { getRoomData } from "../../functions/roomData";
18
15
  import { getRooms } from "../../functions/rooms";
19
16
  import { getGotoCommand, setStage } from "../../functions/stage";
20
- import { runNextRoom } from "../runNextRoom";
21
17
  import { getRandomCustomStageRoom } from "./customStageUtils";
22
18
  import { topStreakTextStart } from "./streakText";
23
19
  import v, {
@@ -136,24 +132,9 @@ export function setCustomStage(name: string, verbose = false): void {
136
132
 
137
133
  // We must reload the current room in order for the `Level.SetStage` method to take effect.
138
134
  // Furthermore, we need to cancel the queued warp to the `GridRoom.DEBUG` room. We can accomplish
139
- // both of these things by initiating a room transition to the starting room of the floor. (We
140
- // assume that since we just warped to a new floor, we are already in the starting room.)
141
- game.StartRoomTransition(
142
- startingRoomGridIndex,
143
- Direction.NO_DIRECTION,
144
- RoomTransitionAnim.FADE,
145
- );
146
-
147
- // We do more setup once the room is reloaded from the transition.
148
- runNextRoom(postRoomTransition);
149
- }
150
-
151
- function postRoomTransition() {
152
- // After the room transition, the players will be placed next to a door, but they should be in the
153
- // center of the room to emulate what happens on a vanilla stage.
154
- movePlayersToCenter();
155
-
156
- topStreakTextStart();
135
+ // both of these things by initiating a room transition to an arbitrary room. However, we rely on
136
+ // the parent function to do this, since for normal purposes, we need to initiate a room
137
+ // transition for pixelation purposes.
157
138
  }
158
139
 
159
140
  export function setCustomStageDebug(): void {
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  DoorSlotFlag,
3
3
  GridEntityType,
4
+ LevelCurse,
4
5
  ModCallback,
5
6
  RoomShape,
6
7
  RoomType,
@@ -8,6 +9,7 @@ import {
8
9
  import { ModUpgraded } from "../../classes/ModUpgraded";
9
10
  import { ModCallbackCustom } from "../../enums/ModCallbackCustom";
10
11
  import { isArray } from "../../functions/array";
12
+ import { hasFlag, removeFlag } from "../../functions/flag";
11
13
  import { CustomStage, RoomTypeMap } from "../../interfaces/CustomStage";
12
14
  import {
13
15
  CustomStageLua,
@@ -26,20 +28,30 @@ import * as metadataJSON from "./metadata.json"; // This will correspond to "met
26
28
  import { setShadows } from "./shadows";
27
29
  import {
28
30
  streakTextGetShaderParams,
31
+ streakTextInit,
29
32
  streakTextPostGameStarted,
30
33
  streakTextPostRender,
31
34
  } from "./streakText";
32
35
  import v, { customStagesMap } from "./v";
33
36
  import {
34
37
  playVersusScreenAnimation,
38
+ versusScreenInit,
35
39
  versusScreenPostRender,
36
40
  } from "./versusScreen";
37
41
 
38
42
  export function customStageInit(mod: ModUpgraded): void {
39
- saveDataManager("customStage", v);
40
43
  initRoomTypeMaps();
44
+ if (customStagesMap.size === 0) {
45
+ // If the end-user has no custom stages, we don't have to initialize any of the callbacks.
46
+ return;
47
+ }
48
+
49
+ saveDataManager("customStage", v);
50
+ streakTextInit();
51
+ versusScreenInit();
41
52
 
42
53
  mod.AddCallback(ModCallback.POST_RENDER, postRender); // 2
54
+ mod.AddCallback(ModCallback.POST_CURSE_EVAL, postCurseEval); // 12
43
55
  mod.AddCallback(ModCallback.POST_GAME_STARTED, postGameStarted); // 15
44
56
  mod.AddCallback(ModCallback.GET_SHADER_PARAMS, getShaderParams); // 21
45
57
  mod.AddCallbackCustom(
@@ -128,6 +140,23 @@ function postRender() {
128
140
  versusScreenPostRender();
129
141
  }
130
142
 
143
+ // ModCallback.POST_CURSE_EVAL (12)
144
+ function postCurseEval(
145
+ curses: BitFlags<LevelCurse>,
146
+ ): BitFlags<LevelCurse> | undefined {
147
+ const customStage = v.run.currentCustomStage;
148
+ if (customStage === null) {
149
+ return undefined;
150
+ }
151
+
152
+ // Prevent XL floors on custom stages, since the streak text will not work properly.
153
+ if (hasFlag(curses, LevelCurse.MAZE)) {
154
+ return removeFlag(curses, LevelCurse.MAZE);
155
+ }
156
+
157
+ return undefined;
158
+ }
159
+
131
160
  // ModCallback.POST_GAME_STARTED (15)
132
161
  function postGameStarted() {
133
162
  // We don't early return here because we need to unconditionally reset the sprites.