isaacscript-common 9.1.0 → 9.2.1

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.
@@ -1 +1 @@
1
- {"version":3,"file":"postPlayerCollectible.d.ts","sourceRoot":"","sources":["../../src/callbacks/postPlayerCollectible.ts"],"names":[],"mappings":";AA4CA,wBAAgB,kCAAkC,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI,CAIjE"}
1
+ {"version":3,"file":"postPlayerCollectible.d.ts","sourceRoot":"","sources":["../../src/callbacks/postPlayerCollectible.ts"],"names":[],"mappings":";AAgDA,wBAAgB,kCAAkC,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI,CAUjE"}
@@ -1,6 +1,6 @@
1
1
  local ____lualib = require("lualib_bundle")
2
- local Map = ____lualib.Map
3
2
  local __TS__New = ____lualib.__TS__New
3
+ local Map = ____lualib.Map
4
4
  local Set = ____lualib.Set
5
5
  local __TS__Spread = ____lualib.__TS__Spread
6
6
  local __TS__SparseArrayNew = ____lualib.__TS__SparseArrayNew
@@ -9,22 +9,28 @@ local __TS__SparseArraySpread = ____lualib.__TS__SparseArraySpread
9
9
  local __TS__Iterator = ____lualib.__TS__Iterator
10
10
  local __TS__ArraySort = ____lualib.__TS__ArraySort
11
11
  local ____exports = {}
12
- local hasSubscriptions, postPEffectUpdate, collectibleCountChanged, checkActiveItemsChanged, activeItemsChanged, v
12
+ local hasSubscriptions, updateCollectibleMapAndFire, useItemD4, postPEffectUpdate, checkActiveItemsChanged, entityTakeDmgPlayer, v
13
13
  local ____isaac_2Dtypescript_2Ddefinitions = require("isaac-typescript-definitions")
14
14
  local ActiveSlot = ____isaac_2Dtypescript_2Ddefinitions.ActiveSlot
15
15
  local CollectibleType = ____isaac_2Dtypescript_2Ddefinitions.CollectibleType
16
+ local DamageFlag = ____isaac_2Dtypescript_2Ddefinitions.DamageFlag
17
+ local EntityType = ____isaac_2Dtypescript_2Ddefinitions.EntityType
16
18
  local ModCallback = ____isaac_2Dtypescript_2Ddefinitions.ModCallback
19
+ local PlayerType = ____isaac_2Dtypescript_2Ddefinitions.PlayerType
17
20
  local ____DefaultMap = require("classes.DefaultMap")
18
21
  local DefaultMap = ____DefaultMap.DefaultMap
22
+ local ____runInNFrames = require("features.runInNFrames")
23
+ local runNextGameFrame = ____runInNFrames.runNextGameFrame
19
24
  local ____exports = require("features.saveDataManager.exports")
20
25
  local saveDataManager = ____exports.saveDataManager
21
26
  local ____array = require("functions.array")
22
27
  local arrayEquals = ____array.arrayEquals
23
28
  local ____enums = require("functions.enums")
24
29
  local getEnumValues = ____enums.getEnumValues
30
+ local ____flag = require("functions.flag")
31
+ local hasFlag = ____flag.hasFlag
25
32
  local ____playerDataStructures = require("functions.playerDataStructures")
26
33
  local defaultMapGetPlayer = ____playerDataStructures.defaultMapGetPlayer
27
- local mapGetPlayer = ____playerDataStructures.mapGetPlayer
28
34
  local mapSetPlayer = ____playerDataStructures.mapSetPlayer
29
35
  local ____players = require("functions.players")
30
36
  local getPlayerCollectibleMap = ____players.getPlayerCollectibleMap
@@ -39,26 +45,7 @@ local postPlayerCollectibleRemovedHasSubscriptions = ____postPlayerCollectibleRe
39
45
  function hasSubscriptions(self)
40
46
  return postPlayerCollectibleAddedHasSubscriptions(nil) or postPlayerCollectibleRemovedHasSubscriptions(nil)
41
47
  end
42
- function postPEffectUpdate(self, player)
43
- if not hasSubscriptions(nil) then
44
- return
45
- end
46
- local oldCollectibleCount = mapGetPlayer(nil, v.run.playersCollectibleCount, player)
47
- local newCollectibleCount = player:GetCollectibleCount()
48
- mapSetPlayer(nil, v.run.playersCollectibleCount, player, newCollectibleCount)
49
- if oldCollectibleCount == nil then
50
- return
51
- end
52
- local difference = newCollectibleCount - oldCollectibleCount
53
- if difference > 0 then
54
- collectibleCountChanged(nil, player, difference)
55
- elseif difference < 0 then
56
- collectibleCountChanged(nil, player, difference * -1)
57
- elseif difference == 0 then
58
- checkActiveItemsChanged(nil, player)
59
- end
60
- end
61
- function collectibleCountChanged(self, player, numCollectiblesChanged)
48
+ function updateCollectibleMapAndFire(self, player, numCollectiblesChanged)
62
49
  local oldCollectibleMap = defaultMapGetPlayer(nil, v.run.playersCollectibleMap, player)
63
50
  local newCollectibleMap = getPlayerCollectibleMap(nil, player)
64
51
  mapSetPlayer(nil, v.run.playersCollectibleMap, player, newCollectibleMap)
@@ -68,12 +55,12 @@ function collectibleCountChanged(self, player, numCollectiblesChanged)
68
55
  ____array_0,
69
56
  __TS__Spread(newCollectibleMap:keys())
70
57
  )
