isaacscript-common 11.2.3 → 12.0.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 (71) hide show
  1. package/dist/index.d.ts +18 -3
  2. package/dist/isaacscript-common.lua +161 -96
  3. package/dist/package.lua +1 -1
  4. package/dist/src/features/customStage/backdrop.lua +2 -2
  5. package/dist/src/features/customStage/{customStageConstants.d.ts → constants.d.ts} +1 -1
  6. package/dist/src/features/customStage/constants.d.ts.map +1 -0
  7. package/dist/src/features/customStage/{customStageConstants.lua → constants.lua} +0 -0
  8. package/dist/src/features/customStage/init.lua +2 -2
  9. package/dist/src/features/customStage/shadows.lua +2 -2
  10. package/dist/src/features/customStage/streakText.d.ts.map +1 -1
  11. package/dist/src/features/customStage/streakText.lua +3 -3
  12. package/dist/src/features/customStage/v.d.ts +1 -1
  13. package/dist/src/features/customStage/v.d.ts.map +1 -1
  14. package/dist/src/features/customStage/v.lua +2 -2
  15. package/dist/src/features/customStage/versusScreen.lua +3 -3
  16. package/dist/src/features/customTrapdoor/{customTrapdoorConstants.d.ts → constants.d.ts} +1 -1
  17. package/dist/src/features/customTrapdoor/constants.d.ts.map +1 -0
  18. package/dist/src/features/customTrapdoor/{customTrapdoorConstants.lua → constants.lua} +0 -0
  19. package/dist/src/features/customTrapdoor/exports.lua +2 -2
  20. package/dist/src/features/customTrapdoor/init.lua +4 -4
  21. package/dist/src/features/customTrapdoor/openClose.lua +4 -4
  22. package/dist/src/features/customTrapdoor/spawn.lua +2 -2
  23. package/dist/src/features/customTrapdoor/touched.lua +6 -6
  24. package/dist/src/features/saveDataManager/constants.d.ts +10 -0
  25. package/dist/src/features/saveDataManager/constants.d.ts.map +1 -0
  26. package/dist/src/features/saveDataManager/constants.lua +10 -0
  27. package/dist/src/features/saveDataManager/exports.d.ts +8 -3
  28. package/dist/src/features/saveDataManager/exports.d.ts.map +1 -1
  29. package/dist/src/features/saveDataManager/exports.lua +10 -5
  30. package/dist/src/features/saveDataManager/load.d.ts.map +1 -1
  31. package/dist/src/features/saveDataManager/load.lua +9 -9
  32. package/dist/src/features/saveDataManager/main.d.ts.map +1 -1
  33. package/dist/src/features/saveDataManager/main.lua +67 -4
  34. package/dist/src/features/saveDataManager/maps.d.ts +5 -0
  35. package/dist/src/features/saveDataManager/maps.d.ts.map +1 -1
  36. package/dist/src/features/saveDataManager/maps.lua +3 -0
  37. package/dist/src/features/saveDataManager/merge.lua +2 -2
  38. package/dist/src/features/saveDataManager/save.lua +3 -3
  39. package/dist/src/functions/charge.d.ts +9 -0
  40. package/dist/src/functions/charge.d.ts.map +1 -1
  41. package/dist/src/functions/charge.lua +23 -34
  42. package/dist/src/functions/deepCopy.lua +2 -2
  43. package/package.json +1 -1
  44. package/src/features/customStage/backdrop.ts +1 -1
  45. package/src/features/customStage/{customStageConstants.ts → constants.ts} +0 -0
  46. package/src/features/customStage/init.ts +1 -1
  47. package/src/features/customStage/shadows.ts +1 -1
  48. package/src/features/customStage/streakText.ts +1 -4
  49. package/src/features/customStage/v.ts +1 -1
  50. package/src/features/customStage/versusScreen.ts +1 -1
  51. package/src/features/customTrapdoor/{customTrapdoorConstants.ts → constants.ts} +0 -0
  52. package/src/features/customTrapdoor/exports.ts +1 -1
  53. package/src/features/customTrapdoor/init.ts +1 -1
  54. package/src/features/customTrapdoor/openClose.ts +1 -1
  55. package/src/features/customTrapdoor/spawn.ts +1 -1
  56. package/src/features/customTrapdoor/touched.ts +1 -1
  57. package/src/features/saveDataManager/constants.ts +15 -0
  58. package/src/features/saveDataManager/exports.ts +9 -4
  59. package/src/features/saveDataManager/load.ts +13 -9
  60. package/src/features/saveDataManager/main.ts +78 -4
  61. package/src/features/saveDataManager/maps.ts +6 -0
  62. package/src/features/saveDataManager/merge.ts +1 -1
  63. package/src/features/saveDataManager/save.ts +1 -1
  64. package/src/functions/charge.ts +39 -54
  65. package/src/functions/deepCopy.ts +1 -1
  66. package/dist/src/features/customStage/customStageConstants.d.ts.map +0 -1
  67. package/dist/src/features/customTrapdoor/customTrapdoorConstants.d.ts.map +0 -1
  68. package/dist/src/features/saveDataManager/saveDataManagerConstants.d.ts +0 -4
  69. package/dist/src/features/saveDataManager/saveDataManagerConstants.d.ts.map +0 -1
  70. package/dist/src/features/saveDataManager/saveDataManagerConstants.lua +0 -5
  71. package/src/features/saveDataManager/saveDataManagerConstants.ts +0 -4
