isaacscript-common 11.2.4 → 12.1.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 +8 -3
  2. package/dist/isaacscript-common.lua +157 -62
  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/extraConsoleCommands/listCommands.d.ts +2 -0
  25. package/dist/src/features/extraConsoleCommands/listCommands.d.ts.map +1 -1
  26. package/dist/src/features/extraConsoleCommands/listCommands.lua +19 -0
  27. package/dist/src/features/saveDataManager/constants.d.ts +10 -0
  28. package/dist/src/features/saveDataManager/constants.d.ts.map +1 -0
  29. package/dist/src/features/saveDataManager/constants.lua +10 -0
  30. package/dist/src/features/saveDataManager/exports.d.ts +8 -3
  31. package/dist/src/features/saveDataManager/exports.d.ts.map +1 -1
  32. package/dist/src/features/saveDataManager/exports.lua +10 -5
  33. package/dist/src/features/saveDataManager/load.d.ts.map +1 -1
  34. package/dist/src/features/saveDataManager/load.lua +9 -9
  35. package/dist/src/features/saveDataManager/main.d.ts.map +1 -1
  36. package/dist/src/features/saveDataManager/main.lua +67 -4
  37. package/dist/src/features/saveDataManager/maps.d.ts +5 -0
  38. package/dist/src/features/saveDataManager/maps.d.ts.map +1 -1
  39. package/dist/src/features/saveDataManager/maps.lua +3 -0
  40. package/dist/src/features/saveDataManager/merge.lua +2 -2
  41. package/dist/src/features/saveDataManager/save.lua +3 -3
  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/extraConsoleCommands/listCommands.ts +21 -1
  58. package/src/features/saveDataManager/constants.ts +15 -0
  59. package/src/features/saveDataManager/exports.ts +9 -4
  60. package/src/features/saveDataManager/load.ts +13 -9
  61. package/src/features/saveDataManager/main.ts +78 -4
  62. package/src/features/saveDataManager/maps.ts +6 -0
  63. package/src/features/saveDataManager/merge.ts +1 -1
  64. package/src/features/saveDataManager/save.ts +1 -1
  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
@@ -67,7 +67,7 @@ import {
67
67
  import { HealthType } from "../../enums/HealthType";
68
68
  import { getCardName } from "../../functions/cards";
69
69
  import { getCharacterName } from "../../functions/characters";
70
- import { addCharge } from "../../functions/charge";
70
+ import { addCharge, getTotalCharge } from "../../functions/charge";
71
71
  import { isValidCollectibleType } from "../../functions/collectibles";
72
72
  import { runDeepCopyTests } from "../../functions/deepCopyTests";
73
73
  import { getNPCs } from "../../functions/entitiesSpecific";
@@ -655,6 +655,26 @@ export function getChallenge(): void {
655
655
  printConsole(`The current challenge is: ${challengeDescription}`);
656
656
  }
657
657
 
658
+ /** Prints the charge for the specified slot. By default, will use `ActiveSlot.PRIMARY`. */
659
+ export function getCharge(params: string): void {
660
+ let activeSlot = ActiveSlot.PRIMARY;
661
+ if (params !== "") {
662
+ const num = tonumber(params) as ActiveSlot | undefined;
663
+ if (num === undefined) {
664
+ printConsole(`The provided slot number is invalid: ${params}`);
665
+ return;
666
+ }
667
+
668
+ activeSlot = num;
669
+ }
670
+
671
+ const player = Isaac.GetPlayer();
672
+ const totalCharge = getTotalCharge(player, activeSlot);
673
+ printConsole(
674
+ `Total charge for ActiveSlot.${ActiveSlot[activeSlot]} (${activeSlot}) is: ${totalCharge}`,
675
+ );
676
+ }
677
+
658
678
  /** Prints the current position of all players. */
659
679
  export function getPosition(): void {
660
680
  for (const player of getPlayers()) {
@@ -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,
@@ -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";