isaacscript-common 3.1.0 → 3.3.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 (40) hide show
  1. package/callbacks/customRevive.lua +3 -3
  2. package/callbacks/postGridEntity.lua +5 -3
  3. package/callbacks/postPickupInitFirst.d.ts +1 -0
  4. package/callbacks/postPickupInitFirst.lua +55 -0
  5. package/callbacks/postRoomClearChanged.lua +5 -3
  6. package/callbacks/postSlotInitUpdate.lua +5 -3
  7. package/callbacks/subscriptions/postPickupInitFirst.d.ts +3 -0
  8. package/callbacks/subscriptions/postPickupInitFirst.lua +29 -0
  9. package/classes/DefaultMap.d.ts +1 -2
  10. package/classes/DefaultMap.lua +1 -4
  11. package/enums/ModCallbackCustom.d.ts +61 -39
  12. package/enums/ModCallbackCustom.lua +40 -38
  13. package/features/deployJSONRoom.lua +5 -4
  14. package/features/extraConsoleCommands/listCommands.lua +1 -0
  15. package/features/persistentEntities.d.ts +28 -0
  16. package/features/persistentEntities.lua +150 -0
  17. package/functions/bombs.d.ts +3 -0
  18. package/functions/bombs.lua +12 -0
  19. package/functions/collectibles.d.ts +7 -7
  20. package/functions/collectibles.lua +8 -8
  21. package/functions/color.d.ts +2 -16
  22. package/functions/color.lua +0 -9
  23. package/functions/direction.d.ts +7 -0
  24. package/functions/direction.lua +10 -5
  25. package/functions/entity.d.ts +10 -0
  26. package/functions/entity.lua +29 -0
  27. package/functions/log.lua +2 -2
  28. package/functions/player.d.ts +7 -0
  29. package/functions/player.lua +44 -9
  30. package/functions/playerHealth.d.ts +2 -0
  31. package/functions/playerHealth.lua +87 -68
  32. package/functions/saveFile.d.ts +15 -0
  33. package/functions/saveFile.lua +106 -0
  34. package/index.d.ts +3 -0
  35. package/index.lua +23 -0
  36. package/initCustomCallbacks.lua +3 -0
  37. package/initFeatures.lua +3 -0
  38. package/interfaces/AddCallbackParameterCustom.d.ts +2 -0
  39. package/objects/callbackRegisterFunctions.lua +3 -0
  40. package/package.json +1 -1
@@ -4,7 +4,7 @@ local __TS__New = ____lualib.__TS__New
4
4
  local Map = ____lualib.Map
5
5
  local __TS__Iterator = ____lualib.__TS__Iterator
6
6
  local ____exports = {}
7
- local postNewRoom, setDecorationsInvisible, respawnPersistentEntities, removeSpecificNPCs, fillRoomWithDecorations, spawnAllEntities, spawnGridEntityForJSONRoom, spawnNormalEntityForJSONRoom, storePersistentEntity, fixPitGraphics, getPitMap, getPitFrame, FEATURE_NAME, NPC_TYPES_TO_NOT_REMOVE, PERSISTENT_ENTITY_TYPES, v
7
+ local postNewRoomReordered, setDecorationsInvisible, respawnPersistentEntities, removeSpecificNPCs, fillRoomWithDecorations, spawnAllEntities, spawnGridEntityForJSONRoom, spawnNormalEntityForJSONRoom, storePersistentEntity, fixPitGraphics, getPitMap, getPitFrame, FEATURE_NAME, NPC_TYPES_TO_NOT_REMOVE, PERSISTENT_ENTITY_TYPES, v
8
8
  local ____isaac_2Dtypescript_2Ddefinitions = require("isaac-typescript-definitions")
9
9
  local EffectVariant = ____isaac_2Dtypescript_2Ddefinitions.EffectVariant
10
10
  local EntityCollisionClass = ____isaac_2Dtypescript_2Ddefinitions.EntityCollisionClass
@@ -12,7 +12,6 @@ local EntityFlag = ____isaac_2Dtypescript_2Ddefinitions.EntityFlag
12
12
  local EntityGridCollisionClass = ____isaac_2Dtypescript_2Ddefinitions.EntityGridCollisionClass
