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.
- package/dist/callbacks/postFlip.lua +2 -2
- package/dist/callbacks/postPlayerFatalDamage.lua +1 -1
- package/dist/callbacks/postPlayerInitFirst.d.ts +2 -0
- package/dist/callbacks/postPlayerInitFirst.d.ts.map +1 -0
- package/dist/callbacks/postPlayerInitFirst.lua +42 -0
- package/dist/callbacks/postPlayerInitLate.lua +5 -5
- package/dist/callbacks/postPlayerReorderedCallbacks.d.ts +2 -0
- package/dist/callbacks/postPlayerReorderedCallbacks.d.ts.map +1 -0
- package/dist/callbacks/{postPlayerReordered.lua → postPlayerReorderedCallbacks.lua} +11 -37
- 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/{postPlayerInitReordered.d.ts → postPlayerInitFirst.d.ts} +2 -2
- package/dist/callbacks/subscriptions/postPlayerInitFirst.d.ts.map +1 -0
- package/dist/callbacks/subscriptions/{postPlayerInitReordered.lua → postPlayerInitFirst.lua} +3 -3
- package/dist/enums/ModCallbackCustom.d.ts +19 -17
- package/dist/enums/ModCallbackCustom.d.ts.map +1 -1
- package/dist/enums/ModCallbackCustom.lua +3 -3
- package/dist/enums/private/StageTravelState.d.ts +9 -0
- package/dist/enums/private/StageTravelState.d.ts.map +1 -0
- package/dist/enums/private/StageTravelState.lua +15 -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/customGridEntity.d.ts +8 -5
- package/dist/features/customGridEntity.d.ts.map +1 -1
- package/dist/features/customGridEntity.lua +66 -17
- 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 +24 -2
- package/dist/features/customStage/streakText.d.ts +6 -0
- package/dist/features/customStage/streakText.d.ts.map +1 -1
- package/dist/features/customStage/streakText.lua +16 -12
- package/dist/features/customStage/versusScreen.d.ts +6 -0
- package/dist/features/customStage/versusScreen.d.ts.map +1 -1
- package/dist/features/customStage/versusScreen.lua +10 -5
- 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 +15 -0
- package/dist/features/customTrapdoor/customTrapdoorConstants.d.ts.map +1 -0
- package/dist/features/customTrapdoor/customTrapdoorConstants.lua +16 -0
- package/dist/features/customTrapdoor/exports.d.ts +29 -0
- package/dist/features/customTrapdoor/exports.d.ts.map +1 -0
- package/dist/features/customTrapdoor/exports.lua +93 -0
- 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 +173 -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 +141 -0
- package/dist/features/customTrapdoor/v.d.ts +18 -0
- package/dist/features/customTrapdoor/v.d.ts.map +1 -0
- package/dist/features/customTrapdoor/v.lua +17 -0
- package/dist/features/deployJSONRoom.d.ts.map +1 -1
- package/dist/features/deployJSONRoom.lua +1 -1
- package/dist/features/extraConsoleCommands/init.d.ts.map +1 -1
- package/dist/features/extraConsoleCommands/init.lua +3 -1
- package/dist/features/extraConsoleCommands/listCommands.lua +2 -2
- package/dist/features/taintedLazarusPlayers.d.ts.map +1 -1
- package/dist/features/taintedLazarusPlayers.lua +13 -21
- package/dist/functions/{character.d.ts → characters.d.ts} +3 -1
- package/dist/functions/characters.d.ts.map +1 -0
- package/dist/functions/{character.lua → characters.lua} +12 -0
- package/dist/functions/deepCopyTests.lua +35 -45
- package/dist/functions/jsonHelpers.d.ts +6 -0
- package/dist/functions/jsonHelpers.d.ts.map +1 -1
- package/dist/functions/jsonHelpers.lua +9 -3
- package/dist/functions/log.lua +3 -3
- package/dist/functions/playerIndex.d.ts +11 -2
- package/dist/functions/playerIndex.d.ts.map +1 -1
- package/dist/functions/playerIndex.lua +20 -8
- package/dist/functions/players.lua +4 -4
- package/dist/functions/revive.lua +2 -2
- package/dist/functions/table.d.ts +1 -1
- package/dist/functions/table.d.ts.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.lua +10 -2
- package/dist/initCustomCallbacks.d.ts.map +1 -1
- package/dist/initCustomCallbacks.lua +5 -2
- package/dist/initFeatures.d.ts +1 -2
- package/dist/initFeatures.d.ts.map +1 -1
- package/dist/initFeatures.lua +10 -2
- package/dist/interfaces/AddCallbackParameterCustom.d.ts +2 -2
- package/dist/interfaces/AddCallbackParameterCustom.d.ts.map +1 -1
- package/dist/interfaces/CustomGridEntityData.d.ts +6 -2
- package/dist/interfaces/CustomGridEntityData.d.ts.map +1 -1
- package/dist/interfaces/private/CustomTrapdoorDescription.d.ts +7 -0
- package/dist/interfaces/private/CustomTrapdoorDescription.d.ts.map +1 -0
- package/dist/interfaces/private/CustomTrapdoorDescription.lua +2 -0
- package/dist/lib/jsonLua.lua +390 -0
- package/dist/objects/callbackRegisterFunctions.d.ts.map +1 -1
- package/dist/objects/callbackRegisterFunctions.lua +3 -3
- package/dist/objects/characterDamageMultipliers.d.ts +6 -0
- package/dist/objects/characterDamageMultipliers.d.ts.map +1 -0
- package/dist/objects/characterDamageMultipliers.lua +49 -0
- package/dist/upgradeMod.d.ts.map +1 -1
- package/dist/upgradeMod.lua +2 -4
- package/package.json +2 -2
- package/src/callbacks/customRevive.ts +3 -3
- package/src/callbacks/itemPickup.ts +3 -3
- package/src/callbacks/postAmbush.ts +3 -3
- package/src/callbacks/postEsauJr.ts +3 -3
- package/src/callbacks/postFlip.ts +6 -5
- package/src/callbacks/postGridEntity.ts +5 -5
- package/src/callbacks/postPlayerCollectible.ts +2 -2
- package/src/callbacks/postPlayerFatalDamage.ts +5 -0
- package/src/callbacks/postPlayerInitFirst.ts +57 -0
- package/src/callbacks/postPlayerInitLate.ts +9 -5
- package/src/callbacks/{postPlayerReordered.ts → postPlayerReorderedCallbacks.ts} +9 -29
- package/src/callbacks/postSlotInitUpdate.ts +5 -2
- package/src/callbacks/postSlotRender.ts +2 -2
- package/src/callbacks/reorderedCallbacks.ts +1 -1
- package/src/callbacks/subscriptions/postFirstFlip.ts +6 -3
- package/src/callbacks/subscriptions/postFlip.ts +6 -3
- package/src/callbacks/subscriptions/{postPlayerInitReordered.ts → postPlayerInitFirst.ts} +6 -6
- package/src/enums/ModCallbackCustom.ts +19 -17
- package/src/enums/private/StageTravelState.ts +8 -0
- package/src/enums/private/TrapdoorAnimation.ts +5 -0
- package/src/features/customGridEntity.ts +93 -12
- package/src/features/customStage/exports.ts +3 -22
- package/src/features/customStage/init.ts +30 -1
- package/src/features/customStage/streakText.ts +13 -5
- package/src/features/customStage/versusScreen.ts +20 -12
- package/src/features/customTrapdoor/blackSprite.ts +16 -0
- package/src/features/customTrapdoor/customTrapdoorConstants.ts +23 -0
- package/src/features/customTrapdoor/exports.ts +99 -0
- package/src/features/customTrapdoor/init.ts +215 -0
- package/src/features/customTrapdoor/openClose.ts +103 -0
- package/src/features/customTrapdoor/touched.ts +175 -0
- package/src/features/customTrapdoor/v.ts +26 -0
- package/src/features/deployJSONRoom.ts +6 -1
- package/src/features/extraConsoleCommands/init.ts +5 -2
- package/src/features/extraConsoleCommands/listCommands.ts +1 -1
- package/src/features/saveDataManager/main.ts +1 -1
- package/src/features/taintedLazarusPlayers.ts +32 -31
- package/src/functions/{character.ts → characters.ts} +13 -0
- package/src/functions/deepCopy.ts +2 -2
- package/src/functions/deepCopyTests.ts +44 -48
- package/src/functions/entities.ts +1 -1
- package/src/functions/jsonHelpers.ts +9 -3
- package/src/functions/playerIndex.ts +18 -2
- package/src/functions/players.ts +1 -1
- package/src/functions/revive.ts +1 -1
- package/src/functions/rng.ts +1 -1
- package/src/functions/table.ts +2 -2
- package/src/index.ts +6 -2
- package/src/initCustomCallbacks.ts +3 -1
- package/src/initFeatures.ts +9 -2
- package/src/interfaces/AddCallbackParameterCustom.ts +2 -2
- package/src/interfaces/CustomGridEntityData.ts +7 -2
- package/src/interfaces/private/CustomTrapdoorDescription.ts +7 -0
- package/src/lib/jsonLua.d.ts +10 -0
- package/src/lib/jsonLua.lua +390 -0
- package/src/objects/callbackRegisterFunctions.ts +2 -3
- package/src/objects/characterDamageMultipliers.ts +49 -0
- package/src/upgradeMod.ts +2 -3
- package/dist/callbacks/postPlayerReordered.d.ts +0 -2
- package/dist/callbacks/postPlayerReordered.d.ts.map +0 -1
- package/dist/callbacks/subscriptions/postPlayerInitReordered.d.ts.map +0 -1
- package/dist/functions/character.d.ts.map +0 -1
|
@@ -88,8 +88,6 @@ const TEXT_OUT_SCALES = [
|
|
|
88
88
|
* "loadGraphics", but still manage playing its animations in the code below.
|
|
89
89
|
*/
|
|
90
90
|
const topStreakSprite = Sprite();
|
|
91
|
-
topStreakSprite.Load("resources/gfx/ui/ui_streak.anm2", false);
|
|
92
|
-
topStreakSprite.PlaybackSpeed = TEXT_PLAYBACK_SPEED;
|
|
93
91
|
|
|
94
92
|
/**
|
|
95
93
|
* We do not actually need to render this sprite at all. It's only purpose is to be an invisible
|
|
@@ -97,8 +95,19 @@ topStreakSprite.PlaybackSpeed = TEXT_PLAYBACK_SPEED;
|
|
|
97
95
|
* "loadGraphics", but still manage playing its animations in the code below.
|
|
98
96
|
*/
|
|
99
97
|
const bottomStreakSprite = Sprite();
|
|
100
|
-
|
|
101
|
-
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* We must load the sprites in an init function to prevent issues with mods that replace the vanilla
|
|
101
|
+
* files. (For some reason, loading the sprites will cause the overwrite to no longer apply on the
|
|
102
|
+
* second and subsequent runs.)
|
|
103
|
+
*/
|
|
104
|
+
export function streakTextInit(): void {
|
|
105
|
+
topStreakSprite.Load("resources/gfx/ui/ui_streak.anm2", false);
|
|
106
|
+
topStreakSprite.PlaybackSpeed = TEXT_PLAYBACK_SPEED;
|
|
107
|
+
|
|
108
|
+
bottomStreakSprite.Load("resources/gfx/ui/ui_streak.anm2", false);
|
|
109
|
+
bottomStreakSprite.PlaybackSpeed = TEXT_PLAYBACK_SPEED;
|
|
110
|
+
}
|
|
102
111
|
|
|
103
112
|
// ModCallback.POST_RENDER (2)
|
|
104
113
|
export function streakTextPostRender(): void {
|
|
@@ -278,7 +287,6 @@ function renderSprite(
|
|
|
278
287
|
const adjustedX = centeredX + adjustment;
|
|
279
288
|
const adjustedY = position.Y + STREAK_TEXT_BOTTOM_Y_OFFSET;
|
|
280
289
|
|
|
281
|
-
sprite.RenderLayer(0, position);
|
|
282
290
|
font.DrawStringScaled(
|
|
283
291
|
name,
|
|
284
292
|
adjustedX,
|
|
@@ -66,30 +66,38 @@ const PLAYER_PORTRAIT_PNG_PATH_PREFIX = "gfx/ui/stage";
|
|
|
66
66
|
const VANILLA_VERSUS_PLAYBACK_SPEED = 0.5;
|
|
67
67
|
|
|
68
68
|
const versusScreenSprite = Sprite();
|
|
69
|
-
versusScreenSprite.Load("gfx/ui/boss/versusscreen.anm2", false);
|
|
70
|
-
|
|
71
|
-
// In vanilla, the "overlay.png" file has a white background. We must convert it to a PNG that uses
|
|
72
|
-
// a transparent background in order for the background behind it to be visible. We use the same
|
|
73
|
-
// "overlay.png" file as StageAPI uses for this purpose.
|
|
74
|
-
versusScreenSprite.ReplaceSpritesheet(
|
|
75
|
-
OVERLAY_ANM2_LAYER,
|
|
76
|
-
`${ISAACSCRIPT_CUSTOM_STAGE_GFX_PATH}/overlay.png`,
|
|
77
|
-
);
|
|
78
|
-
versusScreenSprite.LoadGraphics();
|
|
79
69
|
|
|
80
70
|
/**
|
|
81
71
|
* Unfortunately, we must split the background layer into an entirely different sprite so that we
|
|
82
72
|
* can color it with the `Color` property.
|
|
83
73
|
*/
|
|
84
74
|
const versusScreenBackgroundSprite = Sprite();
|
|
85
|
-
versusScreenBackgroundSprite.Load("gfx/ui/boss/versusscreen.anm2", true);
|
|
86
75
|
|
|
87
76
|
/**
|
|
88
77
|
* Unfortunately, we must split the dirt layer into an entirely different sprite so that we can
|
|
89
78
|
* color it with the `Color` property.
|
|
90
79
|
*/
|
|
91
80
|
const versusScreenDirtSpotSprite = Sprite();
|
|
92
|
-
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* We must load the sprites in an init function to prevent issues with mods that replace the vanilla
|
|
84
|
+
* files. (For some reason, loading the sprites will cause the overwrite to no longer apply on the
|
|
85
|
+
* second and subsequent runs.)
|
|
86
|
+
*/
|
|
87
|
+
export function versusScreenInit(): void {
|
|
88
|
+
// In vanilla, the "overlay.png" file has a white background. We must convert it to a PNG that
|
|
89
|
+
// uses a transparent background in order for the background behind it to be visible. We use the
|
|
90
|
+
// same "overlay.png" file as StageAPI uses for this purpose.
|
|
91
|
+
versusScreenSprite.Load("gfx/ui/boss/versusscreen.anm2", false);
|
|
92
|
+
versusScreenSprite.ReplaceSpritesheet(
|
|
93
|
+
OVERLAY_ANM2_LAYER,
|
|
94
|
+
`${ISAACSCRIPT_CUSTOM_STAGE_GFX_PATH}/overlay.png`,
|
|
95
|
+
);
|
|
96
|
+
versusScreenSprite.LoadGraphics();
|
|
97
|
+
|
|
98
|
+
versusScreenBackgroundSprite.Load("gfx/ui/boss/versusscreen.anm2", true);
|
|
99
|
+
versusScreenDirtSpotSprite.Load("gfx/ui/boss/versusscreen.anm2", true);
|
|
100
|
+
}
|
|
93
101
|
|
|
94
102
|
export function playVersusScreenAnimation(customStage: CustomStage): void {
|
|
95
103
|
const room = game.GetRoom();
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { VectorZero } from "../../constants";
|
|
2
|
+
import { StageTravelState } from "../../enums/private/StageTravelState";
|
|
3
|
+
import { ISAACSCRIPT_CUSTOM_STAGE_GFX_PATH } from "../customStage/customStageConstants";
|
|
4
|
+
import v from "./v";
|
|
5
|
+
|
|
6
|
+
const sprite = Sprite();
|
|
7
|
+
sprite.Load(`${ISAACSCRIPT_CUSTOM_STAGE_GFX_PATH}/black.anm2`, true);
|
|
8
|
+
sprite.SetFrame("Default", 0);
|
|
9
|
+
|
|
10
|
+
export function drawBlackSprite(): void {
|
|
11
|
+
if (v.run.state !== StageTravelState.PAUSING_ON_BLACK) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
sprite.RenderLayer(0, VectorZero);
|
|
16
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { GridEntityType } from "isaac-typescript-definitions";
|
|
2
|
+
|
|
3
|
+
export const CUSTOM_TRAPDOOR_FEATURE_NAME = "customTrapdoor";
|
|
4
|
+
|
|
5
|
+
export const GridEntityTypeCustom = {
|
|
6
|
+
TRAPDOOR_CUSTOM: 1000 as GridEntityType,
|
|
7
|
+
} as const;
|
|
8
|
+
|
|
9
|
+
/** This also applies to crawl spaces. The value was determined through trial and error. */
|
|
10
|
+
export const TRAPDOOR_OPEN_DISTANCE = 60;
|
|
11
|
+
|
|
12
|
+
export const TRAPDOOR_OPEN_DISTANCE_AFTER_BOSS = TRAPDOOR_OPEN_DISTANCE * 2.5;
|
|
13
|
+
export const TRAPDOOR_BOSS_REACTION_FRAMES = 30;
|
|
14
|
+
|
|
15
|
+
export const TRAPDOOR_TOUCH_DISTANCE = 16.5;
|
|
16
|
+
|
|
17
|
+
export const ANIMATIONS_THAT_PREVENT_STAGE_TRAVEL: ReadonlySet<string> =
|
|
18
|
+
new Set(["Happy", "Sad", "Jump"]);
|
|
19
|
+
|
|
20
|
+
export const PIXELATION_TO_BLACK_FRAMES = 52;
|
|
21
|
+
|
|
22
|
+
export const OTHER_PLAYER_TRAPDOOR_JUMP_DELAY_GAME_FRAMES = 10;
|
|
23
|
+
export const OTHER_PLAYER_TRAPDOOR_JUMP_DURATION_GAME_FRAMES = 8;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import {
|
|
2
|
+
GridCollisionClass,
|
|
3
|
+
LevelStage,
|
|
4
|
+
StageType,
|
|
5
|
+
} from "isaac-typescript-definitions";
|
|
6
|
+
import { game } from "../../cachedClasses";
|
|
7
|
+
import { TrapdoorAnimation } from "../../enums/private/TrapdoorAnimation";
|
|
8
|
+
import { errorIfFeaturesNotInitialized } from "../../featuresInitialized";
|
|
9
|
+
import { getNextStage, getNextStageType } from "../../functions/nextStage";
|
|
10
|
+
import { getRoomListIndex } from "../../functions/roomData";
|
|
11
|
+
import { isVector } from "../../functions/vector";
|
|
12
|
+
import { CustomTrapdoorDescription } from "../../interfaces/private/CustomTrapdoorDescription";
|
|
13
|
+
import { spawnCustomGridEntity } from "../customGridEntity";
|
|
14
|
+
import {
|
|
15
|
+
CUSTOM_TRAPDOOR_FEATURE_NAME,
|
|
16
|
+
GridEntityTypeCustom,
|
|
17
|
+
} from "./customTrapdoorConstants";
|
|
18
|
+
import { shouldTrapdoorSpawnOpen } from "./openClose";
|
|
19
|
+
import v from "./v";
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Helper function to spawn a trapdoor grid entity that will have one or more of the following
|
|
23
|
+
* attributes:
|
|
24
|
+
*
|
|
25
|
+
* - custom destination (or custom logic for after the player enters)
|
|
26
|
+
* - custom graphics
|
|
27
|
+
* - custom logic for opening/closing
|
|
28
|
+
* - TODO: player jumping animation?
|
|
29
|
+
*
|
|
30
|
+
* You can use this function to take the player to your custom stage.
|
|
31
|
+
*
|
|
32
|
+
* Under the hood, the custom trapdoor is represented by a decoration grid entity and is manually
|
|
33
|
+
* respawned every time the player re-enters the room.
|
|
34
|
+
*
|
|
35
|
+
* @param gridIndexOrPosition The location in the room to spawn the trapdoor.
|
|
36
|
+
* @param destination Optional. Used to specify where the player will go after jumping into the
|
|
37
|
+
* trapdoor. Can either be a tuple containing the stage and stage type, or a
|
|
38
|
+
* string containing the name of a custom stage. If not specified at all, then
|
|
39
|
+
* the "normal" destination corresponding to the current stage and room will be
|
|
40
|
+
* used (e.g. the next floor).
|
|
41
|
+
* @param anm2Path Optional. The path to the anm2 file to use. By default, the vanilla trapdoor anm2
|
|
42
|
+
* of "gfx/grid/door_11_trapdoor.anm2" will be used. The specified anm2 file must
|
|
43
|
+
* have animations called "Opened", "Closed", and "Open Animation".
|
|
44
|
+
* @param spawnOpen Optional. Whether or not to spawn the trapdoor in an open state. By default,
|
|
45
|
+
* behavior will be used that emulates a vanilla trapdoor.
|
|
46
|
+
*/
|
|
47
|
+
export function spawnCustomTrapdoor(
|
|
48
|
+
gridIndexOrPosition: int | Vector,
|
|
49
|
+
destination?: [stage: LevelStage, stageType: StageType] | string,
|
|
50
|
+
anm2Path = "gfx/grid/door_11_trapdoor.anm2",
|
|
51
|
+
spawnOpen?: boolean,
|
|
52
|
+
): GridEntity {
|
|
53
|
+
errorIfFeaturesNotInitialized(CUSTOM_TRAPDOOR_FEATURE_NAME);
|
|
54
|
+
|
|
55
|
+
const room = game.GetRoom();
|
|
56
|
+
const roomFrameCount = room.GetFrameCount();
|
|
57
|
+
const roomListIndex = getRoomListIndex();
|
|
58
|
+
const gridIndex = isVector(gridIndexOrPosition)
|
|
59
|
+
? room.GetGridIndex(gridIndexOrPosition)
|
|
60
|
+
: gridIndexOrPosition;
|
|
61
|
+
|
|
62
|
+
const gridEntity = spawnCustomGridEntity(
|
|
63
|
+
GridEntityTypeCustom.TRAPDOOR_CUSTOM,
|
|
64
|
+
gridIndexOrPosition,
|
|
65
|
+
GridCollisionClass.NONE,
|
|
66
|
+
anm2Path,
|
|
67
|
+
TrapdoorAnimation.OPENED,
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
const firstSpawn = roomFrameCount !== 0;
|
|
71
|
+
const open =
|
|
72
|
+
spawnOpen === undefined
|
|
73
|
+
? shouldTrapdoorSpawnOpen(gridEntity, firstSpawn)
|
|
74
|
+
: spawnOpen;
|
|
75
|
+
const destinationToUse =
|
|
76
|
+
destination === undefined ? getDefaultDestination() : destination;
|
|
77
|
+
|
|
78
|
+
const roomTrapdoorMap = v.level.trapdoors.getAndSetDefault(roomListIndex);
|
|
79
|
+
const customTrapdoorDescription: CustomTrapdoorDescription = {
|
|
80
|
+
open,
|
|
81
|
+
destination: destinationToUse,
|
|
82
|
+
firstSpawn,
|
|
83
|
+
};
|
|
84
|
+
roomTrapdoorMap.set(gridIndex, customTrapdoorDescription);
|
|
85
|
+
|
|
86
|
+
if (!open) {
|
|
87
|
+
const sprite = gridEntity.GetSprite();
|
|
88
|
+
sprite.Play(TrapdoorAnimation.CLOSED, true);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return gridEntity;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function getDefaultDestination(): [stage: LevelStage, stageType: StageType] {
|
|
95
|
+
const nextStage = getNextStage();
|
|
96
|
+
const nextStageType = getNextStageType();
|
|
97
|
+
|
|
98
|
+
return [nextStage, nextStageType];
|
|
99
|
+
}
|
|
@@ -0,0 +1,215 @@
|
|
|
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
|
+
PIXELATION_TO_BLACK_FRAMES,
|
|
25
|
+
} from "./customTrapdoorConstants";
|
|
26
|
+
import { checkCustomTrapdoorOpenClose } from "./openClose";
|
|
27
|
+
import { checkCustomTrapdoorPlayerTouched } from "./touched";
|
|
28
|
+
import v from "./v";
|
|
29
|
+
|
|
30
|
+
export function customTrapdoorInit(mod: ModUpgraded): void {
|
|
31
|
+
saveDataManager(CUSTOM_TRAPDOOR_FEATURE_NAME, v);
|
|
32
|
+
|
|
33
|
+
mod.AddCallback(ModCallback.POST_RENDER, postRender); // 2
|
|
34
|
+
mod.AddCallback(ModCallback.POST_PEFFECT_UPDATE, postPEffectUpdate); // 4
|
|
35
|
+
mod.AddCallbackCustom(
|
|
36
|
+
ModCallbackCustom.POST_GRID_ENTITY_UPDATE,
|
|
37
|
+
postGridEntityUpdateTrapdoor,
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// ModCallback.POST_RENDER (2)
|
|
42
|
+
function postRender() {
|
|
43
|
+
checkAllPlayersJumpComplete();
|
|
44
|
+
checkPixelationToBlackComplete();
|
|
45
|
+
checkPausingOnBlackComplete();
|
|
46
|
+
checkAllPlayersLayingDownComplete();
|
|
47
|
+
drawBlackSprite();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function checkAllPlayersJumpComplete() {
|
|
51
|
+
if (v.run.state !== StageTravelState.PLAYERS_JUMPING_DOWN) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (anyPlayerPlayingExtraAnimation()) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const renderFrameCount = Isaac.GetFrameCount();
|
|
60
|
+
const roomGridIndex = getRoomGridIndex();
|
|
61
|
+
|
|
62
|
+
v.run.state = StageTravelState.PIXELATION_TO_BLACK;
|
|
63
|
+
v.run.stateRenderFrame = renderFrameCount;
|
|
64
|
+
|
|
65
|
+
// In order to display the pixelation effect that should happen when we go to a new floor, we need
|
|
66
|
+
// to start a room transition. We arbitrarily pick the current room for this purpose.
|
|
67
|
+
game.StartRoomTransition(
|
|
68
|
+
roomGridIndex,
|
|
69
|
+
Direction.NO_DIRECTION,
|
|
70
|
+
RoomTransitionAnim.PIXELATION,
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function checkPixelationToBlackComplete() {
|
|
75
|
+
if (
|
|
76
|
+
v.run.state !== StageTravelState.PIXELATION_TO_BLACK ||
|
|
77
|
+
v.run.stateRenderFrame === null
|
|
78
|
+
) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const hud = game.GetHUD();
|
|
83
|
+
const renderFrameCount = Isaac.GetFrameCount();
|
|
84
|
+
const roomGridIndex = getRoomGridIndex();
|
|
85
|
+
|
|
86
|
+
const renderFrameScreenBlack =
|
|
87
|
+
v.run.stateRenderFrame + PIXELATION_TO_BLACK_FRAMES;
|
|
88
|
+
if (renderFrameCount < renderFrameScreenBlack) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
v.run.state = StageTravelState.PAUSING_ON_BLACK;
|
|
93
|
+
v.run.stateRenderFrame = renderFrameCount;
|
|
94
|
+
|
|
95
|
+
hud.SetVisible(false);
|
|
96
|
+
goToCustomDestination();
|
|
97
|
+
|
|
98
|
+
// Start another pixelation effect. This time, we will keep the screen black with the sprite, and
|
|
99
|
+
// then remove the black sprite once the pixelation effect is halfway complete.
|
|
100
|
+
game.StartRoomTransition(
|
|
101
|
+
roomGridIndex,
|
|
102
|
+
Direction.NO_DIRECTION,
|
|
103
|
+
RoomTransitionAnim.PIXELATION,
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function checkPausingOnBlackComplete() {
|
|
108
|
+
if (
|
|
109
|
+
v.run.state !== StageTravelState.PAUSING_ON_BLACK ||
|
|
110
|
+
v.run.stateRenderFrame === null
|
|
111
|
+
) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const hud = game.GetHUD();
|
|
116
|
+
const renderFrameCount = Isaac.GetFrameCount();
|
|
117
|
+
|
|
118
|
+
const renderFrameScreenBlack =
|
|
119
|
+
v.run.stateRenderFrame + PIXELATION_TO_BLACK_FRAMES;
|
|
120
|
+
if (renderFrameCount < renderFrameScreenBlack) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
v.run.state = StageTravelState.PIXELATION_TO_ROOM;
|
|
125
|
+
|
|
126
|
+
hud.SetVisible(true);
|
|
127
|
+
|
|
128
|
+
runNextRoom(() => {
|
|
129
|
+
// After the room transition, the players will be placed next to a door, but they should be in
|
|
130
|
+
// the center of the room to emulate what happens on a vanilla stage.
|
|
131
|
+
movePlayersToCenter();
|
|
132
|
+
|
|
133
|
+
v.run.state = StageTravelState.PLAYERS_LAYING_DOWN;
|
|
134
|
+
|
|
135
|
+
for (const player of getAllPlayers()) {
|
|
136
|
+
player.AnimateAppear();
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
// In vanilla, the streak text appears about when the pixelation has faded and while Isaac is
|
|
141
|
+
// still laying on the ground. Unfortunately, we cannot exactly replicate the vanilla timing,
|
|
142
|
+
// because the level text will bug out and smear the background if we play it from a `POST_RENDER`
|
|
143
|
+
// callback. Thus, we run it on the next game frame as a workaround.
|
|
144
|
+
runNextGameFrame(() => {
|
|
145
|
+
topStreakTextStart();
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function checkAllPlayersLayingDownComplete() {
|
|
150
|
+
if (v.run.state !== StageTravelState.PLAYERS_LAYING_DOWN) {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (anyPlayerPlayingExtraAnimation()) {
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
v.run.state = StageTravelState.NONE;
|
|
159
|
+
|
|
160
|
+
enableAllInputs(CUSTOM_TRAPDOOR_FEATURE_NAME);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function goToCustomDestination() {
|
|
164
|
+
if (v.run.destination === null) {
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (isString(v.run.destination)) {
|
|
169
|
+
setCustomStage("Slaughterhouse");
|
|
170
|
+
} else {
|
|
171
|
+
const [stage, stageType] = v.run.destination;
|
|
172
|
+
setStage(stage, stageType);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function anyPlayerPlayingExtraAnimation() {
|
|
177
|
+
const players = getAllPlayers();
|
|
178
|
+
return players.some((player) => !player.IsExtraAnimationFinished());
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// ModCallback.POST_PEFFECT_UPDATE (4)
|
|
182
|
+
function postPEffectUpdate(player: EntityPlayer) {
|
|
183
|
+
checkJumpComplete(player);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function checkJumpComplete(player: EntityPlayer) {
|
|
187
|
+
if (v.run.state !== StageTravelState.PLAYERS_JUMPING_DOWN) {
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// In this state, the players are jumping down the hole (i.e. playing the "Trapdoor" animation).
|
|
192
|
+
// When it completes, they will return to normal (i.e. just standing on top of the trapdoor).
|
|
193
|
+
// Thus, make them invisible at the end of the animation. (They will automatically be set to
|
|
194
|
+
// visible again once we travel to the next floor.)
|
|
195
|
+
const sprite = player.GetSprite();
|
|
196
|
+
if (sprite.IsFinished("Trapdoor")) {
|
|
197
|
+
player.Visible = false;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// ModCallbackCustom.POST_GRID_ENTITY_UPDATE
|
|
202
|
+
// GridEntityType.TRAPDOOR (17)
|
|
203
|
+
function postGridEntityUpdateTrapdoor(gridEntity: GridEntity) {
|
|
204
|
+
const roomListIndex = getRoomListIndex();
|
|
205
|
+
const gridIndex = gridEntity.GetGridIndex();
|
|
206
|
+
|
|
207
|
+
const roomTrapdoorMap = v.level.trapdoors.getAndSetDefault(roomListIndex);
|
|
208
|
+
const trapdoorDescription = roomTrapdoorMap.get(gridIndex);
|
|
209
|
+
if (trapdoorDescription === undefined) {
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
checkCustomTrapdoorOpenClose(gridEntity, trapdoorDescription);
|
|
214
|
+
checkCustomTrapdoorPlayerTouched(gridEntity, trapdoorDescription);
|
|
215
|
+
}
|
|
@@ -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
|
+
}
|