isaacscript-common 6.3.0 → 6.4.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.
Files changed (58) hide show
  1. package/cachedClasses.d.ts +15 -0
  2. package/cachedClasses.lua +20 -0
  3. package/constants.d.ts +17 -4
  4. package/constants.lua +13 -4
  5. package/features/customStage/backdrop.lua +4 -2
  6. package/features/customStage/customStageConstants.d.ts +1 -0
  7. package/features/customStage/customStageConstants.lua +3 -0
  8. package/features/customStage/exports.d.ts +27 -0
  9. package/features/customStage/exports.lua +33 -3
  10. package/features/customStage/init.lua +14 -7
  11. package/features/customStage/streakText.d.ts +2 -0
  12. package/features/customStage/streakText.lua +22 -0
  13. package/features/customStage/v.d.ts +3 -0
  14. package/features/customStage/v.lua +3 -1
  15. package/features/customStage/versusScreen.d.ts +3 -0
  16. package/features/customStage/versusScreen.lua +193 -0
  17. package/features/deployJSONRoom.lua +6 -2
  18. package/features/saveDataManager/exports.lua +2 -2
  19. package/features/saveDataManager/load.lua +3 -3
  20. package/features/saveDataManager/main.lua +3 -3
  21. package/features/saveDataManager/merge.lua +2 -2
  22. package/features/saveDataManager/save.lua +3 -3
  23. package/features/saveDataManager/{constants.d.ts → saveDataManagerConstants.d.ts} +0 -0
  24. package/features/saveDataManager/{constants.lua → saveDataManagerConstants.lua} +0 -0
  25. package/functions/color.d.ts +0 -2
  26. package/functions/color.lua +0 -4
  27. package/functions/deepCopy.lua +2 -2
  28. package/functions/entity.d.ts +5 -0
  29. package/functions/entity.lua +13 -0
  30. package/functions/gridEntity.d.ts +5 -0
  31. package/functions/gridEntity.lua +7 -2
  32. package/functions/kColor.d.ts +0 -2
  33. package/functions/kColor.lua +0 -4
  34. package/functions/log.lua +2 -1
  35. package/functions/ui.d.ts +2 -0
  36. package/functions/ui.lua +8 -0
  37. package/functions/utils.d.ts +6 -4
  38. package/functions/utils.lua +6 -4
  39. package/interfaces/CustomStageLua.d.ts +25 -0
  40. package/objects/bossNamePNGFileNames.d.ts +5 -0
  41. package/objects/bossNamePNGFileNames.lua +108 -0
  42. package/objects/bossPortraitPNGFileNames.d.ts +5 -0
  43. package/objects/bossPortraitPNGFileNames.lua +108 -0
  44. package/objects/colors.d.ts +15 -8
  45. package/objects/colors.lua +9 -2
  46. package/objects/playerNamePNGFileNames.d.ts +5 -0
  47. package/objects/playerNamePNGFileNames.lua +49 -0
  48. package/objects/playerPortraitPNGFileNames.d.ts +5 -0
  49. package/objects/playerPortraitPNGFileNames.lua +49 -0
  50. package/objects/versusScreenBackgroundColors.d.ts +5 -0
  51. package/objects/versusScreenBackgroundColors.lua +38 -0
  52. package/objects/versusScreenDirtSpotColors.d.ts +5 -0
  53. package/objects/versusScreenDirtSpotColors.lua +38 -0
  54. package/package.json +2 -2
  55. package/features/customStage/boss.d.ts +0 -2
  56. package/features/customStage/boss.lua +0 -74
  57. package/features/customStage/stageAPIBoss.d.ts +0 -29
  58. package/features/customStage/stageAPIBoss.lua +0 -9
@@ -38,3 +38,18 @@ export declare const musicManager: MusicManager;
38
38
  * `Room`) is not safe and can lead to the game crashing in certain situations.
39
39
  */
40
40
  export declare const sfxManager: SFXManager;
41
+ /**
42
+ * An object containing all 7 vanilla fonts that are pre-loaded and ready to use.
43
+ *
44
+ * For more information on the vanilla fonts and to see what they look like, see:
45
+ * https://wofsauge.github.io/IsaacDocs/rep/tutorials/Tutorial-Rendertext.html
46
+ */
47
+ export declare const fonts: {
48
+ readonly droid: Font;
49
+ readonly pfTempestaSevenCondensed: Font;
50
+ readonly teamMeatFont10: Font;
51
+ readonly teamMeatFont12: Font;
52
+ readonly teamMeatFont16Bold: Font;
53
+ readonly terminus: Font;
54
+ readonly upheaval: Font;
55
+ };
package/cachedClasses.lua CHANGED
@@ -27,4 +27,24 @@ ____exports.musicManager = MusicManager()
27
27
  -- Caching the results of this constructor is safe, but caching other classes (like `Level` or
28
28
  -- `Room`) is not safe and can lead to the game crashing in certain situations.
29
29
  ____exports.sfxManager = SFXManager()
30
+ --- An object containing all 7 vanilla fonts that are pre-loaded and ready to use.
31
+ --
32
+ -- For more information on the vanilla fonts and to see what they look like, see:
33
+ -- https://wofsauge.github.io/IsaacDocs/rep/tutorials/Tutorial-Rendertext.html
34
+ ____exports.fonts = {
35
+ droid = Font(),
36
+ pfTempestaSevenCondensed = Font(),
37
+ teamMeatFont10 = Font(),
38
+ teamMeatFont12 = Font(),
39
+ teamMeatFont16Bold = Font(),
40
+ terminus = Font(),
41
+ upheaval = Font()
42
+ }
43
+ ____exports.fonts.droid:Load("font/droid.fnt")
44
+ ____exports.fonts.pfTempestaSevenCondensed:Load("font/pftempestasevencondensed.fnt")
45
+ ____exports.fonts.teamMeatFont10:Load("font/teammeatfont10.fnt")
46
+ ____exports.fonts.teamMeatFont12:Load("font/teammeatfont12.fnt")
47
+ ____exports.fonts.teamMeatFont16Bold:Load("font/teammeatfont16bold.fnt")
48
+ ____exports.fonts.terminus:Load("font/terminus.fnt")
49
+ ____exports.fonts.upheaval:Load("font/upheaval.fnt")
30
50
  return ____exports
