isaacscript-common 6.11.2 → 6.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/callbacks/postGridEntityCustomRender.d.ts +2 -0
- package/dist/callbacks/postGridEntityCustomRender.d.ts.map +1 -0
- package/dist/callbacks/postGridEntityCustomRender.lua +36 -0
- package/dist/callbacks/postGridEntityCustomUpdate.d.ts +2 -0
- package/dist/callbacks/postGridEntityCustomUpdate.d.ts.map +1 -0
- package/dist/callbacks/postGridEntityCustomUpdate.lua +36 -0
- package/dist/callbacks/postNewRoomEarly.lua +2 -2
- package/dist/callbacks/postPickupInitFirst.lua +1 -20
- package/dist/callbacks/reorderedCallbacks.d.ts +5 -5
- package/dist/callbacks/reorderedCallbacks.d.ts.map +1 -1
- package/dist/callbacks/reorderedCallbacks.lua +5 -5
- package/dist/callbacks/subscriptions/postGridEntityCustomRender.d.ts +6 -0
- package/dist/callbacks/subscriptions/postGridEntityCustomRender.d.ts.map +1 -0
- package/dist/callbacks/subscriptions/postGridEntityCustomRender.lua +29 -0
- package/dist/callbacks/subscriptions/postGridEntityCustomUpdate.d.ts +6 -0
- package/dist/callbacks/subscriptions/postGridEntityCustomUpdate.d.ts.map +1 -0
- package/dist/callbacks/subscriptions/postGridEntityCustomUpdate.lua +29 -0
- package/dist/constants.d.ts +1 -5
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.lua +0 -7
- package/dist/constantsFirstLast.d.ts +5 -1
- package/dist/constantsFirstLast.d.ts.map +1 -1
- package/dist/constantsFirstLast.lua +6 -0
- package/dist/enums/ModCallbackCustom.d.ts +89 -66
- package/dist/enums/ModCallbackCustom.d.ts.map +1 -1
- package/dist/enums/ModCallbackCustom.lua +62 -58
- package/dist/enums/private/SerializationBrand.d.ts +1 -1
- package/dist/enums/private/SerializationBrand.lua +1 -1
- package/dist/features/collectibleItemPoolType.d.ts +2 -2
- package/dist/features/collectibleItemPoolType.lua +2 -2
- package/dist/features/customGridEntity.d.ts +11 -2
- package/dist/features/customGridEntity.d.ts.map +1 -1
- package/dist/features/customGridEntity.lua +22 -2
- package/dist/features/customTrapdoor/blackSprite.d.ts.map +1 -1
- package/dist/features/customTrapdoor/blackSprite.lua +6 -6
- package/dist/features/customTrapdoor/customTrapdoorConstants.d.ts +2 -2
- package/dist/features/customTrapdoor/customTrapdoorConstants.d.ts.map +1 -1
- package/dist/features/customTrapdoor/customTrapdoorConstants.lua +2 -2
- package/dist/features/customTrapdoor/init.d.ts.map +1 -1
- package/dist/features/customTrapdoor/init.lua +4 -3
- package/dist/features/customTrapdoor/touched.d.ts.map +1 -1
- package/dist/features/customTrapdoor/touched.lua +51 -33
- package/dist/features/deployJSONRoom.d.ts +2 -2
- package/dist/features/deployJSONRoom.lua +2 -2
- package/dist/features/extraConsoleCommands/exports.d.ts +4 -3
- package/dist/features/extraConsoleCommands/exports.d.ts.map +1 -1
- package/dist/features/extraConsoleCommands/exports.lua +4 -3
- package/dist/features/extraConsoleCommands/init.lua +12 -14
- package/dist/features/extraConsoleCommands/listCommands.d.ts +15 -19
- package/dist/features/extraConsoleCommands/listCommands.d.ts.map +1 -1
- package/dist/features/extraConsoleCommands/listCommands.lua +34 -42
- package/dist/features/pause.d.ts +1 -1
- package/dist/features/pause.d.ts.map +1 -1
- package/dist/features/pause.lua +87 -8
- package/dist/features/persistentEntities.d.ts.map +1 -1
- package/dist/features/persistentEntities.lua +7 -7
- package/dist/features/pickupIndex.d.ts +19 -0
- package/dist/features/pickupIndex.d.ts.map +1 -0
- package/dist/features/pickupIndex.lua +197 -0
- package/dist/features/roomHistory.d.ts +24 -0
- package/dist/features/roomHistory.d.ts.map +1 -0
- package/dist/features/roomHistory.lua +89 -0
- package/dist/functions/collectibles.d.ts +26 -13
- package/dist/functions/collectibles.d.ts.map +1 -1
- package/dist/functions/collectibles.lua +26 -13
- package/dist/functions/color.d.ts +10 -0
- package/dist/functions/color.d.ts.map +1 -1
- package/dist/functions/color.lua +24 -0
- package/dist/functions/entities.d.ts +3 -3
- package/dist/functions/entities.d.ts.map +1 -1
- package/dist/functions/entities.lua +8 -3
- package/dist/functions/gridEntities.d.ts +4 -22
- package/dist/functions/gridEntities.d.ts.map +1 -1
- package/dist/functions/gridEntities.lua +4 -61
- package/dist/functions/isaacAPIClass.d.ts +64 -0
- package/dist/functions/isaacAPIClass.d.ts.map +1 -1
- package/dist/functions/isaacAPIClass.lua +84 -1
- package/dist/functions/kColor.d.ts +10 -0
- package/dist/functions/kColor.d.ts.map +1 -1
- package/dist/functions/kColor.lua +24 -0
- package/dist/functions/map.d.ts +2 -0
- package/dist/functions/map.d.ts.map +1 -1
- package/dist/functions/map.lua +7 -0
- package/dist/functions/npcs.d.ts +2 -2
- package/dist/functions/npcs.lua +2 -2
- package/dist/functions/pickupVariants.d.ts +2 -2
- package/dist/functions/pickupVariants.d.ts.map +1 -1
- package/dist/functions/pickupVariants.lua +2 -2
- package/dist/functions/playerCenter.lua +2 -2
- package/dist/functions/playerIndex.d.ts +0 -3
- package/dist/functions/playerIndex.d.ts.map +1 -1
- package/dist/functions/playerIndex.lua +4 -23
- package/dist/functions/random.d.ts +1 -1
- package/dist/functions/random.lua +1 -1
- package/dist/functions/rockAlt.d.ts +28 -0
- package/dist/functions/rockAlt.d.ts.map +1 -0
- package/dist/functions/rockAlt.lua +140 -0
- package/dist/functions/roomData.d.ts +3 -2
- package/dist/functions/roomData.d.ts.map +1 -1
- package/dist/functions/roomData.lua +3 -2
- package/dist/functions/rooms.d.ts +6 -6
- package/dist/functions/rooms.lua +6 -6
- package/dist/functions/set.d.ts +2 -0
- package/dist/functions/set.d.ts.map +1 -1
- package/dist/functions/set.lua +6 -0
- package/dist/functions/stage.d.ts +1 -0
- package/dist/functions/stage.d.ts.map +1 -1
- package/dist/functions/stage.lua +4 -0
- package/dist/functions/vector.d.ts +11 -0
- package/dist/functions/vector.d.ts.map +1 -1
- package/dist/functions/vector.lua +23 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.lua +31 -0
- package/dist/initCustomCallbacks.d.ts.map +1 -1
- package/dist/initCustomCallbacks.lua +6 -0
- package/dist/initFeatures.d.ts.map +1 -1
- package/dist/initFeatures.lua +6 -0
- package/dist/interfaces/AddCallbackParameterCustom.d.ts +4 -0
- package/dist/interfaces/AddCallbackParameterCustom.d.ts.map +1 -1
- package/dist/interfaces/RoomDescription.d.ts +14 -0
- package/dist/interfaces/RoomDescription.d.ts.map +1 -0
- package/dist/interfaces/RoomDescription.lua +2 -0
- package/dist/objects/callbackRegisterFunctions.d.ts.map +1 -1
- package/dist/objects/callbackRegisterFunctions.lua +6 -0
- package/dist/types/CollectibleIndex.d.ts +1 -1
- package/dist/types/PickupIndex.d.ts +17 -0
- package/dist/types/PickupIndex.d.ts.map +1 -0
- package/dist/types/PickupIndex.lua +2 -0
- package/dist/types/PlayerIndex.d.ts +1 -1
- package/dist/upgradeMod.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/callbacks/postGridEntityCustomRender.ts +44 -0
- package/src/callbacks/postGridEntityCustomUpdate.ts +44 -0
- package/src/callbacks/postNewRoomEarly.ts +2 -2
- package/src/callbacks/postPickupInitFirst.ts +3 -32
- package/src/callbacks/postPlayerReorderedCallbacks.ts +3 -3
- package/src/callbacks/reorderedCallbacks.ts +9 -8
- package/src/callbacks/subscriptions/postGridEntityCustomRender.ts +41 -0
- package/src/callbacks/subscriptions/postGridEntityCustomUpdate.ts +41 -0
- package/src/constants.ts +1 -9
- package/src/constantsFirstLast.ts +16 -0
- package/src/enums/ModCallbackCustom.ts +33 -8
- package/src/enums/private/SerializationBrand.ts +1 -1
- package/src/features/collectibleItemPoolType.ts +3 -3
- package/src/features/customGridEntity.ts +27 -2
- package/src/features/customTrapdoor/blackSprite.ts +11 -5
- package/src/features/customTrapdoor/customTrapdoorConstants.ts +2 -2
- package/src/features/customTrapdoor/init.ts +7 -5
- package/src/features/customTrapdoor/touched.ts +59 -39
- package/src/features/deployJSONRoom.ts +4 -4
- package/src/features/extraConsoleCommands/exports.ts +4 -3
- package/src/features/extraConsoleCommands/init.ts +18 -14
- package/src/features/extraConsoleCommands/listCommands.ts +38 -43
- package/src/features/pause.ts +97 -7
- package/src/features/persistentEntities.ts +9 -8
- package/src/features/pickupIndex.ts +257 -0
- package/src/features/playerInventory.ts +2 -2
- package/src/features/roomHistory.ts +113 -0
- package/src/features/saveDataManager/main.ts +2 -2
- package/src/features/taintedLazarusPlayers.ts +5 -5
- package/src/functions/collectibles.ts +26 -13
- package/src/functions/color.ts +22 -0
- package/src/functions/entities.ts +6 -3
- package/src/functions/gridEntities.ts +4 -56
- package/src/functions/isaacAPIClass.ts +106 -1
- package/src/functions/kColor.ts +22 -0
- package/src/functions/map.ts +10 -0
- package/src/functions/npcs.ts +2 -2
- package/src/functions/pickupVariants.ts +2 -2
- package/src/functions/playerCenter.ts +2 -2
- package/src/functions/playerIndex.ts +8 -21
- package/src/functions/random.ts +1 -1
- package/src/functions/rockAlt.ts +117 -0
- package/src/functions/roomData.ts +3 -2
- package/src/functions/rooms.ts +6 -6
- package/src/functions/set.ts +7 -1
- package/src/functions/stage.ts +10 -1
- package/src/functions/vector.ts +23 -0
- package/src/index.ts +4 -0
- package/src/initCustomCallbacks.ts +4 -0
- package/src/initFeatures.ts +4 -0
- package/src/interfaces/AddCallbackParameterCustom.ts +4 -0
- package/src/interfaces/RoomDescription.ts +19 -0
- package/src/objects/callbackRegisterFunctions.ts +6 -0
- package/src/types/CollectibleIndex.ts +1 -1
- package/src/types/PickupIndex.ts +15 -0
- package/src/types/PlayerIndex.ts +1 -1
- package/src/upgradeMod.ts +2 -1
package/src/features/pause.ts
CHANGED
|
@@ -4,17 +4,36 @@ import {
|
|
|
4
4
|
InputHook,
|
|
5
5
|
ModCallback,
|
|
6
6
|
} from "isaac-typescript-definitions";
|
|
7
|
+
import { VectorZero } from "../constants";
|
|
8
|
+
import {
|
|
9
|
+
getProjectiles,
|
|
10
|
+
getTears,
|
|
11
|
+
removeAllProjectiles,
|
|
12
|
+
removeAllTears,
|
|
13
|
+
} from "../functions/entitiesSpecific";
|
|
14
|
+
import { isTear } from "../functions/isaacAPIClass";
|
|
7
15
|
import { logError } from "../functions/log";
|
|
16
|
+
import { getAllPlayers } from "../functions/playerIndex";
|
|
8
17
|
import { useActiveItemTemp } from "../functions/players";
|
|
9
18
|
import { disableAllInputsExceptFor, enableAllInputs } from "./disableInputs";
|
|
10
19
|
import { saveDataManager } from "./saveDataManager/exports";
|
|
11
20
|
|
|
12
21
|
const FEATURE_NAME = "pause";
|
|
13
22
|
|
|
23
|
+
interface InitialDescription {
|
|
24
|
+
position: Vector;
|
|
25
|
+
positionOffset: Vector;
|
|
26
|
+
velocity: Vector;
|
|
27
|
+
height: float;
|
|
28
|
+
fallingSpeed: float;
|
|
29
|
+
fallingAcceleration: float;
|
|
30
|
+
}
|
|
31
|
+
|
|
14
32
|
const v = {
|
|
15
33
|
run: {
|
|
16
34
|
isPseudoPaused: false,
|
|
17
35
|
shouldUnpause: false,
|
|
36
|
+
initialDescriptions: new Map<PtrHash, InitialDescription>(),
|
|
18
37
|
},
|
|
19
38
|
};
|
|
20
39
|
|
|
@@ -37,8 +56,34 @@ function postUpdate() {
|
|
|
37
56
|
return;
|
|
38
57
|
}
|
|
39
58
|
|
|
40
|
-
const
|
|
41
|
-
useActiveItemTemp(
|
|
59
|
+
const firstPlayer = Isaac.GetPlayer();
|
|
60
|
+
useActiveItemTemp(firstPlayer, CollectibleType.PAUSE);
|
|
61
|
+
|
|
62
|
+
stopTearsAndProjectilesFromMoving();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function stopTearsAndProjectilesFromMoving() {
|
|
66
|
+
const tearsAndProjectiles = [...getTears(), ...getProjectiles()];
|
|
67
|
+
|
|
68
|
+
for (const tearOrProjectile of tearsAndProjectiles) {
|
|
69
|
+
const ptrHash = GetPtrHash(tearOrProjectile);
|
|
70
|
+
const initialDescription = v.run.initialDescriptions.get(ptrHash);
|
|
71
|
+
if (initialDescription === undefined) {
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
tearOrProjectile.Position = initialDescription.position;
|
|
76
|
+
tearOrProjectile.PositionOffset = initialDescription.positionOffset;
|
|
77
|
+
tearOrProjectile.Velocity = VectorZero;
|
|
78
|
+
tearOrProjectile.Height = initialDescription.height;
|
|
79
|
+
tearOrProjectile.FallingSpeed = 0;
|
|
80
|
+
if (isTear(tearOrProjectile)) {
|
|
81
|
+
tearOrProjectile.FallingAcceleration =
|
|
82
|
+
initialDescription.fallingAcceleration;
|
|
83
|
+
} else {
|
|
84
|
+
tearOrProjectile.FallingAccel = initialDescription.fallingAcceleration;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
42
87
|
}
|
|
43
88
|
|
|
44
89
|
// ModCallback.INPUT_ACTION (13)
|
|
@@ -57,8 +102,8 @@ function inputActionGetActionValue(
|
|
|
57
102
|
}
|
|
58
103
|
v.run.shouldUnpause = false;
|
|
59
104
|
|
|
60
|
-
// Returning a value of 1 for a single frame will be enough for the game to register an
|
|
61
|
-
// but not enough for a tear to actually be fired.
|
|
105
|
+
// Returning a value of 1 for a single sub-frame will be enough for the game to register an
|
|
106
|
+
// unpause but not enough for a tear to actually be fired.
|
|
62
107
|
return 1;
|
|
63
108
|
}
|
|
64
109
|
|
|
@@ -68,7 +113,7 @@ function inputActionGetActionValue(
|
|
|
68
113
|
*
|
|
69
114
|
* Under the hood, this function:
|
|
70
115
|
* - uses the Pause collectible on every game frame
|
|
71
|
-
* - disables any player inputs (except for `ButtonAction.MENU_CONFIRM`)
|
|
116
|
+
* - disables any player inputs (except for `ButtonAction.MENU_CONFIRM` and `ButtonAction.CONSOLE`)
|
|
72
117
|
*/
|
|
73
118
|
export function pause(): void {
|
|
74
119
|
if (v.run.isPseudoPaused) {
|
|
@@ -79,8 +124,43 @@ export function pause(): void {
|
|
|
79
124
|
}
|
|
80
125
|
v.run.isPseudoPaused = true;
|
|
81
126
|
|
|
82
|
-
|
|
127
|
+
// Tears/projectiles in the room will move slightly on every frame, even when the Pause
|
|
128
|
+
// collectible is active. Thus, we manually reset the initial positions and heights on every
|
|
129
|
+
// frame.
|
|
130
|
+
v.run.initialDescriptions.clear();
|
|
131
|
+
const tearsAndProjectiles = [...getTears(), ...getProjectiles()];
|
|
132
|
+
for (const tearOrProjectile of tearsAndProjectiles) {
|
|
133
|
+
const ptrHash = GetPtrHash(tearOrProjectile);
|
|
134
|
+
const initialDescription: InitialDescription = {
|
|
135
|
+
position: tearOrProjectile.Position,
|
|
136
|
+
positionOffset: tearOrProjectile.PositionOffset,
|
|
137
|
+
velocity: tearOrProjectile.Velocity,
|
|
138
|
+
height: tearOrProjectile.Height,
|
|
139
|
+
fallingSpeed: tearOrProjectile.FallingSpeed,
|
|
140
|
+
fallingAcceleration: isTear(tearOrProjectile)
|
|
141
|
+
? tearOrProjectile.FallingAcceleration
|
|
142
|
+
: tearOrProjectile.FallingAccel,
|
|
143
|
+
};
|
|
144
|
+
v.run.initialDescriptions.set(ptrHash, initialDescription);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const firstPlayer = Isaac.GetPlayer();
|
|
148
|
+
useActiveItemTemp(firstPlayer, CollectibleType.PAUSE);
|
|
149
|
+
|
|
150
|
+
const whitelist = new Set([ButtonAction.MENU_CONFIRM, ButtonAction.CONSOLE]);
|
|
83
151
|
disableAllInputsExceptFor(FEATURE_NAME, whitelist);
|
|
152
|
+
|
|
153
|
+
for (const player of getAllPlayers()) {
|
|
154
|
+
// Disable the controls to prevent the players from moving, shooting, and so on. (We also
|
|
155
|
+
// disable the inputs in the `INPUT_ACTION` callback, but that does not prevent mouse inputs.)
|
|
156
|
+
player.ControlsEnabled = false;
|
|
157
|
+
|
|
158
|
+
// Prevent the players from leaving the room. (If we don't reset the velocity, they can continue
|
|
159
|
+
// to move towards a door.)
|
|
160
|
+
player.Velocity = VectorZero;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
stopTearsAndProjectilesFromMoving();
|
|
84
164
|
}
|
|
85
165
|
|
|
86
166
|
/** Helper function to put things back to normal after the `pause` function was used. */
|
|
@@ -92,7 +172,17 @@ export function unpause(): void {
|
|
|
92
172
|
return;
|
|
93
173
|
}
|
|
94
174
|
v.run.isPseudoPaused = false;
|
|
175
|
+
v.run.shouldUnpause = true;
|
|
95
176
|
|
|
96
177
|
enableAllInputs(FEATURE_NAME);
|
|
97
|
-
|
|
178
|
+
for (const player of getAllPlayers()) {
|
|
179
|
+
player.ControlsEnabled = true;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// After a vanilla pause, the tears will not resume their normal velocity and will "stick" to the
|
|
183
|
+
// air. Even if we try to help the tears along by explicitly resetting all of the velocity-related
|
|
184
|
+
// variables to their initial values, this will not make a difference. Thus, revert to removing
|
|
185
|
+
// all of the tears and projectiles in the room.
|
|
186
|
+
removeAllTears();
|
|
187
|
+
removeAllProjectiles();
|
|
98
188
|
}
|
|
@@ -3,12 +3,12 @@ import {
|
|
|
3
3
|
EntityType,
|
|
4
4
|
ModCallback,
|
|
5
5
|
} from "isaac-typescript-definitions";
|
|
6
|
-
import { game } from "../cachedClasses";
|
|
7
6
|
import { ModUpgraded } from "../classes/ModUpgraded";
|
|
8
7
|
import { ModCallbackCustom } from "../enums/ModCallbackCustom";
|
|
9
8
|
import { errorIfFeaturesNotInitialized } from "../featuresInitialized";
|
|
10
9
|
import { spawn } from "../functions/entities";
|
|
11
10
|
import { getRoomListIndex } from "../functions/roomData";
|
|
11
|
+
import { getLatestRoomDescription } from "./roomHistory";
|
|
12
12
|
import { saveDataManager } from "./saveDataManager/exports";
|
|
13
13
|
|
|
14
14
|
interface PersistentEntityDescription {
|
|
@@ -64,18 +64,19 @@ function postEntityRemove(entity: Entity) {
|
|
|
64
64
|
const index = tuple[0];
|
|
65
65
|
|
|
66
66
|
// The persistent entity is despawning, presumably because the player is in the process of leaving
|
|
67
|
-
// the room. Keep track of the position for later. We use the previous room list index because
|
|
68
|
-
//
|
|
69
|
-
|
|
70
|
-
const
|
|
71
|
-
const previousRoomListIndex =
|
|
72
|
-
|
|
67
|
+
// the room. Keep track of the position for later. We use the previous room list index because
|
|
68
|
+
// even though the `POST_NEW_ROOM` callback was not fired yet, we have already traveled to the
|
|
69
|
+
// next room.
|
|
70
|
+
const previousRoomDescription = getLatestRoomDescription();
|
|
71
|
+
const previousRoomListIndex = previousRoomDescription.roomListIndex;
|
|
72
|
+
const persistentEntityDescription: PersistentEntityDescription = {
|
|
73
73
|
entityType: entity.Type,
|
|
74
74
|
variant: entity.Variant,
|
|
75
75
|
subType: entity.SubType,
|
|
76
76
|
roomListIndex: previousRoomListIndex,
|
|
77
77
|
position: entity.Position,
|
|
78
|
-
}
|
|
78
|
+
};
|
|
79
|
+
v.level.persistentEntities.set(index, persistentEntityDescription);
|
|
79
80
|
}
|
|
80
81
|
|
|
81
82
|
// ModCallbackCustom.POST_NEW_ROOM_REORDERED
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import {
|
|
2
|
+
EntityType,
|
|
3
|
+
ModCallback,
|
|
4
|
+
RoomType,
|
|
5
|
+
} from "isaac-typescript-definitions";
|
|
6
|
+
import { game } from "../cachedClasses";
|
|
7
|
+
import { DefaultMap } from "../classes/DefaultMap";
|
|
8
|
+
import { ModUpgraded } from "../classes/ModUpgraded";
|
|
9
|
+
import { ModCallbackCustom } from "../enums/ModCallbackCustom";
|
|
10
|
+
import { errorIfFeaturesNotInitialized } from "../featuresInitialized";
|
|
11
|
+
import { getEntityID } from "../functions/entities";
|
|
12
|
+
import { getPickups } from "../functions/entitiesSpecific";
|
|
13
|
+
import { getRoomListIndex } from "../functions/roomData";
|
|
14
|
+
import { onAscent } from "../functions/stage";
|
|
15
|
+
import { vectorEquals } from "../functions/vector";
|
|
16
|
+
import { PickupIndex } from "../types/PickupIndex";
|
|
17
|
+
import { getLatestRoomDescription } from "./roomHistory";
|
|
18
|
+
import { saveDataManager } from "./saveDataManager/exports";
|
|
19
|
+
|
|
20
|
+
interface PickupDescription {
|
|
21
|
+
position: Vector;
|
|
22
|
+
initSeed: Seed;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const FEATURE_NAME = "pickupIndex";
|
|
26
|
+
|
|
27
|
+
const v = {
|
|
28
|
+
run: {
|
|
29
|
+
pickupCounter: 0 as PickupIndex,
|
|
30
|
+
currentRoomListIndex: 0,
|
|
31
|
+
|
|
32
|
+
pickupDataTreasureRooms: new Map<PickupIndex, PickupDescription>(),
|
|
33
|
+
pickupDataBossRooms: new Map<PickupIndex, PickupDescription>(),
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
level: {
|
|
37
|
+
/** Indexed by room list index. */
|
|
38
|
+
pickupData: new DefaultMap<int, Map<PickupIndex, PickupDescription>>(
|
|
39
|
+
() => new Map(),
|
|
40
|
+
),
|
|
41
|
+
},
|
|
42
|
+
|
|
43
|
+
room: {
|
|
44
|
+
pickupIndexes: new Map<PtrHash, PickupIndex>(),
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export function pickupIndexInit(mod: ModUpgraded): void {
|
|
49
|
+
saveDataManager(FEATURE_NAME, v);
|
|
50
|
+
|
|
51
|
+
mod.AddCallback(ModCallback.POST_PICKUP_INIT, postPickupInit); // 34
|
|
52
|
+
mod.AddCallback(
|
|
53
|
+
ModCallback.POST_ENTITY_REMOVE,
|
|
54
|
+
postEntityRemovePickup,
|
|
55
|
+
EntityType.PICKUP,
|
|
56
|
+
); // 67
|
|
57
|
+
mod.AddCallbackCustom(
|
|
58
|
+
ModCallbackCustom.POST_NEW_ROOM_REORDERED,
|
|
59
|
+
postNewRoomReordered,
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// ModCallback.POST_PICKUP_INIT (34)
|
|
64
|
+
function postPickupInit(pickup: EntityPickup) {
|
|
65
|
+
const ptrHash = GetPtrHash(pickup);
|
|
66
|
+
|
|
67
|
+
// In certain situations, pickups can be morphed, and this should not incur a new pickup counter.
|
|
68
|
+
// (For example, the collectible rotation with Tainted Isaac.)
|
|
69
|
+
if (v.room.pickupIndexes.has(ptrHash)) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// If we are re-entering a room that previously had a pickup, then we don't need to make a new
|
|
74
|
+
// index, because we will re-use the existing one.
|
|
75
|
+
const room = game.GetRoom();
|
|
76
|
+
const isFirstVisit = room.IsFirstVisit();
|
|
77
|
+
const roomFrameCount = room.GetFrameCount();
|
|
78
|
+
if (!isFirstVisit && roomFrameCount <= 0) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
v.run.pickupCounter++;
|
|
83
|
+
v.room.pickupIndexes.set(ptrHash, v.run.pickupCounter);
|
|
84
|
+
|
|
85
|
+
// Additionally, keep track of which room we are storing the pointer hashes for.
|
|
86
|
+
v.run.currentRoomListIndex = getRoomListIndex();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// ModCallback.POST_ENTITY_REMOVE (67)
|
|
90
|
+
// EntityType.PICKUP (5)
|
|
91
|
+
function postEntityRemovePickup(entity: Entity) {
|
|
92
|
+
checkDespawningFromPlayerLeavingRoom(entity);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function checkDespawningFromPlayerLeavingRoom(entity: Entity) {
|
|
96
|
+
const ptrHash = GetPtrHash(entity);
|
|
97
|
+
const pickupIndex = v.room.pickupIndexes.get(ptrHash);
|
|
98
|
+
if (pickupIndex === undefined) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const roomListIndex = getRoomListIndex();
|
|
103
|
+
if (roomListIndex === v.run.currentRoomListIndex) {
|
|
104
|
+
// This is a pickup that is despawning in the current room. For example, it could be a heart
|
|
105
|
+
// pickup that the player picked up. Thus, we do not need to keep track of it's metadata.
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
trackDespawningPickupMetadata(entity, pickupIndex);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* This is a pickup that is despawning because the player is in the process of leaving the room.
|
|
114
|
+
* Keep track of the metadata for later. We need to use the previous room list index because even
|
|
115
|
+
* though the `POST_NEW_ROOM` callback was not fired yet, we have already traveled to the next room.
|
|
116
|
+
*/
|
|
117
|
+
function trackDespawningPickupMetadata(
|
|
118
|
+
entity: Entity,
|
|
119
|
+
pickupIndex: PickupIndex,
|
|
120
|
+
) {
|
|
121
|
+
const previousRoomDescription = getLatestRoomDescription();
|
|
122
|
+
const previousRoomListIndex = previousRoomDescription.roomListIndex;
|
|
123
|
+
const pickupDescriptions = v.level.pickupData.getAndSetDefault(
|
|
124
|
+
previousRoomListIndex,
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
const pickupDescription: PickupDescription = {
|
|
128
|
+
position: entity.Position,
|
|
129
|
+
initSeed: entity.InitSeed,
|
|
130
|
+
};
|
|
131
|
+
pickupDescriptions.set(pickupIndex, pickupDescription);
|
|
132
|
+
|
|
133
|
+
// If the despawning pickup was in a Treasure Room or Boss Room, then it is possible that the
|
|
134
|
+
// pickup could re-appear during The Ascent. If this is the case, we store the metadata on a
|
|
135
|
+
// separate map to reference later.
|
|
136
|
+
if (onAscent()) {
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const room = game.GetRoom();
|
|
141
|
+
const roomType = room.GetType();
|
|
142
|
+
|
|
143
|
+
switch (roomType) {
|
|
144
|
+
case RoomType.TREASURE: {
|
|
145
|
+
v.run.pickupDataTreasureRooms.set(pickupIndex, pickupDescription);
|
|
146
|
+
break;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
case RoomType.BOSS: {
|
|
150
|
+
v.run.pickupDataBossRooms.set(pickupIndex, pickupDescription);
|
|
151
|
+
break;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
default: {
|
|
155
|
+
break;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// ModCallbackCustom.POST_NEW_ROOM_REORDERED
|
|
161
|
+
function postNewRoomReordered() {
|
|
162
|
+
const room = game.GetRoom();
|
|
163
|
+
const isFirstVisit = room.IsFirstVisit();
|
|
164
|
+
|
|
165
|
+
if (isFirstVisit) {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const roomListIndex = getRoomListIndex();
|
|
170
|
+
const pickupDescriptions = v.level.pickupData.getAndSetDefault(roomListIndex);
|
|
171
|
+
|
|
172
|
+
for (const pickup of getPickups()) {
|
|
173
|
+
let pickupIndex = getStoredPickupIndex(pickup, pickupDescriptions);
|
|
174
|
+
if (pickupIndex === undefined) {
|
|
175
|
+
pickupIndex = getPostAscentPickupIndex(pickup);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (pickupIndex === undefined) {
|
|
179
|
+
const entityID = getEntityID(pickup);
|
|
180
|
+
error(
|
|
181
|
+
`Failed to find a pickup index corresponding to existing pickup: ${entityID}`,
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const ptrHash = GetPtrHash(pickup);
|
|
186
|
+
v.room.pickupIndexes.set(ptrHash, pickupIndex);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function getStoredPickupIndex(
|
|
191
|
+
pickup: Entity,
|
|
192
|
+
pickupDescriptions: Map<PickupIndex, PickupDescription>,
|
|
193
|
+
): PickupIndex | undefined {
|
|
194
|
+
for (const [pickupIndex, pickupDescription] of pickupDescriptions.entries()) {
|
|
195
|
+
if (
|
|
196
|
+
vectorEquals(pickupDescription.position, pickup.Position) &&
|
|
197
|
+
pickupDescription.initSeed === pickup.InitSeed
|
|
198
|
+
) {
|
|
199
|
+
return pickupIndex;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
return undefined;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function getPostAscentPickupIndex(pickup: EntityPickup) {
|
|
207
|
+
// If we have not found the pickup index yet, we might be re-entering a post-Ascent Treasure Room
|
|
208
|
+
// or Boss Room.
|
|
209
|
+
if (!onAscent()) {
|
|
210
|
+
return undefined;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const room = game.GetRoom();
|
|
214
|
+
const roomType = room.GetType();
|
|
215
|
+
|
|
216
|
+
switch (roomType) {
|
|
217
|
+
case RoomType.TREASURE: {
|
|
218
|
+
return getStoredPickupIndex(pickup, v.run.pickupDataTreasureRooms);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
case RoomType.BOSS: {
|
|
222
|
+
return getStoredPickupIndex(pickup, v.run.pickupDataBossRooms);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
default: {
|
|
226
|
+
return undefined;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Mods often have to track variables relating to a pickups. Finding an index for these kinds of
|
|
233
|
+
* data structures is difficult, since pickups are respawned every time a player re-enters a room,
|
|
234
|
+
* so the `PtrHash` will change.
|
|
235
|
+
*
|
|
236
|
+
* Use this function to get a unique index for a pickup to use in these data structures.
|
|
237
|
+
*
|
|
238
|
+
* Specifically, `PickupIndex` is a number that represents the spawn order of the pickup on the
|
|
239
|
+
* current run. For example, the first pickup spawned will have an index of 1, the second one will
|
|
240
|
+
* have an index of 2, and so on.
|
|
241
|
+
*
|
|
242
|
+
* Tracking pickups requires stateful tracking, so using pickup indexes requires an upgraded mod.
|
|
243
|
+
*/
|
|
244
|
+
export function getPickupIndex(pickup: EntityPickup): PickupIndex {
|
|
245
|
+
errorIfFeaturesNotInitialized(FEATURE_NAME);
|
|
246
|
+
|
|
247
|
+
const ptrHash = GetPtrHash(pickup);
|
|
248
|
+
const pickupIndex = v.room.pickupIndexes.get(ptrHash);
|
|
249
|
+
if (pickupIndex === undefined) {
|
|
250
|
+
const entityID = getEntityID(pickup);
|
|
251
|
+
error(
|
|
252
|
+
`Failed to get a pickup index for entity ${entityID} with hash: ${ptrHash}`,
|
|
253
|
+
);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return pickupIndex;
|
|
257
|
+
}
|
|
@@ -76,8 +76,8 @@ function useItemD4(
|
|
|
76
76
|
|
|
77
77
|
// ModCallback.POST_GAME_STARTED (15)
|
|
78
78
|
function postGameStarted() {
|
|
79
|
-
// We don't use the
|
|
80
|
-
// point.
|
|
79
|
+
// We don't use the `POST_PLAYER_INIT` callback because some items are not given to the player at
|
|
80
|
+
// that point.
|
|
81
81
|
for (const player of getAllPlayers()) {
|
|
82
82
|
const playerIndex = getPlayerIndex(player);
|
|
83
83
|
if (!v.run.playersInventory.has(playerIndex)) {
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { game } from "../cachedClasses";
|
|
2
|
+
import { ModUpgraded } from "../classes/ModUpgraded";
|
|
3
|
+
import { ModCallbackCustom } from "../enums/ModCallbackCustom";
|
|
4
|
+
import { errorIfFeaturesNotInitialized } from "../featuresInitialized";
|
|
5
|
+
import { getLastElement } from "../functions/array";
|
|
6
|
+
import {
|
|
7
|
+
getRoomGridIndex,
|
|
8
|
+
getRoomListIndex,
|
|
9
|
+
getRoomName,
|
|
10
|
+
getRoomStageID,
|
|
11
|
+
getRoomSubType,
|
|
12
|
+
getRoomVariant,
|
|
13
|
+
} from "../functions/roomData";
|
|
14
|
+
import { RoomDescription } from "../interfaces/RoomDescription";
|
|
15
|
+
import { saveDataManager } from "./saveDataManager/exports";
|
|
16
|
+
|
|
17
|
+
const FEATURE_NAME = "roomHistory";
|
|
18
|
+
|
|
19
|
+
const v = {
|
|
20
|
+
run: {
|
|
21
|
+
roomHistory: [] as RoomDescription[],
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/** @internal */
|
|
26
|
+
export function roomHistoryInit(mod: ModUpgraded): void {
|
|
27
|
+
saveDataManager(FEATURE_NAME, v);
|
|
28
|
+
|
|
29
|
+
mod.AddCallbackCustom(
|
|
30
|
+
ModCallbackCustom.POST_NEW_ROOM_EARLY,
|
|
31
|
+
postNewRoomEarly,
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// ModCallbackCustom.POST_NEW_ROOM_EARLY
|
|
36
|
+
function postNewRoomEarly() {
|
|
37
|
+
const level = game.GetLevel();
|
|
38
|
+
const stage = level.GetStage();
|
|
39
|
+
const stageType = level.GetStageType();
|
|
40
|
+
const room = game.GetRoom();
|
|
41
|
+
const roomType = room.GetType();
|
|
42
|
+
const stageID = getRoomStageID();
|
|
43
|
+
const roomVariant = getRoomVariant();
|
|
44
|
+
const roomSubType = getRoomSubType();
|
|
45
|
+
const roomName = getRoomName();
|
|
46
|
+
const roomGridIndex = getRoomGridIndex();
|
|
47
|
+
const roomListIndex = getRoomListIndex();
|
|
48
|
+
|
|
49
|
+
const roomDescription: RoomDescription = {
|
|
50
|
+
stage,
|
|
51
|
+
stageType,
|
|
52
|
+
stageID,
|
|
53
|
+
roomType,
|
|
54
|
+
roomVariant,
|
|
55
|
+
roomSubType,
|
|
56
|
+
roomName,
|
|
57
|
+
roomGridIndex,
|
|
58
|
+
roomListIndex,
|
|
59
|
+
};
|
|
60
|
+
v.run.roomHistory.push(roomDescription);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Helper function to get information about all of the rooms that a player has visited thus far on
|
|
65
|
+
* this run.
|
|
66
|
+
*/
|
|
67
|
+
export function getRoomHistory(): readonly RoomDescription[] {
|
|
68
|
+
errorIfFeaturesNotInitialized(FEATURE_NAME);
|
|
69
|
+
return v.run.roomHistory;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Helper function to get information about the room that was previously visited.
|
|
74
|
+
*
|
|
75
|
+
* In the special case of only one room having been visited thus far (i.e. the starting room of the
|
|
76
|
+
* run), the starting room will be returned.
|
|
77
|
+
*/
|
|
78
|
+
export function getPreviousRoomDescription(): RoomDescription {
|
|
79
|
+
const previousRoomDescription =
|
|
80
|
+
v.run.roomHistory[v.run.roomHistory.length - 2];
|
|
81
|
+
if (previousRoomDescription !== undefined) {
|
|
82
|
+
return previousRoomDescription;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const startingRoomDescription = v.run.roomHistory[0];
|
|
86
|
+
if (startingRoomDescription !== undefined) {
|
|
87
|
+
return startingRoomDescription;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
error(
|
|
91
|
+
"Failed to find a room description for any rooms thus far on this run.",
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Helper function to get information about the most recent room that is stored in the room history
|
|
97
|
+
* array.
|
|
98
|
+
*
|
|
99
|
+
* This is useful in the `POST_ENTITY_REMOVE` callback, since if an entity is despawning due to a
|
|
100
|
+
* player having left the room, the current room will have changed already, but the `POST_NEW_ROOM`
|
|
101
|
+
* callback will not have fired yet, and there will not be an entry in the room history array for
|
|
102
|
+
* the current room.
|
|
103
|
+
*/
|
|
104
|
+
export function getLatestRoomDescription(): RoomDescription {
|
|
105
|
+
const latestRoomDescription = getLastElement(v.run.roomHistory);
|
|
106
|
+
if (latestRoomDescription === undefined) {
|
|
107
|
+
error(
|
|
108
|
+
"Failed to get the latest room description since the room history array was empty.",
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return latestRoomDescription;
|
|
113
|
+
}
|
|
@@ -65,8 +65,8 @@ function postPlayerInit() {
|
|
|
65
65
|
restoreDefaultsAll();
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
// On continued runs, the
|
|
69
|
-
// saved data based on level getting overwritten.
|
|
68
|
+
// On continued runs, the `POST_NEW_LEVEL` callback will not fire, so we do not have to worry
|
|
69
|
+
// about saved data based on level getting overwritten.
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
// ModCallback.PRE_GAME_EXIT (17)
|
|
@@ -58,11 +58,11 @@ function postPlayerInit(player: EntityPlayer) {
|
|
|
58
58
|
/**
|
|
59
59
|
* Indexes are the `PtrHash`, values are the `EntityPtr` of the *other* Lazarus.
|
|
60
60
|
*
|
|
61
|
-
* When starting a run, the
|
|
62
|
-
* for Tainted Lazarus. When continuing a run, the
|
|
63
|
-
* character that is currently active. Thus, since the order of the characters is not
|
|
64
|
-
* insert each of their pointers into a queue, and then only populate the map when we
|
|
65
|
-
* Tainted Lazarus and one Dead Tainted Lazarus.
|
|
61
|
+
* When starting a run, the `POST_PLAYER_INIT` callback will fire first for Dead Tainted Lazarus,
|
|
62
|
+
* then for Tainted Lazarus. When continuing a run, the `POST_PLAYER_INIT` callback will fire first
|
|
63
|
+
* for the character that is currently active. Thus, since the order of the characters is not
|
|
64
|
+
* certain, we insert each of their pointers into a queue, and then only populate the map when we
|
|
65
|
+
* have one Tainted Lazarus and one Dead Tainted Lazarus.
|
|
66
66
|
*/
|
|
67
67
|
function checkDequeue() {
|
|
68
68
|
if (
|
|
@@ -176,38 +176,51 @@ export function getCollectibleGfxFilename(
|
|
|
176
176
|
}
|
|
177
177
|
|
|
178
178
|
/**
|
|
179
|
-
* Mods
|
|
180
|
-
* data structures is difficult, since collectibles are respawned every time a player re-enters a
|
|
181
|
-
* room, so the `PtrHash` will change.
|
|
182
|
-
*
|
|
179
|
+
* Mods may have to keep track of data relating to a collectible. Finding an index for these kinds
|
|
180
|
+
* of data structures is difficult, since collectibles are respawned every time a player re-enters a
|
|
181
|
+
* room (like all other pickups), so the `PtrHash` will change.
|
|
182
|
+
*
|
|
183
|
+
* Use this function to get a unique index for a collectible to use in these data structures.
|
|
184
|
+
*
|
|
185
|
+
* If your mod is upgraded, then you should use the `getPickupIndex` function instead, as it is more
|
|
186
|
+
* general purpose and less prone to error (but relies on stateful tracking of pickups as the run
|
|
187
|
+
* progresses).
|
|
188
|
+
*
|
|
189
|
+
* Collectibles are a special case of pickups: they cannot be pushed around. (They actually can be
|
|
190
|
+
* pushed, but usually will stay on the same grid index.) Thus, it is possible to generate a
|
|
191
|
+
* somewhat reliable non-stateful index for collectibles. We use a 4-tuple of the room list index,
|
|
192
|
+
* the grid index of the collectible in the room, the collectible's `SubType`, and the collectible's
|
|
193
|
+
* `InitSeed`.
|
|
183
194
|
*
|
|
184
195
|
* Collectibles that are shifted by Tainted Isaac's mechanic will have unique collectible indexes
|
|
185
|
-
* because the SubType is different. (The collectible entities share the same InitSeed
|
|
196
|
+
* because the `SubType` is different. (The collectible entities share the same `InitSeed` and
|
|
197
|
+
* `PtrHash`.)
|
|
186
198
|
*
|
|
187
199
|
* Collectibles that are rolled (with e.g. a D6) will have unique collectible indexes because the
|
|
188
|
-
* SubType and InitSeed are different. If you want to track collectibles independently of any
|
|
200
|
+
* `SubType` and `InitSeed` are different. If you want to track collectibles independently of any
|
|
189
201
|
* rerolls, then you can use the `PtrHash` as an index instead. (The `PtrHash` will not persist
|
|
190
202
|
* between rooms, however.)
|
|
191
203
|
*
|
|
192
204
|
* Note that:
|
|
193
205
|
* - The grid index is a necessary part of the collectible index because Diplopia and Crooked Penny
|
|
194
|
-
* can cause two or more collectibles with the same SubType and InitSeed to exist in the same
|
|
206
|
+
* can cause two or more collectibles with the same `SubType` and `InitSeed` to exist in the same
|
|
195
207
|
* room.
|
|
196
208
|
* - This index will fail in the case where the player uses Diplopia or a successful Crooked Penny
|
|
197
209
|
* seven or more times in the same room, since that will cause two or more collectibles with the
|
|
198
|
-
* same grid index, SubType
|
|
199
|
-
*
|
|
200
|
-
*
|
|
210
|
+
* same grid index, `SubType`, and `InitSeed` to exist. (More than seven is required in non-1x1
|
|
211
|
+
* rooms.)
|
|
212
|
+
* - The `SubType` is a necessary part of the collectible index because Tainted Isaac will
|
|
213
|
+
* continuously cause collectibles to morph into new sub-types with the same `InitSeed`.
|
|
201
214
|
* - Using a collectible's position as part of the index is problematic, since players can push a
|
|
202
215
|
* pedestal. (Even using the grid index does not solve this problem, since it is possible in
|
|
203
216
|
* certain cases for collectibles to be spawned at a position that is not aligned with the grid,
|
|
204
217
|
* and the pedestal pushed to an adjacent tile, but this case should be extremely rare.)
|
|
205
218
|
* - Mega Chests spawn two collectibles on the exact same position. However, both of them will have
|
|
206
|
-
* different
|
|
219
|
+
* a different `InitSeed`, so this is not a problem for this indexing scheme.
|
|
207
220
|
* - The indexing scheme used is different for collectibles that are inside of a Treasure Room or
|
|
208
221
|
* Boss Room, in order to handle the case of the player seeing the same collectible again in a
|
|
209
|
-
* post-Ascent Treasure Room or Boss Room. A 5-tuple of stage, stage type, grid index, SubType
|
|
210
|
-
* and InitSeed is used in this case. (Using the room list index or the room grid index is not
|
|
222
|
+
* post-Ascent Treasure Room or Boss Room. A 5-tuple of stage, stage type, grid index, `SubType`,
|
|
223
|
+
* and `InitSeed` is used in this case. (Using the room list index or the room grid index is not
|
|
211
224
|
* suitable for this purpose, since both of these values can change in the post-Ascent rooms.)
|
|
212
225
|
* Even though Treasure Rooms and Boss Rooms are grouped together in this scheme, there probably
|
|
213
226
|
* will not be collectibles with the same grid index, SubType, and InitSeed.
|