isaacscript-common 6.11.1 → 6.13.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/postFlip.lua +2 -2
- 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/postFirstFlip.d.ts +1 -1
- package/dist/callbacks/subscriptions/postFirstFlip.d.ts.map +1 -1
- package/dist/callbacks/subscriptions/postFirstFlip.lua +2 -2
- package/dist/callbacks/subscriptions/postFlip.d.ts +1 -1
- package/dist/callbacks/subscriptions/postFlip.d.ts.map +1 -1
- package/dist/callbacks/subscriptions/postFlip.lua +2 -2
- 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 +91 -68
- package/dist/enums/ModCallbackCustom.d.ts.map +1 -1
- package/dist/enums/ModCallbackCustom.lua +62 -58
- package/dist/enums/private/StageTravelState.d.ts +6 -1
- package/dist/enums/private/StageTravelState.d.ts.map +1 -1
- package/dist/enums/private/StageTravelState.lua +10 -0
- package/dist/enums/private/TrapdoorAnimation.d.ts +6 -0
- package/dist/enums/private/TrapdoorAnimation.d.ts.map +1 -0
- package/dist/enums/private/TrapdoorAnimation.lua +6 -0
- package/dist/features/collectibleItemPoolType.d.ts +2 -2
- package/dist/features/collectibleItemPoolType.lua +2 -2
- package/dist/features/customGridEntity.d.ts +17 -5
- package/dist/features/customGridEntity.d.ts.map +1 -1
- package/dist/features/customGridEntity.lua +78 -15
- package/dist/features/customStage/exports.d.ts.map +1 -1
- package/dist/features/customStage/exports.lua +0 -13
- package/dist/features/customStage/init.d.ts.map +1 -1
- package/dist/features/customStage/init.lua +16 -1
- package/dist/features/customStage/streakText.d.ts.map +1 -1
- package/dist/features/customStage/streakText.lua +0 -1
- package/dist/features/customTrapdoor/blackSprite.d.ts +2 -0
- package/dist/features/customTrapdoor/blackSprite.d.ts.map +1 -0
- package/dist/features/customTrapdoor/blackSprite.lua +19 -0
- package/dist/features/customTrapdoor/customTrapdoorConstants.d.ts +8 -3
- package/dist/features/customTrapdoor/customTrapdoorConstants.d.ts.map +1 -1
- package/dist/features/customTrapdoor/customTrapdoorConstants.lua +9 -1
- package/dist/features/customTrapdoor/exports.d.ts +11 -19
- package/dist/features/customTrapdoor/exports.d.ts.map +1 -1
- package/dist/features/customTrapdoor/exports.lua +48 -82
- package/dist/features/customTrapdoor/init.d.ts +3 -0
- package/dist/features/customTrapdoor/init.d.ts.map +1 -0
- package/dist/features/customTrapdoor/init.lua +174 -0
- package/dist/features/customTrapdoor/openClose.d.ts +5 -0
- package/dist/features/customTrapdoor/openClose.d.ts.map +1 -0
- package/dist/features/customTrapdoor/openClose.lua +60 -0
- package/dist/features/customTrapdoor/touched.d.ts +4 -0
- package/dist/features/customTrapdoor/touched.d.ts.map +1 -0
- package/dist/features/customTrapdoor/touched.lua +159 -0
- package/dist/features/customTrapdoor/v.d.ts +16 -2
- package/dist/features/customTrapdoor/v.d.ts.map +1 -1
- package/dist/features/customTrapdoor/v.lua +8 -6
- package/dist/features/deployJSONRoom.d.ts +2 -2
- package/dist/features/deployJSONRoom.lua +2 -2
- package/dist/features/extraConsoleCommands/init.d.ts.map +1 -1
- package/dist/features/extraConsoleCommands/init.lua +14 -15
- 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/features/taintedLazarusPlayers.d.ts.map +1 -1
- package/dist/features/taintedLazarusPlayers.lua +13 -21
- 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/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 +2 -2
- package/dist/functions/gridEntities.lua +2 -2
- 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/log.lua +3 -3
- 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/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 +5 -3
- package/dist/functions/playerIndex.d.ts.map +1 -1
- package/dist/functions/playerIndex.lua +15 -24
- 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/table.d.ts +1 -1
- package/dist/functions/table.d.ts.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.lua +23 -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 +9 -0
- package/dist/interfaces/AddCallbackParameterCustom.d.ts +4 -0
- package/dist/interfaces/AddCallbackParameterCustom.d.ts.map +1 -1
- package/dist/interfaces/CustomGridEntityData.d.ts +5 -1
- package/dist/interfaces/CustomGridEntityData.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/interfaces/private/CustomTrapdoorDescription.d.ts +3 -0
- package/dist/interfaces/private/CustomTrapdoorDescription.d.ts.map +1 -1
- 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/postFlip.ts +3 -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/postFirstFlip.ts +6 -3
- package/src/callbacks/subscriptions/postFlip.ts +6 -3
- 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 +35 -10
- package/src/enums/private/StageTravelState.ts +5 -1
- package/src/enums/private/TrapdoorAnimation.ts +5 -0
- package/src/features/collectibleItemPoolType.ts +3 -3
- package/src/features/customGridEntity.ts +93 -10
- package/src/features/customStage/exports.ts +3 -22
- package/src/features/customStage/init.ts +20 -0
- package/src/features/customStage/streakText.ts +0 -1
- package/src/features/customTrapdoor/blackSprite.ts +22 -0
- package/src/features/customTrapdoor/customTrapdoorConstants.ts +13 -3
- package/src/features/customTrapdoor/exports.ts +52 -121
- package/src/features/customTrapdoor/init.ts +217 -0
- package/src/features/customTrapdoor/openClose.ts +103 -0
- package/src/features/customTrapdoor/touched.ts +195 -0
- package/src/features/customTrapdoor/v.ts +16 -10
- package/src/features/deployJSONRoom.ts +5 -5
- package/src/features/extraConsoleCommands/init.ts +22 -16
- 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 +3 -3
- package/src/features/taintedLazarusPlayers.ts +37 -36
- package/src/functions/collectibles.ts +26 -13
- package/src/functions/deepCopy.ts +2 -2
- package/src/functions/entities.ts +7 -4
- package/src/functions/gridEntities.ts +2 -2
- package/src/functions/isaacAPIClass.ts +106 -1
- package/src/functions/map.ts +10 -0
- package/src/functions/pickupVariants.ts +2 -2
- package/src/functions/playerCenter.ts +2 -2
- package/src/functions/playerIndex.ts +20 -21
- package/src/functions/rng.ts +1 -1
- 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/table.ts +2 -2
- package/src/index.ts +3 -0
- package/src/initCustomCallbacks.ts +4 -0
- package/src/initFeatures.ts +6 -0
- package/src/interfaces/AddCallbackParameterCustom.ts +4 -0
- package/src/interfaces/CustomGridEntityData.ts +6 -1
- package/src/interfaces/RoomDescription.ts +19 -0
- package/src/interfaces/private/CustomTrapdoorDescription.ts +4 -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
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Direction,
|
|
3
|
+
ModCallback,
|
|
4
|
+
RoomTransitionAnim,
|
|
5
|
+
} from "isaac-typescript-definitions";
|
|
6
|
+
import { game } from "../../cachedClasses";
|
|
7
|
+
import { ModUpgraded } from "../../classes/ModUpgraded";
|
|
8
|
+
import { ModCallbackCustom } from "../../enums/ModCallbackCustom";
|
|
9
|
+
import { StageTravelState } from "../../enums/private/StageTravelState";
|
|
10
|
+
import { movePlayersToCenter } from "../../functions/playerCenter";
|
|
11
|
+
import { getAllPlayers } from "../../functions/playerIndex";
|
|
12
|
+
import { getRoomGridIndex, getRoomListIndex } from "../../functions/roomData";
|
|
13
|
+
import { setStage } from "../../functions/stage";
|
|
14
|
+
import { isString } from "../../functions/types";
|
|
15
|
+
import { setCustomStage } from "../customStage/exports";
|
|
16
|
+
import { topStreakTextStart } from "../customStage/streakText";
|
|
17
|
+
import { enableAllInputs } from "../disableInputs";
|
|
18
|
+
import { runNextGameFrame } from "../runInNFrames";
|
|
19
|
+
import { runNextRoom } from "../runNextRoom";
|
|
20
|
+
import { saveDataManager } from "../saveDataManager/exports";
|
|
21
|
+
import { drawBlackSprite } from "./blackSprite";
|
|
22
|
+
import {
|
|
23
|
+
CUSTOM_TRAPDOOR_FEATURE_NAME,
|
|
24
|
+
GridEntityTypeCustom,
|
|
25
|
+
PIXELATION_TO_BLACK_FRAMES,
|
|
26
|
+
} from "./customTrapdoorConstants";
|
|
27
|
+
import { checkCustomTrapdoorOpenClose } from "./openClose";
|
|
28
|
+
import { checkCustomTrapdoorPlayerTouched } from "./touched";
|
|
29
|
+
import v from "./v";
|
|
30
|
+
|
|
31
|
+
export function customTrapdoorInit(mod: ModUpgraded): void {
|
|
32
|
+
saveDataManager(CUSTOM_TRAPDOOR_FEATURE_NAME, v);
|
|
33
|
+
|
|
34
|
+
mod.AddCallback(ModCallback.POST_RENDER, postRender); // 2
|
|
35
|
+
mod.AddCallback(ModCallback.POST_PEFFECT_UPDATE, postPEffectUpdate); // 4
|
|
36
|
+
mod.AddCallbackCustom(
|
|
37
|
+
ModCallbackCustom.POST_GRID_ENTITY_CUSTOM_UPDATE,
|
|
38
|
+
postGridEntityCustomUpdateTrapdoor,
|
|
39
|
+
GridEntityTypeCustom.TRAPDOOR_CUSTOM,
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// ModCallback.POST_RENDER (2)
|
|
44
|
+
function postRender() {
|
|
45
|
+
checkAllPlayersJumpComplete();
|
|
46
|
+
checkPixelationToBlackComplete();
|
|
47
|
+
checkPausingOnBlackComplete();
|
|
48
|
+
checkAllPlayersLayingDownComplete();
|
|
49
|
+
drawBlackSprite();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function checkAllPlayersJumpComplete() {
|
|
53
|
+
if (v.run.state !== StageTravelState.PLAYERS_JUMPING_DOWN) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (anyPlayerPlayingExtraAnimation()) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const renderFrameCount = Isaac.GetFrameCount();
|
|
62
|
+
const roomGridIndex = getRoomGridIndex();
|
|
63
|
+
|
|
64
|
+
v.run.state = StageTravelState.PIXELATION_TO_BLACK;
|
|
65
|
+
v.run.stateRenderFrame = renderFrameCount;
|
|
66
|
+
|
|
67
|
+
// In order to display the pixelation effect that should happen when we go to a new floor, we need
|
|
68
|
+
// to start a room transition. We arbitrarily pick the current room for this purpose.
|
|
69
|
+
game.StartRoomTransition(
|
|
70
|
+
roomGridIndex,
|
|
71
|
+
Direction.NO_DIRECTION,
|
|
72
|
+
RoomTransitionAnim.PIXELATION,
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function checkPixelationToBlackComplete() {
|
|
77
|
+
if (
|
|
78
|
+
v.run.state !== StageTravelState.PIXELATION_TO_BLACK ||
|
|
79
|
+
v.run.stateRenderFrame === null
|
|
80
|
+
) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const hud = game.GetHUD();
|
|
85
|
+
const renderFrameCount = Isaac.GetFrameCount();
|
|
86
|
+
const roomGridIndex = getRoomGridIndex();
|
|
87
|
+
|
|
88
|
+
const renderFrameScreenBlack =
|
|
89
|
+
v.run.stateRenderFrame + PIXELATION_TO_BLACK_FRAMES;
|
|
90
|
+
if (renderFrameCount < renderFrameScreenBlack) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
v.run.state = StageTravelState.PAUSING_ON_BLACK;
|
|
95
|
+
v.run.stateRenderFrame = renderFrameCount;
|
|
96
|
+
|
|
97
|
+
hud.SetVisible(false);
|
|
98
|
+
goToCustomDestination();
|
|
99
|
+
|
|
100
|
+
// Start another pixelation effect. This time, we will keep the screen black with the sprite, and
|
|
101
|
+
// then remove the black sprite once the pixelation effect is halfway complete.
|
|
102
|
+
game.StartRoomTransition(
|
|
103
|
+
roomGridIndex,
|
|
104
|
+
Direction.NO_DIRECTION,
|
|
105
|
+
RoomTransitionAnim.PIXELATION,
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function checkPausingOnBlackComplete() {
|
|
110
|
+
if (
|
|
111
|
+
v.run.state !== StageTravelState.PAUSING_ON_BLACK ||
|
|
112
|
+
v.run.stateRenderFrame === null
|
|
113
|
+
) {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const hud = game.GetHUD();
|
|
118
|
+
const renderFrameCount = Isaac.GetFrameCount();
|
|
119
|
+
|
|
120
|
+
const renderFrameScreenBlack =
|
|
121
|
+
v.run.stateRenderFrame + PIXELATION_TO_BLACK_FRAMES;
|
|
122
|
+
if (renderFrameCount < renderFrameScreenBlack) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
v.run.state = StageTravelState.PIXELATION_TO_ROOM;
|
|
127
|
+
|
|
128
|
+
hud.SetVisible(true);
|
|
129
|
+
|
|
130
|
+
runNextRoom(() => {
|
|
131
|
+
// After the room transition, the players will be placed next to a door, but they should be in
|
|
132
|
+
// the center of the room to emulate what happens on a vanilla stage.
|
|
133
|
+
movePlayersToCenter();
|
|
134
|
+
|
|
135
|
+
v.run.state = StageTravelState.PLAYERS_LAYING_DOWN;
|
|
136
|
+
|
|
137
|
+
for (const player of getAllPlayers()) {
|
|
138
|
+
player.AnimateAppear();
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
// In vanilla, the streak text appears about when the pixelation has faded and while Isaac is
|
|
143
|
+
// still laying on the ground. Unfortunately, we cannot exactly replicate the vanilla timing,
|
|
144
|
+
// because the level text will bug out and smear the background if we play it from a `POST_RENDER`
|
|
145
|
+
// callback. Thus, we run it on the next game frame as a workaround.
|
|
146
|
+
runNextGameFrame(() => {
|
|
147
|
+
topStreakTextStart();
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function checkAllPlayersLayingDownComplete() {
|
|
152
|
+
if (v.run.state !== StageTravelState.PLAYERS_LAYING_DOWN) {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (anyPlayerPlayingExtraAnimation()) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
v.run.state = StageTravelState.NONE;
|
|
161
|
+
|
|
162
|
+
enableAllInputs(CUSTOM_TRAPDOOR_FEATURE_NAME);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function goToCustomDestination() {
|
|
166
|
+
if (v.run.destination === null) {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (isString(v.run.destination)) {
|
|
171
|
+
setCustomStage("Slaughterhouse");
|
|
172
|
+
} else {
|
|
173
|
+
const [stage, stageType] = v.run.destination;
|
|
174
|
+
setStage(stage, stageType);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function anyPlayerPlayingExtraAnimation() {
|
|
179
|
+
const players = getAllPlayers();
|
|
180
|
+
return players.some((player) => !player.IsExtraAnimationFinished());
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// ModCallback.POST_PEFFECT_UPDATE (4)
|
|
184
|
+
function postPEffectUpdate(player: EntityPlayer) {
|
|
185
|
+
checkJumpComplete(player);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function checkJumpComplete(player: EntityPlayer) {
|
|
189
|
+
if (v.run.state !== StageTravelState.PLAYERS_JUMPING_DOWN) {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// In this state, the players are jumping down the hole (i.e. playing the "Trapdoor" animation).
|
|
194
|
+
// When it completes, they will return to normal (i.e. just standing on top of the trapdoor).
|
|
195
|
+
// Thus, make them invisible at the end of the animation. (They will automatically be set to
|
|
196
|
+
// visible again once we travel to the next floor.)
|
|
197
|
+
const sprite = player.GetSprite();
|
|
198
|
+
if (sprite.IsFinished("Trapdoor")) {
|
|
199
|
+
player.Visible = false;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// ModCallbackCustom.POST_GRID_ENTITY_CUSTOM_UPDATE
|
|
204
|
+
// GridEntityTypeCustom.TRAPDOOR_CUSTOM
|
|
205
|
+
function postGridEntityCustomUpdateTrapdoor(gridEntity: GridEntity) {
|
|
206
|
+
const roomListIndex = getRoomListIndex();
|
|
207
|
+
const gridIndex = gridEntity.GetGridIndex();
|
|
208
|
+
|
|
209
|
+
const roomTrapdoorMap = v.level.trapdoors.getAndSetDefault(roomListIndex);
|
|
210
|
+
const trapdoorDescription = roomTrapdoorMap.get(gridIndex);
|
|
211
|
+
if (trapdoorDescription === undefined) {
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
checkCustomTrapdoorOpenClose(gridEntity, trapdoorDescription);
|
|
216
|
+
checkCustomTrapdoorPlayerTouched(gridEntity, trapdoorDescription);
|
|
217
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { RoomType } from "isaac-typescript-definitions";
|
|
2
|
+
import { game } from "../../cachedClasses";
|
|
3
|
+
import { TrapdoorAnimation } from "../../enums/private/TrapdoorAnimation";
|
|
4
|
+
import { anyPlayerCloserThan } from "../../functions/positionVelocity";
|
|
5
|
+
import { CustomTrapdoorDescription } from "../../interfaces/private/CustomTrapdoorDescription";
|
|
6
|
+
import { getRoomClearGameFrame } from "../roomClearFrame";
|
|
7
|
+
import {
|
|
8
|
+
TRAPDOOR_BOSS_REACTION_FRAMES,
|
|
9
|
+
TRAPDOOR_OPEN_DISTANCE,
|
|
10
|
+
TRAPDOOR_OPEN_DISTANCE_AFTER_BOSS,
|
|
11
|
+
} from "./customTrapdoorConstants";
|
|
12
|
+
|
|
13
|
+
export function checkCustomTrapdoorOpenClose(
|
|
14
|
+
gridEntity: GridEntity,
|
|
15
|
+
trapdoorDescription: CustomTrapdoorDescription,
|
|
16
|
+
): void {
|
|
17
|
+
/** By default, trapdoors will never close if they are already open. */
|
|
18
|
+
if (trapdoorDescription.open) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (shouldTrapdoorOpen(gridEntity, trapdoorDescription.firstSpawn)) {
|
|
23
|
+
open(gridEntity, trapdoorDescription);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function shouldTrapdoorOpen(
|
|
28
|
+
gridEntity: GridEntity,
|
|
29
|
+
firstSpawn: boolean,
|
|
30
|
+
): boolean {
|
|
31
|
+
const room = game.GetRoom();
|
|
32
|
+
const roomClear = room.IsClear();
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
!anyPlayerCloserThan(gridEntity.Position, TRAPDOOR_OPEN_DISTANCE) &&
|
|
36
|
+
!isPlayerCloseAfterBoss(gridEntity.Position) &&
|
|
37
|
+
!shouldBeClosedFromStartingInRoomWithEnemies(firstSpawn, roomClear)
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function isPlayerCloseAfterBoss(position: Vector) {
|
|
42
|
+
const gameFrameCount = game.GetFrameCount();
|
|
43
|
+
const room = game.GetRoom();
|
|
44
|
+
const roomType = room.GetType();
|
|
45
|
+
const roomClearGameFrame = getRoomClearGameFrame();
|
|
46
|
+
|
|
47
|
+
// In order to prevent a player from accidentally entering a freshly-spawned trapdoor after
|
|
48
|
+
// killing the boss of the floor, we use a wider open distance for a short amount of frames.
|
|
49
|
+
if (
|
|
50
|
+
roomType !== RoomType.BOSS ||
|
|
51
|
+
roomClearGameFrame === undefined ||
|
|
52
|
+
gameFrameCount >= roomClearGameFrame + TRAPDOOR_BOSS_REACTION_FRAMES
|
|
53
|
+
) {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return anyPlayerCloserThan(position, TRAPDOOR_OPEN_DISTANCE_AFTER_BOSS);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function shouldBeClosedFromStartingInRoomWithEnemies(
|
|
61
|
+
firstSpawn: boolean,
|
|
62
|
+
roomClear: boolean,
|
|
63
|
+
) {
|
|
64
|
+
return firstSpawn && !roomClear;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function open(
|
|
68
|
+
gridEntity: GridEntity,
|
|
69
|
+
trapdoorDescription: CustomTrapdoorDescription,
|
|
70
|
+
) {
|
|
71
|
+
trapdoorDescription.open = true;
|
|
72
|
+
|
|
73
|
+
const sprite = gridEntity.GetSprite();
|
|
74
|
+
sprite.Play(TrapdoorAnimation.OPEN_ANIMATION, true);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function shouldTrapdoorSpawnOpen(
|
|
78
|
+
gridEntity: GridEntity,
|
|
79
|
+
firstSpawn: boolean,
|
|
80
|
+
): boolean {
|
|
81
|
+
const room = game.GetRoom();
|
|
82
|
+
const roomFrameCount = room.GetFrameCount();
|
|
83
|
+
const roomClear = room.IsClear();
|
|
84
|
+
|
|
85
|
+
// Trapdoors created after a room has already initialized should spawn closed by default:
|
|
86
|
+
// - Trapdoors created after bosses should spawn closed so that players do not accidentally jump
|
|
87
|
+
// into them.
|
|
88
|
+
// - Trapdoors created by We Need to Go Deeper should spawn closed because the player will be
|
|
89
|
+
// standing on top of them.
|
|
90
|
+
if (roomFrameCount > 0) {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// If we just entered a new room with enemies in it, spawn the trapdoor closed so that the player
|
|
95
|
+
// has to defeat the enemies first before using the trapdoor.
|
|
96
|
+
if (!roomClear) {
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// If we just entered a new room that is already cleared, spawn the trapdoor closed if we are
|
|
101
|
+
// standing close to it, and open otherwise.
|
|
102
|
+
return shouldTrapdoorOpen(gridEntity, firstSpawn);
|
|
103
|
+
}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ButtonAction,
|
|
3
|
+
EntityCollisionClass,
|
|
4
|
+
EntityGridCollisionClass,
|
|
5
|
+
EntityPartition,
|
|
6
|
+
PlayerType,
|
|
7
|
+
} from "isaac-typescript-definitions";
|
|
8
|
+
import { VectorZero } from "../../constants";
|
|
9
|
+
import { StageTravelState } from "../../enums/private/StageTravelState";
|
|
10
|
+
import { easeOutSine } from "../../functions/easing";
|
|
11
|
+
import {
|
|
12
|
+
getAllPlayers,
|
|
13
|
+
getOtherPlayers,
|
|
14
|
+
isChildPlayer,
|
|
15
|
+
} from "../../functions/playerIndex";
|
|
16
|
+
import { isCharacter } from "../../functions/players";
|
|
17
|
+
import { CustomTrapdoorDescription } from "../../interfaces/private/CustomTrapdoorDescription";
|
|
18
|
+
import { disableAllInputsExceptFor } from "../disableInputs";
|
|
19
|
+
import { isPlayerUsingPony } from "../ponyDetection";
|
|
20
|
+
import { runInNGameFrames, runNextRenderFrame } from "../runInNFrames";
|
|
21
|
+
import {
|
|
22
|
+
ANIMATIONS_THAT_PREVENT_STAGE_TRAVEL,
|
|
23
|
+
CUSTOM_TRAPDOOR_FEATURE_NAME,
|
|
24
|
+
OTHER_PLAYER_TRAPDOOR_JUMP_DELAY_GAME_FRAMES,
|
|
25
|
+
OTHER_PLAYER_TRAPDOOR_JUMP_DURATION_GAME_FRAMES,
|
|
26
|
+
TRAPDOOR_TOUCH_DISTANCE,
|
|
27
|
+
} from "./customTrapdoorConstants";
|
|
28
|
+
import v from "./v";
|
|
29
|
+
|
|
30
|
+
export function checkCustomTrapdoorPlayerTouched(
|
|
31
|
+
gridEntity: GridEntity,
|
|
32
|
+
trapdoorDescription: CustomTrapdoorDescription,
|
|
33
|
+
): void {
|
|
34
|
+
if (v.run.state !== StageTravelState.NONE) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (!trapdoorDescription.open) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const playersTouching = Isaac.FindInRadius(
|
|
43
|
+
gridEntity.Position,
|
|
44
|
+
TRAPDOOR_TOUCH_DISTANCE,
|
|
45
|
+
EntityPartition.PLAYER,
|
|
46
|
+
);
|
|
47
|
+
for (const playerEntity of playersTouching) {
|
|
48
|
+
const player = playerEntity.ToPlayer();
|
|
49
|
+
if (player === undefined) {
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (
|
|
54
|
+
// We don't want a Pony dash to transition to a new floor or a crawl space.
|
|
55
|
+
!isPlayerUsingPony(player) &&
|
|
56
|
+
!isChildPlayer(player) &&
|
|
57
|
+
canPlayerInteractWithTrapdoor(player)
|
|
58
|
+
) {
|
|
59
|
+
playerTouchedCustomTrapdoor(gridEntity, trapdoorDescription, player);
|
|
60
|
+
return; // Prevent two players from touching the same entity.
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function canPlayerInteractWithTrapdoor(player: EntityPlayer) {
|
|
66
|
+
// Players cannot interact with stage travel entities when items are queued or while playing
|
|
67
|
+
// certain animations.
|
|
68
|
+
const sprite = player.GetSprite();
|
|
69
|
+
const animation = sprite.GetAnimation();
|
|
70
|
+
return (
|
|
71
|
+
!player.IsHoldingItem() &&
|
|
72
|
+
!ANIMATIONS_THAT_PREVENT_STAGE_TRAVEL.has(animation)
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function playerTouchedCustomTrapdoor(
|
|
77
|
+
gridEntity: GridEntity,
|
|
78
|
+
trapdoorDescription: CustomTrapdoorDescription,
|
|
79
|
+
player: EntityPlayer,
|
|
80
|
+
) {
|
|
81
|
+
v.run.state = StageTravelState.PLAYERS_JUMPING_DOWN;
|
|
82
|
+
v.run.destination = trapdoorDescription.destination;
|
|
83
|
+
|
|
84
|
+
const whitelist = new Set([ButtonAction.CONSOLE]);
|
|
85
|
+
disableAllInputsExceptFor(CUSTOM_TRAPDOOR_FEATURE_NAME, whitelist);
|
|
86
|
+
setPlayerAttributes(player, gridEntity.Position);
|
|
87
|
+
dropTaintedForgotten(player);
|
|
88
|
+
|
|
89
|
+
player.PlayExtraAnimation("Trapdoor");
|
|
90
|
+
|
|
91
|
+
const otherPlayers = getOtherPlayers(player);
|
|
92
|
+
otherPlayers.forEach((otherPlayer, i) => {
|
|
93
|
+
const gameFramesToWaitBeforeJumping =
|
|
94
|
+
OTHER_PLAYER_TRAPDOOR_JUMP_DELAY_GAME_FRAMES * (i + 1);
|
|
95
|
+
const otherPlayerPtr = EntityPtr(otherPlayer);
|
|
96
|
+
runInNGameFrames(() => {
|
|
97
|
+
startDelayedJump(otherPlayerPtr, gridEntity.Position);
|
|
98
|
+
}, gameFramesToWaitBeforeJumping);
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function setPlayerAttributes(trapdoorPlayer: EntityPlayer, position: Vector) {
|
|
103
|
+
// Snap the player to the exact position of the trapdoor so that they cleanly jump down the hole.
|
|
104
|
+
trapdoorPlayer.Position = position;
|
|
105
|
+
|
|
106
|
+
for (const player of getAllPlayers()) {
|
|
107
|
+
// Disable the controls to prevent the player from moving, shooting, and so on. (We also disable
|
|
108
|
+
// the inputs in the `INPUT_ACTION` callback, but that does not prevent mouse inputs.)
|
|
109
|
+
player.ControlsEnabled = false;
|
|
110
|
+
|
|
111
|
+
// Freeze all players.
|
|
112
|
+
player.Velocity = VectorZero;
|
|
113
|
+
|
|
114
|
+
// We don't want enemy attacks to move the players.
|
|
115
|
+
player.EntityCollisionClass = EntityCollisionClass.NONE;
|
|
116
|
+
player.GridCollisionClass = EntityGridCollisionClass.NONE;
|
|
117
|
+
|
|
118
|
+
player.SubType = -1;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function dropTaintedForgotten(player: EntityPlayer) {
|
|
123
|
+
if (isCharacter(player, PlayerType.THE_FORGOTTEN_B)) {
|
|
124
|
+
const taintedSoul = player.GetOtherTwin();
|
|
125
|
+
if (taintedSoul !== undefined) {
|
|
126
|
+
taintedSoul.ThrowHeldEntity(VectorZero);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function startDelayedJump(entityPtr: EntityPtr, trapdoorPosition: Vector) {
|
|
132
|
+
const entity = entityPtr.Ref;
|
|
133
|
+
if (entity === undefined) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const player = entity.ToPlayer();
|
|
138
|
+
if (player === undefined) {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
player.PlayExtraAnimation("Trapdoor");
|
|
143
|
+
|
|
144
|
+
adjustPlayerPositionToTrapdoor(entityPtr, player.Position, trapdoorPosition);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function adjustPlayerPositionToTrapdoor(
|
|
148
|
+
entityPtr: EntityPtr,
|
|
149
|
+
startPos: Vector,
|
|
150
|
+
endPos: Vector,
|
|
151
|
+
) {
|
|
152
|
+
if (v.run.state !== StageTravelState.PLAYERS_JUMPING_DOWN) {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const entity = entityPtr.Ref;
|
|
157
|
+
if (entity === undefined) {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const player = entity.ToPlayer();
|
|
162
|
+
if (player === undefined) {
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
runNextRenderFrame(() => {
|
|
167
|
+
adjustPlayerPositionToTrapdoor(entityPtr, startPos, endPos);
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
const sprite = player.GetSprite();
|
|
171
|
+
if (sprite.IsFinished("Trapdoor")) {
|
|
172
|
+
player.Position = endPos;
|
|
173
|
+
player.Velocity = VectorZero;
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const frame = sprite.GetFrame();
|
|
178
|
+
if (frame >= OTHER_PLAYER_TRAPDOOR_JUMP_DURATION_GAME_FRAMES) {
|
|
179
|
+
// We have already arrived at the trapdoor.
|
|
180
|
+
player.Position = endPos;
|
|
181
|
+
player.Velocity = VectorZero;
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Make the player jump towards the trapdoor. We use an easing function so that the distance
|
|
186
|
+
// traveled is not linear, emulating what the game does.
|
|
187
|
+
const totalDifference = endPos.sub(startPos);
|
|
188
|
+
const progress = frame / OTHER_PLAYER_TRAPDOOR_JUMP_DURATION_GAME_FRAMES;
|
|
189
|
+
const easeProgress = easeOutSine(progress);
|
|
190
|
+
const differenceForThisFrame = totalDifference.mul(easeProgress);
|
|
191
|
+
const targetPosition = startPos.add(differenceForThisFrame);
|
|
192
|
+
|
|
193
|
+
player.Position = targetPosition;
|
|
194
|
+
player.Velocity = VectorZero;
|
|
195
|
+
}
|
|
@@ -1,20 +1,26 @@
|
|
|
1
|
+
import { LevelStage, StageType } from "isaac-typescript-definitions";
|
|
2
|
+
import { DefaultMap } from "../../classes/DefaultMap";
|
|
1
3
|
import { StageTravelState } from "../../enums/private/StageTravelState";
|
|
2
4
|
import { CustomTrapdoorDescription } from "../../interfaces/private/CustomTrapdoorDescription";
|
|
3
5
|
|
|
4
6
|
const v = {
|
|
5
7
|
run: {
|
|
6
8
|
state: StageTravelState.NONE,
|
|
9
|
+
|
|
10
|
+
/** The render frame that this state was reached. */
|
|
11
|
+
stateRenderFrame: null as int | null,
|
|
12
|
+
|
|
13
|
+
destination: null as
|
|
14
|
+
| [stage: LevelStage, stageType: StageType]
|
|
15
|
+
| string
|
|
16
|
+
| null,
|
|
7
17
|
},
|
|
8
18
|
|
|
9
|
-
|
|
10
|
-
/** Indexed by grid index. */
|
|
11
|
-
trapdoors: new Map<int, CustomTrapdoorDescription
|
|
19
|
+
level: {
|
|
20
|
+
/** Indexed by room list index and grid index. */
|
|
21
|
+
trapdoors: new DefaultMap<int, Map<int, CustomTrapdoorDescription>>(
|
|
22
|
+
() => new Map(),
|
|
23
|
+
),
|
|
12
24
|
},
|
|
13
25
|
};
|
|
14
|
-
|
|
15
|
-
export function getCustomTrapdoorDescription(
|
|
16
|
-
gridEntity: GridEntity,
|
|
17
|
-
): CustomTrapdoorDescription | undefined {
|
|
18
|
-
const gridIndex = gridEntity.GetGridIndex();
|
|
19
|
-
return v.room.trapdoors.get(gridIndex);
|
|
20
|
-
}
|
|
26
|
+
export default v;
|
|
@@ -161,7 +161,7 @@ function preUseItemWeNeedToGoDeeper(
|
|
|
161
161
|
fillRoomWithDecorations();
|
|
162
162
|
});
|
|
163
163
|
|
|
164
|
-
// Cancel the effect.
|
|
164
|
+
// Cancel the original effect.
|
|
165
165
|
return true;
|
|
166
166
|
}
|
|
167
167
|
|
|
@@ -225,7 +225,7 @@ function respawnPersistentEntities() {
|
|
|
225
225
|
* Specifically, this will clear the current room of all entities and grid entities, and then spawn
|
|
226
226
|
* all of the entries and grid entities in the provided JSON room.
|
|
227
227
|
*
|
|
228
|
-
* This function is meant to be used in the
|
|
228
|
+
* This function is meant to be used in the `POST_NEW_ROOM` callback.
|
|
229
229
|
*
|
|
230
230
|
* For example:
|
|
231
231
|
*
|
|
@@ -277,7 +277,7 @@ export function deployJSONRoom(
|
|
|
277
277
|
* Specifically, this will clear the current room of all entities and grid entities, and then spawn
|
|
278
278
|
* all of the entries and grid entities in one of the provided JSON rooms.
|
|
279
279
|
*
|
|
280
|
-
* This function is meant to be used in the
|
|
280
|
+
* This function is meant to be used in the `POST_NEW_ROOM` callback.
|
|
281
281
|
*
|
|
282
282
|
* Note that this function does not simply choose a random element in the provided array; it will
|
|
283
283
|
* properly account for each room weight using the algorithm from:
|
|
@@ -355,8 +355,8 @@ export function emptyRoom(fillWithDecorations: boolean): void {
|
|
|
355
355
|
}
|
|
356
356
|
|
|
357
357
|
/**
|
|
358
|
-
* We remove entities in the
|
|
359
|
-
* that they will not re-appear when we re-enter the room.
|
|
358
|
+
* We remove entities in the `POST_NEW_ROOM` callback instead of in the PreRoomEntitySpawn callback
|
|
359
|
+
* so that they will not re-appear when we re-enter the room.
|
|
360
360
|
*/
|
|
361
361
|
function removeSpecificNPCs() {
|
|
362
362
|
const room = game.GetRoom();
|