@@ -24,7 +24,7 @@ import { runNextGameFrame } from "../runInNFrames";
24
24
  import {
25
25
  CUSTOM_STAGE_FEATURE_NAME,
26
26
  ISAACSCRIPT_CUSTOM_STAGE_GFX_PATH,
27
- } from "./customStageConstants";
27
+ } from "./constants";
28
28
  import {
29
29
  CUSTOM_FLOOR_STAGE,
30
30
  CUSTOM_FLOOR_STAGE_TYPE,
@@ -2,7 +2,7 @@ import { LevelStage, StageType } from "isaac-typescript-definitions";
2
2
  import { errorIfFeaturesNotInitialized } from "../../featuresInitialized";
3
3
  import { getNextStage, getNextStageType } from "../../functions/nextStage";
4
4
  import { CustomTrapdoorDestination } from "../../interfaces/private/CustomTrapdoorDestination";
5
- import { CUSTOM_TRAPDOOR_FEATURE_NAME } from "./customTrapdoorConstants";
5
+ import { CUSTOM_TRAPDOOR_FEATURE_NAME } from "./constants";
6
6
  import { spawnCustomTrapdoorToDestination } from "./spawn";
7
7
 
8
8
  /**
@@ -25,7 +25,7 @@ import {
25
25
  CUSTOM_TRAPDOOR_FEATURE_NAME,
26
26
  GridEntityTypeCustom,
27
27
  PIXELATION_TO_BLACK_FRAMES,
28
- } from "./customTrapdoorConstants";
28
+ } from "./constants";
29
29
  import { checkCustomTrapdoorOpenClose } from "./openClose";
30
30
  import { checkCustomTrapdoorPlayerTouched } from "./touched";
31
31
  import v from "./v";
@@ -8,7 +8,7 @@ import {
8
8
  TRAPDOOR_BOSS_REACTION_FRAMES,
9
9
  TRAPDOOR_OPEN_DISTANCE,
10
10
  TRAPDOOR_OPEN_DISTANCE_AFTER_BOSS,
11
- } from "./customTrapdoorConstants";
11
+ } from "./constants";
12
12
 
13
13
  export function checkCustomTrapdoorOpenClose(
14
14
  gridEntity: GridEntity,
@@ -6,7 +6,7 @@ import { isVector } from "../../functions/vector";
6
6
  import { CustomTrapdoorDescription } from "../../interfaces/private/CustomTrapdoorDescription";
7
7
  import { CustomTrapdoorDestination } from "../../interfaces/private/CustomTrapdoorDestination";
8
8
  import { spawnCustomGridEntity } from "../customGridEntity";
9
- import { GridEntityTypeCustom } from "./customTrapdoorConstants";
9
+ import { GridEntityTypeCustom } from "./constants";
10
10
  import { shouldTrapdoorSpawnOpen } from "./openClose";
11
11
  import v from "./v";
12
12
 
@@ -24,7 +24,7 @@ import {
24
24
  OTHER_PLAYER_TRAPDOOR_JUMP_DELAY_GAME_FRAMES,
25
25
  OTHER_PLAYER_TRAPDOOR_JUMP_DURATION_GAME_FRAMES,
26
26
  TRAPDOOR_TOUCH_DISTANCE,
27
- } from "./customTrapdoorConstants";
27
+ } from "./constants";
28
28
  import v from "./v";
29
29
 
30
30
  export function checkCustomTrapdoorPlayerTouched(
@@ -0,0 +1,15 @@
1
+ import { SaveDataKey } from "../../enums/SaveDataKey";
2
+
3
+ /** Set this to true to enable more verbosity in the save data manger. */
4
+ export const SAVE_DATA_MANAGER_DEBUG = false as boolean;
5
+
6
+ export const SAVE_DATA_MANAGER_FEATURE_NAME = "save data manager";
7
+
8
+ /**
9
+ * When the Glowing Hour Glass is used, certain save data keys will automatically be restored to a
10
+ * backup.
11
+ */
12
+ export const SAVE_DATA_MANAGER_GLOWING_HOUR_GLASS_BACKUP_KEYS = [
13
+ SaveDataKey.RUN,
14
+ SaveDataKey.LEVEL,
15
+ ];
@@ -4,6 +4,7 @@ import { errorIfFeaturesNotInitialized } from "../../featuresInitialized";
4
4
  import { deepCopy } from "../../functions/deepCopy";
5
5
  import { isString } from "../../functions/types";
6
6
  import { SaveData } from "../../interfaces/SaveData";
7
+ import { SAVE_DATA_MANAGER_FEATURE_NAME } from "./constants";
7
8
  import {
8
9
  forceSaveDataManagerLoad,
9
10
  forceSaveDataManagerSave,
@@ -14,7 +15,6 @@ import {
14
15
  saveDataDefaultsMap,
15
16
  saveDataMap,
16
17
  } from "./maps";
17
- import { SAVE_DATA_MANAGER_FEATURE_NAME } from "./saveDataManagerConstants";
18
18
 
19
19
  /**
20
20
  * This is the entry point to the save data manager, a system which provides two major features:
@@ -88,9 +88,14 @@ import { SAVE_DATA_MANAGER_FEATURE_NAME } from "./saveDataManagerConstants";
88
88
  * data manager cannot do this on its own because it cannot know when your mod features are finished
89
89
  * initializing.)
90
90
  *
91
- * Finally, some features may have variables that need to be automatically reset per run/level, but
92
- * not saved to disk on game exit. (For example, if they contain functions or other non-serializable
93
- * data.) For these cases, set the second argument to `() => false`.
91
+ * Some features may have variables that need to be automatically reset per run/level, but not saved
92
+ * to disk on game exit. (For example, if they contain functions or other non-serializable data.)
93
+ * For these cases, set the second argument to `() => false`.
94
+ *
95
+ * Note that when the player uses Glowing Hour Glass, the save data manager will automatically
96
+ * restore any variables on a "run" or "level" object with a backup that was created when the room
97
+ * was entered. Thus, you should not have to explicitly program support for Glowing Hour Glass into
98
+ * your mod features that use the save data manager.
94
99
  *
95
100
  * @param key The name of the file or feature that is submitting data to be managed by the save data
96
101
  * manager. The save data manager will throw an error if the key is already registered.
@@ -3,11 +3,11 @@ import { log, logError } from "../../functions/log";
3
3
  import { iterateTableInOrder } from "../../functions/table";
4
4
  import { isString, isTable } from "../../functions/types";
5
5
  import { SaveData } from "../../interfaces/SaveData";
6
- import { merge } from "./merge";
7
6
  import {
8
7
  SAVE_DATA_MANAGER_DEBUG,
9
8
  SAVE_DATA_MANAGER_FEATURE_NAME,
10
- } from "./saveDataManagerConstants";
9
+ } from "./constants";
10
+ import { merge } from "./merge";
11
11
 
12
12
  const DEFAULT_MOD_DATA = "{}";
13
13
 
@@ -31,33 +31,37 @@ export function loadFromDisk(
31
31
  // Second, iterate over all the fields of the new table.)
32
32
  iterateTableInOrder(
33
33
  newSaveData,
34
- (key, value) => {
34
+ (subscriberName, saveData) => {
35
35
  // All elements of loaded save data should have keys that are strings equal to the name of the
36
36
  // subscriber/feature. Ignore elements with other types of keys.
37
- if (!isString(key)) {
37
+ if (!isString(subscriberName)) {
38
38
  return;
39
39
  }
40
40
 
41
41
  // All elements of loaded save data should be tables that contain fields corresponding to the
42
- // SaveData interface. Ignore elements that are not tables.
43
- if (!isTable(value)) {
42
+ // `SaveData` interface. Ignore elements that are not tables.
43
+ if (!isTable(saveData)) {
44
44
  return;
45
45
  }
46
46
 
47
47
  // Ignore elements that represent subscriptions that no longer exist in the current save data.
48
- const oldSaveDataForSubscriber = oldSaveData.get(key);
48
+ const oldSaveDataForSubscriber = oldSaveData.get(subscriberName);
49
49
  if (oldSaveDataForSubscriber === undefined) {
50
50
  return;
51
51
  }
52
52
 
53
53
  if (SAVE_DATA_MANAGER_DEBUG) {
54
- log(`Merging in stored data for feature: ${key}`);
54
+ log(`Merging in stored data for feature: ${subscriberName}`);
55
55
  }
56
56
 
57
57
  // We do not want to blow away the child tables of the existing map, because save data could
58
58
  // contain out-of-date fields. Instead, merge it one field at a time in a recursive way (and
59
59
  // convert Lua tables back to TypeScriptToLua Maps, if necessary).
60
- merge(oldSaveDataForSubscriber as LuaMap<AnyNotNil, unknown>, value, key);
60
+ merge(
61
+ oldSaveDataForSubscriber as LuaMap<AnyNotNil, unknown>,
62
+ saveData,
63
+ subscriberName,
64
+ );
61
65
  },
62
66
  SAVE_DATA_MANAGER_DEBUG,
63
67
  );
@@ -9,17 +9,20 @@ import { logError } from "../../functions/log";
9
9
  import { onFirstFloor } from "../../functions/stage";
10
10
  import { clearTable, iterateTableInOrder } from "../../functions/table";
11
11
  import { SaveData } from "../../interfaces/SaveData";
12
+ import {
13
+ SAVE_DATA_MANAGER_DEBUG,
14
+ SAVE_DATA_MANAGER_FEATURE_NAME,
15
+ SAVE_DATA_MANAGER_GLOWING_HOUR_GLASS_BACKUP_KEYS,
16
+ } from "./constants";
12
17
  import { loadFromDisk } from "./load";
13
18
  import {
14
19
  saveDataConditionalFuncMap,
15
20
  saveDataDefaultsMap,
21
+ saveDataGlowingHourGlassMap,
16
22
  saveDataMap,
17
23
  } from "./maps";
24
+ import { merge } from "./merge";
18
25
  import { saveToDisk } from "./save";
19
- import {
20
- SAVE_DATA_MANAGER_DEBUG,
21
- SAVE_DATA_MANAGER_FEATURE_NAME,
22
- } from "./saveDataManagerConstants";
23
26
 
24
27
  const RESETTABLE_SAVE_DATA_KEYS: ReadonlySet<SaveDataKey> = new Set([
25
28
  SaveDataKey.RUN,
@@ -29,6 +32,7 @@ const RESETTABLE_SAVE_DATA_KEYS: ReadonlySet<SaveDataKey> = new Set([
29
32
 
30
33
  let mod: ModUpgraded | null = null;
31
34
  let loadedDataOnThisRun = false;
35
+ let restoreGlowingHourGlassDataOnNextRoom = false;
32
36
 
33
37
  export function saveDataManagerInit(incomingMod: ModUpgraded): void {
34
38
  mod = incomingMod;
@@ -50,6 +54,7 @@ export function saveDataManagerInit(incomingMod: ModUpgraded): void {
50
54
  // ModCallback.POST_USE_ITEM (3)
51
55
  // CollectibleType.GLOWING_HOUR_GLASS (422)
52
56
  function postUseItemGlowingHourGlass() {
57
+ restoreGlowingHourGlassDataOnNextRoom = true;
53
58
  return undefined;
54
59
  }
55
60
 
@@ -118,6 +123,75 @@ function postNewLevel() {
118
123
  // ModCallbackCustom.POST_NEW_ROOM_EARLY
119
124
  function postNewRoomEarly() {
120
125
  restoreDefaults(SaveDataKey.ROOM);
126
+
127
+ // Handle the Glowing Hour Glass.
128
+ if (restoreGlowingHourGlassDataOnNextRoom) {
129
+ restoreGlowingHourGlassDataOnNextRoom = false;
130
+ restoreGlowingHourGlassBackup();
131
+ } else {
132
+ makeGlowingHourGlassBackup();
133
+ }
134
+ }
135
+
136
+ function makeGlowingHourGlassBackup() {
137
+ iterateTableInOrder(
138
+ saveDataMap,
139
+ (subscriberName, saveData) => {
140
+ for (const saveDataKey of SAVE_DATA_MANAGER_GLOWING_HOUR_GLASS_BACKUP_KEYS) {
141
+ const childTable = saveData[saveDataKey];
142
+ if (childTable === undefined) {
143
+ // This feature does not happen to store any variables on this particular child table.
144
+ continue;
145
+ }
146
+
147
+ let saveDataGlowingHourGlass =
148
+ saveDataGlowingHourGlassMap.get(subscriberName);
149
+ if (saveDataGlowingHourGlass === undefined) {
150
+ saveDataGlowingHourGlass = new LuaMap<string, unknown>() as SaveData;
151
+ }
152
+
153
+ const copiedChildTable = deepCopy(childTable);
154
+ saveDataGlowingHourGlass[saveDataKey] = copiedChildTable;
155
+ }
156
+ },
157
+ SAVE_DATA_MANAGER_DEBUG,
158
+ );
159
+ }
160
+
161
+ function restoreGlowingHourGlassBackup() {
162
+ iterateTableInOrder(
163
+ saveDataMap,
164
+ (subscriberName, saveData) => {
165
+ for (const saveDataKey of SAVE_DATA_MANAGER_GLOWING_HOUR_GLASS_BACKUP_KEYS) {
166
+ const childTable = saveData[saveDataKey];
167
+ if (childTable === undefined) {
168
+ // This feature does not happen to store any variables on this particular child table.
169
+ continue;
170
+ }
171
+
172
+ const saveDataGlowingHourGlass =
173
+ saveDataGlowingHourGlassMap.get(subscriberName);
174
+ if (saveDataGlowingHourGlass === undefined) {
175
+ // This should never happen.
176
+ continue;
177
+ }
178
+
179
+ const childTableBackup = saveDataGlowingHourGlass[saveDataKey];
180
+ if (childTableBackup === undefined) {
181
+ // This should never happen.
182
+ continue;
183
+ }
184
+
185
+ merge(
186
+ childTable as LuaMap<AnyNotNil, unknown>,
187
+ childTableBackup as LuaMap<AnyNotNil, unknown>,
188
+ // Append an arbitrary suffix for better error messages.
189
+ `${subscriberName}__glowingHourGlass`,
190
+ );
191
+ }
192
+ },
193
+ SAVE_DATA_MANAGER_DEBUG,
194
+ );
121
195
  }
122
196
 
123
197
  function restoreDefaultsAll() {
@@ -9,3 +9,9 @@ export const saveDataMap = new LuaMap<string, SaveData>();
9
9
 
10
10
  export const saveDataDefaultsMap = new LuaMap<string, SaveData>();
11
11
  export const saveDataConditionalFuncMap = new LuaMap<string, () => boolean>();
12
+
13
+ /**
14
+ * We backup some save data keys on every new room for the purposes of restoring it when Glowing
15
+ * Hour Glass is used.
16
+ */
17
+ export const saveDataGlowingHourGlassMap = new LuaMap<string, SaveData>();
@@ -11,7 +11,7 @@ import { clearTable, iterateTableInOrder } from "../../functions/table";
11
11
  import { isDefaultMap, isTSTLMap, isTSTLSet } from "../../functions/tstlClass";
12
12
  import { isTable } from "../../functions/types";
13
13
  import { getTraversalDescription } from "../../functions/utils";
14
- import { SAVE_DATA_MANAGER_DEBUG } from "./saveDataManagerConstants";
14
+ import { SAVE_DATA_MANAGER_DEBUG } from "./constants";
15
15
  import { isSerializationBrand } from "./serializationBrands";
16
16
 
17
17
  /**
@@ -7,7 +7,7 @@ import { SaveData } from "../../interfaces/SaveData";
7
7
  import {
8
8
  SAVE_DATA_MANAGER_DEBUG,
9
9
  SAVE_DATA_MANAGER_FEATURE_NAME,
10
- } from "./saveDataManagerConstants";
10
+ } from "./constants";
11
11
 
12
12
  export function saveToDisk(
13
13
  mod: Mod,
@@ -40,8 +40,12 @@ export function addCharge(
40
40
  ): int {
41
41
  const hud = game.GetHUD();
42
42
 
43
- // Ensure that there is enough space on the active item to store these amount of charges.
44
- const chargesToAdd = getClampedChargesToAdd(player, activeSlot, numCharges);
43
+ // Ensure that there is enough space on the active item to store these amount of charges. (If we
44
+ // add too many charges, it will grant orange "battery" charges, even if the player does not have
45
+ // The Battery.)
46
+ const chargesAwayFromMax = getChargesAwayFromMax(player, activeSlot);
47
+ const chargesToAdd =
48
+ numCharges > chargesAwayFromMax ? chargesAwayFromMax : numCharges;
45
49
 
46
50
  // The AAA Battery trinket might grant an additional charge.
47
51
  const modifiedChargesToAdd = getChargesToAddWithAAAModifier(
@@ -139,46 +143,18 @@ export function addRoomClearChargeToSlot(
139
143
  const room = game.GetRoom();
140
144
  const roomShape = room.GetRoomShape();
141
145
 
142
- const numCharges = bigRoomDoubleCharge ? getRoomShapeCharges(roomShape) : 1;
143
- addCharge(player, activeSlot, numCharges, playSoundEffect);
144
- }
146
+ // Big rooms grant two charges and normal rooms grant one charge.
147
+ let numCharges = bigRoomDoubleCharge ? getRoomShapeCharges(roomShape) : 1;
145
148
 
146
- /**
147
- * We don't want to add more charges than is normally possible, so we must check to see if the
148
- * player can hold the specified amount of charges in the given slot.
149
- */
150
- function getClampedChargesToAdd(
151
- player: EntityPlayer,
152
- activeSlot: ActiveSlot,
153
- numCharges: int,
154
- ) {
155
- const activeItem = player.GetActiveItem(activeSlot);
156
- const activeCharge = player.GetActiveCharge(activeSlot);
157
- const batteryCharge = player.GetBatteryCharge(activeSlot);
158
- const hasBattery = player.HasCollectible(CollectibleType.BATTERY);
159
- const maxCharges = getCollectibleMaxCharges(activeItem);
160
-
161
- if (!hasBattery && activeCharge === maxCharges) {
162
- return 0;
163
- }
164
-
165
- if (hasBattery && batteryCharge === maxCharges) {
166
- return 0;
149
+ // Handle the special case of a timed item. When clearing a room with a timed item, it should
150
+ // become fully charged.
151
+ if (chargeType === ItemConfigChargeType.TIMED) {
152
+ // The charges will become clamped to the proper amount in the `addCharge` function. (If the
153
+ // item is at 50% charge and the player has The Battery, it should go to 150% charged.)
154
+ numCharges = getCollectibleMaxCharges(activeItem);
167
155
  }
168
156
 
169
- if (!hasBattery && activeCharge + 1 === maxCharges) {
170
- // We are only 1 charge away from a full charge, so only add one charge to avoid an overcharge.
171
- // (It is possible to set orange charges without the player actually having The Battery.)
172
- return 1;
173
- }
174
-
175
- if (hasBattery && batteryCharge + 1 === maxCharges) {
176
- // We are only 1 charge away from a full double-charge, so only add one charge to avoid an
177
- // overcharge.
178
- return 1;
179
- }
180
-
181
- return numCharges;
157
+ addCharge(player, activeSlot, numCharges, playSoundEffect);
182
158
  }
183
159
 
184
160
  /**
@@ -190,26 +166,14 @@ function getChargesToAddWithAAAModifier(
190
166
  activeSlot: ActiveSlot,
191
167
  chargesToAdd: int,
192
168
  ) {
193
- const activeItem = player.GetActiveItem(activeSlot);
194
- const activeCharge = player.GetActiveCharge(activeSlot);
195
- const batteryCharge = player.GetBatteryCharge(activeSlot);
196
- const hasBattery = player.HasCollectible(CollectibleType.BATTERY);
197
169
  const hasAAABattery = player.HasTrinket(TrinketType.AAA_BATTERY);
198
- const maxCharges = getCollectibleMaxCharges(activeItem);
199
-
200
170
  if (!hasAAABattery) {
201
171
  return chargesToAdd;
202
172
  }
203
173
 
204
- if (!hasBattery && activeCharge + chargesToAdd === maxCharges - 1) {
205
- return chargesToAdd + 1;
206
- }
207
-
208
- if (hasBattery && batteryCharge + chargesToAdd === maxCharges - 1) {
209
- return chargesToAdd + 1;
210
- }
211
-
212
- return chargesToAdd;
174
+ const chargesAwayFromMax = getChargesAwayFromMax(player, activeSlot);
175
+ const AAABatteryShouldApply = chargesToAdd === chargesAwayFromMax - 1;
176
+ return AAABatteryShouldApply ? chargesToAdd + 1 : chargesToAdd;
213
177
  }
214
178
 
215
179
  /**
@@ -231,6 +195,27 @@ export function addRoomClearCharges(bigRoomDoubleCharge = true): void {
231
195
  }
232
196
  }
233
197
 
198
+ /**
199
+ * Helper function to get the amount of charges away from the maximum charge that a particular
200
+ * player is.
201
+ *
202
+ * This function accounts for The Battery. For example, if the player has 2/6 charges on a D6, this
203
+ * function will return 10 (because there are 4 charges remaining on the base charge and 6 charges
204
+ * remaining on The Battery charge).
205
+ */
206
+ export function getChargesAwayFromMax(
207
+ player: EntityPlayer,
208
+ activeSlot: ActiveSlot,
209
+ ): int {
210
+ const totalCharge = getTotalCharge(player, activeSlot);
211
+ const activeItem = player.GetActiveItem(activeSlot);
212
+ const hasBattery = player.HasCollectible(CollectibleType.BATTERY);
213
+ const maxCharges = getCollectibleMaxCharges(activeItem);
214
+ const effectiveMaxCharges = hasBattery ? maxCharges * 2 : maxCharges;
215
+
216
+ return effectiveMaxCharges - totalCharge;
217
+ }
218
+
234
219
  /**
235
220
  * Helper function to get the combined normal charge and the battery charge for the player's active
236
221
  * item. This is useful because you have to add these two values together when setting the active
@@ -1,7 +1,7 @@
1
1
  import { DefaultMap } from "../classes/DefaultMap";
2
2
  import { SerializationBrand } from "../enums/private/SerializationBrand";
3
3
  import { SerializationType } from "../enums/SerializationType";
4
- import { SAVE_DATA_MANAGER_DEBUG } from "../features/saveDataManager/saveDataManagerConstants";
4
+ import { SAVE_DATA_MANAGER_DEBUG } from "../features/saveDataManager/constants";
5
5
  import { isSerializationBrand } from "../features/saveDataManager/serializationBrands";
6
6
  import { TSTLClass } from "../types/TSTLClass";
7
7
  import { isArray } from "./array";
@@ -1 +0,0 @@
1
- {"version":3,"file":"customStageConstants.d.ts","sourceRoot":"","sources":["../../../../src/features/customStage/customStageConstants.ts"],"names":[],"mappings":";AAAA,eAAO,MAAM,yBAAyB,gBAAgB,CAAC;AAEvD,eAAO,MAAM,iCAAiC,iCAAiC,CAAC;AAEhF,uCAAuC;AACvC,oBAAY,iBAAiB;IAC3B,IAAI,IAAA;IACJ,IAAI,IAAA;IACJ,SAAS,IAAA;CACV;AAED,uCAAuC;AACvC,eAAO,MAAM,8BAA8B,EAAE;IAC3C,QAAQ,EAAE,GAAG,IAAI,iBAAiB,GAAG,GAAG;CAKhC,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"customTrapdoorConstants.d.ts","sourceRoot":"","sources":["../../../../src/features/customTrapdoor/customTrapdoorConstants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAE9D,eAAO,MAAM,4BAA4B,mBAAmB,CAAC;AAE7D,eAAO,MAAM,oBAAoB;IAC/B;;;OAGG;;CAEK,CAAC;AAEX,2FAA2F;AAC3F,eAAO,MAAM,sBAAsB,KAAK,CAAC;AAEzC,eAAO,MAAM,iCAAiC,QAA+B,CAAC;AAC9E,eAAO,MAAM,6BAA6B,KAAK,CAAC;AAEhD,eAAO,MAAM,uBAAuB,OAAO,CAAC;AAE5C,eAAO,MAAM,oCAAoC,EAAE,WAAW,CAAC,MAAM,CAClC,CAAC;AAEpC,eAAO,MAAM,0BAA0B,KAAK,CAAC;AAE7C,eAAO,MAAM,4CAA4C,IAAI,CAAC;AAC9D,eAAO,MAAM,+CAA+C,IAAI,CAAC"}
@@ -1,4 +0,0 @@
1
- /** Set this to true to enable more verbosity in the save data manger. */
2
- export declare const SAVE_DATA_MANAGER_DEBUG: boolean;
3
- export declare const SAVE_DATA_MANAGER_FEATURE_NAME = "save data manager";
4
- //# sourceMappingURL=saveDataManagerConstants.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"saveDataManagerConstants.d.ts","sourceRoot":"","sources":["../../../../src/features/saveDataManager/saveDataManagerConstants.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,eAAO,MAAM,uBAAuB,SAAmB,CAAC;AAExD,eAAO,MAAM,8BAA8B,sBAAsB,CAAC"}
@@ -1,5 +0,0 @@
1
- local ____exports = {}
2
- --- Set this to true to enable more verbosity in the save data manger.
3
- ____exports.SAVE_DATA_MANAGER_DEBUG = false
4
- ____exports.SAVE_DATA_MANAGER_FEATURE_NAME = "save data manager"
5
- return ____exports
@@ -1,4 +0,0 @@
1
- /** Set this to true to enable more verbosity in the save data manger. */
2
- export const SAVE_DATA_MANAGER_DEBUG = false as boolean;
3
-
4
- export const SAVE_DATA_MANAGER_FEATURE_NAME = "save data manager";