isaacscript-common 3.1.1 → 3.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 (51) hide show
  1. package/callbacks/customRevive.lua +3 -3
  2. package/callbacks/postGridEntity.lua +5 -3
  3. package/callbacks/postHolyMantleRemoved.lua +2 -2
  4. package/callbacks/postPlayerCollectible.d.ts +1 -0
  5. package/callbacks/postPlayerCollectible.lua +95 -0
  6. package/callbacks/postRoomClearChanged.lua +5 -3
  7. package/callbacks/postSlotInitUpdate.lua +5 -3
  8. package/callbacks/subscriptions/postPlayerCollectibleAdded.d.ts +6 -0
  9. package/callbacks/subscriptions/postPlayerCollectibleAdded.lua +34 -0
  10. package/callbacks/subscriptions/postPlayerCollectibleRemoved.d.ts +6 -0
  11. package/callbacks/subscriptions/postPlayerCollectibleRemoved.lua +34 -0
  12. package/classes/DefaultMap.d.ts +1 -2
  13. package/classes/DefaultMap.lua +1 -4
  14. package/constants.d.ts +5 -0
  15. package/constants.lua +5 -0
  16. package/enums/ModCallbackCustom.d.ts +427 -177
  17. package/enums/ModCallbackCustom.lua +36 -32
  18. package/features/deployJSONRoom.lua +5 -4
  19. package/features/extraConsoleCommands/listCommands.lua +1 -0
  20. package/features/persistentEntities.d.ts +28 -0
  21. package/features/persistentEntities.lua +150 -0
  22. package/features/playerInventory.d.ts +1 -10
  23. package/features/playerInventory.lua +23 -60
  24. package/functions/array.d.ts +3 -3
  25. package/functions/array.lua +3 -3
  26. package/functions/collectibleSet.d.ts +3 -3
  27. package/functions/collectibleSet.lua +3 -5
  28. package/functions/color.d.ts +2 -16
  29. package/functions/color.lua +0 -9
  30. package/functions/entity.d.ts +10 -0
  31. package/functions/entity.lua +29 -0
  32. package/functions/log.lua +2 -2
  33. package/functions/pills.d.ts +10 -0
  34. package/functions/pills.lua +16 -0
  35. package/functions/roomData.d.ts +5 -5
  36. package/functions/roomData.lua +7 -7
  37. package/functions/rooms.d.ts +1 -4
  38. package/functions/rooms.lua +19 -25
  39. package/functions/saveFile.d.ts +15 -0
  40. package/functions/saveFile.lua +105 -0
  41. package/index.d.ts +3 -1
  42. package/index.lua +15 -2
  43. package/initCustomCallbacks.lua +3 -0
  44. package/initFeatures.lua +3 -0
  45. package/interfaces/AddCallbackParameterCustom.d.ts +4 -0
  46. package/maps/PHDPillConversions.d.ts +2 -0
  47. package/maps/PHDPillConversions.lua +25 -0
  48. package/maps/falsePHDPillConversions.d.ts +2 -0
  49. package/maps/falsePHDPillConversions.lua +39 -0
  50. package/objects/callbackRegisterFunctions.lua +6 -0
  51. package/package.json +2 -2
@@ -14,8 +14,6 @@ local tableHasKeys = ____table.tableHasKeys
14
14
  local ____utils = require("functions.utils")
15
15
  local ensureAllCases = ____utils.ensureAllCases
16
16
  --- Helper function to check if something is an instantiated Color object.
17
- --
18
- -- @category color
19
17
  function ____exports.isColor(self, object)
20
18
  return isIsaacAPIClassOfType(nil, object, OBJECT_NAME)
21
19
  end
@@ -29,8 +27,6 @@ local KEYS = {
29
27
  "BO"
30
28
  }
31
29
  OBJECT_NAME = "Color"
32
- ---
33
- -- @category color
34
30
  function ____exports.colorEquals(self, color1, color2)
35
31
  return isaacAPIClassEquals(nil, color1, color2, KEYS)
36
32
  end
@@ -39,7 +35,6 @@ end
39
35
  -- @param color The Color object to copy. In the case of deserialization, this will actually be a
40
36
  -- Lua table instead of an instantiated Color class.
41
37
  -- @param serializationType Default is `SerializationType.NONE`.
42
- -- @category color
43
38
  function ____exports.copyColor(self, color, serializationType)
44
39
  if serializationType == nil then
45
40
  serializationType = SerializationType.NONE
@@ -116,15 +111,11 @@ function ____exports.copyColor(self, color, serializationType)
116
111
  until true
117
112
  end
118
113
  --- Returns `Color(1, 1, 1)`.
119
- --
120
- -- @category color
121
114
  function ____exports.getDefaultColor(self)
122
115
  return Color(1, 1, 1)
123
116
  end
124
117
  --- Used to determine is the given table is a serialized `Color` object created by the save data
125
118
  -- manager and/or the `deepCopy` function.
126
- --
127
- -- @category color
128
119
  function ____exports.isSerializedColor(self, object)
129
120
  local objectType = type(object)
130
121
  if objectType ~= "table" then
@@ -11,6 +11,16 @@ import { AnyEntity } from "../types/AnyEntity";
11
11
  * @param ignoreFriendly Default is false.
12
12
  */
13
13
  export declare function countEntities(entityType?: EntityType, variant?: number, subType?: number, ignoreFriendly?: boolean): int;
