isaacscript-common 3.0.0 → 3.2.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 (95) hide show
  1. package/cachedClasses.d.ts +6 -4
  2. package/cachedClasses.lua +4 -4
  3. package/callbacks/postPickupInitFirst.d.ts +1 -0
  4. package/callbacks/postPickupInitFirst.lua +55 -0
  5. package/callbacks/postSlotDestroyed.d.ts +1 -0
  6. package/callbacks/postSlotDestroyed.lua +66 -0
  7. package/callbacks/postSlotRender.lua +3 -21
  8. package/callbacks/subscriptions/postCustomRevive.d.ts +1 -0
  9. package/callbacks/subscriptions/postDoorRender.d.ts +1 -0
  10. package/callbacks/subscriptions/postDoorUpdate.d.ts +1 -0
  11. package/callbacks/subscriptions/postPickupCollect.d.ts +1 -0
  12. package/callbacks/subscriptions/postPickupInitFirst.d.ts +3 -0
  13. package/callbacks/subscriptions/postPickupInitFirst.lua +29 -0
  14. package/callbacks/subscriptions/postPickupStateChanged.d.ts +1 -0
  15. package/callbacks/subscriptions/postPitRender.d.ts +1 -0
  16. package/callbacks/subscriptions/postPitUpdate.d.ts +1 -0
  17. package/callbacks/subscriptions/postPoopRender.d.ts +1 -0
  18. package/callbacks/subscriptions/postPoopUpdate.d.ts +1 -0
  19. package/callbacks/subscriptions/postPressurePlateRender.d.ts +1 -0
  20. package/callbacks/subscriptions/postPressurePlateUpdate.d.ts +1 -0
  21. package/callbacks/subscriptions/postRockRender.d.ts +1 -0
  22. package/callbacks/subscriptions/postRockUpdate.d.ts +1 -0
  23. package/callbacks/subscriptions/postSpikesRender.d.ts +1 -0
  24. package/callbacks/subscriptions/postSpikesUpdate.d.ts +1 -0
  25. package/callbacks/subscriptions/postTNTRender.d.ts +1 -0
  26. package/callbacks/subscriptions/postTNTUpdate.d.ts +1 -0
  27. package/classes/DefaultMap.d.ts +1 -2
  28. package/classes/DefaultMap.lua +1 -4
  29. package/enums/ModCallbackCustom.d.ts +61 -39
  30. package/enums/ModCallbackCustom.lua +40 -38
  31. package/features/debugDisplay/exports.d.ts +17 -0
  32. package/features/debugDisplay/v.d.ts +17 -0
  33. package/features/deployJSONRoom.d.ts +1 -0
  34. package/features/saveDataManager/load.lua +12 -8
  35. package/features/saveDataManager/main.lua +10 -3
  36. package/features/saveDataManager/merge.lua +33 -21
  37. package/features/saveDataManager/save.lua +12 -7
  38. package/functions/array.d.ts +2 -0
  39. package/functions/bombs.d.ts +3 -0
  40. package/functions/bombs.lua +12 -0
  41. package/functions/chargeBar.d.ts +1 -0
  42. package/functions/collectibles.d.ts +13 -8
  43. package/functions/collectibles.lua +24 -11
  44. package/functions/deepCopy.lua +35 -26
  45. package/functions/deepCopyTests.lua +8 -5
  46. package/functions/direction.d.ts +8 -0
  47. package/functions/direction.lua +27 -0
  48. package/functions/doors.d.ts +1 -0
  49. package/functions/doors.lua +5 -0
  50. package/functions/entity.d.ts +4 -4
  51. package/functions/entity.lua +8 -8
  52. package/functions/entitySpecific.d.ts +20 -20
  53. package/functions/entitySpecific.lua +10 -10
  54. package/functions/enums.d.ts +2 -0
  55. package/functions/globals.lua +2 -10
  56. package/functions/gridEntitySpecific.d.ts +5 -0
  57. package/functions/isaacAPIClass.d.ts +4 -4
  58. package/functions/isaacAPIClass.lua +6 -6
  59. package/functions/jsonRoom.d.ts +2 -0
  60. package/functions/log.lua +3 -3
  61. package/functions/pickups.d.ts +9 -9
  62. package/functions/player.d.ts +7 -0
  63. package/functions/player.lua +44 -9
  64. package/functions/playerHealth.d.ts +3 -0
  65. package/functions/playerHealth.lua +87 -68
  66. package/functions/playerIndex.d.ts +2 -0
  67. package/functions/positionVelocity.d.ts +3 -0
  68. package/functions/random.d.ts +2 -0
  69. package/functions/revive.d.ts +2 -0
  70. package/functions/rng.d.ts +1 -0
  71. package/functions/saveFile.d.ts +15 -0
  72. package/functions/saveFile.lua +106 -0
  73. package/functions/serialization.lua +2 -2
  74. package/functions/set.d.ts +1 -0
  75. package/functions/sprite.d.ts +2 -0
  76. package/functions/table.d.ts +12 -0
  77. package/functions/table.lua +34 -0
  78. package/functions/tears.d.ts +1 -0
  79. package/functions/tstlClass.d.ts +34 -0
  80. package/functions/tstlClass.lua +54 -9
  81. package/functions/ui.d.ts +2 -0
  82. package/functions/utils.d.ts +15 -0
  83. package/functions/utils.lua +20 -0
  84. package/functions/vector.lua +4 -16
  85. package/index.d.ts +2 -0
  86. package/index.lua +16 -0
  87. package/initCustomCallbacks.lua +6 -0
  88. package/interfaces/AddCallbackParameterCustom.d.ts +2 -0
  89. package/interfaces/ChargeBarSprites.d.ts +1 -0
  90. package/interfaces/private/TSTLClassMetatable.d.ts +2 -0
  91. package/objects/callbackRegisterFunctions.lua +3 -0
  92. package/objects/oppositeDoorSlots.d.ts +4 -0
  93. package/objects/oppositeDoorSlots.lua +15 -0
  94. package/package.json +1 -1
  95. package/types/AnyEntity.d.ts +10 -0