package/constants.d.ts CHANGED
@@ -115,12 +115,25 @@ export declare const TAINTED_SAMSON_BERSERK_CHARGE_FROM_TAKING_DAMAGE = 10000;
115
115
  */
116
116
  export declare const UI_HEART_WIDTH = 12;
117
117
  /**
118
- * This is a safer version of the `Vector.One` constant. (Other mods can mutate this `Vector.One`,
119
- * so it is not safe to use.)
118
+ * This is a safer version of the `Vector.One` constant. (Other mods can mutate `Vector.One`, so it
119
+ * is not safe to use.)
120
120
  */
121
121
  export declare const VectorOne: Readonly<Vector>;
122
122
  /**
123
- * This is a safer version of the `Vector.Zero` constant. (Other mods can mutate `Vector.Zero`
124
- * vector, so it is not safe to use.)
123
+ * This is a safer version of the `Vector.Zero` constant. (Other mods can mutate `Vector.Zero`, so
124
+ * it is not safe to use.)
125
125
  */
126
126
  export declare const VectorZero: Readonly<Vector>;
127
+ /**
128
+ * This is a safer version of the `Color.Default` constant. (Other mods can mutate `Color.Default`,
129
+ * so it is not safe to use.)
130
+ *
131
+ * If you need to mutate this, make a copy first with the `copyColor` helper function.
132
+ */
133
+ export declare const ColorDefault: Readonly<Color>;
134
+ /**
135
+ * Equal to `KColor(1, 1, 1, 1)`.
136
+ *
137
+ * If you need to mutate this, make a copy first with the `copyKColor` helper function.
138
+ */
139
+ export declare const KColorDefault: Readonly<KColor>;
package/constants.lua CHANGED
@@ -97,10 +97,19 @@ ____exports.TAINTED_SAMSON_BERSERK_CHARGE_FROM_TAKING_DAMAGE = 10000
97
97
  --- This is the number of draw coordinates that each heart spans on the UI in the upper left hand
98
98
  -- corner.
99
99
  ____exports.UI_HEART_WIDTH = 12
100
- --- This is a safer version of the `Vector.One` constant. (Other mods can mutate this `Vector.One`,
101
- -- so it is not safe to use.)
100
+ --- This is a safer version of the `Vector.One` constant. (Other mods can mutate `Vector.One`, so it
101
+ -- is not safe to use.)
102
102
  ____exports.VectorOne = Vector(1, 1)
103
- --- This is a safer version of the `Vector.Zero` constant. (Other mods can mutate `Vector.Zero`
104
- -- vector, so it is not safe to use.)
103
+ --- This is a safer version of the `Vector.Zero` constant. (Other mods can mutate `Vector.Zero`, so
104
+ -- it is not safe to use.)
105
105
  ____exports.VectorZero = Vector(0, 0)
106
+ --- This is a safer version of the `Color.Default` constant. (Other mods can mutate `Color.Default`,
107
+ -- so it is not safe to use.)
108
+ --
109
+ -- If you need to mutate this, make a copy first with the `copyColor` helper function.
110
+ ____exports.ColorDefault = Color(1, 1, 1)
111
+ --- Equal to `KColor(1, 1, 1, 1)`.
112
+ --
113
+ -- If you need to mutate this, make a copy first with the `copyKColor` helper function.
114
+ ____exports.KColorDefault = KColor(1, 1, 1, 1)
106
115
  return ____exports
@@ -26,6 +26,8 @@ local trimPrefix = ____string.trimPrefix
26
26
  local ____utils = require("functions.utils")
27
27
  local erange = ____utils.erange
28
28
  local irange = ____utils.irange
29
+ local ____customStageConstants = require("features.customStage.customStageConstants")
30
+ local ISAACSCRIPT_CUSTOM_STAGE_GFX_PATH = ____customStageConstants.ISAACSCRIPT_CUSTOM_STAGE_GFX_PATH
29
31
  function getBackdropPNGPath(self, customStage, backdropKind, rng)
30
32
  local pathArray = customStage.backdrop[backdropKind]
31
33
  local path = getRandomArrayElement(nil, pathArray, rng)
@@ -44,7 +46,7 @@ function spawnWallEntity(self, customStage, rng, isExtraWall)
44
46
  )
45
47
  wallEffect:AddEntityFlags(EntityFlag.RENDER_WALL)
46
48
  local sprite = wallEffect:GetSprite()
47
- sprite:Load("gfx/isaacscript-custom-stage/wall-backdrop.anm2", false)
49
+ sprite:Load(ISAACSCRIPT_CUSTOM_STAGE_GFX_PATH .. "/wall-backdrop.anm2", false)
48
50
  local wallLayersArray = isExtraWall and ROOM_SHAPE_WALL_EXTRA_ANM2_LAYERS or ROOM_SHAPE_WALL_ANM2_LAYERS
49
51
  local numWallLayers = wallLayersArray[roomShape]
50
52
  if numWallLayers == nil then
@@ -89,7 +91,7 @@ function spawnFloorEntity(self, customStage, rng)
89
91
  )
90
92
  floorEffect:AddEntityFlags(EntityFlag.RENDER_FLOOR)
91
93
  local sprite = floorEffect:GetSprite()
92
- sprite:Load("gfx/isaacscript-custom-stage/floor-backdrop.anm2", false)
94
+ sprite:Load(ISAACSCRIPT_CUSTOM_STAGE_GFX_PATH .. "/floor-backdrop.anm2", false)
93
95
  local numFloorLayers = getNumFloorLayers(nil, roomShape)