14
+ /**
15
+ * Helper function to check if one or more of a specific kind of entity is present in the current
16
+ * room. It uses the `countEntities` helper function to determine this.
17
+ *
18
+ * @param entityType Default is -1. -1 matches every entity type.
19
+ * @param variant Default is -1. -1 matches every variant.
20
+ * @param subType Default is -1. -1 matches every sub-type.
21
+ * @param ignoreFriendly Default is false.
22
+ */
23
+ export declare function doesEntityExist(entityType?: EntityType, variant?: number, subType?: number, ignoreFriendly?: boolean): boolean;
14
24
  /**
15
25
  * Given an array of entities, this helper function returns the closest one to a provided reference
16
26
  * entity.
@@ -66,6 +66,35 @@ function ____exports.countEntities(self, entityType, variant, subType, ignoreFri
66
66
  )
67
67
  return #entities
68
68
  end
69
+ --- Helper function to check if one or more of a specific kind of entity is present in the current
70
+ -- room. It uses the `countEntities` helper function to determine this.
71
+ --
72
+ -- @param entityType Default is -1. -1 matches every entity type.
73
+ -- @param variant Default is -1. -1 matches every variant.
74
+ -- @param subType Default is -1. -1 matches every sub-type.
75
+ -- @param ignoreFriendly Default is false.
76
+ function ____exports.doesEntityExist(self, entityType, variant, subType, ignoreFriendly)
77
+ if entityType == nil then
78
+ entityType = -1
79
+ end
80
+ if variant == nil then
81
+ variant = -1
82
+ end
83
+ if subType == nil then
84
+ subType = -1
85
+ end
86
+ if ignoreFriendly == nil then
87
+ ignoreFriendly = false
88
+ end
89
+ local count = ____exports.countEntities(
90
+ nil,
91
+ entityType,
92
+ variant,
93
+ subType,
94
+ ignoreFriendly
95
+ )
96
+ return count > 0
97
+ end
69
98
  --- Given an array of entities, this helper function returns the closest one to a provided reference
70
99
  -- entity.
71
100
  --
package/functions/log.lua CHANGED
@@ -229,7 +229,7 @@ function ____exports.logEntities(includeBackgroundEffects, entityTypeFilter)
229
229
  if numMatchedEntities == 0 then
230
230
  msg = msg .. "(no entities matched)\n"
231
231
  else
232
- msg = msg .. ("(" .. tostring(numMatchedEntities)) .. " total entities)\n"
232
+ msg = msg .. ((("(" .. tostring(numMatchedEntities)) .. " total ") .. (numMatchedEntities == 1 and "entity" or "entities")) .. ")\n"
233
233
  end
234
234
  ____exports.log(msg)
235
235
  end
@@ -336,7 +336,7 @@ function ____exports.logGridEntities(includeWalls, gridEntityTypeFilter)
336
336
  if numMatchedEntities == 0 then
337
337
  msg = msg .. "(no grid entities matched)\n"
338
338
  else
339
- msg = msg .. ("(" .. tostring(numMatchedEntities)) .. " total grid entities)\n"
339
+ msg = msg .. ((("(" .. tostring(numMatchedEntities)) .. " total grid ") .. (numMatchedEntities == 1 and "entity" or "entities")) .. ")\n"
340
340
  end
341
341
  ____exports.log(msg)
342
342
  end
@@ -8,6 +8,11 @@ export declare function getAllPillColors(): PillColor[];
8
8
  * Helper function to get an array with every valid pill effect. This includes modded pill effects.
9
9
  */
10
10
  export declare function getAllPillEffects(): PillEffect[];
11
+ /**
12
+ * Helper function to get the associated pill effect after False PHD is acquired. If a pill effect
13
+ * is not altered by False PHD, then the same pill effect will be returned.
14
+ */
15
+ export declare function getFalsePHDPillEffect(pillEffect: PillEffect): PillEffect;
11
16
  /**
12
17
  * Helper function to get the corresponding horse pill color from a normal pill color.
13
18
  *
@@ -33,6 +38,11 @@ export declare function getModdedPillEffects(): PillEffect[];
33
38
  export declare function getNormalPillColorFromHorse(pillColor: PillColor): PillColor;
34
39
  /** Helper function to get an array with every non-gold and non-horse pill color. */
35
40
  export declare function getNormalPillColors(): PillColor[];