13
13
  local EntityType = ____isaac_2Dtypescript_2Ddefinitions.EntityType
14
14
  local GridEntityType = ____isaac_2Dtypescript_2Ddefinitions.GridEntityType
15
- local ModCallback = ____isaac_2Dtypescript_2Ddefinitions.ModCallback
16
15
  local PickupVariant = ____isaac_2Dtypescript_2Ddefinitions.PickupVariant
17
16
  local PitfallVariant = ____isaac_2Dtypescript_2Ddefinitions.PitfallVariant
18
17
  local RoomType = ____isaac_2Dtypescript_2Ddefinitions.RoomType
@@ -20,6 +19,8 @@ local ____cachedClasses = require("cachedClasses")
20
19
  local game = ____cachedClasses.game
21
20
  local ____DefaultMap = require("classes.DefaultMap")
22
21
  local DefaultMap = ____DefaultMap.DefaultMap
22
+ local ____ModCallbackCustom = require("enums.ModCallbackCustom")
23
+ local ModCallbackCustom = ____ModCallbackCustom.ModCallbackCustom
23
24
  local ____featuresInitialized = require("featuresInitialized")
24
25
  local errorIfFeaturesNotInitialized = ____featuresInitialized.errorIfFeaturesNotInitialized
25
26
  local ____entity = require("functions.entity")
@@ -57,7 +58,7 @@ local ____utils = require("functions.utils")
57
58
  local erange = ____utils.erange
58
59
  local ____exports = require("features.saveDataManager.exports")
59
60
  local saveDataManager = ____exports.saveDataManager
60
- function postNewRoom(self)
61
+ function postNewRoomReordered(self)
61
62
  local roomListIndex = getRoomListIndex(nil)
62
63
  if not v.level.deployedRoomListIndexes:has(roomListIndex) then
63
64
  return