94
96
  if numFloorLayers ~= nil then
95
97
  for ____, layerID in ipairs(erange(nil, 0, numFloorLayers)) do
@@ -0,0 +1 @@
1
+ export declare const ISAACSCRIPT_CUSTOM_STAGE_GFX_PATH = "gfx/isaacscript-custom-stage";
@@ -0,0 +1,3 @@
1
+ local ____exports = {}
2
+ ____exports.ISAACSCRIPT_CUSTOM_STAGE_GFX_PATH = "gfx/isaacscript-custom-stage"
3
+ return ____exports
@@ -1,3 +1,4 @@
1
+ import { EntityType } from "isaac-typescript-definitions";
1
2
  /**
2
3
  * Helper function to warp to a custom stage/level.
3
4
  *
@@ -6,3 +7,29 @@
6
7
  */
7
8
  export declare function setCustomStage(name: string, verbose?: boolean): void;
8
9
  export declare function setCustomStageDebug(): void;
10
+ /**
11
+ * By default, unknown bosses will be drawn on the boss "versus" screen as "???". If your custom
12
+ * stage has custom bosses, you can use this function to register the corresponding graphic file
13
+ * files for them.
14
+ *
15
+ * For reference:
16
+ * - The vanilla name sprite for Monstro is located at "C:\Program Files
17
+ * (x86)\Steam\steamapps\common\The Binding of Isaac
18
+ * Rebirth\resources\gfx\ui\boss\bossname_20.0_monstro.png".
19
+ * - The vanilla portrait sprite for Monstro is located at "C:\Program Files
20
+ * (x86)\Steam\steamapps\common\The Binding of Isaac
21
+ * Rebirth\resources\gfx\ui\boss\portrait_20.0_monstro.png".
22
+ *
23
+ * (Note that boss metadata like this cannot be specified with the rest of the custom stage metadata
24
+ * in the "tsconfig.json" file because there is not a way to retrieve the name of an entity at
25
+ * run-time.)
26
+ *
27
+ * @param entityType The entity type of the custom boss.
28
+ * @param variant The variant of the custom boss.
29
+ * @param subType The sub-type of the custom boss.
30
+ * @param namePNGPath The full path to the PNG file that contains the name of the boss that will be
31
+ * displayed on the top of the boss "versus" screen.
32
+ * @param portraitPNGPath The full path to the PNG file that contains the portrait of the boss that
33
+ * will be displayed on the right side of the boss "versus" screen.
34
+ */
35
+ export declare function registerCustomBoss(entityType: EntityType, variant: int, subType: int, namePNGPath: string, portraitPNGPath: string): void;
@@ -13,6 +13,8 @@ local ____cachedClasses = require("cachedClasses")
13
13
  local game = ____cachedClasses.game
14
14
  local ____reorderedCallbacks = require("callbacks.reorderedCallbacks")
15
15
  local reorderedCallbacksSetStage = ____reorderedCallbacks.reorderedCallbacksSetStage
16
+ local ____entity = require("functions.entity")
17
+ local getEntityIDFromConstituents = ____entity.getEntityIDFromConstituents
16
18
  local ____log = require("functions.log")
17
19
  local log = ____log.log
18
20
  local logError = ____log.logError
@@ -29,14 +31,15 @@ local getGotoCommand = ____stage.getGotoCommand
29
31
  local setStage = ____stage.setStage
30
32
  local ____runNextRoom = require("features.runNextRoom")
31
33
  local runNextRoom = ____runNextRoom.runNextRoom
32
- local ____boss = require("features.customStage.boss")
33
- local playBossRoomAnimation = ____boss.playBossRoomAnimation
34
34
  local ____util = require("features.customStage.util")
35
35
  local getRandomCustomStageRoom = ____util.getRandomCustomStageRoom
36
36
  local ____v = require("features.customStage.v")
37
37
  local v = ____v.default
38
+ local customBossPNGPaths = ____v.customBossPNGPaths
38
39
  local customStageCachedRoomData = ____v.customStageCachedRoomData
39
40
  local customStagesMap = ____v.customStagesMap
41
+ local ____versusScreen = require("features.customStage.versusScreen")
42
+ local playVersusScreenAnimation = ____versusScreen.playVersusScreenAnimation
40
43
  function postRoomTransition(self)
41
44
  movePlayersToCenter(nil)
42
45
  end
@@ -116,6 +119,33 @@ function ____exports.setCustomStageDebug(self)
116
119
  log("No custom stage is currently loaded.")
117
120
  return
118
121
  end
119
- playBossRoomAnimation(nil, true)
122
+ playVersusScreenAnimation(nil, customStage, true)
123
+ end
124
+ --- By default, unknown bosses will be drawn on the boss "versus" screen as "???". If your custom
125
+ -- stage has custom bosses, you can use this function to register the corresponding graphic file
126
+ -- files for them.
127
+ --
128
+ -- For reference:
129
+ -- - The vanilla name sprite for Monstro is located at "C:\Program Files
130
+ -- (x86)\Steam\steamapps\common\The Binding of Isaac
131
+ -- Rebirth\resources\gfx\ui\boss\bossname_20.0_monstro.png".
132
+ -- - The vanilla portrait sprite for Monstro is located at "C:\Program Files
133
+ -- (x86)\Steam\steamapps\common\The Binding of Isaac
134
+ -- Rebirth\resources\gfx\ui\boss\portrait_20.0_monstro.png".
135
+ --
136
+ -- (Note that boss metadata like this cannot be specified with the rest of the custom stage metadata
137
+ -- in the "tsconfig.json" file because there is not a way to retrieve the name of an entity at
138
+ -- run-time.)
139
+ --
140
+ -- @param entityType The entity type of the custom boss.
141
+ -- @param variant The variant of the custom boss.
142
+ -- @param subType The sub-type of the custom boss.
143
+ -- @param namePNGPath The full path to the PNG file that contains the name of the boss that will be
144
+ -- displayed on the top of the boss "versus" screen.
145
+ -- @param portraitPNGPath The full path to the PNG file that contains the portrait of the boss that
146
+ -- will be displayed on the right side of the boss "versus" screen.
147
+ function ____exports.registerCustomBoss(self, entityType, variant, subType, namePNGPath, portraitPNGPath)
148
+ local entityID = getEntityIDFromConstituents(nil, entityType, variant, subType)
149
+ customBossPNGPaths:set(entityID, {namePNGPath, portraitPNGPath})
120
150
  end