41
+ /**
42
+ * Helper function to get the associated pill effect after PHD is acquired. If a pill effect is not
43
+ * altered by PHD, then the same pill effect will be returned.
44
+ */
45
+ export declare function getPHDPillEffect(pillEffect: PillEffect): PillEffect;
36
46
  /**
37
47
  * Helper function to get a pill effect class from a PillEffect enum value. In this context, the
38
48
  * class is equal to the numerical prefix in the "class" tag in the "pocketitems.xml" file. Use the
@@ -14,6 +14,10 @@ local LAST_HORSE_PILL_COLOR = ____constantsFirstLast.LAST_HORSE_PILL_COLOR
14
14
  local LAST_NORMAL_PILL_COLOR = ____constantsFirstLast.LAST_NORMAL_PILL_COLOR
15
15
  local LAST_PILL_EFFECT = ____constantsFirstLast.LAST_PILL_EFFECT
16
16
  local LAST_VANILLA_PILL_EFFECT = ____constantsFirstLast.LAST_VANILLA_PILL_EFFECT
17
+ local ____falsePHDPillConversions = require("maps.falsePHDPillConversions")
18
+ local FALSE_PHD_PILL_CONVERSIONS = ____falsePHDPillConversions.FALSE_PHD_PILL_CONVERSIONS
19
+ local ____PHDPillConversions = require("maps.PHDPillConversions")
20
+ local PHD_PILL_CONVERSIONS = ____PHDPillConversions.PHD_PILL_CONVERSIONS
17
21
  local ____pillEffectClasses = require("objects.pillEffectClasses")
18
22
  local DEFAULT_PILL_EFFECT_CLASS = ____pillEffectClasses.DEFAULT_PILL_EFFECT_CLASS
19
23
  local PILL_EFFECT_CLASSES = ____pillEffectClasses.PILL_EFFECT_CLASSES
@@ -44,6 +48,12 @@ end
44
48
  function ____exports.getAllPillEffects(self)
45
49
  return irange(nil, FIRST_PILL_EFFECT, LAST_PILL_EFFECT)
46
50
  end
51
+ --- Helper function to get the associated pill effect after False PHD is acquired. If a pill effect
52
+ -- is not altered by False PHD, then the same pill effect will be returned.
53
+ function ____exports.getFalsePHDPillEffect(self, pillEffect)
54
+ local convertedPillEffect = FALSE_PHD_PILL_CONVERSIONS:get(pillEffect)
55
+ return convertedPillEffect == nil and pillEffect or convertedPillEffect
56
+ end
47
57
  --- Helper function to get the corresponding horse pill color from a normal pill color.
48
58
  --
49
59
  -- For example, passing `PillColor.BLUE_BLUE` would result in 2049, which is the value that
@@ -77,6 +87,12 @@ end
77
87
  function ____exports.getNormalPillColors(self)
78
88
  return irange(nil, FIRST_PILL_COLOR, LAST_NORMAL_PILL_COLOR)
79
89
  end
90
+ --- Helper function to get the associated pill effect after PHD is acquired. If a pill effect is not
91
+ -- altered by PHD, then the same pill effect will be returned.
92
+ function ____exports.getPHDPillEffect(self, pillEffect)
93
+ local convertedPillEffect = PHD_PILL_CONVERSIONS:get(pillEffect)
94
+ return convertedPillEffect == nil and pillEffect or convertedPillEffect
95
+ end
80
96
  --- Helper function to get a pill effect class from a PillEffect enum value. In this context, the
81
97
  -- class is equal to the numerical prefix in the "class" tag in the "pocketitems.xml" file. Use the
82
98
  -- `getPillEffectType` helper function to determine whether or not the pill effect is positive,
@@ -1,9 +1,4 @@
1
1
  import { DoorSlot, RoomShape, RoomType, StageID } from "isaac-typescript-definitions";
2
- /**
3
- * Alias for the `Level.GetCurrentRoomDesc` method. Use this to make it more clear what type of
4
- * `RoomDescriptor` object that you are retrieving.
5
- */
6
- export declare function getCurrentRoomDescriptorReadOnly(): ReadonlyRoomDescriptor;
7
2
  /**
8
3
  * Helper function to get the set of allowed door slots for the room at the supplied grid index.
9
4
  * This corresponds to the doors that are enabled in the STB/XML file for the room.
@@ -21,6 +16,11 @@ export declare function getRoomData(roomGridIndex?: int): RoomConfig | undefined
21
16
  * @param roomGridIndex Optional. Default is the current room index.
22
17
  */
23
18
  export declare function getRoomDescriptor(roomGridIndex?: int): RoomDescriptor;
19
+ /**
20
+ * Alias for the `Level.GetCurrentRoomDesc` method. Use this to make it more clear what type of
21
+ * `RoomDescriptor` object that you are retrieving.
22
+ */
23
+ export declare function getRoomDescriptorReadOnly(): ReadonlyRoomDescriptor;
24
24
  /**
25
25
  * Helper function to get the grid index of the current room.
26
26
  *
@@ -12,12 +12,6 @@ local ____enums = require("functions.enums")
12
12
  local getEnumValues = ____enums.getEnumValues
13
13
  local ____flag = require("functions.flag")
14
14
  local hasFlag = ____flag.hasFlag
15
- --- Alias for the `Level.GetCurrentRoomDesc` method. Use this to make it more clear what type of
16
- -- `RoomDescriptor` object that you are retrieving.
17
- function ____exports.getCurrentRoomDescriptorReadOnly(self)
18
- local level = game:GetLevel()
19
- return level:GetCurrentRoomDesc()
20
- end
21
15
  --- Helper function to get the room data for the provided room.
22
16
  --
23
17
  -- @param roomGridIndex Optional. Default is the current room index.
@@ -35,6 +29,12 @@ function ____exports.getRoomDescriptor(self, roomGridIndex)
35
29
  end
36
30
  return level:GetRoomByIdx(roomGridIndex)
37
31
  end
32
+ --- Alias for the `Level.GetCurrentRoomDesc` method. Use this to make it more clear what type of
33
+ -- `RoomDescriptor` object that you are retrieving.
34
+ function ____exports.getRoomDescriptorReadOnly(self)
35
+ local level = game:GetLevel()
36
+ return level:GetCurrentRoomDesc()
37
+ end
38
38
  --- Helper function to get the grid index of the current room.
39
39
  --
40
40
  -- - If the current room is inside of the grid, this function will return the `SafeGridIndex` from
@@ -55,7 +55,7 @@ function ____exports.getRoomGridIndex(self)
55
55
  if currentRoomIndex < 0 then
56
56
  return currentRoomIndex
57
57
  end
58
- local roomDescriptor = ____exports.getCurrentRoomDescriptorReadOnly(nil)
58
+ local roomDescriptor = ____exports.getRoomDescriptorReadOnly(nil)
59
59
  return roomDescriptor.SafeGridIndex
60
60
  end
61
61
  --- Helper function to get the set of allowed door slots for the room at the supplied grid index.
@@ -13,11 +13,8 @@ export declare function getAllRoomGridIndexes(): int[];
13
13
  /**
14
14
  * Helper function to get the current dimension. Most of the time, this will be `Dimension.MAIN`,
15
15
  * but it can change if e.g. the player is in the mirror world of Downpour/Dross.
16
- *
17
- * Note that this function correctly handles detecting the Death Certificate dimension, which is
18
- * tricky to properly detect.
19
16
  */