@@ -1,4 +1,5 @@
1
1
  local ____lualib = require("lualib_bundle")
2
+ local __TS__ArrayMap = ____lualib.__TS__ArrayMap
2
3
  local __TS__ArrayForEach = ____lualib.__TS__ArrayForEach
3
4
  local ____exports = {}
4
5
  local ____isaac_2Dtypescript_2Ddefinitions = require("isaac-typescript-definitions")
@@ -16,6 +17,79 @@ local isCharacter = ____player.isCharacter
16
17
  local ____utils = require("functions.utils")
17
18
  local ensureAllCases = ____utils.ensureAllCases
18
19
  local ____repeat = ____utils["repeat"]
20
+ function ____exports.removeAllPlayerHealth(self, player)
21
+ local goldenHearts = player:GetGoldenHearts()
22
+ local eternalHearts = player:GetEternalHearts()
23
+ local boneHearts = player:GetBoneHearts()
24
+ local brokenHearts = player:GetBrokenHearts()
25
+ player:AddGoldenHearts(goldenHearts * -1)
26
+ player:AddEternalHearts(eternalHearts * -1)
27
+ player:AddBoneHearts(boneHearts * -1)
28
+ player:AddBrokenHearts(brokenHearts * -1)
29
+ player:AddMaxHearts(MAX_PLAYER_HEART_CONTAINERS * -2, true)
30
+ player:AddSoulHearts(MAX_PLAYER_HEART_CONTAINERS * -2)
31
+ if isCharacter(nil, player, PlayerType.THE_SOUL) then
32
+ local forgotten = player:GetSubPlayer()
33
+ if forgotten ~= nil then
34
+ local forgottenBoneHearts = forgotten:GetBoneHearts()
35
+ forgotten:AddBoneHearts(forgottenBoneHearts * -1)
36
+ end
37
+ end
38
+ end
39
+ --- Helper function to set a player's health to a specific state. You can use this in combination
40
+ -- with the `getPlayerHealth` function to restore the player's health back to a certain
41
+ -- configuration at a later time.
42
+ --
43
+ -- Based on the `REVEL.LoadHealth` function in the Revelations mod.
44
+ function ____exports.setPlayerHealth(self, player, playerHealth)
45
+ local character = player:GetPlayerType()
46
+ local subPlayer = player:GetSubPlayer()
47
+ ____exports.removeAllPlayerHealth(nil, player)
48
+ if character == PlayerType.THE_SOUL and subPlayer ~= nil then
49
+ subPlayer:AddMaxHearts(playerHealth.maxHearts, false)
50
+ else
51
+ player:AddMaxHearts(playerHealth.maxHearts, false)
52
+ end
53
+ player:AddEternalHearts(playerHealth.eternalHearts)
54
+ local soulHeartsRemaining = playerHealth.soulHearts
55
+ __TS__ArrayForEach(
56
+ playerHealth.soulHeartTypes,
57
+ function(____, heartType, i)
58
+ local isHalf = playerHealth.soulHearts + playerHealth.boneHearts * 2 < (i + 1) * 2
59
+ local addAmount = 2
60
+ if isHalf or heartType == HeartSubType.BONE or soulHeartsRemaining < 2 then
61
+ addAmount = 1
62
+ end
63
+ if heartType == HeartSubType.SOUL then
64
+ player:AddSoulHearts(addAmount)
65
+ soulHeartsRemaining = soulHeartsRemaining - addAmount
66
+ elseif heartType == HeartSubType.BLACK then
67
+ player:AddBlackHearts(addAmount)
68
+ soulHeartsRemaining = soulHeartsRemaining - addAmount
69
+ elseif heartType == HeartSubType.BONE then
70
+ player:AddBoneHearts(addAmount)
71
+ end
72
+ end
73
+ )
74
+ player:AddRottenHearts(playerHealth.rottenHearts)
75
+ ____repeat(
76
+ nil,
77
+ playerHealth.hearts,
78
+ function()
79
+ player:AddHearts(1)
80
+ if character == PlayerType.MAGDALENE_B then
81
+ player:AddHearts(-1)
82
+ end
83
+ end
84
+ )
85
+ player:AddGoldenHearts(playerHealth.goldenHearts)
86
+ player:AddBrokenHearts(playerHealth.brokenHearts)
87
+ if character == PlayerType.BETHANY then
88
+ player:SetSoulCharge(playerHealth.soulCharges)
89
+ elseif character == PlayerType.BETHANY_B then
90
+ player:SetBloodCharge(playerHealth.bloodCharges)
91
+ end
92
+ end
19
93
  function ____exports.addPlayerHealthType(self, player, healthType, numHearts)