121
151
  return ____exports
@@ -14,18 +14,20 @@ local ____exports = require("features.saveDataManager.exports")
14
14
  local saveDataManager = ____exports.saveDataManager
15
15
  local ____backdrop = require("features.customStage.backdrop")
16
16
  local setBackdrop = ____backdrop.setBackdrop
17
- local ____boss = require("features.customStage.boss")
18
- local bossPostRender = ____boss.bossPostRender
19
- local playBossRoomAnimation = ____boss.playBossRoomAnimation
20
17
  local metadataJSON = require("features.customStage.metadata")
18
+ local ____streakText = require("features.customStage.streakText")
19
+ local streakTextPostRender = ____streakText.streakTextPostRender
21
20
  local ____v = require("features.customStage.v")
22
21
  local v = ____v.default
23
22
  local customStagesMap = ____v.customStagesMap
23
+ local ____versusScreen = require("features.customStage.versusScreen")
24
+ local playVersusScreenAnimation = ____versusScreen.playVersusScreenAnimation
25
+ local versusScreenPostRender = ____versusScreen.versusScreenPostRender
24
26
  function initRoomTypeMaps(self)
25
- local customStagesLua = metadataJSON
26
- if not isArray(nil, customStagesLua) then
27
+ if not isArray(nil, metadataJSON) then
27
28
  error("The IsaacScript standard library attempted to read the custom stage metadata from the \"metadata.lua\" file, but it was not an array.")
28
29
  end
30
+ local customStagesLua = metadataJSON
29
31
  for ____, customStageLua in ipairs(customStagesLua) do
30
32
  local roomTypeMap = getRoomTypeMap(nil, customStageLua)
31
33
  local customStage = __TS__ObjectAssign({}, customStageLua, {roomTypeMap = roomTypeMap})
@@ -58,7 +60,12 @@ function getRoomTypeMap(self, customStageLua)
58
60
  return roomTypeMap
59
61
  end
60
62
  function postRender(self)
61
- bossPostRender(nil)
63
+ local customStage = v.run.currentCustomStage
64
+ if customStage == nil then
65
+ return
66
+ end
67
+ streakTextPostRender(nil, customStage)
68
+ versusScreenPostRender(nil)
62
69
  end
63
70
  function postNewRoomReordered(self)
64
71
  local customStage = v.run.currentCustomStage
@@ -66,7 +73,7 @@ function postNewRoomReordered(self)
66
73
  return
67
74
  end
68
75
  setBackdrop(nil, customStage)
69
- playBossRoomAnimation(nil)
76
+ playVersusScreenAnimation(nil, customStage)
70
77
  end
71
78
  function ____exports.customStageInit(self, mod)
72
79
  saveDataManager(nil, "customStage", v)
@@ -0,0 +1,2 @@
1
+ import { CustomStage } from "../../interfaces/CustomStage";
2
+ export declare function streakTextPostRender(customStage: CustomStage): void;
@@ -0,0 +1,22 @@
1
+ local ____exports = {}
2
+ local ____cachedClasses = require("cachedClasses")
3
+ local fonts = ____cachedClasses.fonts
4
+ local ____constants = require("constants")
5
+ local KColorDefault = ____constants.KColorDefault
6
+ local ____ui = require("functions.ui")
7
+ local getScreenBottomCenterPos = ____ui.getScreenBottomCenterPos
8
+ local ____v = require("features.customStage.v")
9
+ local v = ____v.default
10
+ local STREAK_TEXT_BOTTOM_OFFSET = Vector(0, -60)
11
+ function ____exports.streakTextPostRender(self, customStage)
12
+ if not v.run.showingStreakText then
13
+ return
14
+ end
15
+ local font = fonts.upheaval
16
+ local length = font:GetStringWidthUTF8(customStage.name)
17
+ local bottomCenterPos = getScreenBottomCenterPos(nil)
18
+ local position = bottomCenterPos + STREAK_TEXT_BOTTOM_OFFSET
19
+ local adjustedX = position.X - length / 2
20
+ font:DrawString(customStage.name, adjustedX, position.Y, KColorDefault)
21
+ end
22
+ return ____exports
@@ -3,6 +3,7 @@ import { CustomStage } from "../../interfaces/CustomStage";
3
3
  declare const v: {
4
4
  run: {
5
5
  currentCustomStage: CustomStage | null;
6
+ showingStreakText: boolean;
6
7
  showingBossVersusScreen: boolean;
7
8
  };
8
9
  };
@@ -11,3 +12,5 @@ export default v;
11
12
  export declare const customStagesMap: Map<string, CustomStage>;
12
13
  /** Indexed by room variant. */
13
14
  export declare const customStageCachedRoomData: Map<number, Readonly<RoomConfig>>;
15
+ /** Indexed by entity ID. */
16
+ export declare const customBossPNGPaths: Map<string, [namePNGPath: string, portraitPNGPath: string]>;
@@ -2,10 +2,12 @@ local ____lualib = require("lualib_bundle")
2
2
  local Map = ____lualib.Map
3
3
  local __TS__New = ____lualib.__TS__New