20
- export declare function getCurrentDimension(): Dimension;
17
+ export declare function getDimension(): Dimension;
21
18
  /**
22
19
  * Helper function to get the number of rooms that are currently on the floor layout. This does not
23
20
  * include off-grid rooms, like the Devil Room.
@@ -51,10 +51,10 @@ local getEntityVelocities = ____positionVelocity.getEntityVelocities
51
51
  local setEntityPositions = ____positionVelocity.setEntityPositions
52
52
  local setEntityVelocities = ____positionVelocity.setEntityVelocities
53
53
  local ____roomData = require("functions.roomData")
54
- local getCurrentRoomDescriptorReadOnly = ____roomData.getCurrentRoomDescriptorReadOnly
55
54
  local getRoomAllowedDoors = ____roomData.getRoomAllowedDoors
56
55
  local getRoomData = ____roomData.getRoomData
57
56
  local getRoomDescriptor = ____roomData.getRoomDescriptor
57
+ local getRoomDescriptorReadOnly = ____roomData.getRoomDescriptorReadOnly
58
58
  local getRoomGridIndex = ____roomData.getRoomGridIndex
59
59
  local getRoomName = ____roomData.getRoomName
60
60
  local getRoomShape = ____roomData.getRoomShape
@@ -103,13 +103,6 @@ function ____exports.getRooms(self, includeExtraDimensionalRooms)
103
103
  end
104
104
  return {__TS__Spread(roomsMap:values())}
105
105
  end
106
- --- We cannot use the standard code in the `inDimension` function for this purpose since it is bugged
107
- -- with the Death Certificate area.
108
- function ____exports.inDeathCertificateArea(self)
109
- local roomStageID = getRoomStageID(nil)
110
- local roomSubType = getRoomSubType(nil)
111
- return roomStageID == StageID.HOME and (roomSubType == HomeRoomSubType.DEATH_CERTIFICATE_ENTRANCE or roomSubType == HomeRoomSubType.DEATH_CERTIFICATE_ITEMS)
112
- end
113
106
  --- Helper function to check if a room exists at the given room grid index.
114
107
  function ____exports.roomExists(self, roomGridIndex)
115
108
  local roomData = getRoomData(nil, roomGridIndex)
@@ -140,25 +133,19 @@ function ____exports.getAllRoomGridIndexes(self)
140
133
  end
141
134
  --- Helper function to get the current dimension. Most of the time, this will be `Dimension.MAIN`,
142
135
  -- but it can change if e.g. the player is in the mirror world of Downpour/Dross.
143
- --
144
- -- Note that this function correctly handles detecting the Death Certificate dimension, which is
145
- -- tricky to properly detect.
146
- function ____exports.getCurrentDimension(self)
136
+ function ____exports.getDimension(self)
147
137
  local level = game:GetLevel()
148
- if ____exports.inDeathCertificateArea(nil) then
149
- return Dimension.DEATH_CERTIFICATE
150
- end
151
- local startingRoomGridIndex = level:GetStartingRoomIndex()
152
- local startingRoomDescription = level:GetRoomByIdx(startingRoomGridIndex, Dimension.CURRENT)
153
- local startingRoomHash = GetPtrHash(startingRoomDescription)
138
+ local roomGridIndex = getRoomGridIndex(nil)
139
+ local roomDescription = level:GetRoomByIdx(roomGridIndex, Dimension.CURRENT)
140
+ local currentRoomHash = GetPtrHash(roomDescription)
154
141
  for ____, dimension in ipairs(____exports.getAllDimensions(nil)) do
155
- local dimensionRoomDescription = level:GetRoomByIdx(startingRoomGridIndex, dimension)
142
+ local dimensionRoomDescription = level:GetRoomByIdx(roomGridIndex, dimension)
156
143
  local dimensionRoomHash = GetPtrHash(dimensionRoomDescription)
157
- if dimensionRoomHash == startingRoomHash then
144
+ if dimensionRoomHash == currentRoomHash then
158
145
  return dimension
159
146
  end
160
147
  end
161
- return error("Failed to get the current dimension using the starting room index of: " .. tostring(startingRoomGridIndex))
148
+ return error("Failed to get the current dimension.")
162
149
  end
163
150
  --- Helper function to get the number of rooms that are currently on the floor layout. This does not
164
151
  -- include off-grid rooms, like the Devil Room.
@@ -277,15 +264,22 @@ function ____exports.inCrawlspace(self)
277
264
  local roomSubType = getRoomSubType(nil)
278
265
  return roomType == RoomType.DUNGEON and roomSubType == DungeonSubType.NORMAL
279
266
  end
267
+ --- We cannot use the standard code in the `inDimension` function for this purpose since it is bugged
268
+ -- with the Death Certificate area.
269
+ function ____exports.inDeathCertificateArea(self)
270
+ local roomStageID = getRoomStageID(nil)
271
+ local roomSubType = getRoomSubType(nil)
272
+ return roomStageID == StageID.HOME and (roomSubType == HomeRoomSubType.DEATH_CERTIFICATE_ENTRANCE or roomSubType == HomeRoomSubType.DEATH_CERTIFICATE_ITEMS)
273
+ end
280
274
  --- Helper function to detect if the current room is a Treasure Room created when entering with a
281
275
  -- Devil's Crown trinket. Under the hood, this checks for the `RoomDescriptorFlag.DEVIL_TREASURE`
282
276
  -- flag.
283
277
  function ____exports.inDevilsCrownTreasureRoom(self)
284
- local roomDescriptor = getCurrentRoomDescriptorReadOnly(nil)
278
+ local roomDescriptor = getRoomDescriptorReadOnly(nil)
285
279
  return hasFlag(nil, roomDescriptor.Flags, RoomDescriptorFlag.DEVIL_TREASURE)
286
280
  end
287
281
  function ____exports.inDimension(self, dimension)
288
- return dimension == ____exports.getCurrentDimension(nil)
282
+ return dimension == ____exports.getDimension(nil)
289
283
  end
290
284
  function ____exports.inDoubleTrouble(self)
291
285
  local room = game:GetRoom()
@@ -438,12 +432,12 @@ function ____exports.setRoomCleared(self)
438
432
  for ____, door in ipairs(getDoors(nil)) do
439
433
  do
440
434
  if isHiddenSecretRoomDoor(nil, door) then
441
- goto __continue68
435
+ goto __continue67
442
436
  end
443
437
  openDoorFast(nil, door)
444
438
  door.ExtraVisible = false
445
439
  end
446
- ::__continue68::
440
+ ::__continue67::
447
441
  end
448
442
  sfxManager:Stop(SoundEffect.DOOR_HEAVY_OPEN)
449
443
  game:ShakeScreen(0)
@@ -0,0 +1,15 @@
1
+ import { CollectibleType, ItemPoolType } from "isaac-typescript-definitions";
2
+ /**
3
+ * Helper function to see if the given collectible is unlocked on the player's save file. This
4
+ * requires providing the corresponding item pool that the collectible is located in.
5
+ *
6
+ * - If any player currently has the item, then it is assumed to be unlocked. (This is because Eden
7
+ * may have randomly started with the provided collectible, and it will be subsequently removed
8
+ * from all pools.)
9
+ * - If the collectible is located in more than one item pool, then any item pool can be provided.
10
+ * - If the collectible is not located in any item pools, then this function will always return
11
+ * false.
12
+ * - If any player is Tainted Lost, they will be temporarily changed to Isaac and then temporarily
13
+ * changed back (because Tainted Lost is not able to retrieve some collectibles from item pools).
14
+ */
15
+ export declare function isCollectibleUnlocked(collectibleTypeToCheckFor: CollectibleType, itemPoolToCheckFor: ItemPoolType): boolean;
@@ -0,0 +1,105 @@
1
+ local ____lualib = require("lualib_bundle")
2
+ local Map = ____lualib.Map
3
+ local __TS__New = ____lualib.__TS__New
4
+ local __TS__Iterator = ____lualib.__TS__Iterator
5
+ local ____exports = {}
6
+ local ____isaac_2Dtypescript_2Ddefinitions = require("isaac-typescript-definitions")
7
+ local CollectibleType = ____isaac_2Dtypescript_2Ddefinitions.CollectibleType
8
+ local PlayerType = ____isaac_2Dtypescript_2Ddefinitions.PlayerType
9
+ local TrinketType = ____isaac_2Dtypescript_2Ddefinitions.TrinketType
10
+ local ____cachedClasses = require("cachedClasses")
11
+ local game = ____cachedClasses.game
12
+ local ____collectibleSet = require("functions.collectibleSet")
13
+ local getCollectibleSet = ____collectibleSet.getCollectibleSet
14
+ local ____player = require("functions.player")
15
+ local anyPlayerHasCollectible = ____player.anyPlayerHasCollectible
16
+ local getPlayersOfType = ____player.getPlayersOfType
17
+ local ____playerDataStructures = require("functions.playerDataStructures")
18
+ local mapGetPlayer = ____playerDataStructures.mapGetPlayer
19
+ local mapSetPlayer = ____playerDataStructures.mapSetPlayer
20
+ local ____playerIndex = require("functions.playerIndex")
21
+ local getPlayers = ____playerIndex.getPlayers
22
+ local ____utils = require("functions.utils")
23
+ local ____repeat = ____utils["repeat"]
24
+ local COLLECTIBLES_THAT_AFFECT_ITEM_POOLS = {CollectibleType.CHAOS, CollectibleType.SACRED_ORB, CollectibleType.TMTRAINER}
25
+ local TRINKETS_THAT_AFFECT_ITEM_POOLS = {TrinketType.NO}
26
+ --- Helper function to see if the given collectible is unlocked on the player's save file. This
27
+ -- requires providing the corresponding item pool that the collectible is located in.
28
+ --
29
+ -- - If any player currently has the item, then it is assumed to be unlocked. (This is because Eden
30
+ -- may have randomly started with the provided collectible, and it will be subsequently removed
31
+ -- from all pools.)
32
+ -- - If the collectible is located in more than one item pool, then any item pool can be provided.
33
+ -- - If the collectible is not located in any item pools, then this function will always return
34
+ -- false.
35
+ -- - If any player is Tainted Lost, they will be temporarily changed to Isaac and then temporarily
36
+ -- changed back (because Tainted Lost is not able to retrieve some collectibles from item pools).
37
+ function ____exports.isCollectibleUnlocked(self, collectibleTypeToCheckFor, itemPoolToCheckFor)
38
+ if anyPlayerHasCollectible(nil, collectibleTypeToCheckFor) then
39
+ return true
40
+ end
41
+ local taintedLosts = getPlayersOfType(nil, PlayerType.THE_LOST_B)
42
+ for ____, player in ipairs(taintedLosts) do
43
+ player:ChangePlayerType(PlayerType.ISAAC)
44
+ end
45
+ local removedItemsMap = __TS__New(Map)
46
+ local removedTrinketsMap = __TS__New(Map)
47
+ for ____, player in ipairs(getPlayers(nil)) do
48
+ local removedItems = {}
49
+ for ____, itemToRemove in ipairs(COLLECTIBLES_THAT_AFFECT_ITEM_POOLS) do
50
+ if player:HasCollectible(itemToRemove) then
51
+ local numCollectibles = player:GetCollectibleNum(itemToRemove)
52
+ ____repeat(
53
+ nil,
54
+ numCollectibles,
55
+ function()
56
+ player:RemoveCollectible(itemToRemove)
57
+ removedItems[#removedItems + 1] = itemToRemove
58
+ end
59
+ )
60
+ end
61
+ end
62
+ mapSetPlayer(nil, removedItemsMap, player, removedItems)
63
+ local removedTrinkets = {}
64
+ for ____, trinketToRemove in ipairs(TRINKETS_THAT_AFFECT_ITEM_POOLS) do
65
+ if player:HasTrinket(trinketToRemove) then
66
+ local numTrinkets = player:GetTrinketMultiplier(trinketToRemove)
67
+ ____repeat(
68
+ nil,
69
+ numTrinkets,
70
+ function()
71
+ player:TryRemoveTrinket(trinketToRemove)
72
+ removedTrinkets[#removedTrinkets + 1] = trinketToRemove
73
+ end
74
+ )
75
+ end
76
+ end
77
+ mapSetPlayer(nil, removedTrinketsMap, player, removedTrinkets)
78
+ end
79
+ local itemPool = game:GetItemPool()
80
+ local collectibleSet = getCollectibleSet(nil)
81
+ for ____, collectibleType in __TS__Iterator(collectibleSet:values()) do
82
+ if collectibleType ~= collectibleTypeToCheckFor then
83
+ itemPool:AddRoomBlacklist(collectibleType)
84
+ end
85
+ end
86
+ local retrievedCollectibleType = itemPool:GetCollectible(itemPoolToCheckFor, false, 1)
87
+ local collectibleUnlocked = retrievedCollectibleType == collectibleTypeToCheckFor
88
+ itemPool:ResetRoomBlacklist()
89
+ for ____, player in ipairs(getPlayers(nil)) do
90
+ local removedItems = mapGetPlayer(nil, removedItemsMap, player)
91
+ if removedItems ~= nil then
92
+ for ____, collectibleType in ipairs(removedItems) do
93
+ player:AddCollectible(collectibleType, 0, false)
94
+ end
95
+ end
96
+ local removedTrinkets = mapGetPlayer(nil, removedTrinketsMap, player)
97
+ if removedTrinkets ~= nil then
98
+ for ____, trinketType in ipairs(removedTrinkets) do
99
+ player:AddTrinket(trinketType, false)
100
+ end
101
+ end
102
+ end
103
+ return collectibleUnlocked
104
+ end
105
+ return ____exports
package/index.d.ts CHANGED
@@ -20,7 +20,8 @@ export { removeFadeIn, restoreFadeIn } from "./features/fadeInRemover";
20
20
  export { disableFastReset, enableFastReset } from "./features/fastReset";
21
21
  export { forgottenSwitch } from "./features/forgottenSwitch";
22
22
  export { getCollectibleItemPoolType } from "./features/getCollectibleItemPoolType";
23
- export { addCollectible, getPlayerInventory } from "./features/playerInventory";
23
+ export { removePersistentEntity, spawnPersistentEntity, } from "./features/persistentEntities";
24
+ export { getPlayerInventory } from "./features/playerInventory";
24
25
  export * from "./features/ponyDetection";
25
26
  export { preventCollectibleRotation } from "./features/preventCollectibleRotation";
26
27
  export { runInNGameFrames, runInNRenderFrames, runNextGameFrame, runNextRenderFrame, } from "./features/runInNFrames";
@@ -89,6 +90,7 @@ export * from "./functions/roomGrid";
89
90
  export * from "./functions/rooms";
90
91
  export * from "./functions/roomShape";
91
92
  export * from "./functions/run";
93
+ export * from "./functions/saveFile";
92
94
  export * from "./functions/seeds";
93
95
  export * from "./functions/serialization";
94
96
  export * from "./functions/set";
package/index.lua CHANGED
@@ -167,11 +167,16 @@ do
167
167
  local getCollectibleItemPoolType = ____getCollectibleItemPoolType.getCollectibleItemPoolType
168
168
  ____exports.getCollectibleItemPoolType = getCollectibleItemPoolType
169
169
  end
170
+ do
171
+ local ____persistentEntities = require("features.persistentEntities")
172
+ local removePersistentEntity = ____persistentEntities.removePersistentEntity
173
+ local spawnPersistentEntity = ____persistentEntities.spawnPersistentEntity
174
+ ____exports.removePersistentEntity = removePersistentEntity
175
+ ____exports.spawnPersistentEntity = spawnPersistentEntity
176
+ end
170
177
  do
171
178
  local ____playerInventory = require("features.playerInventory")
172
- local addCollectible = ____playerInventory.addCollectible
173
179
  local getPlayerInventory = ____playerInventory.getPlayerInventory
174
- ____exports.addCollectible = addCollectible
175
180
  ____exports.getPlayerInventory = getPlayerInventory
176
181
  end
177
182
  do
@@ -705,6 +710,14 @@ do
705
710
  end
706
711
  end
707
712
  end
713
+ do
714
+ local ____export = require("functions.saveFile")
715
+ for ____exportKey, ____exportValue in pairs(____export) do
716
+ if ____exportKey ~= "default" then
717
+ ____exports[____exportKey] = ____exportValue
718
+ end
719
+ end
720
+ end
708
721
  do
709
722
  local ____export = require("functions.seeds")
710
723
  for ____exportKey, ____exportValue in pairs(____export) do
@@ -65,6 +65,8 @@ local ____postPlayerChangeHealth = require("callbacks.postPlayerChangeHealth")
65
65
  local postPlayerChangeHealthCallbackInit = ____postPlayerChangeHealth.postPlayerChangeHealthCallbackInit
66
66
  local ____postPlayerChangeType = require("callbacks.postPlayerChangeType")
67
67
  local postPlayerChangeTypeCallbackInit = ____postPlayerChangeType.postPlayerChangeTypeCallbackInit
68
+ local ____postPlayerCollectible = require("callbacks.postPlayerCollectible")
69
+ local postPlayerCollectibleCallbackInit = ____postPlayerCollectible.postPlayerCollectibleCallbackInit
68
70
  local ____postPlayerFatalDamage = require("callbacks.postPlayerFatalDamage")
69
71
  local postPlayerFatalDamageCallbackInit = ____postPlayerFatalDamage.postPlayerFatalDamageCallbackInit
70
72
  local ____postPlayerInitLate = require("callbacks.postPlayerInitLate")
@@ -153,6 +155,7 @@ function ____exports.initCustomCallbacks(self, mod)
153
155
  postPitUpdateInit(nil, mod)
154
156
  postPlayerChangeHealthCallbackInit(nil, mod)
155
157
  postPlayerChangeTypeCallbackInit(nil, mod)
158
+ postPlayerCollectibleCallbackInit(nil, mod)
156
159
  postPlayerFatalDamageCallbackInit(nil, mod)
157
160
  postPlayerInitLateCallbackInit(nil, mod)
158
161
  postPlayerReorderedCallbacksInit(nil, mod)
package/initFeatures.lua CHANGED
@@ -17,6 +17,8 @@ local ____forgottenSwitch = require("features.forgottenSwitch")
17
17
  local forgottenSwitchInit = ____forgottenSwitch.forgottenSwitchInit
18
18
  local ____getCollectibleItemPoolType = require("features.getCollectibleItemPoolType")
19
19
  local getCollectibleItemPoolTypeInit = ____getCollectibleItemPoolType.getCollectibleItemPoolTypeInit
20
+ local ____persistentEntities = require("features.persistentEntities")
21
+ local persistentEntitiesInit = ____persistentEntities.persistentEntitiesInit
20
22
  local ____playerInventory = require("features.playerInventory")
21
23
  local playerInventoryInit = ____playerInventory.playerInventoryInit
22
24
  local ____ponyDetection = require("features.ponyDetection")
@@ -42,6 +44,7 @@ function ____exports.initFeaturesMinor(self, mod)
42
44
  fastResetInit(nil, mod)
43
45
  forgottenSwitchInit(nil, mod)
44
46
  getCollectibleItemPoolTypeInit(nil, mod)
47
+ persistentEntitiesInit(nil, mod)
45
48
  playerInventoryInit(nil, mod)
46
49
  ponyDetectionInit(nil, mod)
47
50
  preventCollectibleRotationInit(nil, mod)
@@ -42,6 +42,8 @@ import { PostPitRenderRegisterParameters } from "../callbacks/subscriptions/post
42
42
  import { PostPitUpdateRegisterParameters } from "../callbacks/subscriptions/postPitUpdate";
43
43
  import { PostPlayerChangeHealthRegisterParameters } from "../callbacks/subscriptions/postPlayerChangeHealth";
44
44
  import { PostPlayerChangeTypeRegisterParameters } from "../callbacks/subscriptions/postPlayerChangeType";
45
+ import { PostPlayerCollectibleAddedRegisterParameters } from "../callbacks/subscriptions/postPlayerCollectibleAdded";
46
+ import { PostPlayerCollectibleRemovedRegisterParameters } from "../callbacks/subscriptions/postPlayerCollectibleRemoved";
45
47
  import { PostPlayerFatalDamageRegisterParameters } from "../callbacks/subscriptions/postPlayerFatalDamage";
46
48
  import { PostPlayerInitLateRegisterParameters } from "../callbacks/subscriptions/postPlayerInitLate";
47
49
  import { PostPlayerInitReorderedRegisterParameters } from "../callbacks/subscriptions/postPlayerInitReordered";
@@ -120,6 +122,8 @@ export interface AddCallbackParameterCustom {
120
122
  [ModCallbackCustom.POST_PIT_UPDATE]: PostPitUpdateRegisterParameters;
121
123
  [ModCallbackCustom.POST_PLAYER_CHANGE_HEALTH]: PostPlayerChangeHealthRegisterParameters;
122
124
  [ModCallbackCustom.POST_PLAYER_CHANGE_TYPE]: PostPlayerChangeTypeRegisterParameters;
125
+ [ModCallbackCustom.POST_PLAYER_COLLECTIBLE_ADDED]: PostPlayerCollectibleAddedRegisterParameters;
126
+ [ModCallbackCustom.POST_PLAYER_COLLECTIBLE_REMOVED]: PostPlayerCollectibleRemovedRegisterParameters;
123
127
  [ModCallbackCustom.POST_PLAYER_FATAL_DAMAGE]: PostPlayerFatalDamageRegisterParameters;
124
128
  [ModCallbackCustom.POST_PLAYER_INIT_LATE]: PostPlayerInitLateRegisterParameters;
125
129
  [ModCallbackCustom.POST_PLAYER_INIT_REORDERED]: PostPlayerInitReorderedRegisterParameters;
@@ -0,0 +1,2 @@
1
+ import { PillEffect } from "isaac-typescript-definitions";
2
+ export declare const PHD_PILL_CONVERSIONS: ReadonlyMap<PillEffect, PillEffect>;
@@ -0,0 +1,25 @@
1
+ local ____lualib = require("lualib_bundle")
2
+ local Map = ____lualib.Map
3
+ local __TS__New = ____lualib.__TS__New
4
+ local ____exports = {}
5
+ local ____isaac_2Dtypescript_2Ddefinitions = require("isaac-typescript-definitions")
6
+ local PillEffect = ____isaac_2Dtypescript_2Ddefinitions.PillEffect
7
+ ____exports.PHD_PILL_CONVERSIONS = __TS__New(Map, {
8
+ {PillEffect.BAD_TRIP, PillEffect.BALLS_OF_STEEL},
9
+ {PillEffect.HEALTH_DOWN, PillEffect.HEALTH_UP},
10
+ {PillEffect.RANGE_DOWN, PillEffect.RANGE_UP},
11
+ {PillEffect.SPEED_DOWN, PillEffect.SPEED_UP},
12
+ {PillEffect.TEARS_DOWN, PillEffect.TEARS_UP},
13
+ {PillEffect.LUCK_DOWN, PillEffect.LUCK_UP},
14
+ {PillEffect.PARALYSIS, PillEffect.PHEROMONES},
15
+ {PillEffect.AMNESIA, PillEffect.I_CAN_SEE_FOREVER},
16
+ {PillEffect.R_U_A_WIZARD, PillEffect.POWER},
17
+ {PillEffect.ADDICTED, PillEffect.PERCS},
18
+ {PillEffect.QUESTION_MARKS, PillEffect.TELEPILLS},
19
+ {PillEffect.RETRO_VISION, PillEffect.I_CAN_SEE_FOREVER},
20
+ {PillEffect.X_LAX, PillEffect.SOMETHINGS_WRONG},
21
+ {PillEffect.IM_EXCITED, PillEffect.IM_DROWSY},
22
+ {PillEffect.HORF, PillEffect.GULP},
23
+ {PillEffect.SHOT_SPEED_DOWN, PillEffect.SHOT_SPEED_UP}
24
+ })
25
+ return ____exports
@@ -0,0 +1,2 @@
1
+ import { PillEffect } from "isaac-typescript-definitions";
2
+ export declare const FALSE_PHD_PILL_CONVERSIONS: ReadonlyMap<PillEffect, PillEffect>;
@@ -0,0 +1,39 @@
1
+ local ____lualib = require("lualib_bundle")
2
+ local Map = ____lualib.Map
3
+ local __TS__New = ____lualib.__TS__New
4
+ local ____exports = {}
5
+ local ____isaac_2Dtypescript_2Ddefinitions = require("isaac-typescript-definitions")
6
+ local PillEffect = ____isaac_2Dtypescript_2Ddefinitions.PillEffect
7
+ ____exports.FALSE_PHD_PILL_CONVERSIONS = __TS__New(Map, {
8
+ {PillEffect.BAD_GAS, PillEffect.HEALTH_DOWN},
9
+ {PillEffect.BALLS_OF_STEEL, PillEffect.BAD_TRIP},
10
+ {PillEffect.BOMBS_ARE_KEYS, PillEffect.TEARS_DOWN},
11
+ {PillEffect.EXPLOSIVE_DIARRHEA, PillEffect.RANGE_DOWN},
12
+ {PillEffect.FULL_HEALTH, PillEffect.BAD_TRIP},
13
+ {PillEffect.HEALTH_UP, PillEffect.HEALTH_DOWN},
14
+ {PillEffect.PRETTY_FLY, PillEffect.LUCK_DOWN},
15
+ {PillEffect.RANGE_UP, PillEffect.RANGE_DOWN},
16
+ {PillEffect.SPEED_UP, PillEffect.SPEED_DOWN},
17
+ {PillEffect.TEARS_UP, PillEffect.TEARS_DOWN},
18
+ {PillEffect.LUCK_UP, PillEffect.LUCK_DOWN},
19
+ {PillEffect.TELEPILLS, PillEffect.QUESTION_MARKS},
20
+ {PillEffect.FORTY_EIGHT_HOUR_ENERGY, PillEffect.SPEED_DOWN},
21
+ {PillEffect.HEMATEMESIS, PillEffect.BAD_TRIP},
22
+ {PillEffect.I_CAN_SEE_FOREVER, PillEffect.AMNESIA},
23
+ {PillEffect.PHEROMONES, PillEffect.PARALYSIS},
24
+ {PillEffect.LEMON_PARTY, PillEffect.AMNESIA},
25
+ {PillEffect.PERCS, PillEffect.ADDICTED},
26
+ {PillEffect.ONE_MAKES_YOU_LARGER, PillEffect.RANGE_DOWN},
27
+ {PillEffect.ONE_MAKES_YOU_SMALL, PillEffect.SPEED_DOWN},
28
+ {PillEffect.INFESTED_EXCLAMATION, PillEffect.TEARS_DOWN},
29
+ {PillEffect.INFESTED_QUESTION, PillEffect.LUCK_DOWN},
30
+ {PillEffect.POWER, PillEffect.R_U_A_WIZARD},
31
+ {PillEffect.FRIENDS_TILL_THE_END, PillEffect.HEALTH_DOWN},
32
+ {PillEffect.SOMETHINGS_WRONG, PillEffect.X_LAX},
33
+ {PillEffect.IM_DROWSY, PillEffect.IM_EXCITED},
34
+ {PillEffect.GULP, PillEffect.HORF},
35
+ {PillEffect.FEELS_LIKE_IM_WALKING_ON_SUNSHINE, PillEffect.RETRO_VISION},
36
+ {PillEffect.VURP, PillEffect.HORF},
37
+ {PillEffect.SHOT_SPEED_UP, PillEffect.SHOT_SPEED_DOWN}
38
+ })
39
+ return ____exports