20
94
  repeat
21
95
  local ____switch3 = healthType
@@ -220,77 +294,22 @@ function ____exports.getPlayerHealthType(self, player, healthType)
220
294
  end
221
295
  until true
222
296
  end
223
- function ____exports.removeAllPlayerHealth(self, player)
224
- local goldenHearts = player:GetGoldenHearts()
225
- local eternalHearts = player:GetEternalHearts()
226
- local boneHearts = player:GetBoneHearts()
227
- local brokenHearts = player:GetBrokenHearts()
228
- player:AddGoldenHearts(goldenHearts * -1)
229
- player:AddEternalHearts(eternalHearts * -1)
230
- player:AddBoneHearts(boneHearts * -1)
231
- player:AddBrokenHearts(brokenHearts * -1)
232
- player:AddMaxHearts(MAX_PLAYER_HEART_CONTAINERS * -2, true)
233
- player:AddSoulHearts(MAX_PLAYER_HEART_CONTAINERS * -2)
234
- if isCharacter(nil, player, PlayerType.THE_SOUL) then
235
- local forgotten = player:GetSubPlayer()
236
- if forgotten ~= nil then
237
- local forgottenBoneHearts = forgotten:GetBoneHearts()
238
- forgotten:AddBoneHearts(forgottenBoneHearts * -1)
239
- end
240
- end
241
- end
242
- --- Helper function to set a player's health to a specific state. You can use this in combination
243
- -- with the `getPlayerHealth` function to restore the player's health back to a certain
244
- -- configuration at a later time.
245
- --
246
- -- Based on the `REVEL.LoadHealth` function in the Revelations mod.
247
- function ____exports.setPlayerHealth(self, player, playerHealth)
248
- local character = player:GetPlayerType()
249
- local subPlayer = player:GetSubPlayer()
297
+ function ____exports.playerConvertBlackHeartsToSoulHearts(self, player)
298
+ local playerHealth = ____exports.getPlayerHealth(nil, player)
250
299
  ____exports.removeAllPlayerHealth(nil, player)