4
4
  local ____exports = {}
5
- local v = {run = {currentCustomStage = nil, showingBossVersusScreen = false}}
5
+ local v = {run = {currentCustomStage = nil, showingStreakText = false, showingBossVersusScreen = false}}
6
6
  ____exports.default = v
7
7
  --- Indexed by custom stage name.
8
8
  ____exports.customStagesMap = __TS__New(Map)
9
9
  --- Indexed by room variant.
10
10
  ____exports.customStageCachedRoomData = __TS__New(Map)
11
+ --- Indexed by entity ID.
12
+ ____exports.customBossPNGPaths = __TS__New(Map)
11
13
  return ____exports
@@ -0,0 +1,3 @@
1
+ import { CustomStage } from "../../interfaces/CustomStage";
2
+ export declare function playVersusScreenAnimation(customStage: CustomStage, force?: boolean): void;
3
+ export declare function versusScreenPostRender(): void;
@@ -0,0 +1,193 @@
1
+ local ____lualib = require("lualib_bundle")
2
+ local Map = ____lualib.Map
3
+ local ____exports = {}
4
+ local getPlayerPNGPaths, getBossPNGPaths, DEFAULT_CHARACTER, PNG_PATH_PREFIX, PLAYER_PORTRAIT_PNG_PATH_PREFIX
5
+ local ____isaac_2Dtypescript_2Ddefinitions = require("isaac-typescript-definitions")
6
+ local BossID = ____isaac_2Dtypescript_2Ddefinitions.BossID
7
+ local PlayerType = ____isaac_2Dtypescript_2Ddefinitions.PlayerType
8
+ local RoomType = ____isaac_2Dtypescript_2Ddefinitions.RoomType
9
+ local SoundEffect = ____isaac_2Dtypescript_2Ddefinitions.SoundEffect
10
+ local StageID = ____isaac_2Dtypescript_2Ddefinitions.StageID
11
+ local ____cachedClasses = require("cachedClasses")
12
+ local game = ____cachedClasses.game
13
+ local sfxManager = ____cachedClasses.sfxManager
14
+ local ____array = require("functions.array")
15
+ local arrayRemove = ____array.arrayRemove
16
+ local ____boss = require("functions.boss")
17
+ local getBosses = ____boss.getBosses
18
+ local ____entity = require("functions.entity")
19
+ local getEntityID = ____entity.getEntityID
20
+ local ____utils = require("functions.utils")
21
+ local erange = ____utils.erange
22
+ local ____bossNamePNGFileNames = require("objects.bossNamePNGFileNames")
23
+ local BOSS_NAME_PNG_FILE_NAMES = ____bossNamePNGFileNames.BOSS_NAME_PNG_FILE_NAMES
24
+ local ____bossPortraitPNGFileNames = require("objects.bossPortraitPNGFileNames")
25
+ local BOSS_PORTRAIT_PNG_FILE_NAMES = ____bossPortraitPNGFileNames.BOSS_PORTRAIT_PNG_FILE_NAMES
26
+ local ____playerNamePNGFileNames = require("objects.playerNamePNGFileNames")
27
+ local PLAYER_NAME_PNG_FILE_NAMES = ____playerNamePNGFileNames.PLAYER_NAME_PNG_FILE_NAMES
28
+ local ____playerPortraitPNGFileNames = require("objects.playerPortraitPNGFileNames")
29
+ local PLAYER_PORTRAIT_PNG_FILE_NAMES = ____playerPortraitPNGFileNames.PLAYER_PORTRAIT_PNG_FILE_NAMES
30
+ local ____versusScreenBackgroundColors = require("objects.versusScreenBackgroundColors")
31
+ local VERSUS_SCREEN_BACKGROUND_COLORS = ____versusScreenBackgroundColors.VERSUS_SCREEN_BACKGROUND_COLORS
32
+ local ____versusScreenDirtSpotColors = require("objects.versusScreenDirtSpotColors")
33
+ local VERSUS_SCREEN_DIRT_SPOT_COLORS = ____versusScreenDirtSpotColors.VERSUS_SCREEN_DIRT_SPOT_COLORS
34
+ local ____pause = require("features.pause")
35
+ local pause = ____pause.pause
36
+ local unpause = ____pause.unpause
37
+ local ____customStageConstants = require("features.customStage.customStageConstants")
38
+ local ISAACSCRIPT_CUSTOM_STAGE_GFX_PATH = ____customStageConstants.ISAACSCRIPT_CUSTOM_STAGE_GFX_PATH
39
+ local ____v = require("features.customStage.v")
40
+ local v = ____v.default
41
+ local customBossPNGPaths = ____v.customBossPNGPaths
42
+ function getPlayerPNGPaths(self)
43
+ local player = Isaac.GetPlayer()
44
+ local character = player:GetPlayerType()
45
+ local playerNamePNGFileName = PLAYER_NAME_PNG_FILE_NAMES[character]
46
+ if playerNamePNGFileName == nil then
47
+ playerNamePNGFileName = PLAYER_NAME_PNG_FILE_NAMES[DEFAULT_CHARACTER]
48
+ end
49
+ local playerNamePNGPath = (PNG_PATH_PREFIX .. "/") .. tostring(playerNamePNGFileName)
50
+ local playerPortraitFileName = PLAYER_PORTRAIT_PNG_FILE_NAMES[character]
51
+ if playerNamePNGFileName == nil then
52
+ playerPortraitFileName = PLAYER_PORTRAIT_PNG_FILE_NAMES[DEFAULT_CHARACTER]
53
+ end
54
+ local playerPortraitPNGPath = (PLAYER_PORTRAIT_PNG_PATH_PREFIX .. "/") .. tostring(playerPortraitFileName)
55
+ return {playerNamePNGPath, playerPortraitPNGPath}
56
+ end
57
+ function getBossPNGPaths(self)
58
+ local bosses = getBosses(nil)
59
+ local firstBoss = bosses[1]
60
+ if firstBoss ~= nil then
61
+ local entityID = getEntityID(nil, firstBoss)
62
+ local pngPaths = customBossPNGPaths:get(entityID)
63
+ if pngPaths ~= nil then
64
+ return pngPaths
65
+ end
66
+ end
67
+ local bossID = firstBoss == nil and 0 or firstBoss:GetBossID()
68
+ if bossID == 0 then
69
+ local questionMarkSprite = (PNG_PATH_PREFIX .. "/") .. BOSS_NAME_PNG_FILE_NAMES[BossID.BLUE_BABY]
70
+ local bossNamePNGPath = questionMarkSprite
71
+ local bossPortraitPNGPath = questionMarkSprite
72
+ return {bossNamePNGPath, bossPortraitPNGPath}
73
+ end
74
+ local bossNamePNGFileName = BOSS_NAME_PNG_FILE_NAMES[bossID]
75
+ local bossNamePNGPath = (PNG_PATH_PREFIX .. "/") .. bossNamePNGFileName
76
+ local bossPortraitPNGFileName = BOSS_PORTRAIT_PNG_FILE_NAMES[bossID]
77
+ local bossPortraitPNGPath = (PNG_PATH_PREFIX .. "/") .. bossPortraitPNGFileName
78
+ return {bossNamePNGPath, bossPortraitPNGPath}
79
+ end
80
+ DEFAULT_CHARACTER = PlayerType.ISAAC
81
+ local DEFAULT_STAGE_ID = StageID.BASEMENT
82
+ local VERSUS_SCREEN_ANIMATION_NAME = "Scene"
83
+ --- The layers range from 0 to 13.
84
+ local NUM_VERSUS_SCREEN_ANM2_LAYERS = 14
85
+ local BACKGROUND_ANM2_LAYER = 0
86
+ local BOSS_DIRT_SPOT_ANM2_LAYER = 2
87
+ local PLAYER_DIRT_SPOT_ANM2_LAYER = 3
88
+ local BOSS_PORTRAIT_ANM2_LAYER = 4
89
+ local PLAYER_PORTRAIT_ANM2_LAYER = 5
90
+ local PLAYER_NAME_ANM2_LAYER = 6
91
+ local BOSS_NAME_ANM2_LAYER = 7
92
+ local OVERLAY_ANM2_LAYER = 11
93
+ --- We only need to render either the normal player portrait layer or the alternate player portrait
94
+ -- layer. Rendering both will cause the player not to shake.
95
+ local PLAYER_PORTRAIT_ALT_ANM2_LAYER = 12
96
+ --- These are the non-special layers that we will render last.
97
+ local OTHER_ANM2_LAYERS = arrayRemove(
98
+ nil,
99
+ erange(nil, NUM_VERSUS_SCREEN_ANM2_LAYERS),
100
+ BACKGROUND_ANM2_LAYER,
101
+ BOSS_DIRT_SPOT_ANM2_LAYER,
102
+ PLAYER_DIRT_SPOT_ANM2_LAYER,
103
+ OVERLAY_ANM2_LAYER,
104
+ PLAYER_PORTRAIT_ALT_ANM2_LAYER
105
+ )
106
+ PNG_PATH_PREFIX = "gfx/ui/boss"
107
+ PLAYER_PORTRAIT_PNG_PATH_PREFIX = "gfx/ui/stage"
108
+ local VANILLA_VERSUS_PLAYBACK_SPEED = 0.5
109
+ local versusScreenSprite = Sprite()
110
+ versusScreenSprite:Load("gfx/ui/boss/versusscreen.anm2", false)
111
+ versusScreenSprite:ReplaceSpritesheet(OVERLAY_ANM2_LAYER, ISAACSCRIPT_CUSTOM_STAGE_GFX_PATH .. "/overlay.png")
112
+ versusScreenSprite:LoadGraphics()
113
+ --- Unfortunately, we must split the background layer into an entirely different sprite so that we
114
+ -- can color it with the `Color` property.
115
+ local versusScreenBackgroundSprite = Sprite()
116
+ versusScreenBackgroundSprite:Load("gfx/ui/boss/versusscreen.anm2", true)
117
+ --- Unfortunately, we must split the dirt layer into an entirely different sprite so that we can
118
+ -- color it with the `Color` property.
119
+ local versusScreenDirtSpotSprite = Sprite()
120
+ versusScreenDirtSpotSprite:Load("gfx/ui/boss/versusscreen.anm2", true)
121
+ function ____exports.playVersusScreenAnimation(self, customStage, force)
122
+ if force == nil then
123
+ force = false
124
+ end
125
+ local room = game:GetRoom()
126
+ local roomType = room:GetType()
127
+ local hud = game:GetHUD()
128
+ if roomType ~= RoomType.BOSS and not force then
129
+ return
130
+ end
131
+ v.run.showingBossVersusScreen = true
132
+ pause(nil)
133
+ hud:SetVisible(false)
134
+ local playerNamePNGPath, playerPortraitPNGPath = table.unpack(getPlayerPNGPaths(nil))
135
+ versusScreenSprite:ReplaceSpritesheet(PLAYER_NAME_ANM2_LAYER, playerNamePNGPath)
136
+ versusScreenSprite:ReplaceSpritesheet(PLAYER_PORTRAIT_ANM2_LAYER, playerPortraitPNGPath)
137
+ local bossNamePNGPath, bossPortraitPNGPath = table.unpack(getBossPNGPaths(nil))
138
+ versusScreenSprite:ReplaceSpritesheet(BOSS_NAME_ANM2_LAYER, bossNamePNGPath)
139
+ versusScreenSprite:ReplaceSpritesheet(BOSS_PORTRAIT_ANM2_LAYER, bossPortraitPNGPath)
140
+ versusScreenSprite:LoadGraphics()
141
+ local backgroundColor = VERSUS_SCREEN_BACKGROUND_COLORS[DEFAULT_STAGE_ID]
142
+ if customStage.versusScreenBackgroundColor ~= nil then
143
+ local ____customStage_versusScreenBackgroundColor_0 = customStage.versusScreenBackgroundColor
144
+ local r = ____customStage_versusScreenBackgroundColor_0.r
145
+ local g = ____customStage_versusScreenBackgroundColor_0.g
146
+ local b = ____customStage_versusScreenBackgroundColor_0.b
147
+ backgroundColor = Color(r, g, b)
148
+ end
149
+ versusScreenBackgroundSprite.Color = backgroundColor
150
+ local dirtSpotColor = VERSUS_SCREEN_DIRT_SPOT_COLORS[DEFAULT_STAGE_ID]
151
+ if customStage.versusScreenDirtSpotColor ~= nil then
152
+ local ____customStage_versusScreenDirtSpotColor_1 = customStage.versusScreenDirtSpotColor
153
+ local r = ____customStage_versusScreenDirtSpotColor_1.r
154
+ local g = ____customStage_versusScreenDirtSpotColor_1.g
155
+ local b = ____customStage_versusScreenDirtSpotColor_1.b
156
+ dirtSpotColor = Color(r, g, b)
157
+ end
158
+ versusScreenDirtSpotSprite.Color = dirtSpotColor
159
+ for ____, sprite in ipairs({versusScreenBackgroundSprite, versusScreenDirtSpotSprite, versusScreenSprite}) do
160
+ sprite:Play(VERSUS_SCREEN_ANIMATION_NAME, true)
161
+ sprite.PlaybackSpeed = VANILLA_VERSUS_PLAYBACK_SPEED
162
+ end
163
+ end
164
+ local function finishVersusScreenAnimation(self)
165
+ local hud = game:GetHUD()
166
+ v.run.showingBossVersusScreen = false
167
+ unpause(nil)
168
+ hud:SetVisible(true)
169
+ sfxManager:Play(SoundEffect.CASTLE_PORTCULLIS)
170
+ end
171
+ function ____exports.versusScreenPostRender(self)
172
+ if not v.run.showingBossVersusScreen then
173
+ return
174
+ end
175
+ if versusScreenSprite:IsFinished(VERSUS_SCREEN_ANIMATION_NAME) then
176
+ finishVersusScreenAnimation(nil)
177
+ return
178
+ end
179
+ local room = game:GetRoom()
180
+ local centerPos = room:GetCenterPos()
181
+ local position = Isaac.WorldToRenderPosition(centerPos)
182
+ versusScreenBackgroundSprite:RenderLayer(BACKGROUND_ANM2_LAYER, position)
183
+ versusScreenBackgroundSprite:Update()
184
+ versusScreenSprite:RenderLayer(OVERLAY_ANM2_LAYER, position)
185
+ versusScreenDirtSpotSprite:RenderLayer(BOSS_DIRT_SPOT_ANM2_LAYER, position)
186
+ versusScreenDirtSpotSprite:RenderLayer(PLAYER_DIRT_SPOT_ANM2_LAYER, position)
187
+ versusScreenDirtSpotSprite:Update()
188
+ for ____, layerID in ipairs(OTHER_ANM2_LAYERS) do
189
+ versusScreenSprite:RenderLayer(layerID, position)
190
+ end
191
+ versusScreenSprite:Update()
192
+ end
193
+ return ____exports
@@ -28,6 +28,7 @@ local errorIfFeaturesNotInitialized = ____featuresInitialized.errorIfFeaturesNot
28
28
  local ____array = require("functions.array")
