isaacscript-common 6.20.2 → 6.21.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/constantsFirstLast.d.ts +2 -2
- package/dist/constantsFirstLast.lua +2 -2
- package/dist/enums/RockAltType.d.ts +12 -1
- package/dist/enums/RockAltType.d.ts.map +1 -1
- package/dist/enums/RockAltType.lua +4 -2
- package/dist/features/customStage/backdrop.d.ts.map +1 -1
- package/dist/features/customStage/backdrop.lua +3 -2
- package/dist/features/customStage/customStageConstants.d.ts +11 -0
- package/dist/features/customStage/customStageConstants.d.ts.map +1 -1
- package/dist/features/customStage/customStageConstants.lua +10 -0
- package/dist/features/customStage/customStageGridEntities.d.ts +1 -0
- package/dist/features/customStage/customStageGridEntities.d.ts.map +1 -1
- package/dist/features/customStage/customStageGridEntities.lua +58 -23
- package/dist/features/customStage/exports.d.ts +4 -5
- package/dist/features/customStage/exports.d.ts.map +1 -1
- package/dist/features/customStage/exports.lua +49 -51
- package/dist/features/customStage/init.d.ts.map +1 -1
- package/dist/features/customStage/init.lua +7 -12
- package/dist/features/customStage/shadows.d.ts.map +1 -1
- package/dist/features/customStage/shadows.lua +2 -1
- package/dist/features/customStage/streakText.d.ts +0 -7
- package/dist/features/customStage/streakText.d.ts.map +1 -1
- package/dist/features/customStage/streakText.lua +51 -84
- package/dist/features/customStage/v.d.ts +13 -0
- package/dist/features/customStage/v.d.ts.map +1 -1
- package/dist/features/customStage/v.lua +6 -1
- package/dist/features/customTrapdoor/exports.d.ts +7 -6
- package/dist/features/customTrapdoor/exports.d.ts.map +1 -1
- package/dist/features/customTrapdoor/exports.lua +6 -5
- package/dist/features/customTrapdoor/init.d.ts.map +1 -1
- package/dist/features/customTrapdoor/init.lua +11 -6
- package/dist/features/customTrapdoor/touched.lua +0 -1
- package/dist/features/customTrapdoor/v.d.ts +1 -1
- package/dist/features/extraConsoleCommands/commandsSubroutines.d.ts.map +1 -1
- package/dist/features/extraConsoleCommands/commandsSubroutines.lua +3 -3
- package/dist/features/saveDataManager/exports.d.ts +3 -0
- package/dist/features/saveDataManager/exports.d.ts.map +1 -1
- package/dist/features/saveDataManager/exports.lua +3 -0
- package/dist/functions/collectibleSet.d.ts +1 -1
- package/dist/functions/collectibleSet.lua +1 -1
- package/dist/functions/doors.d.ts +10 -0
- package/dist/functions/doors.d.ts.map +1 -1
- package/dist/functions/doors.lua +6 -0
- package/dist/functions/log.d.ts +1 -15
- package/dist/functions/log.d.ts.map +1 -1
- package/dist/functions/log.lua +3 -218
- package/dist/functions/logEntities.d.ts +16 -0
- package/dist/functions/logEntities.d.ts.map +1 -0
- package/dist/functions/logEntities.lua +220 -0
- package/dist/functions/rockAlt.d.ts +6 -5
- package/dist/functions/rockAlt.d.ts.map +1 -1
- package/dist/functions/rockAlt.lua +147 -18
- package/dist/functions/roomTransition.d.ts +26 -0
- package/dist/functions/roomTransition.d.ts.map +1 -0
- package/dist/functions/roomTransition.lua +75 -0
- package/dist/functions/rooms.d.ts +1 -18
- package/dist/functions/rooms.d.ts.map +1 -1
- package/dist/functions/rooms.lua +3 -52
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.lua +8 -0
- package/dist/interfaces/private/CustomTrapdoorDescription.d.ts +1 -1
- package/dist/interfaces/private/CustomTrapdoorDescription.d.ts.map +1 -1
- package/dist/objects/backdropTypeToRockAltType.lua +3 -3
- package/package.json +1 -1
- package/src/constantsFirstLast.ts +2 -2
- package/src/enums/RockAltType.ts +14 -1
- package/src/features/customStage/backdrop.ts +2 -1
- package/src/features/customStage/customStageConstants.ts +16 -0
- package/src/features/customStage/customStageGridEntities.ts +47 -0
- package/src/features/customStage/exports.ts +44 -40
- package/src/features/customStage/init.ts +7 -18
- package/src/features/customStage/shadows.ts +2 -1
- package/src/features/customStage/streakText.ts +58 -95
- package/src/features/customStage/v.ts +17 -0
- package/src/features/customTrapdoor/exports.ts +9 -6
- package/src/features/customTrapdoor/init.ts +16 -5
- package/src/features/customTrapdoor/touched.ts +0 -2
- package/src/features/customTrapdoor/v.ts +1 -1
- package/src/features/extraConsoleCommands/commandsSubroutines.ts +4 -1
- package/src/features/saveDataManager/exports.ts +3 -0
- package/src/functions/collectibleSet.ts +1 -1
- package/src/functions/doors.ts +10 -0
- package/src/functions/log.ts +1 -279
- package/src/functions/logEntities.ts +276 -0
- package/src/functions/rockAlt.ts +147 -19
- package/src/functions/roomTransition.ts +78 -0
- package/src/functions/rooms.ts +2 -60
- package/src/index.ts +1 -0
- package/src/interfaces/private/CustomTrapdoorDescription.ts +3 -1
- package/src/objects/backdropTypeToRockAltType.ts +3 -3
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
CollectibleType,
|
|
3
3
|
EntityType,
|
|
4
|
+
GridEntityType,
|
|
4
5
|
TrinketType,
|
|
5
6
|
} from "isaac-typescript-definitions";
|
|
6
7
|
import { DecorationVariant } from "../../enums/DecorationVariant";
|
|
7
8
|
import { removeEntities } from "../../functions/entities";
|
|
8
9
|
import { getNPCs } from "../../functions/entitiesSpecific";
|
|
10
|
+
import { removeGridEntity } from "../../functions/gridEntities";
|
|
9
11
|
import {
|
|
10
12
|
getCoins,
|
|
11
13
|
getCollectibles,
|
|
@@ -13,6 +15,8 @@ import {
|
|
|
13
15
|
} from "../../functions/pickupsSpecific";
|
|
14
16
|
import { vectorEquals } from "../../functions/vector";
|
|
15
17
|
import { CustomStage } from "../../interfaces/CustomStage";
|
|
18
|
+
import { spawnCustomTrapdoor } from "../customTrapdoor/exports";
|
|
19
|
+
import v from "./v";
|
|
16
20
|
|
|
17
21
|
/** For `GridEntityType.DECORATION` (1) */
|
|
18
22
|
export function setCustomDecorationGraphics(
|
|
@@ -25,6 +29,11 @@ export function setCustomDecorationGraphics(
|
|
|
25
29
|
return;
|
|
26
30
|
}
|
|
27
31
|
|
|
32
|
+
const gridEntityType = gridEntity.GetType();
|
|
33
|
+
if (gridEntityType !== GridEntityType.DECORATION) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
28
37
|
// Ignore custom grid entities. (They are represented as decorations with a non-zero variant.)
|
|
29
38
|
const variant = gridEntity.GetVariant();
|
|
30
39
|
if (variant !== (DecorationVariant.VANILLA_DECORATION as int)) {
|
|
@@ -51,6 +60,11 @@ export function setCustomRockGraphics(
|
|
|
51
60
|
return;
|
|
52
61
|
}
|
|
53
62
|
|
|
63
|
+
const gridEntityRock = gridEntity.ToRock();
|
|
64
|
+
if (gridEntityRock === undefined) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
54
68
|
const sprite = gridEntity.GetSprite();
|
|
55
69
|
const fileName = sprite.GetFilename();
|
|
56
70
|
if (fileName === "gfx/grid/grid_rock.anm2") {
|
|
@@ -73,6 +87,11 @@ export function setCustomPitGraphics(
|
|
|
73
87
|
return;
|
|
74
88
|
}
|
|
75
89
|
|
|
90
|
+
const gridEntityPit = gridEntity.ToPit();
|
|
91
|
+
if (gridEntityPit === undefined) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
|
|
76
95
|
const sprite = gridEntity.GetSprite();
|
|
77
96
|
const fileName = sprite.GetFilename();
|
|
78
97
|
if (fileName === "gfx/grid/grid_pit.anm2") {
|
|
@@ -86,6 +105,17 @@ export function setCustomDoorGraphics(
|
|
|
86
105
|
customStage: CustomStage,
|
|
87
106
|
gridEntity: GridEntity,
|
|
88
107
|
): void {
|
|
108
|
+
// If the end-user did not specify custom pit graphics, default to Basement graphics. (We don't
|
|
109
|
+
// have to adjust anything for this case.)
|
|
110
|
+
if (customStage.doorPNGPaths === undefined) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const gridEntityDoor = gridEntity.ToDoor();
|
|
115
|
+
if (gridEntityDoor === undefined) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
|
|
89
119
|
const sprite = gridEntity.GetSprite();
|
|
90
120
|
const fileName = sprite.GetFilename();
|
|
91
121
|
const doorPNGPath = getNewDoorPNGPath(customStage, fileName);
|
|
@@ -148,6 +178,23 @@ function getNewDoorPNGPath(
|
|
|
148
178
|
return undefined;
|
|
149
179
|
}
|
|
150
180
|
|
|
181
|
+
export function convertVanillaTrapdoors(
|
|
182
|
+
customStage: CustomStage,
|
|
183
|
+
gridEntity: GridEntity,
|
|
184
|
+
): void {
|
|
185
|
+
const gridEntityType = gridEntity.GetType();
|
|
186
|
+
if (gridEntityType !== GridEntityType.TRAPDOOR) {
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
removeGridEntity(gridEntity, true);
|
|
191
|
+
|
|
192
|
+
const destination: [string, int] | undefined = v.run.firstFloor
|
|
193
|
+
? [customStage.name, 2]
|
|
194
|
+
: undefined;
|
|
195
|
+
spawnCustomTrapdoor(gridEntity.Position, destination);
|
|
196
|
+
}
|
|
197
|
+
|
|
151
198
|
/**
|
|
152
199
|
* The rewards are based on the ones from the wiki:
|
|
153
200
|
* https://bindingofisaacrebirth.fandom.com/wiki/Rocks#Urns
|
|
@@ -8,15 +8,15 @@ import {
|
|
|
8
8
|
import { game } from "../../cachedClasses";
|
|
9
9
|
import { reorderedCallbacksSetStage } from "../../callbacks/reorderedCallbacks";
|
|
10
10
|
import { getEntityIDFromConstituents } from "../../functions/entities";
|
|
11
|
-
import {
|
|
11
|
+
import { logError } from "../../functions/log";
|
|
12
12
|
import { newRNG } from "../../functions/rng";
|
|
13
13
|
import {
|
|
14
14
|
getRoomDataForTypeVariant,
|
|
15
15
|
getRoomsInGrid,
|
|
16
16
|
} from "../../functions/rooms";
|
|
17
17
|
import { setStage } from "../../functions/stage";
|
|
18
|
+
import { CustomStage } from "../../interfaces/CustomStage";
|
|
18
19
|
import { getRandomCustomStageRoom } from "./customStageUtils";
|
|
19
|
-
import { topStreakTextStart } from "./streakText";
|
|
20
20
|
import v, {
|
|
21
21
|
customBossPNGPaths,
|
|
22
22
|
customStageCachedRoomData,
|
|
@@ -33,13 +33,13 @@ const DEFAULT_BASE_STAGE_TYPE = StageType.ORIGINAL;
|
|
|
33
33
|
* more details: https://isaacscript.github.io/main/custom-stages/
|
|
34
34
|
*
|
|
35
35
|
* @param name The name of the custom stage, corresponding to what is in the "tsconfig.json" file.
|
|
36
|
-
* @param
|
|
37
|
-
*
|
|
38
|
-
*
|
|
36
|
+
* @param firstFloor Whether to go to the first floor or the second floor. For example, if you have
|
|
37
|
+
* a custom stage emulating Caves, then the first floor would be Caves 1, and the
|
|
38
|
+
* second floor would be Caves 2.
|
|
39
39
|
*/
|
|
40
40
|
export function setCustomStage(
|
|
41
41
|
name: string,
|
|
42
|
-
|
|
42
|
+
firstFloor = true,
|
|
43
43
|
verbose = false,
|
|
44
44
|
): void {
|
|
45
45
|
const customStage = customStagesMap.get(name);
|
|
@@ -50,24 +50,53 @@ export function setCustomStage(
|
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
const level = game.GetLevel();
|
|
53
|
-
const startingRoomGridIndex = level.GetStartingRoomIndex();
|
|
54
53
|
const seeds = game.GetSeeds();
|
|
55
54
|
const startSeed = seeds.GetStartSeed();
|
|
56
55
|
const rng = newRNG(startSeed);
|
|
57
56
|
|
|
58
57
|
v.run.currentCustomStage = customStage;
|
|
58
|
+
v.run.firstFloor = firstFloor;
|
|
59
59
|
|
|
60
|
-
|
|
60
|
+
let baseStage: int =
|
|
61
61
|
customStage.baseStage === undefined
|
|
62
62
|
? DEFAULT_BASE_STAGE
|
|
63
|
-
:
|
|
63
|
+
: customStage.baseStage;
|
|
64
|
+
if (!firstFloor) {
|
|
65
|
+
baseStage++;
|
|
66
|
+
}
|
|
64
67
|
const baseStageType =
|
|
65
68
|
customStage.baseStageType === undefined
|
|
66
69
|
? DEFAULT_BASE_STAGE_TYPE
|
|
67
70
|
: (customStage.baseStageType as StageType);
|
|
68
|
-
setStage(baseStage, baseStageType);
|
|
71
|
+
setStage(baseStage as LevelStage, baseStageType);
|
|
72
|
+
|
|
73
|
+
setStageRoomsData(customStage, rng, verbose);
|
|
74
|
+
|
|
75
|
+
// Set the stage to an invalid value, which will prevent the walls and floors from loading. We
|
|
76
|
+
// must use `StageType.WRATH_OF_THE_LAMB` instead of `StageType.ORIGINAL` or else the walls will
|
|
77
|
+
// not render properly. DeadInfinity suspects that this might be because it is trying to use the
|
|
78
|
+
// Dark Room's backdrop (instead of The Chest).
|
|
79
|
+
const stage = -1 as LevelStage;
|
|
80
|
+
const stageType = StageType.WRATH_OF_THE_LAMB;
|
|
81
|
+
level.SetStage(stage, stageType);
|
|
82
|
+
reorderedCallbacksSetStage(stage, stageType);
|
|
83
|
+
|
|
84
|
+
// We must reload the current room in order for the `Level.SetStage` method to take effect.
|
|
85
|
+
// Furthermore, we need to cancel the queued warp to the `GridRoom.DEBUG` room. We can accomplish
|
|
86
|
+
// both of these things by initiating a room transition to an arbitrary room. However, we rely on
|
|
87
|
+
// the parent function to do this, since for normal purposes, we need to initiate a room
|
|
88
|
+
// transition for the pixelation effect.
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** Pick a custom room for each vanilla room. */
|
|
92
|
+
function setStageRoomsData(
|
|
93
|
+
customStage: CustomStage,
|
|
94
|
+
rng: RNG,
|
|
95
|
+
verbose: boolean,
|
|
96
|
+
) {
|
|
97
|
+
const level = game.GetLevel();
|
|
98
|
+
const startingRoomGridIndex = level.GetStartingRoomIndex();
|
|
69
99
|
|
|
70
|
-
// Now, we need to pick a custom room for each vanilla room.
|
|
71
100
|
for (const room of getRoomsInGrid()) {
|
|
72
101
|
// The starting floor of each room should stay empty.
|
|
73
102
|
if (room.SafeGridIndex === startingRoomGridIndex) {
|
|
@@ -85,7 +114,7 @@ export function setCustomStage(
|
|
|
85
114
|
// special rooms.)
|
|
86
115
|
if (roomType === RoomType.DEFAULT) {
|
|
87
116
|
logError(
|
|
88
|
-
`Failed to find any custom rooms for RoomType.${RoomType[roomType]} (${roomType}) for custom stage: ${name}`,
|
|
117
|
+
`Failed to find any custom rooms for RoomType.${RoomType[roomType]} (${roomType}) for custom stage: ${customStage.name}`,
|
|
89
118
|
);
|
|
90
119
|
}
|
|
91
120
|
continue;
|
|
@@ -95,7 +124,7 @@ export function setCustomStage(
|
|
|
95
124
|
const roomDoorSlotFlagMap = roomShapeMap.get(roomShape);
|
|
96
125
|
if (roomDoorSlotFlagMap === undefined) {
|
|
97
126
|
logError(
|
|
98
|
-
`Failed to find any custom rooms for RoomType.${RoomType[roomType]} (${roomType}) + RoomShape.${RoomShape[roomShape]} (${roomShape}) for custom stage: ${name}`,
|
|
127
|
+
`Failed to find any custom rooms for RoomType.${RoomType[roomType]} (${roomType}) + RoomShape.${RoomShape[roomShape]} (${roomShape}) for custom stage: ${customStage.name}`,
|
|
99
128
|
);
|
|
100
129
|
continue;
|
|
101
130
|
}
|
|
@@ -104,7 +133,7 @@ export function setCustomStage(
|
|
|
104
133
|
const roomsMetadata = roomDoorSlotFlagMap.get(doorSlotFlags);
|
|
105
134
|
if (roomsMetadata === undefined) {
|
|
106
135
|
logError(
|
|
107
|
-
`Failed to find any custom rooms for RoomType.${RoomType[roomType]} (${roomType}) + RoomShape.${RoomShape[roomShape]} (${roomShape}) + DoorSlotFlags ${doorSlotFlags} for custom stage: ${name}`,
|
|
136
|
+
`Failed to find any custom rooms for RoomType.${RoomType[roomType]} (${roomType}) + RoomShape.${RoomShape[roomShape]} (${roomShape}) + DoorSlotFlags ${doorSlotFlags} for custom stage: ${customStage.name}`,
|
|
108
137
|
);
|
|
109
138
|
continue;
|
|
110
139
|
}
|
|
@@ -121,7 +150,7 @@ export function setCustomStage(
|
|
|
121
150
|
);
|
|
122
151
|
if (newRoomData === undefined) {
|
|
123
152
|
logError(
|
|
124
|
-
`Failed to get the room data for room variant ${randomRoom.variant} for custom stage: ${name}`,
|
|
153
|
+
`Failed to get the room data for room variant ${randomRoom.variant} for custom stage: ${customStage.name}`,
|
|
125
154
|
);
|
|
126
155
|
continue;
|
|
127
156
|
}
|
|
@@ -131,31 +160,6 @@ export function setCustomStage(
|
|
|
131
160
|
|
|
132
161
|
room.Data = newRoomData;
|
|
133
162
|
}
|
|
134
|
-
|
|
135
|
-
// Set the stage to an invalid value, which will prevent the walls and floors from loading. We
|
|
136
|
-
// must use `StageType.WRATH_OF_THE_LAMB` instead of `StageType.ORIGINAL` or else the walls will
|
|
137
|
-
// not render properly. DeadInfinity suspects that this might be because it is trying to use the
|
|
138
|
-
// Dark Room's backdrop (instead of The Chest).
|
|
139
|
-
const stage = -1 as LevelStage;
|
|
140
|
-
const stageType = StageType.WRATH_OF_THE_LAMB;
|
|
141
|
-
level.SetStage(stage, stageType);
|
|
142
|
-
reorderedCallbacksSetStage(stage, stageType);
|
|
143
|
-
|
|
144
|
-
// We must reload the current room in order for the `Level.SetStage` method to take effect.
|
|
145
|
-
// Furthermore, we need to cancel the queued warp to the `GridRoom.DEBUG` room. We can accomplish
|
|
146
|
-
// both of these things by initiating a room transition to an arbitrary room. However, we rely on
|
|
147
|
-
// the parent function to do this, since for normal purposes, we need to initiate a room
|
|
148
|
-
// transition for the pixelation effect.
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
export function setCustomStageDebug(): void {
|
|
152
|
-
const customStage = v.run.currentCustomStage;
|
|
153
|
-
if (customStage === null) {
|
|
154
|
-
log("No custom stage is currently loaded.");
|
|
155
|
-
return;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
topStreakTextStart();
|
|
159
163
|
}
|
|
160
164
|
|
|
161
165
|
/**
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
import { saveDataManager } from "../saveDataManager/exports";
|
|
19
19
|
import { setBackdrop } from "./backdrop";
|
|
20
20
|
import {
|
|
21
|
+
convertVanillaTrapdoors,
|
|
21
22
|
removeUrnRewards,
|
|
22
23
|
setCustomDecorationGraphics,
|
|
23
24
|
setCustomDoorGraphics,
|
|
@@ -26,12 +27,7 @@ import {
|
|
|
26
27
|
} from "./customStageGridEntities";
|
|
27
28
|
import * as metadataJSON from "./metadata.json"; // This will correspond to "metadata.lua" at run-time.
|
|
28
29
|
import { setShadows } from "./shadows";
|
|
29
|
-
import {
|
|
30
|
-
streakTextGetShaderParams,
|
|
31
|
-
streakTextInit,
|
|
32
|
-
streakTextPostGameStarted,
|
|
33
|
-
streakTextPostRender,
|
|
34
|
-
} from "./streakText";
|
|
30
|
+
import { streakTextGetShaderParams, streakTextPostRender } from "./streakText";
|
|
35
31
|
import v, { customStagesMap } from "./v";
|
|
36
32
|
import {
|
|
37
33
|
playVersusScreenAnimation,
|
|
@@ -47,12 +43,10 @@ export function customStageInit(mod: ModUpgraded): void {
|
|
|
47
43
|
}
|
|
48
44
|
|
|
49
45
|
saveDataManager("customStage", v);
|
|
50
|
-
streakTextInit();
|
|
51
46
|
versusScreenInit();
|
|
52
47
|
|
|
53
48
|
mod.AddCallback(ModCallback.POST_RENDER, postRender); // 2
|
|
54
49
|
mod.AddCallback(ModCallback.POST_CURSE_EVAL, postCurseEval); // 12
|
|
55
|
-
mod.AddCallback(ModCallback.POST_GAME_STARTED, postGameStarted); // 15
|
|
56
50
|
mod.AddCallback(ModCallback.GET_SHADER_PARAMS, getShaderParams); // 21
|
|
57
51
|
mod.AddCallbackCustom(
|
|
58
52
|
ModCallbackCustom.POST_GRID_ENTITY_BROKEN,
|
|
@@ -61,7 +55,7 @@ export function customStageInit(mod: ModUpgraded): void {
|
|
|
61
55
|
);
|
|
62
56
|
mod.AddCallbackCustom(
|
|
63
57
|
ModCallbackCustom.POST_GRID_ENTITY_INIT,
|
|
64
|
-
|
|
58
|
+
postGridEntityInit,
|
|
65
59
|
);
|
|
66
60
|
mod.AddCallbackCustom(
|
|
67
61
|
ModCallbackCustom.POST_NEW_ROOM_REORDERED,
|
|
@@ -150,19 +144,13 @@ function postCurseEval(
|
|
|
150
144
|
}
|
|
151
145
|
|
|
152
146
|
// Prevent XL floors on custom stages, since the streak text will not work properly.
|
|
153
|
-
if (hasFlag(curses, LevelCurse.
|
|
154
|
-
return removeFlag(curses, LevelCurse.
|
|
147
|
+
if (hasFlag(curses, LevelCurse.LABYRINTH)) {
|
|
148
|
+
return removeFlag(curses, LevelCurse.LABYRINTH);
|
|
155
149
|
}
|
|
156
150
|
|
|
157
151
|
return undefined;
|
|
158
152
|
}
|
|
159
153
|
|
|
160
|
-
// ModCallback.POST_GAME_STARTED (15)
|
|
161
|
-
function postGameStarted() {
|
|
162
|
-
// We don't early return here because we need to unconditionally reset the sprites.
|
|
163
|
-
streakTextPostGameStarted();
|
|
164
|
-
}
|
|
165
|
-
|
|
166
154
|
// ModCallback.GET_SHADER_PARAMS (22)
|
|
167
155
|
function getShaderParams(
|
|
168
156
|
shaderName: string,
|
|
@@ -188,7 +176,7 @@ function postGridEntityBrokenRockAlt(gridEntity: GridEntity) {
|
|
|
188
176
|
}
|
|
189
177
|
|
|
190
178
|
// ModCallbackCustom.POST_GRID_ENTITY_INIT
|
|
191
|
-
function
|
|
179
|
+
function postGridEntityInit(gridEntity: GridEntity) {
|
|
192
180
|
const customStage = v.run.currentCustomStage;
|
|
193
181
|
if (customStage === null) {
|
|
194
182
|
return;
|
|
@@ -198,6 +186,7 @@ function postGridEntityBrokenInit(gridEntity: GridEntity) {
|
|
|
198
186
|
setCustomRockGraphics(customStage, gridEntity);
|
|
199
187
|
setCustomPitGraphics(customStage, gridEntity);
|
|
200
188
|
setCustomDoorGraphics(customStage, gridEntity);
|
|
189
|
+
convertVanillaTrapdoors(customStage, gridEntity);
|
|
201
190
|
}
|
|
202
191
|
|
|
203
192
|
// ModCallbackCustom.POST_NEW_ROOM_REORDERED
|
|
@@ -17,6 +17,7 @@ type ShadowAnimation = "1x1" | "1x2" | "2x1" | "2x2";
|
|
|
17
17
|
* time passes, like most other effects.
|
|
18
18
|
*/
|
|
19
19
|
const SHADOW_EFFECT_VARIANT = EffectVariant.LADDER;
|
|
20
|
+
const SHADOW_EFFECT_SUBTYPE = 102;
|
|
20
21
|
|
|
21
22
|
/** The animation comes from StageAPI. */
|
|
22
23
|
const ROOM_SHAPE_TO_SHADOW_ANIMATION: {
|
|
@@ -57,7 +58,7 @@ export function setShadows(customStage: CustomStage): void {
|
|
|
57
58
|
// rendering throughout this animation.)
|
|
58
59
|
const shadowEffect = spawnEffectWithSeed(
|
|
59
60
|
SHADOW_EFFECT_VARIANT,
|
|
60
|
-
|
|
61
|
+
SHADOW_EFFECT_SUBTYPE,
|
|
61
62
|
centerPos,
|
|
62
63
|
1 as Seed,
|
|
63
64
|
);
|
|
@@ -7,15 +7,12 @@ import {
|
|
|
7
7
|
getScreenTopCenterPos,
|
|
8
8
|
} from "../../functions/ui";
|
|
9
9
|
import { CustomStage } from "../../interfaces/CustomStage";
|
|
10
|
+
import {
|
|
11
|
+
UIStreakAnimation,
|
|
12
|
+
UI_STREAK_ANIMATION_END_FRAMES,
|
|
13
|
+
} from "./customStageConstants";
|
|
10
14
|
import v from "./v";
|
|
11
15
|
|
|
12
|
-
enum UIStreakAnimation {
|
|
13
|
-
TEXT = "Text",
|
|
14
|
-
TEXT_IN = "TextIn",
|
|
15
|
-
TEXT_OUT = "TextOut",
|
|
16
|
-
TEXT_STAY = "TextStay",
|
|
17
|
-
}
|
|
18
|
-
|
|
19
16
|
/** This must match the name of the shader in "shaders.xml". */
|
|
20
17
|
const EMPTY_SHADER_NAME = "IsaacScript-RenderAboveHUD";
|
|
21
18
|
|
|
@@ -47,9 +44,6 @@ const STREAK_TEXT_BOTTOM_Y_OFFSET = -9;
|
|
|
47
44
|
*/
|
|
48
45
|
const NUM_RENDER_FRAMES_MAP_HELD_BEFORE_STREAK_TEXT = 11;
|
|
49
46
|
|
|
50
|
-
/** Corresponds to the vanilla value; determined through trial and error. */
|
|
51
|
-
const TEXT_PLAYBACK_SPEED = 0.5;
|
|
52
|
-
|
|
53
47
|
/** Taken from StageAPI. */
|
|
54
48
|
const TEXT_IN_ADJUSTMENTS = [-800, -639, -450, -250, -70, 10, 6, 3];
|
|
55
49
|
|
|
@@ -82,33 +76,6 @@ const TEXT_OUT_SCALES = [
|
|
|
82
76
|
Vector(3, 0.2),
|
|
83
77
|
];
|
|
84
78
|
|
|
85
|
-
/**
|
|
86
|
-
* We do not actually need to render this sprite at all. It's only purpose is to be an invisible
|
|
87
|
-
* reference for when and where we need to render the stage's name. Thus, we specify "false" for
|
|
88
|
-
* "loadGraphics", but still manage playing its animations in the code below.
|
|
89
|
-
*/
|
|
90
|
-
const topStreakSprite = Sprite();
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* We do not actually need to render this sprite at all. It's only purpose is to be an invisible
|
|
94
|
-
* reference for when and where we need to render the stage's name. Thus, we specify "false" for
|
|
95
|
-
* "loadGraphics", but still manage playing its animations in the code below.
|
|
96
|
-
*/
|
|
97
|
-
const bottomStreakSprite = Sprite();
|
|
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
|
-
}
|
|
111
|
-
|
|
112
79
|
// ModCallback.POST_RENDER (2)
|
|
113
80
|
export function streakTextPostRender(): void {
|
|
114
81
|
// The top streak only plays when the player arrives on the floor (or continues a game from the
|
|
@@ -124,7 +91,7 @@ export function streakTextPostRender(): void {
|
|
|
124
91
|
function checkEndTopStreakText() {
|
|
125
92
|
if (
|
|
126
93
|
v.run.topStreakTextStartedRenderFrame === null ||
|
|
127
|
-
|
|
94
|
+
v.run.topStreakText.animation !== UIStreakAnimation.TEXT_STAY
|
|
128
95
|
) {
|
|
129
96
|
return;
|
|
130
97
|
}
|
|
@@ -133,7 +100,10 @@ function checkEndTopStreakText() {
|
|
|
133
100
|
const elapsedFrames =
|
|
134
101
|
renderFrameCount - v.run.topStreakTextStartedRenderFrame;
|
|
135
102
|
if (elapsedFrames >= 115) {
|
|
136
|
-
|
|
103
|
+
v.run.topStreakText.animation = UIStreakAnimation.TEXT;
|
|
104
|
+
// We adjust by the frame backwards by an arbitrary amount to roughly align with the speed of
|
|
105
|
+
// the vanilla animation.
|
|
106
|
+
v.run.topStreakText.frame = TEXT_OUT_FRAME - 2;
|
|
137
107
|
}
|
|
138
108
|
}
|
|
139
109
|
|
|
@@ -165,7 +135,7 @@ function trackMapInputPressed() {
|
|
|
165
135
|
* slides in from the left.
|
|
166
136
|
*/
|
|
167
137
|
function checkStartBottomStreakText() {
|
|
168
|
-
if (
|
|
138
|
+
if (v.run.bottomStreakText.animation !== UIStreakAnimation.NONE) {
|
|
169
139
|
return;
|
|
170
140
|
}
|
|
171
141
|
|
|
@@ -180,7 +150,8 @@ function checkStartBottomStreakText() {
|
|
|
180
150
|
const gameFrameCount = game.GetFrameCount();
|
|
181
151
|
const elapsedFrames = gameFrameCount - earliestFrame;
|
|
182
152
|
if (elapsedFrames >= NUM_RENDER_FRAMES_MAP_HELD_BEFORE_STREAK_TEXT) {
|
|
183
|
-
|
|
153
|
+
v.run.bottomStreakText.animation = UIStreakAnimation.TEXT;
|
|
154
|
+
v.run.bottomStreakText.frame = 0;
|
|
184
155
|
}
|
|
185
156
|
}
|
|
186
157
|
|
|
@@ -189,7 +160,7 @@ function checkStartBottomStreakText() {
|
|
|
189
160
|
* right.
|
|
190
161
|
*/
|
|
191
162
|
function checkEndBottomStreakText() {
|
|
192
|
-
if (
|
|
163
|
+
if (v.run.bottomStreakText.animation !== UIStreakAnimation.TEXT_STAY) {
|
|
193
164
|
return;
|
|
194
165
|
}
|
|
195
166
|
|
|
@@ -197,16 +168,13 @@ function checkEndBottomStreakText() {
|
|
|
197
168
|
...v.run.controllerIndexPushingMapRenderFrame.values(),
|
|
198
169
|
];
|
|
199
170
|
if (pushedMapFrames.length === 0) {
|
|
200
|
-
|
|
171
|
+
v.run.bottomStreakText.animation = UIStreakAnimation.TEXT;
|
|
172
|
+
// We adjust by the frame backwards by an arbitrary amount to roughly align with the speed of
|
|
173
|
+
// the vanilla animation.
|
|
174
|
+
v.run.bottomStreakText.frame = TEXT_OUT_FRAME - 2;
|
|
201
175
|
}
|
|
202
176
|
}
|
|
203
177
|
|
|
204
|
-
// ModCallback.POST_GAME_STARTED (15)
|
|
205
|
-
export function streakTextPostGameStarted(): void {
|
|
206
|
-
topStreakSprite.Stop();
|
|
207
|
-
bottomStreakSprite.Stop();
|
|
208
|
-
}
|
|
209
|
-
|
|
210
178
|
// ModCallback.GET_SHADER_PARAMS (22)
|
|
211
179
|
export function streakTextGetShaderParams(
|
|
212
180
|
customStage: CustomStage,
|
|
@@ -218,27 +186,44 @@ export function streakTextGetShaderParams(
|
|
|
218
186
|
|
|
219
187
|
const topCenterPos = getScreenTopCenterPos();
|
|
220
188
|
const topStreakPosition = topCenterPos.add(STREAK_SPRITE_TOP_OFFSET);
|
|
221
|
-
|
|
189
|
+
renderStreakText(customStage, v.run.topStreakText, topStreakPosition);
|
|
222
190
|
|
|
223
191
|
const bottomCenterPos = getScreenBottomCenterPos();
|
|
224
192
|
const bottomStreakPosition = bottomCenterPos.add(STREAK_SPRITE_BOTTOM_OFFSET);
|
|
225
|
-
|
|
193
|
+
renderStreakText(customStage, v.run.bottomStreakText, bottomStreakPosition);
|
|
226
194
|
}
|
|
227
195
|
|
|
228
|
-
function
|
|
196
|
+
function renderStreakText(
|
|
229
197
|
customStage: CustomStage,
|
|
230
|
-
|
|
198
|
+
streakText: { animation: UIStreakAnimation; frame: int; pauseFrame: boolean },
|
|
231
199
|
position: Vector,
|
|
232
200
|
) {
|
|
233
|
-
|
|
234
|
-
|
|
201
|
+
if (streakText.animation === UIStreakAnimation.NONE) {
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if (streakText.animation !== UIStreakAnimation.TEXT_STAY) {
|
|
206
|
+
const { pauseFrame } = streakText;
|
|
207
|
+
streakText.pauseFrame = !streakText.pauseFrame;
|
|
208
|
+
|
|
209
|
+
if (!pauseFrame) {
|
|
210
|
+
streakText.frame++;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const endFrame = UI_STREAK_ANIMATION_END_FRAMES[streakText.animation];
|
|
215
|
+
if (streakText.frame > endFrame) {
|
|
216
|
+
streakText.animation = UIStreakAnimation.NONE;
|
|
217
|
+
streakText.frame = 0;
|
|
235
218
|
return;
|
|
236
219
|
}
|
|
237
220
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
221
|
+
if (
|
|
222
|
+
streakText.animation === UIStreakAnimation.TEXT &&
|
|
223
|
+
streakText.frame === TEXT_STAY_FRAME
|
|
224
|
+
) {
|
|
225
|
+
streakText.animation = UIStreakAnimation.TEXT_STAY;
|
|
226
|
+
streakText.frame = 0;
|
|
242
227
|
}
|
|
243
228
|
|
|
244
229
|
const isPaused = game.IsPaused();
|
|
@@ -248,39 +233,22 @@ function renderSprite(
|
|
|
248
233
|
|
|
249
234
|
const font = fonts.upheaval;
|
|
250
235
|
const { name } = customStage;
|
|
251
|
-
const
|
|
236
|
+
const numberSuffix = v.run.firstFloor ? "I" : "II";
|
|
237
|
+
const nameWithNumberSuffix = `${name} ${numberSuffix}`;
|
|
238
|
+
const length = font.GetStringWidthUTF8(nameWithNumberSuffix);
|
|
252
239
|
const centeredX = position.X - length / 2;
|
|
253
240
|
|
|
254
241
|
let adjustment = 0;
|
|
255
242
|
let scale = VectorOne;
|
|
256
|
-
switch (animation) {
|
|
257
|
-
case UIStreakAnimation.TEXT: {
|
|
258
|
-
if (frame < TEXT_STAY_FRAME) {
|
|
259
|
-
adjustment = TEXT_IN_ADJUSTMENTS[frame] ?? 0;
|
|
260
|
-
scale = TEXT_IN_SCALES[frame] ?? VectorOne;
|
|
261
|
-
} else {
|
|
262
|
-
const adjustedFrame = frame - TEXT_OUT_FRAME;
|
|
263
|
-
adjustment = TEXT_OUT_ADJUSTMENTS[adjustedFrame] ?? 0;
|
|
264
|
-
scale = TEXT_OUT_SCALES[adjustedFrame] ?? VectorOne;
|
|
265
|
-
}
|
|
266
243
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
case UIStreakAnimation.TEXT_OUT: {
|
|
277
|
-
adjustment = TEXT_OUT_ADJUSTMENTS[frame] ?? 0;
|
|
278
|
-
scale = TEXT_OUT_SCALES[frame] ?? VectorOne;
|
|
279
|
-
break;
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
default: {
|
|
283
|
-
break;
|
|
244
|
+
if (streakText.animation === UIStreakAnimation.TEXT) {
|
|
245
|
+
if (streakText.frame < TEXT_STAY_FRAME) {
|
|
246
|
+
adjustment = TEXT_IN_ADJUSTMENTS[streakText.frame] ?? 0;
|
|
247
|
+
scale = TEXT_IN_SCALES[streakText.frame] ?? VectorOne;
|
|
248
|
+
} else {
|
|
249
|
+
const adjustedFrame = streakText.frame - TEXT_OUT_FRAME;
|
|
250
|
+
adjustment = TEXT_OUT_ADJUSTMENTS[adjustedFrame] ?? 0;
|
|
251
|
+
scale = TEXT_OUT_SCALES[adjustedFrame] ?? VectorOne;
|
|
284
252
|
}
|
|
285
253
|
}
|
|
286
254
|
|
|
@@ -288,7 +256,7 @@ function renderSprite(
|
|
|
288
256
|
const adjustedY = position.Y + STREAK_TEXT_BOTTOM_Y_OFFSET;
|
|
289
257
|
|
|
290
258
|
font.DrawStringScaled(
|
|
291
|
-
|
|
259
|
+
nameWithNumberSuffix,
|
|
292
260
|
adjustedX,
|
|
293
261
|
adjustedY,
|
|
294
262
|
scale.X,
|
|
@@ -297,12 +265,6 @@ function renderSprite(
|
|
|
297
265
|
);
|
|
298
266
|
}
|
|
299
267
|
|
|
300
|
-
function playTextOut(sprite: Sprite) {
|
|
301
|
-
sprite.Play(UIStreakAnimation.TEXT, true);
|
|
302
|
-
// We adjust by 2 to roughly align with the speed of the vanilla animation.
|
|
303
|
-
sprite.SetFrame(TEXT_OUT_FRAME - 2);
|
|
304
|
-
}
|
|
305
|
-
|
|
306
268
|
export function topStreakTextStart(): void {
|
|
307
269
|
const level = game.GetLevel();
|
|
308
270
|
const renderFrameCount = Isaac.GetFrameCount();
|
|
@@ -311,6 +273,7 @@ export function topStreakTextStart(): void {
|
|
|
311
273
|
level.ShowName(false);
|
|
312
274
|
|
|
313
275
|
// Initiate the animation for the custom text.
|
|
276
|
+
v.run.topStreakText.animation = UIStreakAnimation.TEXT;
|
|
277
|
+
v.run.topStreakText.frame = 0;
|
|
314
278
|
v.run.topStreakTextStartedRenderFrame = renderFrameCount;
|
|
315
|
-
topStreakSprite.Play(UIStreakAnimation.TEXT, true);
|
|
316
279
|
}
|
|
@@ -1,15 +1,32 @@
|
|
|
1
1
|
import { ControllerIndex } from "isaac-typescript-definitions";
|
|
2
2
|
import { CustomStage } from "../../interfaces/CustomStage";
|
|
3
|
+
import { UIStreakAnimation } from "./customStageConstants";
|
|
3
4
|
|
|
4
5
|
const v = {
|
|
5
6
|
run: {
|
|
6
7
|
currentCustomStage: null as CustomStage | null,
|
|
8
|
+
|
|
9
|
+
/** Whether we are on e.g. Caves 1 or Caves 2. */
|
|
10
|
+
firstFloor: true,
|
|
11
|
+
|
|
7
12
|
showingBossVersusScreen: false,
|
|
8
13
|
|
|
9
14
|
/** Values are the render frame that the controller first pressed the map button. */
|
|
10
15
|
controllerIndexPushingMapRenderFrame: new Map<ControllerIndex, int>(),
|
|
11
16
|
|
|
12
17
|
topStreakTextStartedRenderFrame: null as int | null,
|
|
18
|
+
|
|
19
|
+
topStreakText: {
|
|
20
|
+
animation: UIStreakAnimation.NONE,
|
|
21
|
+
frame: 0,
|
|
22
|
+
pauseFrame: false,
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
bottomStreakText: {
|
|
26
|
+
animation: UIStreakAnimation.NONE,
|
|
27
|
+
frame: 0,
|
|
28
|
+
pauseFrame: false,
|
|
29
|
+
},
|
|
13
30
|
},
|
|
14
31
|
|
|
15
32
|
room: {
|