251
- if character == PlayerType.THE_SOUL and subPlayer ~= nil then
252
- subPlayer:AddMaxHearts(playerHealth.maxHearts, false)
253
- else
254
- player:AddMaxHearts(playerHealth.maxHearts, false)
255
- end
256
- player:AddEternalHearts(playerHealth.eternalHearts)
257
- local soulHeartsRemaining = playerHealth.soulHearts
258
- __TS__ArrayForEach(
300
+ playerHealth.soulHeartTypes = __TS__ArrayMap(
259
301
  playerHealth.soulHeartTypes,
260
- function(____, heartType, i)
261
- local isHalf = playerHealth.soulHearts + playerHealth.boneHearts * 2 < (i + 1) * 2
262
- local addAmount = 2
263
- if isHalf or heartType == HeartSubType.BONE or soulHeartsRemaining < 2 then
264
- addAmount = 1
265
- end
266
- if heartType == HeartSubType.SOUL then
267
- player:AddSoulHearts(addAmount)
268
- soulHeartsRemaining = soulHeartsRemaining - addAmount
269
- elseif heartType == HeartSubType.BLACK then
270
- player:AddBlackHearts(addAmount)
271
- soulHeartsRemaining = soulHeartsRemaining - addAmount
272
- elseif heartType == HeartSubType.BONE then
273
- player:AddBoneHearts(addAmount)
274
- end
275
- end
302
+ function(____, soulHeartType) return soulHeartType == HeartSubType.BLACK and HeartSubType.SOUL or soulHeartType end
276
303
  )
277
- player:AddRottenHearts(playerHealth.rottenHearts)
278
- ____repeat(
279
- nil,
280
- playerHealth.hearts,
281
- function()
282
- player:AddHearts(1)
283
- if character == PlayerType.MAGDALENE_B then
284
- player:AddHearts(-1)
285
- end
286
- end
304
+ ____exports.setPlayerHealth(nil, player, playerHealth)
305
+ end
306
+ function ____exports.playerConvertSoulHeartsToBlackHearts(self, player)
307
+ local playerHealth = ____exports.getPlayerHealth(nil, player)
308
+ ____exports.removeAllPlayerHealth(nil, player)
309
+ playerHealth.soulHeartTypes = __TS__ArrayMap(
310
+ playerHealth.soulHeartTypes,
311
+ function(____, soulHeartType) return soulHeartType == HeartSubType.SOUL and HeartSubType.BLACK or soulHeartType end
287
312
  )
288
- player:AddGoldenHearts(playerHealth.goldenHearts)
289
- player:AddBrokenHearts(playerHealth.brokenHearts)
290
- if character == PlayerType.BETHANY then
291
- player:SetSoulCharge(playerHealth.soulCharges)
292
- elseif character == PlayerType.BETHANY_B then
293
- player:SetBloodCharge(playerHealth.bloodCharges)
294
- end
313
+ ____exports.setPlayerHealth(nil, player, playerHealth)
295
314
  end
296
315
  return ____exports
@@ -1,4 +1,6 @@
1
1
  /// <reference types="isaac-typescript-definitions" />
2
+ /// <reference types="isaac-typescript-definitions" />
3
+ /// <reference types="isaac-typescript-definitions" />
2
4
  import { PlayerIndex } from "../types/PlayerIndex";
3
5
  /**
4
6
  * Helper function to get every player with no restrictions, by using `Game.GetNumPlayers` and
@@ -1,4 +1,7 @@
1
1
  /// <reference types="isaac-typescript-definitions" />
2
+ /// <reference types="isaac-typescript-definitions" />
3
+ /// <reference types="isaac-typescript-definitions" />
4
+ /// <reference types="isaac-typescript-definitions" />
2
5
  export declare function anyEntityCloserThan(entities: Entity[], position: Vector, distance: int): boolean;
3
6
  /** Iterates over all players and checks if any player is close enough to the specified position. */
4
7
  export declare function anyPlayerCloserThan(position: Vector, distance: float): boolean;
@@ -1,4 +1,6 @@
1
1
  /// <reference types="isaac-typescript-definitions" />
2
+ /// <reference types="isaac-typescript-definitions" />
3
+ /// <reference types="isaac-typescript-definitions" />
2
4
  /**
3
5
  * This returns a random float between 0 and 1. It is inclusive on the low end, but exclusive on the
4
6
  * high end. (This is because the `RNG.RandomFloat` method will never return a value of exactly 1.)
@@ -1,4 +1,6 @@
1
1
  /// <reference types="isaac-typescript-definitions" />
2
+ /// <reference types="isaac-typescript-definitions" />
3
+ /// <reference types="isaac-typescript-definitions" />
2
4
  /**
3
5
  * Uses the player's current health and other miscellaneous things to determine if incoming damage
4
6
  * will be fatal.
@@ -1,4 +1,5 @@
1
1
  /// <reference types="isaac-typescript-definitions" />
2
+ /// <reference types="isaac-typescript-definitions" />
2
3
  /// <reference types="typescript-to-lua/language-extensions" />
3
4
  import { SerializationType } from "../enums/SerializationType";
4
5
  declare type SerializedRNG = LuaTable<string, unknown> & {
@@ -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,106 @@
1
+ local ____lualib = require("lualib_bundle")
2
+ local Map = ____lualib.Map
3
+ local __TS__New = ____lualib.__TS__New
4
+ local Set = ____lualib.Set
5
+ local __TS__Iterator = ____lualib.__TS__Iterator
6
+ local ____exports = {}
7
+ local ____isaac_2Dtypescript_2Ddefinitions = require("isaac-typescript-definitions")
8
+ local CollectibleType = ____isaac_2Dtypescript_2Ddefinitions.CollectibleType
9
+ local PlayerType = ____isaac_2Dtypescript_2Ddefinitions.PlayerType
10
+ local TrinketType = ____isaac_2Dtypescript_2Ddefinitions.TrinketType
11
+ local ____cachedClasses = require("cachedClasses")
12
+ local game = ____cachedClasses.game
13
+ local ____collectibleSet = require("functions.collectibleSet")
14
+ local getCollectibleSet = ____collectibleSet.getCollectibleSet
15
+ local ____player = require("functions.player")
16
+ local anyPlayerHasCollectible = ____player.anyPlayerHasCollectible
17
+ local getPlayersOfType = ____player.getPlayersOfType
18
+ local ____playerDataStructures = require("functions.playerDataStructures")
19
+ local mapGetPlayer = ____playerDataStructures.mapGetPlayer
20
+ local mapSetPlayer = ____playerDataStructures.mapSetPlayer
21
+ local ____playerIndex = require("functions.playerIndex")
22
+ local getPlayers = ____playerIndex.getPlayers
23
+ local ____utils = require("functions.utils")
24
+ local ____repeat = ____utils["repeat"]
25
+ local COLLECTIBLES_THAT_AFFECT_ITEM_POOLS = {CollectibleType.CHAOS, CollectibleType.SACRED_ORB, CollectibleType.TMTRAINER}
26
+ local TRINKETS_THAT_AFFECT_ITEM_POOLS = {TrinketType.NO}
27
+ --- Helper function to see if the given collectible is unlocked on the player's save file. This
28
+ -- requires providing the corresponding item pool that the collectible is located in.
29
+ --
30
+ -- - If any player currently has the item, then it is assumed to be unlocked. (This is because Eden
31
+ -- may have randomly started with the provided collectible, and it will be subsequently removed
32
+ -- from all pools.)
33
+ -- - If the collectible is located in more than one item pool, then any item pool can be provided.
34
+ -- - If the collectible is not located in any item pools, then this function will always return
35
+ -- false.
36
+ -- - If any player is Tainted Lost, they will be temporarily changed to Isaac and then temporarily
37
+ -- changed back (because Tainted Lost is not able to retrieve some collectibles from item pools).
38
+ function ____exports.isCollectibleUnlocked(self, collectibleTypeToCheckFor, itemPoolToCheckFor)
39
+ if anyPlayerHasCollectible(nil, collectibleTypeToCheckFor) then
40
+ return true
41
+ end
42
+ local taintedLosts = getPlayersOfType(nil, PlayerType.THE_LOST_B)
43
+ for ____, player in ipairs(taintedLosts) do
44
+ player:ChangePlayerType(PlayerType.ISAAC)
45
+ end
46
+ local removedItemsMap = __TS__New(Map)
47
+ local removedTrinketsMap = __TS__New(Map)
48
+ for ____, player in ipairs(getPlayers(nil)) do
49
+ local removedItems = {}
50
+ for ____, itemToRemove in ipairs(COLLECTIBLES_THAT_AFFECT_ITEM_POOLS) do
51
+ if player:HasCollectible(itemToRemove) then
52
+ local numCollectibles = player:GetCollectibleNum(itemToRemove)
53
+ ____repeat(
54
+ nil,
55
+ numCollectibles,
56
+ function()
57
+ player:RemoveCollectible(itemToRemove)
58
+ removedItems[#removedItems + 1] = itemToRemove
59
+ end
60
+ )
61
+ end
62
+ end
63
+ mapSetPlayer(nil, removedItemsMap, player, removedItems)
64
+ local removedTrinkets = {}
65
+ for ____, trinketToRemove in ipairs(TRINKETS_THAT_AFFECT_ITEM_POOLS) do
66
+ if player:HasTrinket(trinketToRemove) then
67
+ local numTrinkets = player:GetTrinketMultiplier(trinketToRemove)
68
+ ____repeat(
69
+ nil,
70
+ numTrinkets,
71
+ function()
72
+ player:TryRemoveTrinket(trinketToRemove)
73
+ removedTrinkets[#removedTrinkets + 1] = trinketToRemove
74
+ end
75
+ )
76
+ end
77
+ end
78
+ mapSetPlayer(nil, removedTrinketsMap, player, removedTrinkets)
79
+ end
80
+ local itemPool = game:GetItemPool()
81
+ local collectibleSet = getCollectibleSet(nil)
82
+ for ____, collectibleType in __TS__Iterator(collectibleSet:values()) do
83
+ if collectibleType ~= collectibleTypeToCheckFor then
84
+ itemPool:AddRoomBlacklist(collectibleType)
85
+ end
86
+ end
87
+ local retrievedCollectibleType = itemPool:GetCollectible(itemPoolToCheckFor, false, 1)
88
+ local collectibleUnlocked = retrievedCollectibleType == collectibleTypeToCheckFor
89
+ itemPool:ResetRoomBlacklist()
90
+ for ____, player in ipairs(getPlayers(nil)) do
91
+ local removedItems = mapGetPlayer(nil, removedItemsMap, player)
92
+ if removedItems ~= nil then
93
+ for ____, collectibleType in ipairs(removedItems) do
94
+ player:AddCollectible(collectibleType, 0, false)
95
+ end
96
+ end
97
+ local removedTrinkets = mapGetPlayer(nil, removedTrinketsMap, player)
98
+ if removedTrinkets ~= nil then
99
+ for ____, trinketType in ipairs(removedTrinkets) do
100
+ player:AddTrinket(trinketType, false)
101
+ end
102
+ end
103
+ end
104
+ return collectibleUnlocked
105
+ end
106
+ return ____exports
@@ -13,7 +13,7 @@ local ISAAC_API_CLASS_TYPE_TO_COPY_FUNCTION = ____isaacAPIClassTypeToCopyFunctio
13
13
  local ____serializedIsaacAPIClassTypeToIdentityFunction = require("objects.serializedIsaacAPIClassTypeToIdentityFunction")
14
14
  local SERIALIZED_ISAAC_API_CLASS_TYPE_TO_IDENTITY_FUNCTION = ____serializedIsaacAPIClassTypeToIdentityFunction.SERIALIZED_ISAAC_API_CLASS_TYPE_TO_IDENTITY_FUNCTION
15
15
  local ____isaacAPIClass = require("functions.isaacAPIClass")
16
- local getIsaacAPIClassType = ____isaacAPIClass.getIsaacAPIClassType
16
+ local getIsaacAPIClassName = ____isaacAPIClass.getIsaacAPIClassName
17
17
  function getSerializedTableType(self, serializedIsaacAPIClass)
18
18
  for ____, ____value in ipairs(__TS__ObjectEntries(ISAAC_API_CLASS_TYPE_TO_BRAND)) do
19
19
  local copyableIsaacAPIClassType = ____value[1]
@@ -29,7 +29,7 @@ function ____exports.copyIsaacAPIClass(self, isaacAPIClass, serializationType)
29
29
  if objectType ~= "userdata" then
30
30
  error("Failed to copy an Isaac API class since the provided object was of type: " .. objectType)
31
31
  end
32
- local isaacAPIClassType = getIsaacAPIClassType(nil, isaacAPIClass)
32
+ local isaacAPIClassType = getIsaacAPIClassName(nil, isaacAPIClass)
33
33
  if isaacAPIClassType == nil then
34
34
  error("Failed to copy an Isaac API class since it does not have a class type.")
35
35
  end
@@ -1,4 +1,5 @@
1
1
  /// <reference types="isaac-typescript-definitions" />
2
+ /// <reference types="isaac-typescript-definitions" />
2
3
  /**
3
4
  * Helper function to add all of the values in one set to another set. The first set passed will be
4
5
  * modified in place.
@@ -1,4 +1,6 @@
1
1
  /// <reference types="isaac-typescript-definitions" />
2
+ /// <reference types="isaac-typescript-definitions" />
3
+ /// <reference types="isaac-typescript-definitions" />
2
4
  /**
3
5
  * Helper function to clear a specific layer from a sprite.
4
6
  *
@@ -27,6 +27,18 @@ export declare function getNumbersFromTable(table: LuaTable<string, unknown>, ob
27
27
  * This function is variadic, meaning that you can specify N arguments to get N values.
28
28
  */
29
29
  export declare function getStringsFromTable(table: LuaTable<string, unknown>, objectName: string, ...keys: string[]): string[];
30
+ /**
31
+ * Helper function to iterate over a table deterministically. This is useful because by default, the
32
+ * `pairs` function will return the keys of a Lua table in a random order.
33
+ *
34
+ * This function will sort the table entries based on the value of the key.
35
+ *
36
+ * @param table The table to iterate over.
37
+ * @param func The function to run for each iteration.
38
+ * @param deterministic Optional. Whether to iterate deterministically. True by default. You can
39
+ * dynamically set to false in situations where you need extra performance.
40
+ */
41
+ export declare function iterateTableDeterministically<K, V>(table: LuaTable<K, V>, func: (key: K, value: V) => void, deterministic?: boolean): void;
30
42
  /**
31
43
  * Helper function to check if a Lua table has all of the provided keys.
32
44
  *
@@ -1,7 +1,10 @@
1
1
  local ____lualib = require("lualib_bundle")
2
2
  local __TS__TypeOf = ____lualib.__TS__TypeOf
3
+ local __TS__ArraySort = ____lualib.__TS__ArraySort
3
4
  local __TS__ArrayEvery = ____lualib.__TS__ArrayEvery
4
5
  local ____exports = {}
6
+ local ____utils = require("functions.utils")
7
+ local twoDimensionalSort = ____utils.twoDimensionalSort
5
8
  --- In a Map, you can use the `clear` method to delete every element. However, in a LuaTable, the
6
9
  -- `clear` method does not exist. Use this helper function as a drop-in replacement for this.
7
10
  function ____exports.clearTable(self, ____table)
@@ -84,6 +87,37 @@ function ____exports.getStringsFromTable(self, ____table, objectName, ...)
84
87
  end
85
88
  return strings
86
89
  end
90
+ --- Helper function to iterate over a table deterministically. This is useful because by default, the
91
+ -- `pairs` function will return the keys of a Lua table in a random order.
92
+ --
93
+ -- This function will sort the table entries based on the value of the key.
94
+ --
95
+ -- @param table The table to iterate over.
96
+ -- @param func The function to run for each iteration.
97
+ -- @param deterministic Optional. Whether to iterate deterministically. True by default. You can
98
+ -- dynamically set to false in situations where you need extra performance.
99
+ function ____exports.iterateTableDeterministically(self, ____table, func, deterministic)
100
+ if deterministic == nil then
101
+ deterministic = true
102
+ end
103
+ if not deterministic then
104
+ for key, value in pairs(____table) do
105
+ func(nil, key, value)
106
+ end
107
+ return
108
+ end
109
+ local entriesArray = {}
110
+ for key, value in pairs(____table) do
111
+ local entry = {key, value}
112
+ entriesArray[#entriesArray + 1] = entry
113
+ end
114
+ __TS__ArraySort(entriesArray, twoDimensionalSort)
115
+ for ____, ____value in ipairs(entriesArray) do
116
+ local key = ____value[1]
117
+ local value = ____value[2]
118
+ func(nil, key, value)
119
+ end
120
+ end
87
121
  --- Helper function to check if a Lua table has all of the provided keys.
88
122
  --
89
123
  -- This function is variadic, meaning that you can specify as many arguments as you want to check
@@ -1,4 +1,5 @@
1
1
  /// <reference types="isaac-typescript-definitions" />
2
+ /// <reference types="isaac-typescript-definitions" />
2
3
  /**
3
4
  * - Converts the specified amount of tears stat into MaxFireDelay and adds it to the player.
4
5
  * - This function should only be used inside the EvaluateCache callback.
@@ -1,9 +1,43 @@
1
+ /// <reference types="typescript-to-lua/language-extensions" />
2
+ import { DefaultMap } from "../classes/DefaultMap";
1
3
  import { TSTLClass } from "../types/private/TSTLClass";
4
+ /**
5
+ * Helper function to get the name of a TypeScriptToLua class. TSTL classes are Lua tables created
6
+ * with the `__TS__Class` Lua function from the TSTL lualib. Their name is contained within
7
+ * "constructor.name" metatable key.
8
+ *
9
+ * For example, a `Map` class is has a name of "Map".
10
+ *
11
+ * Returns undefined if the object is not a table or if the aforementioned metatable key does not
12
+ * exist.
13
+ */
14
+ export declare function getTSTLClassName(object: unknown): string | undefined;
15
+ /**
16
+ * Helper function to determine if a given object is a TypeScriptToLua `Map`.
17
+ *
18
+ * It is not reliable to use the `instanceof` operator to determine this because each Lua module has
19
+ * their own copies of the entire lualib and thus their own instantiated version of a `Map`.
20
+ */
21
+ export declare function isDefaultMap(object: unknown): object is DefaultMap<AnyNotNil, unknown>;
2
22
  /**
3
23
  * Returns whether or not this is a class that is provided by the `isaacscript-common` library, such
4
24
  * as a `DefaultMap`.
5
25
  */
6
26
  export declare function isIsaacScriptCommonClass(object: unknown): boolean;
27
+ /**
28
+ * Helper function to determine if a given object is a TypeScriptToLua `Map`.
29
+ *
30
+ * It is not reliable to use the `instanceof` operator to determine this because each Lua module has
31
+ * their own copies of the entire lualib and thus their own instantiated version of a `Map`.
32
+ */
33
+ export declare function isTSTLMap(object: unknown): object is Map<AnyNotNil, unknown>;
34
+ /**
35
+ * Helper function to determine if a given object is a TypeScriptToLua `Set`.
36
+ *
37
+ * It is not reliable to use the `instanceof` operator to determine this because each Lua module has
38
+ * their own copies of the entire lualib and thus their own instantiated version of a `Set`.
39
+ */
40
+ export declare function isTSTLSet(object: unknown): object is Set<AnyNotNil>;
7
41
  /** TypeScriptToLua classes are Lua tables that have a metatable with a certain amount of keys. */
8
42
  export declare function isUserDefinedTSTLClass(object: unknown): object is TSTLClass;
9
43
  /**
@@ -1,18 +1,38 @@
1
1
  local ____lualib = require("lualib_bundle")
2
2
  local Set = ____lualib.Set
3
3
  local __TS__New = ____lualib.__TS__New
4
- local __TS__InstanceOf = ____lualib.__TS__InstanceOf
5
- local Map = ____lualib.Map
6
- local WeakMap = ____lualib.WeakMap
7
- local WeakSet = ____lualib.WeakSet
8
4
  local ____exports = {}
9
- local newTSTLClassFromMetatable
10
- local ____DefaultMap = require("classes.DefaultMap")
11
- local DefaultMap = ____DefaultMap.DefaultMap
5
+ local newTSTLClassFromMetatable, VANILLA_TSTL_CLASSES
6
+ --- Helper function to get the name of a TypeScriptToLua class. TSTL classes are Lua tables created
7
+ -- with the `__TS__Class` Lua function from the TSTL lualib. Their name is contained within
8
+ -- "constructor.name" metatable key.
9
+ --
10
+ -- For example, a `Map` class is has a name of "Map".
11
+ --
12
+ -- Returns undefined if the object is not a table or if the aforementioned metatable key does not
13
+ -- exist.
14
+ function ____exports.getTSTLClassName(self, object)
15
+ if type(object) ~= "table" then
16
+ return nil
17
+ end
18
+ local metatable = getmetatable(object)
19
+ if metatable == nil then
20
+ return nil
21
+ end
22
+ local constructor = metatable.constructor
23
+ if constructor == nil then
24
+ return nil
25
+ end
26
+ return constructor.name
27
+ end
12
28
  --- Returns whether or not this is a class that is provided as part of the TypeScriptToLua
13
29
  -- transpiler, such as a `Map` or a `Set`.
14
30
  function ____exports.isVanillaTSTLClass(self, object)
15
- return __TS__InstanceOf(object, Map) or __TS__InstanceOf(object, Set) or __TS__InstanceOf(object, WeakMap) or __TS__InstanceOf(object, WeakSet)
31
+ local className = ____exports.getTSTLClassName(nil, object)
32
+ if className == nil then
33
+ return false
34
+ end
35
+ return VANILLA_TSTL_CLASSES:has(className)
16
36
  end
17
37
  function newTSTLClassFromMetatable(self, metatable)
18
38
  local newClass = {}
@@ -20,11 +40,36 @@ function newTSTLClassFromMetatable(self, metatable)
20
40
  newClassMetatable:____constructor()
21
41
  return newClass
22
42
  end
43
+ VANILLA_TSTL_CLASSES = __TS__New(Set, {"Map", "Set", "WeakMap", "WeakSet"})
23
44
  local TSTL_CLASS_METATABLE_KEYS = __TS__New(Set, {"____constructor", "__index", "constructor"})
45
+ --- Helper function to determine if a given object is a TypeScriptToLua `Map`.
46
+ --
47
+ -- It is not reliable to use the `instanceof` operator to determine this because each Lua module has
48
+ -- their own copies of the entire lualib and thus their own instantiated version of a `Map`.
49
+ function ____exports.isDefaultMap(self, object)
50
+ local className = ____exports.getTSTLClassName(nil, object)
51
+ return className == "DefaultMap"
52
+ end
24
53
  --- Returns whether or not this is a class that is provided by the `isaacscript-common` library, such
25
54
  -- as a `DefaultMap`.
26
55
  function ____exports.isIsaacScriptCommonClass(self, object)
27
- return __TS__InstanceOf(object, DefaultMap)
56
+ return ____exports.isDefaultMap(nil, object)
57
+ end
58
+ --- Helper function to determine if a given object is a TypeScriptToLua `Map`.
59
+ --
60
+ -- It is not reliable to use the `instanceof` operator to determine this because each Lua module has
61
+ -- their own copies of the entire lualib and thus their own instantiated version of a `Map`.
62
+ function ____exports.isTSTLMap(self, object)
63
+ local className = ____exports.getTSTLClassName(nil, object)
64
+ return className == "Map"
65
+ end
66
+ --- Helper function to determine if a given object is a TypeScriptToLua `Set`.
67
+ --
68
+ -- It is not reliable to use the `instanceof` operator to determine this because each Lua module has
69
+ -- their own copies of the entire lualib and thus their own instantiated version of a `Set`.
70
+ function ____exports.isTSTLSet(self, object)
71
+ local className = ____exports.getTSTLClassName(nil, object)
72
+ return className == "Set"
28
73
  end
29
74
  --- TypeScriptToLua classes are Lua tables that have a metatable with a certain amount of keys.
30
75
  function ____exports.isUserDefinedTSTLClass(self, object)
package/functions/ui.d.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  /// <reference types="isaac-typescript-definitions" />
2
+ /// <reference types="isaac-typescript-definitions" />
3
+ /// <reference types="isaac-typescript-definitions" />
2
4
  /**
3
5
  * In the options menu, players have the ability to set a HUD offset. However, mods do not have
4
6
  * access to this value. To get around this, Mod Config Menu provides a separate HUD offset setting
@@ -1,4 +1,5 @@
1
1
  /// <reference types="isaac-typescript-definitions" />
2
+ /// <reference types="isaac-typescript-definitions" />
2
3
  /**
3
4
  * Helper function to get type safety on a switch statement.
4
5
  *
@@ -111,3 +112,17 @@ export declare function repeat(n: int, func: (i: int) => void): void;
111
112
  * This function does not actually do anything. (It is an "empty" function.)
112
113
  */
113
114
  export declare function todo(): void;
115
+ /**
116
+ * Helper function to sort a two-dimensional array by the first element.
117
+ *
118
+ * For example:
119
+ *
120
+ * ```ts
121
+ * const myArray = [[1, 2], [2, 3], [3, 4]];
122
+ * myArray.sort(twoDimensionalSort);
123
+ * ```
124
+ *
125
+ * From:
126
+ * https://stackoverflow.com/questions/16096872/how-to-sort-2-dimensional-array-by-column-value
127
+ */
128
+ export declare function twoDimensionalSort<T>(a: T[], b: T[]): -1 | 0 | 1;
@@ -179,4 +179,24 @@ end
179
179
  -- This function does not actually do anything. (It is an "empty" function.)
180
180
  function ____exports.todo(self)
181
181
  end
182
+ --- Helper function to sort a two-dimensional array by the first element.
183
+ --
184
+ -- For example:
185
+ --
186
+ -- ```ts
187
+ -- const myArray = [[1, 2], [2, 3], [3, 4]];
188
+ -- myArray.sort(twoDimensionalSort);
189
+ -- ```
190
+ --
191
+ -- From:
192
+ -- https://stackoverflow.com/questions/16096872/how-to-sort-2-dimensional-array-by-column-value
193
+ function ____exports.twoDimensionalSort(self, a, b)
194
+ if a[1] == nil or b[1] == nil then
195
+ error("Failed to two-dimensional sort since the first element of the array was undefined.")
196
+ end
197
+ if a[1] == b[1] then
198
+ return 0
199
+ end
200
+ return a[1] < b[1] and -1 or 1
201
+ end
182
202
  return ____exports