29
29
  local emptyArray = ____array.emptyArray
30
30
  local ____entity = require("functions.entity")
31
+ local getEntityIDFromConstituents = ____entity.getEntityIDFromConstituents
31
32
  local removeAllMatchingEntities = ____entity.removeAllMatchingEntities
32
33
  local spawn = ____entity.spawn
33
34
  local spawnWithSeed = ____entity.spawnWithSeed
@@ -39,6 +40,7 @@ local ____gridEntity = require("functions.gridEntity")
39
40
  local convertXMLGridEntityType = ____gridEntity.convertXMLGridEntityType
40
41
  local getAllGridIndexes = ____gridEntity.getAllGridIndexes
41
42
  local getGridEntities = ____gridEntity.getGridEntities
43
+ local getGridEntityIDFromConstituents = ____gridEntity.getGridEntityIDFromConstituents
42
44
  local removeAllGridExcept = ____gridEntity.removeAllGridExcept
43
45
  local removeGrid = ____gridEntity.removeGrid
44
46
  local setGridEntityInvisible = ____gridEntity.setGridEntityInvisible
@@ -239,7 +241,8 @@ function spawnAllEntities(self, jsonRoom, rng, verbose)
239
241
  end
240
242
  if entityType >= 1000 then
241
243
  if verbose then