@@ -427,7 +428,7 @@ v = {level = {
427
428
  -- @internal
428
429
  function ____exports.deployJSONRoomInit(self, mod)
429
430
  saveDataManager(nil, "deployJSONRoom", v)
430
- mod:AddCallback(ModCallback.POST_NEW_ROOM, postNewRoom)
431
+ mod:AddCallbackCustom(ModCallbackCustom.POST_NEW_ROOM_REORDERED, postNewRoomReordered)
431
432
  end
432
433
  --- Helper function to deconstruct a vanilla room and set up a custom room in its place.
433
434
  -- Specifically, this will clear the current room of all entities and grid entities, and then spawn
@@ -810,6 +810,7 @@ end
810
810
  --- Logs information about the room to the "log.txt" file.
811
811
  function ____exports.roomCommand(self)
812
812
  logRoom()
813
+ printConsole(nil, "Logged room information to the \"log.txt\" file.")
813
814
  end
814
815
  --- Gives a rotten heart. Provide a number to give a custom amount of hearts. (You can use negative
815
816
  -- numbers to remove hearts.)
@@ -0,0 +1,28 @@
1
+ import { EntityType } from "isaac-typescript-definitions";
2
+ /**
3
+ * Helper function to spawn an entity that will have persistence similar to a pickup.
4
+ *
5
+ * By default, as soon as you leave a room, any spawned entities will be despawned and will not
6
+ * return if the player revisits the room. This means that if you want to have an entity like a
7
+ * pickup, you have to manually respawn it when the player re-enters the room. Use this helper
8
+ * function to avoid having to do any tracking on your own.
9
+ *
10
+ * Conventionally, the word "persistent" refers to `EntityFlag.FLAG_PERSISTENT`, which is used on
11
+ * e.g. familiars to make them appear in every room. On the other hand, pickups are also persistent,
12
+ * but they are not present in every room, only one specific room. This function spawns entities
13
+ * like pickups, not familiars.
14
+ *
15
+ * @returns A tuple containing the entity and the persistent entity index. You can use the index
16
+ * with the `removePersistentEntity` function.
17
+ */
18
+ export declare function spawnPersistentEntity(entityType: EntityType, variant: int, subType: int, position: Vector): [Entity, int];
19
+ /**
20
+ * Helper function to stop an entity spawned with the `spawnPersistentEntity` helper function from
21
+ * respawning.
22
+ *
23
+ * @param persistentEntityIndex The index that was returned by the `spawnPersistentEntity` function.
24
+ * @param removeEntity Optional. True by default. Set to false if you want to stop an entity from
25
+ * being persistent but you don't want to actually remove the currently-spawned
26
+ * entity from the room.
27
+ */
28
+ export declare function removePersistentEntity(persistentEntityIndex: int, removeEntity?: boolean): void;
@@ -0,0 +1,150 @@
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 postEntityRemove, postNewRoomReordered, spawnAndTrack, v
7
+ local ____isaac_2Dtypescript_2Ddefinitions = require("isaac-typescript-definitions")
8
+ local EntityFlag = ____isaac_2Dtypescript_2Ddefinitions.EntityFlag
9
+ local ModCallback = ____isaac_2Dtypescript_2Ddefinitions.ModCallback
10
+ local ____cachedClasses = require("cachedClasses")
11
+ local game = ____cachedClasses.game
12
+ local ____ModCallbackCustom = require("enums.ModCallbackCustom")
13
+ local ModCallbackCustom = ____ModCallbackCustom.ModCallbackCustom
14
+ local ____entity = require("functions.entity")
15
+ local spawn = ____entity.spawn
16
+ local ____roomData = require("functions.roomData")
17
+ local getRoomListIndex = ____roomData.getRoomListIndex
18
+ local ____exports = require("features.saveDataManager.exports")
19
+ local saveDataManager = ____exports.saveDataManager
20
+ function postEntityRemove(self, entity)
21
+ local ptrHash = GetPtrHash(entity)
22
+ local tuple = v.room.spawnedPersistentEntities:get(ptrHash)
23
+ if tuple == nil then
24
+ return
25
+ end
26
+ local index = tuple[1]
27
+ local level = game:GetLevel()
28
+ local previousRoomGridIndex = level:GetPreviousRoomIndex()
29
+ local previousRoomListIndex = getRoomListIndex(nil, previousRoomGridIndex)
30
+ v.level.persistentEntities:set(index, {
31
+ entityType = entity.Type,
32
+ variant = entity.Variant,
33
+ subType = entity.SubType,
34
+ roomListIndex = previousRoomListIndex,
35
+ position = entity.Position
36
+ })
37
+ end
38
+ function postNewRoomReordered(self)
39
+ local roomListIndex = getRoomListIndex(nil)
40
+ for ____, ____value in __TS__Iterator(v.level.persistentEntities:entries()) do
41
+ local index = ____value[1]
42
+ local description = ____value[2]
43
+ do
44
+ if roomListIndex ~= description.roomListIndex then
45
+ goto __continue6
46
+ end
47
+ v.level.persistentEntities:delete(index)
48
+ spawnAndTrack(
49
+ nil,
50
+ description.entityType,
51
+ description.variant,
52
+ description.subType,
53
+ description.position,
54
+ index,
55
+ true
56
+ )
57
+ end
58
+ ::__continue6::
59
+ end
60
+ end
61
+ function spawnAndTrack(self, entityType, variant, subType, position, index, respawning)
62
+ if respawning == nil then
63
+ respawning = false
64
+ end
65
+ local entity = spawn(
66
+ nil,
67
+ entityType,
68
+ variant,
69
+ subType,
70
+ position
71
+ )
72
+ if respawning then
73
+ entity:ClearEntityFlags(EntityFlag.APPEAR)
74
+ end
75
+ local ptrHash = GetPtrHash(entity)
76
+ local tuple = {
77
+ index,
78
+ EntityPtr(entity)
79
+ }
80
+ v.room.spawnedPersistentEntities:set(ptrHash, tuple)
81
+ return entity
82
+ end
83
+ --- Iterates upward as new persistent entities are created.
84
+ local persistentEntityIndexCounter = 0
85
+ v = {
86
+ level = {persistentEntities = __TS__New(Map)},
87
+ room = {spawnedPersistentEntities = __TS__New(Map)}
88
+ }
89
+ ---
90
+ -- @internal
91
+ function ____exports.persistentEntitiesInit(self, mod)
92
+ saveDataManager(nil, "persistentEntities", v)
93
+ mod:AddCallback(ModCallback.POST_ENTITY_REMOVE, postEntityRemove)
94
+ mod:AddCallbackCustom(ModCallbackCustom.POST_NEW_ROOM_REORDERED, postNewRoomReordered)
95
+ end
96
+ --- Helper function to spawn an entity that will have persistence similar to a pickup.
97
+ --
98
+ -- By default, as soon as you leave a room, any spawned entities will be despawned and will not
99
+ -- return if the player revisits the room. This means that if you want to have an entity like a
100
+ -- pickup, you have to manually respawn it when the player re-enters the room. Use this helper
101
+ -- function to avoid having to do any tracking on your own.
102
+ --
103
+ -- Conventionally, the word "persistent" refers to `EntityFlag.FLAG_PERSISTENT`, which is used on
104
+ -- e.g. familiars to make them appear in every room. On the other hand, pickups are also persistent,
105
+ -- but they are not present in every room, only one specific room. This function spawns entities
106
+ -- like pickups, not familiars.
107
+ --
108
+ -- @returns A tuple containing the entity and the persistent entity index. You can use the index
109
+ -- with the `removePersistentEntity` function.
110
+ function ____exports.spawnPersistentEntity(self, entityType, variant, subType, position)
111
+ persistentEntityIndexCounter = persistentEntityIndexCounter + 1
112
+ local entity = spawnAndTrack(
113
+ nil,
114
+ entityType,
115
+ variant,
116
+ subType,
117
+ position,
118
+ persistentEntityIndexCounter
119
+ )
120
+ return {entity, persistentEntityIndexCounter}
121
+ end
122
+ --- Helper function to stop an entity spawned with the `spawnPersistentEntity` helper function from
123
+ -- respawning.
124
+ --
125
+ -- @param persistentEntityIndex The index that was returned by the `spawnPersistentEntity` function.
126
+ -- @param removeEntity Optional. True by default. Set to false if you want to stop an entity from
127
+ -- being persistent but you don't want to actually remove the currently-spawned
128
+ -- entity from the room.
129
+ function ____exports.removePersistentEntity(self, persistentEntityIndex, removeEntity)
130
+ if removeEntity == nil then
131
+ removeEntity = true
132
+ end
133
+ v.level.persistentEntities:delete(persistentEntityIndex)
134
+ for ____, ____value in __TS__Iterator(v.room.spawnedPersistentEntities:entries()) do
135
+ local ptrHash = ____value[1]
136
+ local tuple = ____value[2]
137
+ do
138
+ local index, entityPtr = table.unpack(tuple)
139
+ if index ~= persistentEntityIndex then
140
+ goto __continue13
141
+ end
142
+ v.room.spawnedPersistentEntities:delete(ptrHash)
143
+ if removeEntity and entityPtr.Ref ~= nil then
144
+ entityPtr.Ref:Remove()
145
+ end
146
+ end
147
+ ::__continue13::
148
+ end
149
+ end
150
+ return ____exports
@@ -0,0 +1,3 @@
1
+ /// <reference types="isaac-typescript-definitions" />
2
+ /** Helper function to find out how large a bomb explosion is based on the damage inflicted. */
3
+ export declare function getBombRadiusFromDamage(damage: float): float;
@@ -0,0 +1,12 @@
1
+ local ____exports = {}
2
+ --- Helper function to find out how large a bomb explosion is based on the damage inflicted.
3
+ function ____exports.getBombRadiusFromDamage(self, damage)
4
+ if damage > 175 then
5
+ return 105
6
+ end
7
+ if damage <= 140 then
8
+ return 75
9
+ end
10
+ return 90
11
+ end
12
+ return ____exports
@@ -52,13 +52,13 @@ export declare function getCollectibleGfxFilename(collectibleType: CollectibleTy
52
52
  * and the pedestal pushed to an adjacent tile, but this case should be extremely rare.)
53
53
  * - Mega Chests spawn two collectibles on the exact same position. However, both of them will have
54
54
  * different InitSeeds, so this is not a problem for this indexing scheme.
55
- * - The indexing scheme used is different for collectibles that are inside of a Treasure Room, in
56
- * order to handle the case of the player seeing the same collectible again in a post-Ascent
57
- * Treasure Room. A 5-tuple of stage, stage type, grid index, SubType, and InitSeed is used in
58
- * this case. (Using the room list index or the room grid index is not suitable for this purpose,
59
- * since both of these values can change in the post-Ascent Treasure Room.) Even though there can
60
- * be two Treasure Rooms on an XL floor, both Treasure Rooms should not have collectibles with the
61
- * same grid index, Subtype, and InitSeed.
55
+ * - The indexing scheme used is different for collectibles that are inside of a Treasure Room or
56
+ * Boss Room, in order to handle the case of the player seeing the same collectible again in a
57
+ * post-Ascent Treasure Room or Boss Room. A 5-tuple of stage, stage type, grid index, SubType,
58
+ * and InitSeed is used in this case. (Using the room list index or the room grid index is not
59
+ * suitable for this purpose, since both of these values can change in the post-Ascent rooms.)
60
+ * Even though Treasure Rooms and Boss Rooms are grouped together in this scheme, there probably
61
+ * will not be collectibles with the same grid index, SubType, and InitSeed.
62
62
  */
63
63
  export declare function getCollectibleIndex(collectible: EntityPickup): CollectibleIndex;
64
64
  /**
@@ -176,13 +176,13 @@ end
176
176
  -- and the pedestal pushed to an adjacent tile, but this case should be extremely rare.)
177
177
  -- - Mega Chests spawn two collectibles on the exact same position. However, both of them will have
178
178
  -- different InitSeeds, so this is not a problem for this indexing scheme.
179
- -- - The indexing scheme used is different for collectibles that are inside of a Treasure Room, in
180
- -- order to handle the case of the player seeing the same collectible again in a post-Ascent
181
- -- Treasure Room. A 5-tuple of stage, stage type, grid index, SubType, and InitSeed is used in
182
- -- this case. (Using the room list index or the room grid index is not suitable for this purpose,
183
- -- since both of these values can change in the post-Ascent Treasure Room.) Even though there can
184
- -- be two Treasure Rooms on an XL floor, both Treasure Rooms should not have collectibles with the
185
- -- same grid index, Subtype, and InitSeed.
179
+ -- - The indexing scheme used is different for collectibles that are inside of a Treasure Room or
180
+ -- Boss Room, in order to handle the case of the player seeing the same collectible again in a
181
+ -- post-Ascent Treasure Room or Boss Room. A 5-tuple of stage, stage type, grid index, SubType,
182
+ -- and InitSeed is used in this case. (Using the room list index or the room grid index is not
183
+ -- suitable for this purpose, since both of these values can change in the post-Ascent rooms.)
184
+ -- Even though Treasure Rooms and Boss Rooms are grouped together in this scheme, there probably
185
+ -- will not be collectibles with the same grid index, SubType, and InitSeed.
186
186
  function ____exports.getCollectibleIndex(self, collectible)
187
187
  if not isCollectible(nil, collectible) then
188
188
  local entityID = getEntityID(nil, collectible)
@@ -195,7 +195,7 @@ function ____exports.getCollectibleIndex(self, collectible)
195
195
  local roomType = room:GetType()
196
196
  local gridIndex = room:GetGridIndex(collectible.Position)
197
197
  local roomListIndex = getRoomListIndex(nil)
198
- if roomType == RoomType.TREASURE then
198
+ if roomType == RoomType.TREASURE or roomType == RoomType.BOSS then
199
199
  return (((((((tostring(stage) .. ",") .. tostring(stageType)) .. ",") .. tostring(gridIndex)) .. ",") .. tostring(collectible.SubType)) .. ",") .. tostring(collectible.InitSeed)
200
200
  end
201
201
  return (((((tostring(roomListIndex) .. ",") .. tostring(gridIndex)) .. ",") .. tostring(collectible.SubType)) .. ",") .. tostring(collectible.InitSeed)
@@ -9,9 +9,6 @@ interface CopyColorReturn {
9
9
  [SerializationType.SERIALIZE]: SerializedColor;
10
10
  [SerializationType.DESERIALIZE]: Color;
11
11
  }
12
- /**
13
- * @category color
14
- */
15
12
  export declare function colorEquals(color1: Color, color2: Color): boolean;
16
13
  /**
17
14
  * Helper function to copy a `Color` object.
@@ -19,27 +16,16 @@ export declare function colorEquals(color1: Color, color2: Color): boolean;
19
16
  * @param color The Color object to copy. In the case of deserialization, this will actually be a
20
17
  * Lua table instead of an instantiated Color class.
21
18
  * @param serializationType Default is `SerializationType.NONE`.
22
- * @category color
23
19
  */
24
20
  export declare function copyColor<C extends Color | SerializedColor, S extends SerializationType>(color: C, serializationType: S): CopyColorReturn[S];
25
21
  export declare function copyColor<C extends Color | SerializedColor>(color: C): CopyColorReturn[SerializationType.NONE];
26
- /**
27
- * Returns `Color(1, 1, 1)`.
28
- *
29
- * @category color
30
- */
22
+ /** Returns `Color(1, 1, 1)`. */
31
23
  export declare function getDefaultColor(): Color;
32
- /**
33
- * Helper function to check if something is an instantiated Color object.
34
- *
35
- * @category color
36
- */
24
+ /** Helper function to check if something is an instantiated Color object. */
37
25
  export declare function isColor(object: unknown): object is Color;
38
26
  /**
39
27
  * Used to determine is the given table is a serialized `Color` object created by the save data
40
28
  * manager and/or the `deepCopy` function.
41
- *
42
- * @category color
43
29
  */
44
30
  export declare function isSerializedColor(object: unknown): object is SerializedColor;
45
31
  export {};
@@ -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
@@ -1,4 +1,11 @@
1
1
  import { Direction } from "isaac-typescript-definitions";
2
+ /**
3
+ * Helper function to convert the degrees of an angle to the `Direction` enum.
4
+ *
5
+ * Note that this function considers 0 degrees to be pointing to the right, which is unusual because
6
+ * 0 normally corresponds to up. (This corresponds to how the `Vector.GetAngleDegrees` method
7
+ * works.)
8
+ */
2
9
  export declare function angleToDirection(angleDegrees: int): Direction;
3
10
  export declare function directionToDegrees(direction: Direction): int;
4
11
  export declare function directionToVector(direction: Direction): Vector;
@@ -7,6 +7,11 @@ local ____directionToDegrees = require("objects.directionToDegrees")
7
7
  local DIRECTION_TO_DEGREES = ____directionToDegrees.DIRECTION_TO_DEGREES
8
8
  local ____directionToVector = require("objects.directionToVector")
9
9
  local DIRECTION_TO_VECTOR = ____directionToVector.DIRECTION_TO_VECTOR
10
+ --- Helper function to convert the degrees of an angle to the `Direction` enum.
11
+ --
12
+ -- Note that this function considers 0 degrees to be pointing to the right, which is unusual because
13
+ -- 0 normally corresponds to up. (This corresponds to how the `Vector.GetAngleDegrees` method
14
+ -- works.)
10
15
  function ____exports.angleToDirection(self, angleDegrees)
11
16
  local positiveDegrees = angleDegrees
12
17
  while positiveDegrees < 0 do
@@ -14,18 +19,18 @@ function ____exports.angleToDirection(self, angleDegrees)
14
19
  end
15
20
  local normalizedDegrees = positiveDegrees % 360
16
21
  if normalizedDegrees < 45 then
17
- return Direction.UP
22
+ return Direction.RIGHT
18
23
  end
19
24
  if normalizedDegrees < 135 then
20
- return Direction.RIGHT
25
+ return Direction.DOWN
21
26
  end
22
27
  if normalizedDegrees < 225 then
23
- return Direction.DOWN
28
+ return Direction.LEFT
24
29
  end
25
30
  if normalizedDegrees < 315 then
26
- return Direction.RIGHT
31
+ return Direction.UP
27
32
  end
28
- return Direction.UP
33
+ return Direction.RIGHT
29
34
  end
30
35
  function ____exports.directionToDegrees(self, direction)
31
36
  return DIRECTION_TO_DEGREES[direction]
@@ -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
@@ -100,6 +100,8 @@ export declare function getPlayerCollectibleCount(player: EntityPlayer, ...colle
100
100
  * the player has.
101
101
  */
102
102
  export declare function getPlayerCollectibleMap(player: EntityPlayer): Map<CollectibleType, int>;
103
+ /** Helper function to get the player from a tear, laser, bomb, etc. */
104
+ export declare function getPlayerFromTear(entity: Entity): EntityPlayer | undefined;
103
105
  /**
104
106
  * Returns the number of red hearts that the player has, excluding any rotten hearts. For example,
105
107
  * if the player has one full black heart, one full soul heart, and one half black heart, this
@@ -207,6 +209,11 @@ export declare function isBethany(player: EntityPlayer): boolean;
207
209
  * for. Returns true if the player is any of the supplied characters.
208
210
  */
209
211
  export declare function isCharacter(player: EntityPlayer, ...characters: PlayerType[]): boolean;
212
+ /**
213
+ * Helper function to see if a damage source is from a player. Use this instead of comparing to the
214
+ * entity directly because it takes familiars into account.
215
+ */
216
+ export declare function isDamageFromPlayer(damageSource: Entity): boolean;
210
217
  /**
211
218
  * Helper function for detecting when a player is Eden or Tainted Eden. Useful for situations where
212
219
  * you want to know if the starting stats were randomized, for example.
@@ -15,6 +15,7 @@ local ActiveSlot = ____isaac_2Dtypescript_2Ddefinitions.ActiveSlot
15
15
  local CacheFlag = ____isaac_2Dtypescript_2Ddefinitions.CacheFlag
16
16
  local Challenge = ____isaac_2Dtypescript_2Ddefinitions.Challenge
17
17
  local CollectibleType = ____isaac_2Dtypescript_2Ddefinitions.CollectibleType
18
+ local FamiliarVariant = ____isaac_2Dtypescript_2Ddefinitions.FamiliarVariant
18
19
  local NullItemID = ____isaac_2Dtypescript_2Ddefinitions.NullItemID
19
20
  local PlayerForm = ____isaac_2Dtypescript_2Ddefinitions.PlayerForm
20
21
  local PlayerType = ____isaac_2Dtypescript_2Ddefinitions.PlayerType
@@ -377,6 +378,30 @@ function ____exports.getPlayerCollectibleMap(self, player)
377
378
  end
378
379
  return collectibleMap
379
380
  end
381
+ --- Helper function to get the player from a tear, laser, bomb, etc.
382
+ function ____exports.getPlayerFromTear(self, entity)
383
+ if entity.Parent ~= nil then
384
+ local player = entity.Parent:ToPlayer()
385
+ if player ~= nil then
386
+ return player
387
+ end
388
+ local familiar = entity.Parent:ToFamiliar()
389
+ if familiar ~= nil and familiar.Variant == FamiliarVariant.INCUBUS then
390
+ return familiar.Player
391
+ end
392
+ end
393
+ if entity.SpawnerEntity ~= nil then
394
+ local player = entity.SpawnerEntity:ToPlayer()
395
+ if player ~= nil then
396
+ return player
397
+ end
398
+ local familiar = entity.SpawnerEntity:ToFamiliar()
399
+ if familiar ~= nil and familiar.Variant == FamiliarVariant.INCUBUS then
400
+ return familiar.Player
401
+ end
402
+ end
403
+ return nil
404
+ end
380
405
  --- Returns the number of red hearts that the player has, excluding any rotten hearts. For example,
381
406
  -- if the player has one full black heart, one full soul heart, and one half black heart, this
382
407
  -- function returns 3.
@@ -567,6 +592,16 @@ function ____exports.isBethany(self, player)
567
592
  local character = player:GetPlayerType()
568
593
  return character == PlayerType.BETHANY or character == PlayerType.BETHANY_B
569
594
  end
595
+ --- Helper function to see if a damage source is from a player. Use this instead of comparing to the
596
+ -- entity directly because it takes familiars into account.
597
+ function ____exports.isDamageFromPlayer(self, damageSource)
598
+ local player = damageSource:ToPlayer()
599
+ if player ~= nil then
600
+ return true
601
+ end
602
+ local indirectPlayer = ____exports.getPlayerFromTear(nil, damageSource)
603
+ return indirectPlayer ~= nil
604
+ end
570
605
  --- Helper function for detecting when a player is Eden or Tainted Eden. Useful for situations where
571
606
  -- you want to know if the starting stats were randomized, for example.
572
607
  function ____exports.isEden(self, player)
@@ -684,9 +719,9 @@ function ____exports.setActiveItem(self, player, collectibleType, activeSlot, ch
684
719
  itemPool:RemoveCollectible(collectibleType)
685
720
  end
686
721
  repeat
687
- local ____switch113 = activeSlot
688
- local ____cond113 = ____switch113 == ActiveSlot.PRIMARY
689
- if ____cond113 then
722
+ local ____switch122 = activeSlot
723
+ local ____cond122 = ____switch122 == ActiveSlot.PRIMARY
724
+ if ____cond122 then
690
725
  do
691
726
  if primaryCollectibleType ~= CollectibleType.NULL then
692
727
  player:RemoveCollectible(primaryCollectibleType)
@@ -695,8 +730,8 @@ function ____exports.setActiveItem(self, player, collectibleType, activeSlot, ch
695
730
  break
696
731
  end
697
732
  end
698
- ____cond113 = ____cond113 or ____switch113 == ActiveSlot.SECONDARY
699
- if ____cond113 then
733
+ ____cond122 = ____cond122 or ____switch122 == ActiveSlot.SECONDARY
734
+ if ____cond122 then
700
735
  do
701
736
  if primaryCollectibleType ~= CollectibleType.NULL then
702
737
  player:RemoveCollectible(primaryCollectibleType)
@@ -711,16 +746,16 @@ function ____exports.setActiveItem(self, player, collectibleType, activeSlot, ch
711
746
  break
712
747
  end
713
748
  end
714
- ____cond113 = ____cond113 or ____switch113 == ActiveSlot.POCKET
715
- if ____cond113 then
749
+ ____cond122 = ____cond122 or ____switch122 == ActiveSlot.POCKET
750
+ if ____cond122 then
716
751
  do
717
752
  player:SetPocketActiveItem(collectibleType, activeSlot, keepInPools)
718
753
  player:SetActiveCharge(charge, activeSlot)
719
754
  break
720
755
  end
721
756
  end
722
- ____cond113 = ____cond113 or ____switch113 == ActiveSlot.POCKET_SINGLE_USE
723
- if ____cond113 then
757
+ ____cond122 = ____cond122 or ____switch122 == ActiveSlot.POCKET_SINGLE_USE
758
+ if ____cond122 then
724
759
  do
725
760
  player:SetPocketActiveItem(collectibleType, activeSlot, keepInPools)
726
761
  break
@@ -12,6 +12,8 @@ export declare function addPlayerHealthType(player: EntityPlayer, healthType: He
12
12
  */
13
13
  export declare function getPlayerHealth(player: EntityPlayer): PlayerHealth;
14
14
  export declare function getPlayerHealthType(player: EntityPlayer, healthType: HealthType): int;
15
+ export declare function playerConvertBlackHeartsToSoulHearts(player: EntityPlayer): void;
16
+ export declare function playerConvertSoulHeartsToBlackHearts(player: EntityPlayer): void;
15
17
  export declare function removeAllPlayerHealth(player: EntityPlayer): void;
16
18
  /**
17
19
  * Helper function to set a player's health to a specific state. You can use this in combination