71
- local collectibleTypeSet = __TS__New(
58
+ local collectibleTypesSet = __TS__New(
72
59
  ____Set_1,
73
60
  {__TS__SparseArraySpread(____array_0)}
74
61
  )
75
62
  local numFired = 0
76
- for ____, collectibleType in __TS__Iterator(collectibleTypeSet:values()) do
63
+ for ____, collectibleType in __TS__Iterator(collectibleTypesSet:values()) do
77
64
  local oldNum = oldCollectibleMap:get(collectibleType) or 0
78
65
  local newNum = newCollectibleMap:get(collectibleType) or 0
79
66
  local difference = newNum - oldNum
@@ -96,6 +83,26 @@ function collectibleCountChanged(self, player, numCollectiblesChanged)
96
83
  end
97
84
  end
98
85
  end
86
+ function useItemD4(self, _collectibleType, _rng, player)
87
+ updateCollectibleMapAndFire(nil, player, nil)
88
+ return nil
89
+ end
90
+ function postPEffectUpdate(self, player)
91
+ if not hasSubscriptions(nil) then
92
+ return
93
+ end
94
+ local oldCollectibleCount = defaultMapGetPlayer(nil, v.run.playersCollectibleCount, player)
95
+ local newCollectibleCount = player:GetCollectibleCount()
96
+ mapSetPlayer(nil, v.run.playersCollectibleCount, player, newCollectibleCount)
97
+ local difference = newCollectibleCount - oldCollectibleCount
98
+ if difference > 0 then
99
+ updateCollectibleMapAndFire(nil, player, difference)
100
+ elseif difference < 0 then
101
+ updateCollectibleMapAndFire(nil, player, difference * -1)
102
+ elseif difference == 0 then
103
+ checkActiveItemsChanged(nil, player)
104
+ end
105
+ end
99
106
  function checkActiveItemsChanged(self, player)
100
107
  local activeItemMap = defaultMapGetPlayer(nil, v.run.playersActiveItemMap, player)
101
108
  local oldCollectibleTypes = {}
@@ -110,44 +117,40 @@ function checkActiveItemsChanged(self, player)
110
117
  __TS__ArraySort(oldCollectibleTypes)
111
118
  __TS__ArraySort(newCollectibleTypes)
112
119
  if not arrayEquals(nil, oldCollectibleTypes, newCollectibleTypes) then
113
- local ____Set_3 = Set
114
- local ____array_2 = __TS__SparseArrayNew(table.unpack(oldCollectibleTypes))
115
- __TS__SparseArrayPush(
116
- ____array_2,
117
- table.unpack(newCollectibleTypes)
118
- )
119
- local collectibleTypeSet = __TS__New(
120
- ____Set_3,
121
- {__TS__SparseArraySpread(____array_2)}
122
- )
123
- activeItemsChanged(nil, player, collectibleTypeSet)
120
+ updateCollectibleMapAndFire(nil, player, nil)
124
121
  end
125
122
  end
126
- function activeItemsChanged(self, player, collectibleTypesSet)
127
- local oldCollectibleMap = defaultMapGetPlayer(nil, v.run.playersCollectibleMap, player)
128
- local newCollectibleMap = getPlayerCollectibleMap(nil, player)
129
- mapSetPlayer(nil, v.run.playersCollectibleMap, player, newCollectibleMap)
130
- for ____, collectibleType in __TS__Iterator(collectibleTypesSet:values()) do
131
- local oldNum = oldCollectibleMap:get(collectibleType) or 0
132
- local newNum = newCollectibleMap:get(collectibleType) or 0
133
- local difference = newNum - oldNum
134
- local increased = difference > 0
135
- local absoluteDifference = math.abs(difference)
136
- ____repeat(
137
- nil,
138
- absoluteDifference,
139
- function()
140
- if increased then
141
- postPlayerCollectibleAddedFire(nil, player, collectibleType)
142
- else
143
- postPlayerCollectibleRemovedFire(nil, player, collectibleType)
144
- end
145
- end
146
- )
123
+ function entityTakeDmgPlayer(self, entity, _amount, damageFlags, _source, _countdownFrames)
124
+ if hasFlag(nil, damageFlags, DamageFlag.FAKE) then
125
+ return nil
126
+ end
127
+ local player = entity:ToPlayer()
128
+ if player == nil then
129
+ return nil
147
130
  end
131
+ local character = player:GetPlayerType()
132
+ if character ~= PlayerType.EDEN_B then
133
+ return nil
134
+ end
135
+ local ptr = EntityPtr(player)
136
+ runNextGameFrame(
137
+ nil,
138
+ function()
139
+ local futureEntity = ptr.Ref
140
+ if futureEntity == nil then
141
+ return
142
+ end
143
+ local futurePlayer = futureEntity:ToPlayer()
144
+ if futurePlayer == nil then
145
+ return
146
+ end
147
+ updateCollectibleMapAndFire(nil, player, nil)
148
+ end
149
+ )
150
+ return nil
148
151
  end
149
152
  v = {run = {
150
- playersCollectibleCount = __TS__New(Map),
153
+ playersCollectibleCount = __TS__New(DefaultMap, 0),
151
154
  playersCollectibleMap = __TS__New(
152
155
  DefaultMap,
153
156
  function() return __TS__New(Map) end
@@ -159,6 +162,8 @@ v = {run = {
159
162
  }}
160
163
  function ____exports.postPlayerCollectibleCallbacksInit(self, mod)
161
164
  saveDataManager(nil, "postPlayerCollectible", v, hasSubscriptions)
165
+ mod:AddCallback(ModCallback.POST_USE_ITEM, useItemD4, CollectibleType.D4)
162
166
  mod:AddCallback(ModCallback.POST_PEFFECT_UPDATE, postPEffectUpdate)
167
+ mod:AddCallback(ModCallback.ENTITY_TAKE_DMG, entityTakeDmgPlayer, EntityType.PLAYER)
163
168
  end
164
169
  return ____exports
@@ -892,7 +892,8 @@ export declare enum ModCallbackCustom {
892
892
  POST_PLAYER_CHANGE_TYPE = 57,
893
893
  /**
894
894
  * Fires from the `POST_PEFFECT_UPDATE` callback when a player's collectible count is higher than
895
- * what it was on the previous frame or when a new active collectible is acquired.
895
+ * what it was on the previous frame, or when the active items change, or when the build is
896
+ * rerolled.
896
897
  *
897
898
  * When registering the callback, takes an optional second argument that will make the callback
898
899
  * only fire if the collectible matches the `CollectibleType` provided.
@@ -907,7 +908,8 @@ export declare enum ModCallbackCustom {
907
908
  POST_PLAYER_COLLECTIBLE_ADDED = 58,
908
909
  /**
909
910
  * Fires from the `POST_PEFFECT_UPDATE` callback when a player's collectible count is lower than
910
- * what it was on the previous frame or when an active collectible is no longer present.
911
+ * what it was on the previous frame, or when the active items change, or when the build is
912
+ * rerolled.
911
913
  *
912
914
  * When registering the callback, takes an optional second argument that will make the callback
913
915
  * only fire if the collectible matches the `CollectibleType` provided.
@@ -1 +1 @@
1
- {"version":3,"file":"ModCallbackCustom.d.ts","sourceRoot":"","sources":["../../src/enums/ModCallbackCustom.ts"],"names":[],"mappings":"AASA;;;;;;;GAOG;AACH,oBAAY,iBAAiB;IAC3B;;;;;;;;;;OAUG;IACH,oBAAoB,IAAA;IAEpB;;;;;;;;;;OAUG;IACH,mBAAmB,IAAA;IAEnB;;;;;;;;;OASG;IACH,kBAAkB,IAAA;IAElB;;;;;;;;;;;;OAYG;IACH,mBAAmB,IAAA;IAEnB;;;;;;OAMG;IACH,eAAe,IAAA;IAEf;;;;;;;;;;;;;OAaG;IACH,sBAAsB,IAAA;IAEtB;;;;;;;;;;;;;;;OAeG;IACH,2BAA2B,IAAA;IAE3B;;;;;;;;OAQG;IACH,oBAAoB,IAAA;IAEpB;;;;;;;;;;;;;;;OAeG;IACH,sBAAsB,IAAA;IAEtB;;;;;;;;;;;;;;;OAeG;IACH,kBAAkB,IAAA;IAElB;;;;;;;;;;;;;OAaG;IACH,wBAAwB,KAAA;IAExB;;;;;;;;;OASG;IACH,gBAAgB,KAAA;IAEhB;;;;;;;;;OASG;IACH,gBAAgB,KAAA;IAEhB;;;;;;;;;;;;OAYG;IACH,qBAAqB,KAAA;IAErB;;;;;;;;;;;;;;OAcG;IACH,yBAAyB,KAAA;IAEzB;;;;;;;OAOG;IACH,YAAY,KAAA;IAEZ;;;;;;;;;;;;OAYG;IACH,uBAAuB,KAAA;IAEvB;;;;;;;;;;;;;;;OAeG;IACH,2BAA2B,KAAA;IAE3B;;;;;;;;;;OAUG;IACH,kBAAkB,KAAA;IAElB;;;;;;;;;;;OAWG;IACH,eAAe,KAAA;IAEf;;;;;;;;;;;OAWG;IACH,SAAS,KAAA;IAET;;;;;;;;;OASG;IACH,2BAA2B,KAAA;IAE3B;;;;;;;;;OASG;IACH,gCAAgC,KAAA;IAEhC;;;;;;OAMG;IACH,oBAAoB,KAAA;IAEpB;;;;;;;;;;;;;;OAcG;IACH,uBAAuB,KAAA;IAEvB;;;;;;;;;;;;;;;;;OAiBG;IACH,0BAA0B,KAAA;IAE1B;;;;;;;;;;;;;OAaG;IACH,8BAA8B,KAAA;IAE9B;;;;;;;;;;;;;;OAcG;IACH,iCAAiC,KAAA;IAEjC;;;;;;;;;;;;;OAaG;IACH,4BAA4B,KAAA;IAE5B;;;;;;;;;;;;;OAaG;IACH,8BAA8B,KAAA;IAE9B;;;;;;;;;;;;;OAaG;IACH,8BAA8B,KAAA;IAE9B;;;;;;;;;;;;;;;OAeG;IACH,qCAAqC,KAAA;IAErC;;;;;;;;;;;;;OAaG;IACH,8BAA8B,KAAA;IAE9B;;;;;;;;;;;;;;;;;OAiBG;IACH,qBAAqB,KAAA;IAErB;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,uBAAuB,KAAA;IAEvB;;;;;;;;;;;;;;OAcG;IACH,uBAAuB,KAAA;IAEvB;;;;;;;;;;;;;;;;;OAiBG;IACH,8BAA8B,KAAA;IAE9B;;;;;;;;;;;;;;OAcG;IACH,uBAAuB,KAAA;IAEvB;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,wBAAwB,KAAA;IAExB;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,mBAAmB,KAAA;IAEnB;;;;;;;;;;;;;;;;;;OAkBG;IACH,gBAAgB,KAAA;IAEhB;;;;;;;;;;;;OAYG;IACH,oBAAoB,KAAA;IAEpB;;;;;;;;;;;;OAYG;IACH,oBAAoB,KAAA;IAEpB;;;;;;;;;;;;;;;OAeG;IACH,wBAAwB,KAAA;IAExB;;;;;;;;;OASG;IACH,mBAAmB,KAAA;IAEnB;;;;;;;;;;;;;;;OAeG;IACH,uBAAuB,KAAA;IAEvB;;;;;;;;;;;;OAYG;IACH,kBAAkB,KAAA;IAElB;;;;;;;;;;;;;;;;OAgBG;IACH,sBAAsB,KAAA;IAEtB;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,6BAA6B,KAAA;IAE7B;;;;;;;;;;;OAWG;IACH,mBAAmB,KAAA;IAEnB;;;;;;;;;;;;;OAaG;IACH,sBAAsB,KAAA;IAEtB;;;;;;;;;;;;OAYG;IACH,qBAAqB,KAAA;IAErB;;;;;;;;;;;;;;OAcG;IACH,yBAAyB,KAAA;IAEzB;;;;;;;;;OASG;IACH,eAAe,KAAA;IAEf;;;;;;;;;OASG;IACH,eAAe,KAAA;IAEf;;;;;;;;;;;;;;;;;;OAkBG;IACH,yBAAyB,KAAA;IAEzB;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BG;IACH,uBAAuB,KAAA;IAEvB;;;;;;;;;;;;;;;;OAgBG;IACH,uBAAuB,KAAA;IAEvB;;;;;;;;;;;;;OAaG;IACH,6BAA6B,KAAA;IAE7B;;;;;;;;;;;;;OAaG;IACH,+BAA+B,KAAA;IAE/B;;;;;;;;;;;;;;;OAeG;IACH,wBAAwB,KAAA;IAExB;;;;;;;;;;;;;;;;;;;OAmBG;IACH,sBAAsB,KAAA;IAEtB;;;;;;;;;;;;;;;;;OAiBG;IACH,qBAAqB,KAAA;IAErB;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,4BAA4B,KAAA;IAE5B;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,4BAA4B,KAAA;IAE5B;;;;;;;;;OASG;IACH,gBAAgB,KAAA;IAEhB;;;;;;;;;OASG;IACH,gBAAgB,KAAA;IAEhB;;;;;;;;;OASG;IACH,0BAA0B,KAAA;IAE1B;;;;;;;;;OASG;IACH,0BAA0B,KAAA;IAE1B;;;;;;;;;;;;OAYG;IACH,yBAAyB,KAAA;IAEzB;;;;;;;;;;;;OAYG;IACH,aAAa,KAAA;IAEb;;;;;;;;;OASG;IACH,gBAAgB,KAAA;IAEhB;;;;;;;;;OASG;IACH,gBAAgB,KAAA;IAEhB;;;;;;;;;;OAUG;IACH,uBAAuB,KAAA;IAEvB;;;;;;;;;;;;OAYG;IACH,cAAc,KAAA;IAEd;;;;;;;;;OASG;IACH,2BAA2B,KAAA;IAE3B;;;;;;;;;;;;;;;;;OAiBG;IACH,mBAAmB,KAAA;IAEnB;;;;;;;;;;;;OAYG;IACH,mBAAmB,KAAA;IAEnB;;;;;;;;;;;;;;OAcG;IACH,cAAc,KAAA;IAEd;;;;;;;;;OASG;IACH,gBAAgB,KAAA;IAEhB;;;;;;;;;OASG;IACH,gBAAgB,KAAA;IAEhB;;;;;;;;;OASG;IACH,kBAAkB,KAAA;IAElB;;;;;;;;;OASG;IACH,kBAAkB,KAAA;IAElB;;;;;;;;;;;;;OAaG;IACH,mBAAmB,KAAA;IAEnB;;;;;;;;;;;;OAYG;IACH,wBAAwB,KAAA;IAExB;;;;;;;;;OASG;IACH,eAAe,KAAA;IAEf;;;;;;;;;OASG;IACH,eAAe,KAAA;IAEf;;;;;;;;;;;;;;;;OAgBG;IACH,mBAAmB,KAAA;IAEnB;;;;;;;;;;;;OAYG;IACH,kBAAkB,KAAA;IAElB;;;;;;;;;;;;;OAaG;IACH,iBAAiB,KAAA;IAEjB;;;;;;;;;;;;;;;;OAgBG;IACH,iBAAiB,KAAA;IAEjB;;;;;;;;;;;;;;;;;OAiBG;IACH,eAAe,KAAA;IAEf;;;;;;;;;;;;OAYG;IACH,aAAa,KAAA;CACd"}
1
+ {"version":3,"file":"ModCallbackCustom.d.ts","sourceRoot":"","sources":["../../src/enums/ModCallbackCustom.ts"],"names":[],"mappings":"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"}
@@ -4,12 +4,6 @@ import { LevelStage, StageType } from "isaac-typescript-definitions";
4
4
  * want to create a custom trapdoor that goes to a vanilla stage instead, use the
5
5
  * `spawnCustomTrapdoorToVanilla` helper function.
6
6
  *
7
- * Custom trapdoors can have one or more of the following attributes:
8
- *
9
- * - custom destination (or custom logic for after the player enters)
10
- * - custom graphics
11
- * - custom logic for opening/closing
12
- *
13
7
  * Under the hood, the custom trapdoor is represented by a decoration grid entity and is manually
14
8
  * respawned every time the player re-enters the room.
15
9
  *
@@ -1 +1 @@
1
- {"version":3,"file":"exports.d.ts","sourceRoot":"","sources":["../../../src/features/customTrapdoor/exports.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAOrE;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,mBAAmB,CACjC,mBAAmB,EAAE,GAAG,GAAG,MAAM,EACjC,eAAe,EAAE,MAAM,EACvB,mBAAmB,EAAE,GAAG,EACxB,QAAQ,SAAmC,EAC3C,SAAS,CAAC,EAAE,OAAO,GAClB,UAAU,CAcZ;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,4BAA4B,CAC1C,mBAAmB,EAAE,GAAG,GAAG,MAAM,EACjC,KAAK,CAAC,EAAE,UAAU,EAClB,SAAS,CAAC,EAAE,SAAS,EACrB,QAAQ,SAAmC,EAC3C,SAAS,CAAC,EAAE,OAAO,GAClB,UAAU,CAkBZ"}
1
+ {"version":3,"file":"exports.d.ts","sourceRoot":"","sources":["../../../src/features/customTrapdoor/exports.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAOrE;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,mBAAmB,CACjC,mBAAmB,EAAE,GAAG,GAAG,MAAM,EACjC,eAAe,EAAE,MAAM,EACvB,mBAAmB,EAAE,GAAG,EACxB,QAAQ,SAAmC,EAC3C,SAAS,CAAC,EAAE,OAAO,GAClB,UAAU,CAcZ;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,4BAA4B,CAC1C,mBAAmB,EAAE,GAAG,GAAG,MAAM,EACjC,KAAK,CAAC,EAAE,UAAU,EAClB,SAAS,CAAC,EAAE,SAAS,EACrB,QAAQ,SAAmC,EAC3C,SAAS,CAAC,EAAE,OAAO,GAClB,UAAU,CAkBZ"}
@@ -12,12 +12,6 @@ local spawnCustomTrapdoorToDestination = ____spawn.spawnCustomTrapdoorToDestinat
12
12
  -- want to create a custom trapdoor that goes to a vanilla stage instead, use the
13
13
  -- `spawnCustomTrapdoorToVanilla` helper function.
14
14
  --
15
- -- Custom trapdoors can have one or more of the following attributes:
16
- --
17
- -- - custom destination (or custom logic for after the player enters)
18
- -- - custom graphics
19
- -- - custom logic for opening/closing
20
- --
21
15
  -- Under the hood, the custom trapdoor is represented by a decoration grid entity and is manually
22
16
  -- respawned every time the player re-enters the room.
23
17
  --
@@ -1054,7 +1054,7 @@ end
1054
1054
  -- "debug 10".
1055
1055
  function ____exports.spam(self)
1056
1056
  v.run.spamBloodRights = not v.run.spamBloodRights
1057
- printEnabled(nil, v.run.maxSpeed, "spamming Blood Rights")
1057
+ printEnabled(nil, v.run.spamBloodRights, "spamming Blood Rights")
1058
1058
  end
1059
1059
  --- Spawns a golden version of the specified trinket type.
1060
1060
  function ____exports.spawnGoldenTrinket(self, params)
@@ -1 +1 @@
1
- {"version":3,"file":"playerInventory.d.ts","sourceRoot":"","sources":["../../src/features/playerInventory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAe,MAAM,8BAA8B,CAAC;AAkH5E;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,YAAY,EACpB,yBAAyB,UAAO,GAC/B,eAAe,EAAE,CAanB;AAED;;;;;GAKG;AACH,wBAAgB,+BAA+B,CAC7C,MAAM,EAAE,YAAY,GACnB,eAAe,GAAG,SAAS,CAK7B"}
1
+ {"version":3,"file":"playerInventory.d.ts","sourceRoot":"","sources":["../../src/features/playerInventory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AA2D/D;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,YAAY,EACpB,yBAAyB,UAAO,GAC/B,eAAe,EAAE,CAYnB;AAED;;;;;GAKG;AACH,wBAAgB,+BAA+B,CAC7C,MAAM,EAAE,YAAY,GACnB,eAAe,GAAG,SAAS,CAK7B"}
@@ -2,10 +2,7 @@ local ____lualib = require("lualib_bundle")
2
2
  local __TS__New = ____lualib.__TS__New
3
3
  local __TS__ArrayFilter = ____lualib.__TS__ArrayFilter
4
4
  local ____exports = {}
5
- local newPlayerInventory, resetInventory, useItemD4, postGameStarted, postCollectibleAdded, postCollectibleRemoved, v
6
- local ____isaac_2Dtypescript_2Ddefinitions = require("isaac-typescript-definitions")
7
- local CollectibleType = ____isaac_2Dtypescript_2Ddefinitions.CollectibleType
8
- local ModCallback = ____isaac_2Dtypescript_2Ddefinitions.ModCallback
5
+ local postCollectibleAdded, postCollectibleRemoved, v
9
6
  local ____DefaultMap = require("classes.DefaultMap")
10
7
  local DefaultMap = ____DefaultMap.DefaultMap
11
8
  local ____ModCallbackCustom = require("enums.ModCallbackCustom")
@@ -18,48 +15,10 @@ local copyArray = ____array.copyArray
18
15
  local getLastElement = ____array.getLastElement
19
16
  local ____collectibles = require("functions.collectibles")
20
17
  local isActiveCollectible = ____collectibles.isActiveCollectible
21
- local ____collectibleSet = require("functions.collectibleSet")
22
- local getCollectibleArray = ____collectibleSet.getCollectibleArray
23
18
  local ____playerDataStructures = require("functions.playerDataStructures")
24
19
  local defaultMapGetPlayer = ____playerDataStructures.defaultMapGetPlayer
25
- local mapSetPlayer = ____playerDataStructures.mapSetPlayer
26
- local ____playerIndex = require("functions.playerIndex")
27
- local getAllPlayers = ____playerIndex.getAllPlayers
28
- local getPlayerIndex = ____playerIndex.getPlayerIndex
29
- local ____utils = require("functions.utils")
30
- local ____repeat = ____utils["repeat"]
31
20
  local ____exports = require("features.saveDataManager.exports")
32
21
  local saveDataManager = ____exports.saveDataManager
33
- function newPlayerInventory(self, player)
34
- local inventory = {}
35
- for ____, collectibleType in ipairs(getCollectibleArray(nil)) do
36
- local numCollectibles = player:GetCollectibleNum(collectibleType, true)
37
- ____repeat(
38
- nil,
39
- numCollectibles,
40
- function()
41
- inventory[#inventory + 1] = collectibleType
42
- end
43
- )
44
- end
45
- return inventory
46
- end
47
- function resetInventory(self, player)
48
- local inventory = newPlayerInventory(nil, player)
49
- mapSetPlayer(nil, v.run.playersInventory, player, inventory)
50
- end
51
- function useItemD4(self, _collectibleType, _rng, player)
52
- resetInventory(nil, player)
53
- return nil
54
- end
55
- function postGameStarted(self)
56
- for ____, player in ipairs(getAllPlayers(nil)) do
57
- local playerIndex = getPlayerIndex(nil, player)
58
- if not v.run.playersInventory:has(playerIndex) then
59
- resetInventory(nil, player)
60
- end
61
- end
62
- end
63
22
  function postCollectibleAdded(self, player, collectibleType)
64
23
  local inventory = defaultMapGetPlayer(nil, v.run.playersInventory, player, player)
65
24
  inventory[#inventory + 1] = collectibleType
@@ -71,14 +30,12 @@ end
71
30
  local FEATURE_NAME = "playerInventory"
72
31
  v = {run = {playersInventory = __TS__New(
73
32
  DefaultMap,
74
- function(____, player) return newPlayerInventory(nil, player) end
33
+ function() return {} end
75
34
  )}}
76
35
  ---
77
36
  -- @internal
78
37
  function ____exports.playerInventoryInit(self, mod)
79
38
  saveDataManager(nil, FEATURE_NAME, v)
80
- mod:AddCallback(ModCallback.POST_USE_ITEM, useItemD4, CollectibleType.D4)
81
- mod:AddCallback(ModCallback.POST_GAME_STARTED, postGameStarted)
82
39
  mod:AddCallbackCustom(ModCallbackCustom.POST_PLAYER_COLLECTIBLE_ADDED, postCollectibleAdded)
83
40
  mod:AddCallbackCustom(ModCallbackCustom.POST_PLAYER_COLLECTIBLE_REMOVED, postCollectibleRemoved)
84
41
  end
@@ -106,12 +63,11 @@ function ____exports.getPlayerInventory(self, player, includeActiveCollectibles)
106
63
  end
107
64
  errorIfFeaturesNotInitialized(nil, FEATURE_NAME)
108
65
  local inventory = defaultMapGetPlayer(nil, v.run.playersInventory, player, player)
109
- local copiedInventory = copyArray(nil, inventory)
110
66
  if includeActiveCollectibles then
111
- return copiedInventory
67
+ return copyArray(nil, inventory)
112
68
  end
113
69
  return __TS__ArrayFilter(
114
- copiedInventory,
70
+ inventory,
115
71
  function(____, collectibleType) return not isActiveCollectible(nil, collectibleType) end
116
72
  )
117
73
  end
@@ -1 +1 @@
1
- {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../../src/features/saveDataManager/main.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAGxD,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAKtD,OAAO,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAsBrD,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI,CAUlE;AAuED,wBAAgB,sBAAsB,CACpC,cAAc,EAAE,MAAM,EACtB,QAAQ,EAAE,QAAQ,EAClB,WAAW,EAAE,WAAW,GACvB,IAAI,CA4CN;AAiBD,wBAAgB,wBAAwB,IAAI,IAAI,CAM/C;AAED,wBAAgB,wBAAwB,IAAI,IAAI,CAM/C"}
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../../src/features/saveDataManager/main.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAGxD,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAMtD,OAAO,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAsBrD,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI,CAUlE;AAqFD,wBAAgB,sBAAsB,CACpC,cAAc,EAAE,MAAM,EACtB,QAAQ,EAAE,QAAQ,EAClB,WAAW,EAAE,WAAW,GACvB,IAAI,CA4CN;AAiBD,wBAAgB,wBAAwB,IAAI,IAAI,CAM/C;AAED,wBAAgB,wBAAwB,IAAI,IAAI,CAM/C"}
@@ -17,6 +17,8 @@ local ____deepCopy = require("functions.deepCopy")
17
17
  local deepCopy = ____deepCopy.deepCopy
18
18
  local ____log = require("functions.log")
19
19
  local logError = ____log.logError
20
+ local ____stage = require("functions.stage")
21
+ local onFirstFloor = ____stage.onFirstFloor
20
22
  local ____table = require("functions.table")
21
23
  local clearTable = ____table.clearTable
22
24
  local iterateTableInOrder = ____table.iterateTableInOrder
@@ -55,7 +57,13 @@ function preGameExit(self)
55
57
  loadedDataOnThisRun = false
56
58
  end
57
59
  function postNewLevel(self)
60
+ if mod == nil then
61
+ error(("The mod for the " .. SAVE_DATA_MANAGER_FEATURE_NAME) .. " was not initialized.")
62
+ end
58
63
  restoreDefaults(nil, SaveDataKey.LEVEL)
64
+ if not onFirstFloor(nil) then
65
+ saveToDisk(nil, mod, saveDataMap, saveDataConditionalFuncMap)
66
+ end
59
67
  end
60
68
  function postNewRoomEarly(self)
61
69
  restoreDefaults(nil, SaveDataKey.ROOM)
@@ -127,6 +127,7 @@ export declare function inDoubleTrouble(): boolean;
127
127
  export declare function inGenesisRoom(): boolean;
128
128
  /** Helper function to determine if the current room shape is one of the four L room shapes. */
129
129
  export declare function inLRoom(): boolean;
130
+ /** Helper function to determine if the current room index is equal to `GridRoom.MEGA_SATAN`. */
130
131
  export declare function inMegaSatanRoom(): boolean;
131
132
  /**
132
133
  * Helper function to determine if the current room is part of the Repentance "escape sequence" in
@@ -1 +1 @@
1
- {"version":3,"file":"rooms.d.ts","sourceRoot":"","sources":["../../src/functions/rooms.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,YAAY,EACZ,MAAM,EACN,SAAS,EAMT,YAAY,EACZ,UAAU,EAGV,QAAQ,EAGT,MAAM,8BAA8B,CAAC;AAkCtC;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,aAAa,EAAE,GAAG,GAAG,IAAI,CAenD;AAED;;;GAGG;AACH,wBAAgB,WAAW,IAAI,GAAG,CAGjC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,IAAI,KAAK,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,CAiBlE;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,QAAQ,EAClB,WAAW,EAAE,GAAG,EAChB,oBAAoB,UAAO,GAC1B,QAAQ,CAAC,UAAU,CAAC,GAAG,SAAS,CAUlC;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,IAAI,YAAY,CAOlD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAE1D;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,QAAQ,CACtB,4BAA4B,UAAQ,GACnC,cAAc,EAAE,CAOlB;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAChC,4BAA4B,UAAQ,GACnC,cAAc,EAAE,CAqBlB;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,SAAS,GAAG,cAAc,EAAE,CAe1E;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,IAAI,cAAc,EAAE,CAWtD;AAED;;;GAGG;AACH,wBAAgB,SAAS,IAAI,OAAO,CAKnC;AAED,wBAAgB,WAAW,IAAI,OAAO,CASrC;AAED,wBAAgB,WAAW,IAAI,OAAO,CASrC;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAWpD;AAED;;;;GAIG;AACH,wBAAgB,YAAY,IAAI,OAAO,CAStC;AAED;;GAEG;AACH,wBAAgB,sBAAsB,IAAI,OAAO,CAShD;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,IAAI,OAAO,CAGnD;AAED,wBAAgB,eAAe,IAAI,OAAO,CAMzC;AAED,wBAAgB,aAAa,IAAI,OAAO,CAIvC;AAED,+FAA+F;AAC/F,wBAAgB,OAAO,IAAI,OAAO,CAUjC;AAED,wBAAgB,eAAe,IAAI,OAAO,CAIzC;AAED;;;GAGG;AACH,wBAAgB,WAAW,IAAI,OAAO,CASrC;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAWhE;AAED;;;GAGG;AACH,wBAAgB,YAAY,IAAI,OAAO,CAWtC;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,IAAI,OAAO,CAItC;AAED;;;;GAIG;AACH,wBAAgB,cAAc,IAAI,OAAO,CAMxC;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,kBAAkB,CAAC,EAAE,QAAQ,EAAE,GAAG,OAAO,CAcxE;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,IAAI,IAAI,CAWrC;AAED,+DAA+D;AAC/D,wBAAgB,WAAW,CAAC,YAAY,EAAE,YAAY,GAAG,IAAI,CAG5D;AAED;;;;GAIG;AACH,wBAAgB,cAAc,IAAI,IAAI,CA8BrC;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CAKvC"}
1
+ {"version":3,"file":"rooms.d.ts","sourceRoot":"","sources":["../../src/functions/rooms.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,YAAY,EACZ,MAAM,EACN,SAAS,EAMT,YAAY,EACZ,UAAU,EAGV,QAAQ,EAGT,MAAM,8BAA8B,CAAC;AAkCtC;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,aAAa,EAAE,GAAG,GAAG,IAAI,CAenD;AAED;;;GAGG;AACH,wBAAgB,WAAW,IAAI,GAAG,CAGjC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,IAAI,KAAK,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,CAiBlE;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,QAAQ,EAClB,WAAW,EAAE,GAAG,EAChB,oBAAoB,UAAO,GAC1B,QAAQ,CAAC,UAAU,CAAC,GAAG,SAAS,CAUlC;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,IAAI,YAAY,CAOlD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAE1D;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,QAAQ,CACtB,4BAA4B,UAAQ,GACnC,cAAc,EAAE,CAOlB;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAChC,4BAA4B,UAAQ,GACnC,cAAc,EAAE,CAqBlB;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,SAAS,GAAG,cAAc,EAAE,CAe1E;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,IAAI,cAAc,EAAE,CAWtD;AAED;;;GAGG;AACH,wBAAgB,SAAS,IAAI,OAAO,CAKnC;AAED,wBAAgB,WAAW,IAAI,OAAO,CASrC;AAED,wBAAgB,WAAW,IAAI,OAAO,CASrC;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAWpD;AAED;;;;GAIG;AACH,wBAAgB,YAAY,IAAI,OAAO,CAStC;AAED;;GAEG;AACH,wBAAgB,sBAAsB,IAAI,OAAO,CAShD;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,IAAI,OAAO,CAGnD;AAED,wBAAgB,eAAe,IAAI,OAAO,CAMzC;AAED,wBAAgB,aAAa,IAAI,OAAO,CAIvC;AAED,+FAA+F;AAC/F,wBAAgB,OAAO,IAAI,OAAO,CAUjC;AAED,gGAAgG;AAChG,wBAAgB,eAAe,IAAI,OAAO,CAIzC;AAED;;;GAGG;AACH,wBAAgB,WAAW,IAAI,OAAO,CASrC;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAWhE;AAED;;;GAGG;AACH,wBAAgB,YAAY,IAAI,OAAO,CAWtC;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,IAAI,OAAO,CAItC;AAED;;;;GAIG;AACH,wBAAgB,cAAc,IAAI,OAAO,CAMxC;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,kBAAkB,CAAC,EAAE,QAAQ,EAAE,GAAG,OAAO,CAcxE;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,IAAI,IAAI,CAWrC;AAED,+DAA+D;AAC/D,wBAAgB,WAAW,CAAC,YAAY,EAAE,YAAY,GAAG,IAAI,CAG5D;AAED;;;;GAIG;AACH,wBAAgB,cAAc,IAAI,IAAI,CA8BrC;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CAKvC"}
@@ -305,6 +305,7 @@ function ____exports.inLRoom(self)
305
305
  local roomShape = room:GetRoomShape()
306
306
  return roomShape == RoomShape.LTL or roomShape == RoomShape.LTR or roomShape == RoomShape.LBL or roomShape == RoomShape.LBR
307
307
  end
308
+ --- Helper function to determine if the current room index is equal to `GridRoom.MEGA_SATAN`.
308
309
  function ____exports.inMegaSatanRoom(self)
309
310
  local roomGridIndex = getRoomGridIndex(nil)
310
311
  return roomGridIndex == asNumber(nil, GridRoom.MEGA_SATAN)
@@ -26,6 +26,10 @@ export declare function getStage(): LevelStage;
26
26
  export declare function getStageType(): StageType;
27
27
  /** Helper function to directly warp to a specific stage using the "stage" console command. */
28
28
  export declare function goToStage(stage: LevelStage, stageType: StageType): void;
29
+ /**
30
+ * Helper function to check if the provided stage type is equal to `StageType.REPENTANCE` or
31
+ * `StageType.REPENTANCE_B`.
32
+ */
29
33
  export declare function isRepentanceStage(stageType: StageType): boolean;
30
34
  export declare function onAscent(): boolean;
31
35
  export declare function onCathedral(): boolean;
@@ -40,6 +44,17 @@ export declare function onDarkRoom(): boolean;
40
44
  * I AM ERROR room is never entered into the list of possibilities.
41
45
  */
42
46
  export declare function onFinalFloor(): boolean;
47
+ /**
48
+ * Returns whether or not the player is on the first floor of the particular run.
49
+ *
50
+ * This is tricky to determine because we have to handle the cases of Downpour/Dross 1 not being the
51
+ * first floor and The Ascent.
52
+ */
53
+ export declare function onFirstFloor(): boolean;
54
+ /**
55
+ * Helper function to check if the current stage type is equal to `StageType.REPENTANCE` or
56
+ * `StageType.REPENTANCE_B`.
57
+ */
43
58
  export declare function onRepentanceStage(): boolean;
44
59
  export declare function onSheol(): boolean;
45
60
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"stage.d.ts","sourceRoot":"","sources":["../../src/functions/stage.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,UAAU,EACV,QAAQ,EACR,SAAS,EACV,MAAM,8BAA8B,CAAC;AAOtC;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,UAAU,GAAG,SAAS,CA6B/D;AAED;;;GAGG;AACH,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,UAAU,GAAG,SAAS,CAmBzE;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,IAAI,GAAG,CASvC;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,GAAG,GAAG,MAAM,CAG3E;AAED,6CAA6C;AAC7C,wBAAgB,QAAQ,IAAI,UAAU,CAIrC;AAED,iDAAiD;AACjD,wBAAgB,YAAY,IAAI,SAAS,CAIxC;AAED,8FAA8F;AAC9F,wBAAgB,SAAS,CAAC,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,GAAG,IAAI,CAIvE;AAED,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAI/D;AAED,wBAAgB,QAAQ,IAAI,OAAO,CAElC;AAED,wBAAgB,WAAW,IAAI,OAAO,CASrC;AAED,wBAAgB,OAAO,IAAI,OAAO,CASjC;AAED,wBAAgB,UAAU,IAAI,OAAO,CAQpC;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,IAAI,OAAO,CAUtC;AAED,wBAAgB,iBAAiB,IAAI,OAAO,CAK3C;AAED,wBAAgB,OAAO,IAAI,OAAO,CAQjC;AAED;;;;;;;;GAQG;AACH,wBAAgB,QAAQ,CACtB,KAAK,EAAE,UAAU,EACjB,SAAS,EAAE,SAAS,EACpB,MAAM,UAAQ,GACb,IAAI,CAUN;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,SAAS,GAAG,MAAM,CAE9D"}
1
+ {"version":3,"file":"stage.d.ts","sourceRoot":"","sources":["../../src/functions/stage.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,UAAU,EACV,QAAQ,EACR,SAAS,EACV,MAAM,8BAA8B,CAAC;AAOtC;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,UAAU,GAAG,SAAS,CA6B/D;AAED;;;GAGG;AACH,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,UAAU,GAAG,SAAS,CAmBzE;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,IAAI,GAAG,CASvC;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,GAAG,GAAG,MAAM,CAG3E;AAED,6CAA6C;AAC7C,wBAAgB,QAAQ,IAAI,UAAU,CAIrC;AAED,iDAAiD;AACjD,wBAAgB,YAAY,IAAI,SAAS,CAIxC;AAED,8FAA8F;AAC9F,wBAAgB,SAAS,CAAC,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,GAAG,IAAI,CAIvE;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAI/D;AAED,wBAAgB,QAAQ,IAAI,OAAO,CAElC;AAED,wBAAgB,WAAW,IAAI,OAAO,CASrC;AAED,wBAAgB,OAAO,IAAI,OAAO,CASjC;AAED,wBAAgB,UAAU,IAAI,OAAO,CAQpC;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,IAAI,OAAO,CAUtC;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,IAAI,OAAO,CAKtC;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,CAK3C;AAED,wBAAgB,OAAO,IAAI,OAAO,CAQjC;AAED;;;;;;;;GAQG;AACH,wBAAgB,QAAQ,CACtB,KAAK,EAAE,UAAU,EACjB,SAAS,EAAE,SAAS,EACpB,MAAM,UAAQ,GACb,IAAI,CAUN;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,SAAS,GAAG,MAAM,CAE9D"}
@@ -14,9 +14,13 @@ local STAGE_TYPE_TO_LETTER = ____stageTypeToLetter.STAGE_TYPE_TO_LETTER
14
14
  local ____types = require("functions.types")
15
15
  local asLevelStage = ____types.asLevelStage
16
16
  local asNumber = ____types.asNumber
17
+ --- Helper function to check if the provided stage type is equal to `StageType.REPENTANCE` or
18
+ -- `StageType.REPENTANCE_B`.
17
19
  function ____exports.isRepentanceStage(self, stageType)
18
20
  return stageType == StageType.REPENTANCE or stageType == StageType.REPENTANCE_B
19
21
  end
22
+ --- Helper function to check if the current stage type is equal to `StageType.REPENTANCE` or
23
+ -- `StageType.REPENTANCE_B`.
20
24
  function ____exports.onRepentanceStage(self)
21
25
  local level = game:GetLevel()
22
26
  local stageType = level:GetStageType()
@@ -125,6 +129,15 @@ function ____exports.onFinalFloor(self)
125
129
  local stage = level:GetStage()
126
130
  return stage == LevelStage.DARK_ROOM_CHEST or stage == LevelStage.THE_VOID or stage == LevelStage.HOME or stage == LevelStage.WOMB_2 and ____exports.onRepentanceStage(nil)
127
131
  end
132
+ --- Returns whether or not the player is on the first floor of the particular run.
133
+ --
134
+ -- This is tricky to determine because we have to handle the cases of Downpour/Dross 1 not being the
135
+ -- first floor and The Ascent.
136
+ function ____exports.onFirstFloor(self)
137
+ local effectiveStage = ____exports.getEffectiveStage(nil)
138
+ local isOnAscent = ____exports.onAscent(nil)
139
+ return effectiveStage == 1 and not isOnAscent
140
+ end
128
141
  function ____exports.onSheol(self)
129
142
  local level = game:GetLevel()
130
143
  local stage = level:GetStage()
package/dist/index.d.ts CHANGED
@@ -5433,6 +5433,7 @@ export declare function initCustomDoor(mod: ModUpgraded, effectVariant: EffectVa
5433
5433
  /** Helper function to determine if the current room shape is one of the four L room shapes. */
5434
5434
  export declare function inLRoom(): boolean;
5435
5435
 
5436
+ /** Helper function to determine if the current room index is equal to `GridRoom.MEGA_SATAN`. */
5436
5437
  export declare function inMegaSatanRoom(): boolean;
5437
5438
 
5438
5439
  /**
@@ -6049,6 +6050,10 @@ export declare function isReflectionRender(): boolean;
6049
6050
  */
6050
6051
  export declare function isRepentanceDoor(door: GridEntityDoor): boolean;
6051
6052
 
6053
+ /**
6054
+ * Helper function to check if the provided stage type is equal to `StageType.REPENTANCE` or
6055
+ * `StageType.REPENTANCE_B`.
6056
+ */
6052
6057
  export declare function isRepentanceStage(stageType: StageType): boolean;
6053
6058
 
6054
6059
  /** Returns true for cards that have `ItemConfigCardType.TAROT_REVERSE`. */
@@ -7583,7 +7588,8 @@ export declare enum ModCallbackCustom {
7583
7588
  POST_PLAYER_CHANGE_TYPE = 57,
7584
7589
  /**
7585
7590
  * Fires from the `POST_PEFFECT_UPDATE` callback when a player's collectible count is higher than
7586
- * what it was on the previous frame or when a new active collectible is acquired.
7591
+ * what it was on the previous frame, or when the active items change, or when the build is
7592
+ * rerolled.
7587
7593
  *
7588
7594
  * When registering the callback, takes an optional second argument that will make the callback
7589
7595
  * only fire if the collectible matches the `CollectibleType` provided.
@@ -7598,7 +7604,8 @@ export declare enum ModCallbackCustom {
7598
7604
  POST_PLAYER_COLLECTIBLE_ADDED = 58,
7599
7605
  /**
7600
7606
  * Fires from the `POST_PEFFECT_UPDATE` callback when a player's collectible count is lower than
7601
- * what it was on the previous frame or when an active collectible is no longer present.
7607
+ * what it was on the previous frame, or when the active items change, or when the build is
7608
+ * rerolled.
7602
7609
  *
7603
7610
  * When registering the callback, takes an optional second argument that will make the callback
7604
7611
  * only fire if the collectible matches the `CollectibleType` provided.
@@ -8253,6 +8260,18 @@ export declare const ONE_BY_ONE_ROOM_GRID_SIZE = 135;
8253
8260
  */
8254
8261
  export declare function onFinalFloor(): boolean;
8255
8262
 
8263
+ /**
8264
+ * Returns whether or not the player is on the first floor of the particular run.
8265
+ *
8266
+ * This is tricky to determine because we have to handle the cases of Downpour/Dross 1 not being the
8267
+ * first floor and The Ascent.
8268
+ */
8269
+ export declare function onFirstFloor(): boolean;
8270
+
8271
+ /**
8272
+ * Helper function to check if the current stage type is equal to `StageType.REPENTANCE` or
8273
+ * `StageType.REPENTANCE_B`.
8274
+ */
8256
8275
  export declare function onRepentanceStage(): boolean;
8257
8276
 
8258
8277
  /**
@@ -10861,12 +10880,6 @@ export declare function spawnCustomGridEntity(gridEntityTypeCustom: GridEntityTy
10861
10880
  * want to create a custom trapdoor that goes to a vanilla stage instead, use the
10862
10881
  * `spawnCustomTrapdoorToVanilla` helper function.
10863
10882
  *
10864
- * Custom trapdoors can have one or more of the following attributes:
10865
- *
10866
- * - custom destination (or custom logic for after the player enters)
10867
- * - custom graphics
10868
- * - custom logic for opening/closing
10869
- *
10870
10883
  * Under the hood, the custom trapdoor is represented by a decoration grid entity and is manually
10871
10884
  * respawned every time the player re-enters the room.
10872
10885
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "isaacscript-common",
3
- "version": "9.1.0",
3
+ "version": "9.2.1",
4
4
  "description": "Helper functions and features for IsaacScript mods.",
5
5
  "keywords": [
6
6
  "isaac",
@@ -5,15 +5,19 @@
5
5
  import {
6
6
  ActiveSlot,
7
7
  CollectibleType,
8
+ DamageFlag,
9
+ EntityType,
8
10
  ModCallback,
11
+ PlayerType,
9
12
  } from "isaac-typescript-definitions";
10
13
  import { DefaultMap } from "../classes/DefaultMap";
14
+ import { runNextGameFrame } from "../features/runInNFrames";
11
15
  import { saveDataManager } from "../features/saveDataManager/exports";
12
16
  import { arrayEquals } from "../functions/array";
13
17
  import { getEnumValues } from "../functions/enums";
18
+ import { hasFlag } from "../functions/flag";
14
19
  import {
15
20
  defaultMapGetPlayer,
16
- mapGetPlayer,
17
21
  mapSetPlayer,
18
22
  } from "../functions/playerDataStructures";
19
23
  import { getPlayerCollectibleMap } from "../functions/players";
@@ -30,7 +34,7 @@ import {
30
34
 
31
35
  const v = {
32
36
  run: {
33
- playersCollectibleCount: new Map<PlayerIndex, int>(),
37
+ playersCollectibleCount: new DefaultMap<PlayerIndex, int>(0),
34
38
  playersCollectibleMap: new DefaultMap<
35
39
  PlayerIndex,
36
40
  Map<CollectibleType, int>
@@ -45,7 +49,13 @@ const v = {
45
49
  export function postPlayerCollectibleCallbacksInit(mod: Mod): void {
46
50
  saveDataManager("postPlayerCollectible", v, hasSubscriptions);
47
51
 
52
+ mod.AddCallback(ModCallback.POST_USE_ITEM, useItemD4, CollectibleType.D4); // 3
48
53
  mod.AddCallback(ModCallback.POST_PEFFECT_UPDATE, postPEffectUpdate); // 4
54
+ mod.AddCallback(
55
+ ModCallback.ENTITY_TAKE_DMG,
56
+ entityTakeDmgPlayer,
57
+ EntityType.PLAYER,
58
+ ); // 11
49
59
  }
50
60
 
51
61
  function hasSubscriptions() {
@@ -55,37 +65,20 @@ function hasSubscriptions() {
55
65
  );
56
66
  }
57
67
 
58
- // ModCallback.POST_PEFFECT_UPDATE (4)
59
- function postPEffectUpdate(player: EntityPlayer) {
60
- if (!hasSubscriptions()) {
61
- return;
62
- }
63
-
64
- const oldCollectibleCount = mapGetPlayer(
65
- v.run.playersCollectibleCount,
66
- player,
67
- );
68
- const newCollectibleCount = player.GetCollectibleCount();
69
- mapSetPlayer(v.run.playersCollectibleCount, player, newCollectibleCount);
70
-
71
- if (oldCollectibleCount === undefined) {
72
- return;
73
- }
74
-
75
- const difference = newCollectibleCount - oldCollectibleCount;
76
-
77
- if (difference > 0) {
78
- collectibleCountChanged(player, difference);
79
- } else if (difference < 0) {
80
- collectibleCountChanged(player, difference * -1);
81
- } else if (difference === 0) {
82
- checkActiveItemsChanged(player);
83
- }
84
- }
85
-
86
- function collectibleCountChanged(
68
+ /**
69
+ * This is called when the collectible count changes and in situations where the entire build is
70
+ * rerolled.
71
+ *
72
+ * Since getting a new player collectible map is expensive, we want to only run this function when
73
+ * necessary, and not on e.g. every frame. Unfortunately, this has the side effect of missing out on
74
+ * collectible changes from mods that add and remove a collectible on the same frame.
75
+ *
76
+ * @param player The player to update.
77
+ * @param numCollectiblesChanged Pass undefined for situations where the entire build was rerolled.
78
+ */
79
+ function updateCollectibleMapAndFire(
87
80
  player: EntityPlayer,
88
- numCollectiblesChanged: int,
81
+ numCollectiblesChanged: int | undefined,
89
82
  ) {
90
83
  const oldCollectibleMap = defaultMapGetPlayer(
91
84
  v.run.playersCollectibleMap,
@@ -94,13 +87,13 @@ function collectibleCountChanged(
94
87
  const newCollectibleMap = getPlayerCollectibleMap(player);
95
88
  mapSetPlayer(v.run.playersCollectibleMap, player, newCollectibleMap);
96
89
 
97
- const collectibleTypeSet = new Set<CollectibleType>([
90
+ const collectibleTypesSet = new Set<CollectibleType>([
98
91
  ...oldCollectibleMap.keys(),
99
92
  ...newCollectibleMap.keys(),
100
93
  ]);
101
94
 
102
95
  let numFired = 0;
103
- for (const collectibleType of collectibleTypeSet.values()) {
96
+ for (const collectibleType of collectibleTypesSet.values()) {
104
97
  const oldNum = oldCollectibleMap.get(collectibleType) ?? 0;
105
98
  const newNum = newCollectibleMap.get(collectibleType) ?? 0;
106
99
  const difference = newNum - oldNum;
@@ -122,9 +115,63 @@ function collectibleCountChanged(
122
115
  }
123
116
  }
124
117
 
118
+ // ModCallback.POST_USE_ITEM (3)
119
+ // CollectibleType.D4 (284)
120
+ function useItemD4(
121
+ _collectibleType: CollectibleType,
122
+ _rng: RNG,
123
+ player: EntityPlayer,
124
+ ): boolean | undefined {
125
+ // This function is also triggered for:
126
+ // - D100
127
+ // - D Infinity copying D4 or D100
128
+ // - 1-pip dice room
129
+ // - 6-pip dice room
130
+ // - Reverse Wheel of Fortune copying 1-pip or 6-pip dice room
131
+ // - First getting Missing No.
132
+ // - Arriving on a new floor with Missing No.
133
+
134
+ // This function is not triggered for:
135
+ // - Tainted Eden getting hit (this is explicitly handled elsewhere)
136
+ // - Genesis (which is automatically handled by the collectibles being removed in the normal
137
+ // `POST_PLAYER_COLLECTIBLE_REMOVED` callback)
138
+ updateCollectibleMapAndFire(player, undefined);
139
+
140
+ return undefined;
141
+ }
142
+
143
+ // ModCallback.POST_PEFFECT_UPDATE (4)
144
+ function postPEffectUpdate(player: EntityPlayer) {
145
+ if (!hasSubscriptions()) {
146
+ return;
147
+ }
148
+
149
+ const oldCollectibleCount = defaultMapGetPlayer(
150
+ v.run.playersCollectibleCount,
151
+ player,
152
+ );
153
+ const newCollectibleCount = player.GetCollectibleCount();
154
+ mapSetPlayer(v.run.playersCollectibleCount, player, newCollectibleCount);
155
+
156
+ const difference = newCollectibleCount - oldCollectibleCount;
157
+
158
+ if (difference > 0) {
159
+ updateCollectibleMapAndFire(player, difference);
160
+ } else if (difference < 0) {
161
+ updateCollectibleMapAndFire(player, difference * -1);
162
+ } else if (difference === 0) {
163
+ checkActiveItemsChanged(player);
164
+ }
165
+ }
166
+
125
167
  /**
126
- * The special case is when a player swaps their active item for another active item. In this
127
- * situation, their overall collectible count will not change. Thus, we explicitly check for this.
168
+ * Checking for collectible count will work to detect when a player swaps their active item for
169
+ * another active item. This is because the collectible count will decrement by 1 when the item is
170
+ * swapped onto the pedestal and the hold animation begins, and increment by 1 when the item is
171
+ * dequeued and the hold animation ends.
172
+ *
173
+ * However, we also want to explicitly check for the case where a mod swaps in a custom active
174
+ * collectible on the same frame, since doing so is cheap.
128
175
  */
129
176
  function checkActiveItemsChanged(player: EntityPlayer) {
130
177
  const activeItemMap = defaultMapGetPlayer(v.run.playersActiveItemMap, player);
@@ -143,48 +190,58 @@ function checkActiveItemsChanged(player: EntityPlayer) {
143
190
  }
144
191
 
145
192
  // For example, it is possible for the player to switch Schoolbag items, which will cause the
146
- // collectibles in the array to be the same, but in a different order. Thus, sort both arrays
193
+ // collectibles in the array to be the same, but in a different order. Thus, we sort both arrays
147
194
  // before comparing them.
148
195
  oldCollectibleTypes.sort();
149
196
  newCollectibleTypes.sort();
150
197
 
151
198
  if (!arrayEquals(oldCollectibleTypes, newCollectibleTypes)) {
152
- const collectibleTypeSet = new Set<CollectibleType>([
153
- ...oldCollectibleTypes,
154
- ...newCollectibleTypes,
155
- ]);
156
- activeItemsChanged(player, collectibleTypeSet);
199
+ // One or more active items have changed (with the player's total collectible count remaining
200
+ // the same).
201
+ updateCollectibleMapAndFire(player, undefined);
157
202
  }
158
203
  }
159
204
 
160
- /**
161
- * One or more active items have changed (with the player's total collectible count remaining the
162
- * same).
163
- */
164
- function activeItemsChanged(
165
- player: EntityPlayer,
166
- collectibleTypesSet: Set<CollectibleType>,
167
- ) {
168
- const oldCollectibleMap = defaultMapGetPlayer(
169
- v.run.playersCollectibleMap,
170
- player,
171
- );
172
- const newCollectibleMap = getPlayerCollectibleMap(player);
173
- mapSetPlayer(v.run.playersCollectibleMap, player, newCollectibleMap);
205
+ // ModCallback.ENTITY_TAKE_DMG (11)
206
+ // EntityType.PLAYER (1)
207
+ // We need to handle the case of Tainted Eden taking damage.
208
+ function entityTakeDmgPlayer(
209
+ entity: Entity,
210
+ _amount: float,
211
+ damageFlags: BitFlags<DamageFlag>,
212
+ _source: EntityRef,
213
+ _countdownFrames: int,
214
+ ): boolean | undefined {
215
+ // Tainted Eden's mechanic does not apply if she e.g. uses Dull Razor.
216
+ if (hasFlag(damageFlags, DamageFlag.FAKE)) {
217
+ return undefined;
218
+ }
174
219
 
175
- for (const collectibleType of collectibleTypesSet.values()) {
176
- const oldNum = oldCollectibleMap.get(collectibleType) ?? 0;
177
- const newNum = newCollectibleMap.get(collectibleType) ?? 0;
178
- const difference = newNum - oldNum;
179
- const increased = difference > 0;
180
- const absoluteDifference = Math.abs(difference);
220
+ const player = entity.ToPlayer();
221
+ if (player === undefined) {
222
+ return undefined;
223
+ }
181
224
 
182
- repeat(absoluteDifference, () => {
183
- if (increased) {
184
- postPlayerCollectibleAddedFire(player, collectibleType);
185
- } else {
186
- postPlayerCollectibleRemovedFire(player, collectibleType);
187
- }
188
- });
225
+ const character = player.GetPlayerType();
226
+ if (character !== PlayerType.EDEN_B) {
227
+ return undefined;
189
228
  }
229
+
230
+ // The items will only be rerolled after the damage is successfully applied.
231
+ const ptr = EntityPtr(player);
232
+ runNextGameFrame(() => {
233
+ const futureEntity = ptr.Ref;
234
+ if (futureEntity === undefined) {
235
+ return;
236
+ }
237
+
238
+ const futurePlayer = futureEntity.ToPlayer();
239
+ if (futurePlayer === undefined) {
240
+ return;
241
+ }
242
+
243
+ updateCollectibleMapAndFire(player, undefined);
244
+ });
245
+
246
+ return undefined;
190
247
  }
@@ -959,7 +959,8 @@ export enum ModCallbackCustom {
959
959
 
960
960
  /**
961
961
  * Fires from the `POST_PEFFECT_UPDATE` callback when a player's collectible count is higher than
962
- * what it was on the previous frame or when a new active collectible is acquired.
962
+ * what it was on the previous frame, or when the active items change, or when the build is
963
+ * rerolled.
963
964
  *
964
965
  * When registering the callback, takes an optional second argument that will make the callback
965
966
  * only fire if the collectible matches the `CollectibleType` provided.
@@ -975,7 +976,8 @@ export enum ModCallbackCustom {
975
976
 
976
977
  /**
977
978
  * Fires from the `POST_PEFFECT_UPDATE` callback when a player's collectible count is lower than
978
- * what it was on the previous frame or when an active collectible is no longer present.
979
+ * what it was on the previous frame, or when the active items change, or when the build is
980
+ * rerolled.
979
981
  *
980
982
  * When registering the callback, takes an optional second argument that will make the callback
981
983
  * only fire if the collectible matches the `CollectibleType` provided.
@@ -10,12 +10,6 @@ import { spawnCustomTrapdoorToDestination } from "./spawn";
10
10
  * want to create a custom trapdoor that goes to a vanilla stage instead, use the
11
11
  * `spawnCustomTrapdoorToVanilla` helper function.
12
12
  *
13
- * Custom trapdoors can have one or more of the following attributes:
14
- *
15
- * - custom destination (or custom logic for after the player enters)
16
- * - custom graphics
17
- * - custom logic for opening/closing
18
- *
19
13
  * Under the hood, the custom trapdoor is represented by a decoration grid entity and is manually
20
14
  * respawned every time the player re-enters the room.
21
15
  *
@@ -1249,7 +1249,7 @@ export function sounds(): void {
1249
1249
  */
1250
1250
  export function spam(): void {
1251
1251
  v.run.spamBloodRights = !v.run.spamBloodRights;
1252
- printEnabled(v.run.maxSpeed, "spamming Blood Rights");
1252
+ printEnabled(v.run.spamBloodRights, "spamming Blood Rights");
1253
1253
  }
1254
1254
 
1255
1255
  /** Spawns a golden version of the specified trinket type. */
@@ -1,4 +1,4 @@
1
- import { CollectibleType, ModCallback } from "isaac-typescript-definitions";
1
+ import { CollectibleType } from "isaac-typescript-definitions";
2
2
  import { DefaultMap } from "../classes/DefaultMap";
3
3
  import { ModUpgraded } from "../classes/ModUpgraded";
4
4
  import { ModCallbackCustom } from "../enums/ModCallbackCustom";
@@ -9,13 +9,7 @@ import {
9
9
  getLastElement,
10
10
  } from "../functions/array";
11
11
  import { isActiveCollectible } from "../functions/collectibles";
12
- import { getCollectibleArray } from "../functions/collectibleSet";
13
- import {
14
- defaultMapGetPlayer,
15
- mapSetPlayer,
16
- } from "../functions/playerDataStructures";
17
- import { getAllPlayers, getPlayerIndex } from "../functions/playerIndex";
18
- import { repeat } from "../functions/utils";
12
+ import { defaultMapGetPlayer } from "../functions/playerDataStructures";
19
13
  import { PlayerIndex } from "../types/PlayerIndex";
20
14
  import { saveDataManager } from "./saveDataManager/exports";
21
15
 
@@ -27,36 +21,14 @@ const v = {
27
21
  PlayerIndex,
28
22
  CollectibleType[],
29
23
  [player: EntityPlayer]
30
- >((player: EntityPlayer) => newPlayerInventory(player)),
24
+ >(() => []),
31
25
  },
32
26
  };
33
27
 
34
- function newPlayerInventory(player: EntityPlayer) {
35
- const inventory: CollectibleType[] = [];
36
-
37
- for (const collectibleType of getCollectibleArray()) {
38
- // We need to specify "true" as the second argument here to filter out things like Lilith's
39
- // Incubus.
40
- const numCollectibles = player.GetCollectibleNum(collectibleType, true);
41
- repeat(numCollectibles, () => {
42
- inventory.push(collectibleType);
43
- });
44
- }
45
-
46
- return inventory;
47
- }
48
-
49
- function resetInventory(player: EntityPlayer) {
50
- const inventory = newPlayerInventory(player);
51
- mapSetPlayer(v.run.playersInventory, player, inventory);
52
- }
53
-
54
28
  /** @internal */
55
29
  export function playerInventoryInit(mod: ModUpgraded): void {
56
30
  saveDataManager(FEATURE_NAME, v);
57
31
 
58
- mod.AddCallback(ModCallback.POST_USE_ITEM, useItemD4, CollectibleType.D4); // 3
59
- mod.AddCallback(ModCallback.POST_GAME_STARTED, postGameStarted); // 15
60
32
  mod.AddCallbackCustom(
61
33
  ModCallbackCustom.POST_PLAYER_COLLECTIBLE_ADDED,
62
34
  postCollectibleAdded,
@@ -67,33 +39,6 @@ export function playerInventoryInit(mod: ModUpgraded): void {
67
39
  );
68
40
  }
69
41
 
70
- // ModCallback.POST_USE_ITEM (3)
71
- // CollectibleType.D4 (284)
72
- function useItemD4(
73
- _collectibleType: CollectibleType,
74
- _rng: RNG,
75
- player: EntityPlayer,
76
- ): boolean | undefined {
77
- // This function is also triggered when the player uses D100, D Infinity, a 1-pip dice room, or a
78
- // 6-pip dice room. (Genesis should be automatically handled by the
79
- // `POST_PLAYER_COLLECTIBLE_REMOVED` callback.)
80
- resetInventory(player);
81
-
82
- return undefined;
83
- }
84
-
85
- // ModCallback.POST_GAME_STARTED (15)
86
- function postGameStarted() {
87
- // We don't use the `POST_PLAYER_INIT` callback because some items are not given to the player at
88
- // that point.
89
- for (const player of getAllPlayers()) {
90
- const playerIndex = getPlayerIndex(player);
91
- if (!v.run.playersInventory.has(playerIndex)) {
92
- resetInventory(player);
93
- }
94
- }
95
- }
96
-
97
42
  // ModCallbackCustom.POST_PLAYER_COLLECTIBLE_ADDED
98
43
  function postCollectibleAdded(
99
44
  player: EntityPlayer,
@@ -140,12 +85,11 @@ export function getPlayerInventory(
140
85
 
141
86
  const inventory = defaultMapGetPlayer(v.run.playersInventory, player, player);
142
87
 
143
- const copiedInventory = copyArray(inventory);
144
88
  if (includeActiveCollectibles) {
145
- return copiedInventory;
89
+ return copyArray(inventory);
146
90
  }
147
91
 
148
- return copiedInventory.filter(
92
+ return inventory.filter(
149
93
  (collectibleType) => !isActiveCollectible(collectibleType),
150
94
  );
151
95
  }
@@ -6,6 +6,7 @@ import { SaveDataKey } from "../../enums/SaveDataKey";
6
6
  import { SerializationType } from "../../enums/SerializationType";
7
7
  import { deepCopy } from "../../functions/deepCopy";
8
8
  import { logError } from "../../functions/log";
9
+ import { onFirstFloor } from "../../functions/stage";
9
10
  import { clearTable, iterateTableInOrder } from "../../functions/table";
10
11
  import { SaveData } from "../../interfaces/SaveData";
11
12
  import { loadFromDisk } from "./load";
@@ -49,6 +50,8 @@ function postPlayerInit() {
49
50
  );
50
51
  }
51
52
 
53
+ // We want to only load data once per run to handle the case of a player using Genesis, a second
54
+ // player joining the run, and so on.
52
55
  if (loadedDataOnThisRun) {
53
56
  return;
54
57
  }
@@ -86,7 +89,19 @@ function preGameExit() {
86
89
 
87
90
  // ModCallback.POST_NEW_LEVEL (18)
88
91
  function postNewLevel() {
92
+ if (mod === null) {
93
+ error(
94
+ `The mod for the ${SAVE_DATA_MANAGER_FEATURE_NAME} was not initialized.`,
95
+ );
96
+ }
97
+
89
98
  restoreDefaults(SaveDataKey.LEVEL);
99
+
100
+ // We save data to disk at the beginning of every floor (for the 2nd floor and beyond) to emulate
101
+ // what the game does internally. (This mitigates data loss in the event of a crash).
102
+ if (!onFirstFloor()) {
103
+ saveToDisk(mod, saveDataMap, saveDataConditionalFuncMap);
104
+ }
90
105
  }
91
106
 
92
107
  // ModCallbackCustom.POST_NEW_ROOM_EARLY
@@ -388,6 +388,7 @@ export function inLRoom(): boolean {
388
388
  );
389
389
  }
390
390
 
391
+ /** Helper function to determine if the current room index is equal to `GridRoom.MEGA_SATAN`. */
391
392
  export function inMegaSatanRoom(): boolean {
392
393
  const roomGridIndex = getRoomGridIndex();
393
394
 
@@ -116,6 +116,10 @@ export function goToStage(stage: LevelStage, stageType: StageType): void {
116
116
  Isaac.ExecuteCommand(command);
117
117
  }
118
118
 
119
+ /**
120
+ * Helper function to check if the provided stage type is equal to `StageType.REPENTANCE` or
121
+ * `StageType.REPENTANCE_B`.
122
+ */
119
123
  export function isRepentanceStage(stageType: StageType): boolean {
120
124
  return (
121
125
  stageType === StageType.REPENTANCE || stageType === StageType.REPENTANCE_B
@@ -178,6 +182,23 @@ export function onFinalFloor(): boolean {
178
182
  );
179
183
  }
180
184
 
185
+ /**
186
+ * Returns whether or not the player is on the first floor of the particular run.
187
+ *
188
+ * This is tricky to determine because we have to handle the cases of Downpour/Dross 1 not being the
189
+ * first floor and The Ascent.
190
+ */
191
+ export function onFirstFloor(): boolean {
192
+ const effectiveStage = getEffectiveStage();
193
+ const isOnAscent = onAscent();
194
+
195
+ return effectiveStage === 1 && !isOnAscent;
196
+ }
197
+
198
+ /**
199
+ * Helper function to check if the current stage type is equal to `StageType.REPENTANCE` or
200
+ * `StageType.REPENTANCE_B`.
201
+ */
181
202
  export function onRepentanceStage(): boolean {
182
203
  const level = game.GetLevel();
183
204
  const stageType = level.GetStageType();