242
- log(((((((("Spawning grid entity " .. tostring(entityType)) .. ".") .. tostring(variant)) .. " at: (") .. tostring(x)) .. ", ") .. tostring(y)) .. ")")
244
+ local gridEntityID = getGridEntityIDFromConstituents(nil, entityType, variant)
245
+ log(((((("Spawning grid entity " .. gridEntityID) .. " at: (") .. tostring(x)) .. ", ") .. tostring(y)) .. ")")
243
246
  end
244
247
  spawnGridEntityForJSONRoom(
245
248
  nil,
@@ -250,7 +253,8 @@ function spawnAllEntities(self, jsonRoom, rng, verbose)
250
253
  )
251
254
  else
252
255
  if verbose then
253
- log(((((((((("Spawning normal entity " .. tostring(entityType)) .. ".") .. tostring(variant)) .. ".") .. tostring(subType)) .. " at: (") .. tostring(x)) .. ", ") .. tostring(y)) .. ")")
256
+ local entityID = getEntityIDFromConstituents(nil, entityType, variant, subType)
257
+ log(((((("Spawning normal entity " .. entityID) .. " at: (") .. tostring(x)) .. ", ") .. tostring(y)) .. ")")
254
258
  end
255
259
  local entity = spawnNormalEntityForJSONRoom(
256
260
  nil,
@@ -11,8 +11,6 @@ local ____deepCopy = require("functions.deepCopy")
11
11
  local deepCopy = ____deepCopy.deepCopy
12
12
  local ____types = require("functions.types")
13
13
  local isString = ____types.isString
14
- local ____constants = require("features.saveDataManager.constants")
15
- local SAVE_DATA_MANAGER_FEATURE_NAME = ____constants.SAVE_DATA_MANAGER_FEATURE_NAME
16
14
  local ____main = require("features.saveDataManager.main")
17
15
  local forceSaveDataManagerLoad = ____main.forceSaveDataManagerLoad
18
16
  local forceSaveDataManagerSave = ____main.forceSaveDataManagerSave
@@ -21,6 +19,8 @@ local ____maps = require("features.saveDataManager.maps")
21
19
  local saveDataConditionalFuncMap = ____maps.saveDataConditionalFuncMap
22
20
  local saveDataDefaultsMap = ____maps.saveDataDefaultsMap
23
21
  local saveDataMap = ____maps.saveDataMap
22
+ local ____saveDataManagerConstants = require("features.saveDataManager.saveDataManagerConstants")
23
+ local SAVE_DATA_MANAGER_FEATURE_NAME = ____saveDataManagerConstants.SAVE_DATA_MANAGER_FEATURE_NAME
24
24
  --- This is the entry point to the save data manager, a system which provides two major features:
25
25
  --
26
26
  -- 1. automatic resetting of variables on a new run, on a new level, or on a new room (as desired)
@@ -12,11 +12,11 @@ local iterateTableInOrder = ____table.iterateTableInOrder
12
12
  local ____types = require("functions.types")
13
13
  local isString = ____types.isString
14
14
  local isTable = ____types.isTable
15
- local ____constants = require("features.saveDataManager.constants")
16
- local SAVE_DATA_MANAGER_DEBUG = ____constants.SAVE_DATA_MANAGER_DEBUG
17
- local SAVE_DATA_MANAGER_FEATURE_NAME = ____constants.SAVE_DATA_MANAGER_FEATURE_NAME
18
15
  local ____merge = require("features.saveDataManager.merge")
19
16
  local merge = ____merge.merge
17
+ local ____saveDataManagerConstants = require("features.saveDataManager.saveDataManagerConstants")
18
+ local SAVE_DATA_MANAGER_DEBUG = ____saveDataManagerConstants.SAVE_DATA_MANAGER_DEBUG
19
+ local SAVE_DATA_MANAGER_FEATURE_NAME = ____saveDataManagerConstants.SAVE_DATA_MANAGER_FEATURE_NAME
20
20
  function readSaveDatFile(self, mod)
21
21
  local renderFrameCount = Isaac.GetFrameCount()
22
22
  local ok, jsonStringOrErrMsg = pcall(tryLoadModData, mod)
@@ -21,9 +21,6 @@ local logError = ____log.logError
21
21
  local ____table = require("functions.table")
22
22
  local clearTable = ____table.clearTable
23
23
  local iterateTableInOrder = ____table.iterateTableInOrder
24
- local ____constants = require("features.saveDataManager.constants")
25
- local SAVE_DATA_MANAGER_DEBUG = ____constants.SAVE_DATA_MANAGER_DEBUG
26
- local SAVE_DATA_MANAGER_FEATURE_NAME = ____constants.SAVE_DATA_MANAGER_FEATURE_NAME
27
24
  local ____load = require("features.saveDataManager.load")
28
25
  local loadFromDisk = ____load.loadFromDisk
29
26
  local ____maps = require("features.saveDataManager.maps")
@@ -32,6 +29,9 @@ local saveDataDefaultsMap = ____maps.saveDataDefaultsMap
32
29
  local saveDataMap = ____maps.saveDataMap
33
30
  local ____save = require("features.saveDataManager.save")
34
31
  local saveToDisk = ____save.saveToDisk
32
+ local ____saveDataManagerConstants = require("features.saveDataManager.saveDataManagerConstants")
33
+ local SAVE_DATA_MANAGER_DEBUG = ____saveDataManagerConstants.SAVE_DATA_MANAGER_DEBUG
34
+ local SAVE_DATA_MANAGER_FEATURE_NAME = ____saveDataManagerConstants.SAVE_DATA_MANAGER_FEATURE_NAME
35
35
  function postPlayerInit(self)
36
36
  if mod == nil then
37
37
  error(("The mod for the " .. SAVE_DATA_MANAGER_FEATURE_NAME) .. " was not initialized.")
@@ -26,8 +26,8 @@ local ____types = require("functions.types")
26
26
  local isTable = ____types.isTable
27
27
  local ____utils = require("functions.utils")
28
28
  local getTraversalDescription = ____utils.getTraversalDescription
29
- local ____constants = require("features.saveDataManager.constants")
30
- local SAVE_DATA_MANAGER_DEBUG = ____constants.SAVE_DATA_MANAGER_DEBUG
29
+ local ____saveDataManagerConstants = require("features.saveDataManager.saveDataManagerConstants")
30
+ local SAVE_DATA_MANAGER_DEBUG = ____saveDataManagerConstants.SAVE_DATA_MANAGER_DEBUG
31
31
  local ____serializationBrand = require("features.saveDataManager.serializationBrand")
32
32
  local isSerializationBrand = ____serializationBrand.isSerializationBrand
33
33
  --- `merge` takes the values from a new table and recursively merges them into an old object (while