diff --git a/Classes/Events/EventDatabase.cs b/Classes/Events/EventDatabase.cs
index 89a97a82..fea84d92 100644
--- a/Classes/Events/EventDatabase.cs
+++ b/Classes/Events/EventDatabase.cs
@@ -17,7 +17,7 @@ public class EventDatabase
["EVENT_EVENT1_OPTION1", "EVENT_EVENT1_OPTION2", "EVENT_EVENT1_OPTION3"],
["EVENT_EVENT1_OUTCOME1", "EVENT_EVENT1_OUTCOME2", "EVENT_EVENT1_OUTCOME3"],
[
- (self, node) =>
+ (self, _) =>
{
int randIndex = StageProducer.GlobalRng.RandiRange(
0,
@@ -33,7 +33,7 @@ public class EventDatabase
localizedName
);
},
- (self, node) =>
+ (self, _) =>
{
int randIndex = StageProducer.GlobalRng.RandiRange(
0,
@@ -49,12 +49,12 @@ public class EventDatabase
localizedName
);
},
- (self, node) =>
+ (self, _) =>
{
string stolenMoney = (StageProducer.PlayerStats.Money / 2).ToString();
StageProducer.PlayerStats.Money /= 2;
- self.OutcomeDescriptions[2] = self.OutcomeDescriptions[0] = string.Format(
+ self.OutcomeDescriptions[2] = string.Format(
TranslationServer.Translate("EVENT_EVENT1_OUTCOME3"),
stolenMoney
);
@@ -176,18 +176,18 @@ public class EventDatabase
["EVENT_EVENT3_OPTION1", "EVENT_EVENT3_OPTION2", "EVENT_EVENT3_OPTION3"],
["EVENT_EVENT3_OUTCOME1", "EVENT_EVENT3_OUTCOME2", "EVENT_EVENT3_OUTCOME3"],
[
- (self, node) =>
+ (_, _) =>
{
StageProducer.PlayerStats.CurrentHealth = Math.Min(
StageProducer.PlayerStats.CurrentHealth + 10,
StageProducer.PlayerStats.MaxHealth
);
},
- (self, node) =>
+ (_, _) =>
{
StageProducer.PlayerStats.MaxComboBar -= 5;
},
- (self, node) =>
+ (_, _) =>
{
StageProducer.PlayerStats.Money -= 30;
StageProducer.PlayerStats.AddNote(Scribe.NoteDictionary[3]);
diff --git a/Classes/MidiMaestro/MidiMaestro.cs b/Classes/MidiMaestro/MidiMaestro.cs
index 2c7bfa8f..be5d6c33 100644
--- a/Classes/MidiMaestro/MidiMaestro.cs
+++ b/Classes/MidiMaestro/MidiMaestro.cs
@@ -15,25 +15,12 @@ public partial class MidiMaestro : Resource
private readonly NoteInfo[] _leftNotes;
private readonly NoteInfo[] _rightNotes;
- //private MidiFile strippedSong;
/**
* Constructor loads resource file and populates lane note arrays with NoteInfo
* A string file path to a valid songMap .tres file
*/
public MidiMaestro(NoteChart savedChart)
{
- /*if (!OS.HasFeature("editor"))
- {
- filePath = OS.GetExecutablePath().GetBaseDir() + "/" + filePath;
- }
-
- if (!FileAccess.FileExists(filePath))
- {
- GD.PushError("ERROR: Unable to load level songMap resource file: " + filePath);
- }
-
- NoteChart savedChart = ResourceLoader.Load(filePath);*/
-
if (savedChart != null)
{
_upNotes = savedChart.GetLane(ArrowType.Up).ToArray();
diff --git a/Globals/SaveSystem.cs b/Globals/Configkeeper.cs
similarity index 79%
rename from Globals/SaveSystem.cs
rename to Globals/Configkeeper.cs
index 8e478d50..85e635bd 100644
--- a/Globals/SaveSystem.cs
+++ b/Globals/Configkeeper.cs
@@ -7,7 +7,7 @@
/**
* SaveSystem: Manages FileI/O of configs and save files.
*/
-public static class SaveSystem
+public static class Configkeeper
{
#region Config
private const string UserConfigPath = "user://Options.cfg";
@@ -31,8 +31,6 @@ public static class SaveSystem
private const bool DefaultTypeIsArrow = false;
private const bool DefaultVerticalScroll = true;
private const bool DefaultHighCon = false;
- private const bool DefaultFirstTime = true;
- private const bool DefaultHasWon = false;
public enum ConfigSettings
{
@@ -53,8 +51,6 @@ public enum ConfigSettings
LanguageKey,
TypeIsArrow,
HighContrast,
- FirstTime,
- HasWon,
VerticalScroll,
}
@@ -81,8 +77,6 @@ private static void InitConfig()
UpdateConfig(ConfigSettings.LanguageKey, DefaultLanguage);
UpdateConfig(ConfigSettings.TypeIsArrow, DefaultTypeIsArrow);
UpdateConfig(ConfigSettings.HighContrast, DefaultHighCon);
- UpdateConfig(ConfigSettings.FirstTime, DefaultFirstTime);
- UpdateConfig(ConfigSettings.HasWon, DefaultHasWon);
UpdateConfig(ConfigSettings.VerticalScroll, DefaultVerticalScroll);
}
@@ -151,12 +145,6 @@ public static void UpdateConfig(ConfigSettings setting, Variant value)
case ConfigSettings.HighContrast:
_curConfigData.SetValue("Options", "HighContrast", value);
break;
- case ConfigSettings.FirstTime:
- _curConfigData.SetValue("Game", "FirstTime", value);
- break;
- case ConfigSettings.HasWon:
- _curConfigData.SetValue("Game", "HasWon", value);
- break;
default:
GD.PushError("SaveSystem.UpdateConfig: Invalid config setting passed. " + setting);
break;
@@ -298,10 +286,6 @@ public static Variant GetConfigValue(ConfigSettings setting)
return _curConfigData.GetValue("Options", "VerticalScroll", DefaultVerticalScroll);
case ConfigSettings.HighContrast:
return _curConfigData.GetValue("Options", "HighContrast", DefaultHighCon);
- case ConfigSettings.FirstTime:
- return _curConfigData.GetValue("Game", "FirstTime", DefaultFirstTime);
- case ConfigSettings.HasWon:
- return _curConfigData.GetValue("Game", "HasWon", DefaultHasWon);
default:
GD.PushError("Invalid config setting passed. " + setting);
return float.MinValue;
@@ -399,110 +383,4 @@ public static void ClearConfig()
InitConfig();
}
#endregion
-
- #region Save
-
- private const string UserSavePath = "user://MidnighRiff.save";
-
- public class SaveFile
- {
- public ulong RngSeed { get; init; }
- public ulong RngState { get; init; }
- public int LastRoomIdx { get; init; }
- public int Area { get; init; }
-
- public int Money { get; init; }
- public int[] NoteIds { get; init; }
- public int[] RelicIds { get; init; }
- public int[] BattlePool { get; init; }
- public int[] EventPool { get; init; }
- public int PlayerHealth { get; init; }
- public int Shortcuts { get; init; }
- public int PlayerMaxCombo { get; init; }
-
- public SaveFile(
- ulong rngSeed,
- ulong rngState,
- int lastRoomIdx,
- int[] noteIds,
- int[] relicIds,
- int[] battlePool,
- int[] eventPool,
- int playerHealth,
- int area,
- int money,
- int shortcuts,
- int playerMaxCombo
- )
- {
- RngSeed = rngSeed;
- RngState = rngState;
- LastRoomIdx = lastRoomIdx;
- NoteIds = noteIds;
- RelicIds = relicIds;
- BattlePool = battlePool ?? [];
- EventPool = eventPool ?? [];
- PlayerHealth = playerHealth;
- Area = area;
- Money = money;
- Shortcuts = shortcuts;
- PlayerMaxCombo = playerMaxCombo;
- }
- }
-
- public static void SaveGame()
- {
- int[] relicIds = StageProducer.PlayerStats.CurRelics.Select(r => r.Id).ToArray();
- int[] noteIds = StageProducer.PlayerStats.CurNotes.Select(r => r.Id).ToArray();
- SaveFile sv = new SaveFile(
- StageProducer.GlobalRng.Seed,
- StageProducer.GlobalRng.State,
- StageProducer.CurRoom,
- noteIds,
- relicIds,
- StageProducer.BattlePool?.ToArray(),
- EventScene.EventPool?.ToArray(),
- StageProducer.PlayerStats.CurrentHealth,
- StageProducer.CurLevel.Id,
- StageProducer.PlayerStats.Money,
- StageProducer.PlayerStats.Shortcuts,
- StageProducer.PlayerStats.MaxComboBar
- );
- string json = JsonSerializer.Serialize(sv);
-
- FileAccess file = FileAccess.Open(UserSavePath, FileAccess.ModeFlags.Write);
-
- file.StoreLine(json);
- file.Close();
- }
-
- /**
- * Returns null if invalid save or save 404's.
- */
- public static SaveFile LoadGame()
- {
- if (!FileAccess.FileExists(UserSavePath))
- return null;
- FileAccess file = FileAccess.Open(UserSavePath, FileAccess.ModeFlags.Read);
- string json = file.GetAsText();
-
- file.Close();
- SaveFile sv;
- try
- {
- sv = JsonSerializer.Deserialize(json);
- }
- catch (JsonException)
- {
- GD.PushWarning("Cannot deserialize save file, returning null.");
- return null;
- }
- return sv;
- }
-
- public static void ClearSave()
- {
- DirAccess.RemoveAbsolute(UserSavePath);
- }
- #endregion
}
diff --git a/Globals/Configkeeper.cs.uid b/Globals/Configkeeper.cs.uid
new file mode 100644
index 00000000..55fcc578
--- /dev/null
+++ b/Globals/Configkeeper.cs.uid
@@ -0,0 +1 @@
+uid://bbkyrplc17j0w
diff --git a/Globals/Savekeeper.cs b/Globals/Savekeeper.cs
new file mode 100644
index 00000000..68cf96fe
--- /dev/null
+++ b/Globals/Savekeeper.cs
@@ -0,0 +1,281 @@
+using System;
+using System.Collections.Generic;
+using Godot;
+using FileAccess = Godot.FileAccess;
+
+///
+/// v1 of a drag and drop save system.
+/// Does not work with Godot resources for safer handling.
+/// Assumptions:
+/// T needs ToString() and T.TryParse(string value, out T result) -> bool
+/// Objects need to implement their own Serialize and Deserialize
+///
+public partial class Savekeeper : Node
+{
+ private const string SaveFileDirectory = "user://saves";
+ private const string SaveFileExtension = ".save";
+ private const string DefaultSaveFileName = "MidnightRiff";
+
+ private const char Delimiter = '|';
+
+ public delegate void SavingHandler();
+
+ ///
+ /// Event that a save is underway. Subscribe to serialize data before writing.
+ ///
+ public static event SavingHandler Saving;
+
+ public delegate void GameSavedHandler();
+ public static event GameSavedHandler GameSaved;
+
+ public delegate void LoadedHandler();
+ public static event LoadedHandler Loaded;
+
+ public override void _EnterTree()
+ {
+ DirAccess.MakeDirAbsolute(SaveFileDirectory);
+ }
+
+ public static Dictionary GameSaveObjects { get; private set; } =
+ new Dictionary();
+
+ private static void HandlePrevSave()
+ {
+ return; //Placeholder to do things, e.g. make a backup
+ }
+
+ public static void RecordSave(string savePath = DefaultSaveFileName + SaveFileExtension)
+ {
+ Saving?.Invoke();
+ Callable.From(() => SaveToFile(savePath)).CallDeferred();
+ }
+
+ public static bool SaveToFile(string savePath = DefaultSaveFileName + SaveFileExtension)
+ {
+ if (string.IsNullOrEmpty(savePath))
+ return false;
+ FileAccess file = FileAccess.Open(
+ SaveFileDirectory + "/" + savePath,
+ FileAccess.ModeFlags.Write
+ );
+ if (file == null)
+ return false;
+
+ foreach ((string key, string value) in GameSaveObjects)
+ file.StoreLine(key + Delimiter + value);
+ file.Close();
+
+ GameSaved?.Invoke();
+ return true;
+ }
+
+ public static bool LoadFromFile(string savePath = DefaultSaveFileName + SaveFileExtension)
+ {
+ if (string.IsNullOrEmpty(savePath))
+ return false;
+ FileAccess file = FileAccess.Open(
+ SaveFileDirectory + "/" + savePath,
+ FileAccess.ModeFlags.Read
+ );
+ if (file == null)
+ return false;
+
+ HandlePrevSave();
+
+ while (file.GetPosition() < file.GetLength())
+ {
+ string line = file.GetLine().Trim();
+ int idx = line.IndexOf(Delimiter);
+ if (idx == -1)
+ continue;
+
+ string key = line.Substring(0, idx);
+ string value = SanitizeSaveString(line.Substring(idx));
+ if (value == null)
+ continue;
+
+ GameSaveObjects[key] = value;
+ }
+
+ Loaded?.Invoke();
+ return true;
+ }
+
+ private static string SanitizeSaveString(string saveString)
+ {
+ if (string.IsNullOrEmpty(saveString))
+ return null;
+ saveString = saveString.Trim();
+ if (saveString.Length == 0 || saveString[0] != Delimiter)
+ return null;
+ return saveString.Substring(1);
+ }
+
+ const string InvalidFormatString = "InvalidString";
+
+ //Ex: Position.X|45.8|
+ public static string Format(string valName, object value)
+ {
+ if (value == null)
+ return "";
+ if (value is string s && !s.IsValidFileName())
+ return valName + Delimiter + InvalidFormatString + Delimiter;
+
+ return valName + Delimiter + value + Delimiter;
+ }
+
+ private const string ArrayDelimiter = "*";
+
+ //Ex: ValidIds|[12*1*4*5]|
+ public static string FormatArray(string valName, T[] value)
+ {
+ if (value == null)
+ return "";
+ String retString = valName + Delimiter + '[';
+
+ foreach (object o in value)
+ {
+ if (o is string s && !s.IsValidFileName())
+ {
+ retString += InvalidFormatString + ArrayDelimiter;
+ continue;
+ }
+ retString += o.ToString() + ArrayDelimiter;
+ }
+ retString += "]" + Delimiter;
+ return retString;
+ }
+
+ public readonly struct ParseResult(
+ T value,
+ bool success,
+ int nextIdx,
+ string message = "Success!"
+ )
+ {
+ public T Value { get; init; } = value;
+ public bool Success { get; init; } = success;
+ public int NextIdx { get; init; } = nextIdx;
+ public string Message { get; init; } = message;
+ }
+
+ public delegate bool TryParseHandler(string value, out T result); //https://stackoverflow.com/questions/2961656/generic-tryparse
+
+ public static bool StringParse(string value, out string result)
+ {
+ result = value;
+ return true;
+ }
+
+ public static ParseResult Parse(
+ string valName,
+ string saveString,
+ int startIdx,
+ TryParseHandler handler
+ )
+ {
+ if (string.IsNullOrEmpty(valName) || string.IsNullOrEmpty(saveString))
+ return new ParseResult(
+ default,
+ false,
+ startIdx,
+ $"String was empty! {valName} {saveString}"
+ );
+
+ ParseResult success = ParseToSubStringValue(saveString, valName, startIdx);
+ if (!success.Success)
+ return new ParseResult(default, false, startIdx, success.Message);
+ string value = success.Value;
+ int finalIdx = success.NextIdx;
+
+ if (handler(value, out var result))
+ return new ParseResult(result, true, finalIdx);
+
+ return new ParseResult(
+ default,
+ false,
+ startIdx,
+ $"Unable to parse from: \"{value}\" to type: {typeof(T)}"
+ );
+ }
+
+ public static ParseResult ParseArray(
+ string valName,
+ string saveString,
+ int startIdx,
+ TryParseHandler handler
+ )
+ {
+ if (string.IsNullOrEmpty(valName) || string.IsNullOrEmpty(saveString))
+ return new ParseResult(
+ default,
+ false,
+ startIdx,
+ $"String was empty! {valName} {saveString}"
+ );
+
+ ParseResult success = ParseToSubStringValue(saveString, valName, startIdx);
+ if (!success.Success)
+ return new ParseResult(default, false, startIdx, success.Message);
+ string value = success.Value;
+ int finalIdx = success.NextIdx;
+
+ string[] values = value.Replace("[", "").Replace("]", "").Split(ArrayDelimiter);
+ List list = new List();
+ foreach (String s in values)
+ {
+ if (string.IsNullOrEmpty(s))
+ continue;
+ if (!handler(s, out var result))
+ return new ParseResult(
+ list.ToArray(),
+ false,
+ finalIdx,
+ $"Unable to parse from: \"{s}\" to type: {typeof(T)}. Returning any successful values."
+ );
+
+ list.Add(result);
+ }
+
+ return new ParseResult(list.ToArray(), true, finalIdx);
+ }
+
+ private static ParseResult ParseToSubStringValue(
+ string saveString,
+ string valName,
+ int startIdx
+ )
+ {
+ int nextIdx = saveString.IndexOf(valName, startIdx, StringComparison.Ordinal);
+ if (nextIdx == -1)
+ return new ParseResult(default, false, startIdx, $"Name not found! {valName}");
+
+ nextIdx += valName.Length + 1;
+ int finalIdx = saveString.IndexOf(Delimiter, nextIdx);
+ if (finalIdx == -1)
+ return new ParseResult(
+ default,
+ false,
+ startIdx,
+ $"No final delimiter found around value! \n String received: {saveString}, from position {nextIdx}"
+ );
+ string value = saveString.Substring(nextIdx, finalIdx - nextIdx);
+
+ return new ParseResult(value, true, finalIdx);
+ }
+
+ #region Project Specific
+
+ public const string DefaultRunSaveHeader = "CurrentGame";
+
+ public static void ClearRun()
+ {
+ if (GameSaveObjects.ContainsKey(DefaultRunSaveHeader))
+ {
+ GameSaveObjects.Remove(DefaultRunSaveHeader);
+ SaveToFile();
+ }
+ }
+
+ #endregion
+}
diff --git a/Globals/Savekeeper.cs.uid b/Globals/Savekeeper.cs.uid
new file mode 100644
index 00000000..18d0030f
--- /dev/null
+++ b/Globals/Savekeeper.cs.uid
@@ -0,0 +1 @@
+uid://ckw1qew68cetv
diff --git a/Globals/Scribe.cs b/Globals/Scribe.cs
index 7cab15df..80f0a6d2 100644
--- a/Globals/Scribe.cs
+++ b/Globals/Scribe.cs
@@ -715,7 +715,7 @@ e is BattleDirector.Harbinger.OnDamageInstanceArgs dmgArgs
),
};
- private static string DefaultNoteChartPath = "Audio/songMaps/";
+ private static string DefaultNoteChartPath = "res://Audio/songMaps/";
public static readonly SongTemplate[] SongDictionary = new[] //Generalize and make pools for areas/room types
{
@@ -800,13 +800,13 @@ e is BattleDirector.Harbinger.OnDamageInstanceArgs dmgArgs
ResourceLoader.Load(DefaultNoteChartPath + "FrostWaltz.tres")
),
new SongTemplate( // 16
- name: "Astrorat",
- enemyScenePath: [P_Astrorat.LoadPath],
+ "Astrorat",
+ [P_Astrorat.LoadPath],
ResourceLoader.Load(DefaultNoteChartPath + "Astrorat.tres")
),
new SongTemplate( // 17
- name: "CatGirl",
- enemyScenePath: [P_Midriff.LoadPath],
+ "CatGirl",
+ [P_Midriff.LoadPath],
ResourceLoader.Load(DefaultNoteChartPath + "Jammin' Forest.tres")
),
};
diff --git a/Globals/StageProducer.cs b/Globals/StageProducer.cs
index b0a3e6e0..62f8a742 100644
--- a/Globals/StageProducer.cs
+++ b/Globals/StageProducer.cs
@@ -16,7 +16,7 @@ public partial class StageProducer : Node
public static readonly RandomNumberGenerator GlobalRng = new();
public static MapLevels CurLevel { get; private set; }
- public static List BattlePool { get; private set; }
+ public static List BattlePool { get; private set; } = [];
public static MapGrid Map { get; private set; } = new();
private Stages _curStage = Stages.Title;
@@ -34,6 +34,11 @@ public partial class StageProducer : Node
#region Initialization
public override void _EnterTree()
{
+ Savekeeper.Saving += SerializeRun;
+ Savekeeper.Saving += SerializePersist;
+ Savekeeper.LoadFromFile();
+ DeserializePersist();
+
InitFromCfg();
LiveInstance = this;
@@ -48,22 +53,22 @@ public override void _EnterTree()
public void InitFromCfg()
{
OptionsMenu.ChangeVolume(
- SaveSystem.GetConfigValue(SaveSystem.ConfigSettings.Volume).As()
+ Configkeeper.GetConfigValue(Configkeeper.ConfigSettings.Volume).As()
);
TranslationServer.SetLocale(
- SaveSystem.GetConfigValue(SaveSystem.ConfigSettings.LanguageKey).As()
+ Configkeeper.GetConfigValue(Configkeeper.ConfigSettings.LanguageKey).As()
);
ContrastFilter = GD.Load("res://Globals/ContrastFilter/ContrastFilter.tscn")
.Instantiate();
- ContrastFilter.Visible = SaveSystem
- .GetConfigValue(SaveSystem.ConfigSettings.HighContrast)
+ ContrastFilter.Visible = Configkeeper
+ .GetConfigValue(Configkeeper.ConfigSettings.HighContrast)
.AsBool();
GetTree().Root.CallDeferred("add_child", ContrastFilter);
- InputHandler.UseArrows = SaveSystem
- .GetConfigValue(SaveSystem.ConfigSettings.TypeIsArrow)
+ InputHandler.UseArrows = Configkeeper
+ .GetConfigValue(Configkeeper.ConfigSettings.TypeIsArrow)
.AsBool();
- BattleDirector.VerticalScroll = SaveSystem
- .GetConfigValue(SaveSystem.ConfigSettings.VerticalScroll)
+ BattleDirector.VerticalScroll = Configkeeper
+ .GetConfigValue(Configkeeper.ConfigSettings.VerticalScroll)
.AsBool();
}
@@ -77,7 +82,7 @@ private void GenerateMapConsistent()
private void StartNewGame()
{
GlobalRng.Randomize();
- if ((bool)SaveSystem.GetConfigValue(SaveSystem.ConfigSettings.FirstTime))
+ if (GetPersistantVal(PersistKeys.TutorialDone) == 0)
CurLevel = MapLevels.GetLevelFromId(0);
else
CurLevel = MapLevels.GetLevelFromId(1);
@@ -86,8 +91,8 @@ private void StartNewGame()
PlayerStats = new PlayerStats();
CurRoom = Map.GetRooms()[0].Idx;
- BattlePool = null;
- EventScene.EventPool = null;
+ BattlePool = [];
+ EventScene.EventPool = [];
Scribe.InitRelicPools();
IsInitialized = true;
MapGrid.ForceEliteBattles = false;
@@ -95,36 +100,12 @@ private void StartNewGame()
private bool LoadGame()
{
- SaveSystem.SaveFile sv = SaveSystem.LoadGame();
- if (sv == null)
+ if (!DeserializeRun())
{
GD.PushWarning("Can't load game, either file 404 or invalid file.");
return false;
}
- GlobalRng.Seed = sv.RngSeed;
- CurLevel = MapLevels.GetLevelFromId(sv.Area);
- BattlePool = sv.BattlePool.ToList();
- EventScene.EventPool = sv.EventPool.ToList();
- GenerateMapConsistent();
- GlobalRng.State = sv.RngState;
- CurRoom = sv.LastRoomIdx;
-
- Scribe.InitRelicPools();
- PlayerStats = new PlayerStats();
- PlayerStats.CurNotes = [];
- foreach (int noteId in sv.NoteIds)
- {
- PlayerStats.AddNote(Scribe.NoteDictionary[noteId]);
- }
- foreach (int relicId in sv.RelicIds)
- {
- PlayerStats.AddRelic(Scribe.RelicDictionary[relicId]);
- }
- PlayerStats.CurrentHealth = sv.PlayerHealth;
- PlayerStats.Money = sv.Money;
- PlayerStats.Shortcuts = sv.Shortcuts;
- PlayerStats.MaxComboBar = sv.PlayerMaxCombo;
IsInitialized = true;
return true;
}
@@ -360,13 +341,282 @@ public static bool IsMoreLevels()
public void ProgressLevels()
{
- GD.Print(CurLevel.Id);
CurLevel = CurLevel.GetNextLevel();
Map = new();
GenerateMapConsistent();
CurRoom = Map.GetRooms()[0].Idx;
- BattlePool = null;
+ BattlePool = [];
+ }
+
+ #endregion
+
+ #region Persistent Data
+ private const string PersistenceHeader = "PersistVals";
+
+ public enum PersistKeys
+ {
+ TutorialDone = 0,
+ HasWon = 1,
+ } //Relative order needs to be preserved between versions.
+
+ private static int[] PersistantValues { get; set; } = [0, 0]; //Dumb and hacky right now. Literally doing this to avoid bool spam for now.
+ private const string PersistentIntValName = "PersistInts";
+
+ public static int GetPersistantVal(PersistKeys key)
+ {
+ return PersistantValues[(int)key];
+ }
+
+ public static void UpdatePersistantValues(PersistKeys key, int newVal)
+ {
+ PersistantValues[(int)key] = newVal;
+ SerializePersist();
+ Savekeeper.SaveToFile();
+ }
+
+ private static void SerializePersist()
+ {
+ string saveString = "";
+ saveString += Savekeeper.FormatArray(PersistentIntValName, PersistantValues);
+ Savekeeper.GameSaveObjects[PersistenceHeader] = saveString;
+ }
+
+ private void DeserializePersist()
+ {
+ if (!Savekeeper.GameSaveObjects.TryGetValue(PersistenceHeader, out var loadPers))
+ {
+ GD.PushWarning("Savekeeper does not contain persistence key!");
+ return;
+ }
+
+ int idx = 0;
+ var success = Savekeeper.ParseArray(PersistentIntValName, loadPers, idx, int.TryParse);
+ if (success.Success)
+ {
+ int[] tempVals = success.Value;
+ for (int i = 0; i < tempVals.Length && i < PersistantValues.Length; i++) //Manually update to safeguard against saves breaking when values are added.
+ PersistantValues[i] = tempVals[i];
+ return;
+ }
+ GD.PushWarning(
+ $"Error deserializing persistent values: {loadPers} Error: {success.Message}"
+ );
+ }
+ #endregion
+
+ #region Saving
+
+ enum RunSaveValues
+ { //Maintain in order of needing to be saved & loaded
+ RngSeed,
+ Area,
+ BattlePool,
+ EventPool,
+ RngState,
+ LastRoomIdx,
+ NoteIds,
+ RelicIds,
+ PlayerHealth,
+ Money,
+ Shortcuts,
+ PlayerMaxCombo,
+ }
+
+ private void SerializeRun()
+ {
+ if (!IsInitialized)
+ return;
+ string saveString = "";
+ saveString +=
+ Savekeeper.Format(RunSaveValues.RngSeed.ToString(), GlobalRng.Seed)
+ + Savekeeper.Format(RunSaveValues.Area.ToString(), CurLevel.Id)
+ + Savekeeper.FormatArray(RunSaveValues.BattlePool.ToString(), BattlePool.ToArray())
+ + Savekeeper.FormatArray(
+ RunSaveValues.EventPool.ToString(),
+ EventScene.EventPool.ToArray()
+ )
+ + Savekeeper.Format(RunSaveValues.RngState.ToString(), GlobalRng.State)
+ + Savekeeper.Format(RunSaveValues.LastRoomIdx.ToString(), CurRoom)
+ + Savekeeper.FormatArray(
+ RunSaveValues.NoteIds.ToString(),
+ PlayerStats.CurNotes.Select(r => r.Id).ToArray()
+ )
+ + Savekeeper.FormatArray(
+ RunSaveValues.RelicIds.ToString(),
+ PlayerStats.CurRelics.Select(r => r.Id).ToArray()
+ )
+ + Savekeeper.Format(RunSaveValues.PlayerHealth.ToString(), PlayerStats.CurrentHealth)
+ + Savekeeper.Format(RunSaveValues.Money.ToString(), PlayerStats.Money)
+ + Savekeeper.Format(RunSaveValues.Shortcuts.ToString(), PlayerStats.Shortcuts)
+ + Savekeeper.Format(RunSaveValues.PlayerMaxCombo.ToString(), PlayerStats.MaxComboBar);
+
+ Savekeeper.GameSaveObjects[Savekeeper.DefaultRunSaveHeader] = saveString;
+ }
+
+ private bool DeserializeRun() //TODO: This is really verbose and bad.
+ {
+ if (!Savekeeper.GameSaveObjects.ContainsKey(Savekeeper.DefaultRunSaveHeader))
+ return false;
+ int idx = 0;
+ string loadRun = Savekeeper.GameSaveObjects[Savekeeper.DefaultRunSaveHeader];
+
+ var ulongSuccess = Savekeeper.Parse(
+ RunSaveValues.RngSeed.ToString(),
+ loadRun,
+ idx,
+ ulong.TryParse
+ );
+ if (!ulongSuccess.Success)
+ return false;
+ GlobalRng.Seed = ulongSuccess.Value;
+ idx = ulongSuccess.NextIdx;
+
+ var intSuccess = Savekeeper.Parse(
+ RunSaveValues.Area.ToString(),
+ loadRun,
+ idx,
+ int.TryParse
+ );
+ if (!intSuccess.Success)
+ return false;
+ CurLevel = MapLevels.GetLevelFromId(intSuccess.Value);
+ idx = intSuccess.NextIdx;
+
+ var bPoolSuccess = Savekeeper.ParseArray(
+ RunSaveValues.BattlePool.ToString(),
+ loadRun,
+ idx,
+ int.TryParse
+ );
+ if (bPoolSuccess.Success)
+ {
+ BattlePool = bPoolSuccess.Value.ToList();
+ idx = bPoolSuccess.NextIdx;
+ }
+ else
+ {
+ GD.PushWarning("Could not parse battle pool!");
+ BattlePool = [];
+ }
+
+ var ePoolSuccess = Savekeeper.ParseArray(
+ RunSaveValues.EventPool.ToString(),
+ loadRun,
+ idx,
+ int.TryParse
+ );
+ if (ePoolSuccess.Success)
+ {
+ EventScene.EventPool = ePoolSuccess.Value.ToList();
+ idx = ePoolSuccess.NextIdx;
+ }
+ else
+ {
+ GD.PushWarning("Could not parse event pool!");
+ EventScene.EventPool = [];
+ }
+
+ GenerateMapConsistent();
+
+ ulongSuccess = Savekeeper.Parse(
+ RunSaveValues.RngState.ToString(),
+ loadRun,
+ idx,
+ ulong.TryParse
+ );
+ if (!ulongSuccess.Success)
+ return false;
+ GlobalRng.State = ulongSuccess.Value;
+ idx = ulongSuccess.NextIdx;
+
+ intSuccess = Savekeeper.Parse(
+ RunSaveValues.LastRoomIdx.ToString(),
+ loadRun,
+ idx,
+ int.TryParse
+ );
+ if (!intSuccess.Success)
+ return false;
+ CurRoom = intSuccess.Value;
+ idx = intSuccess.NextIdx;
+
+ Scribe.InitRelicPools();
+ PlayerStats = new PlayerStats();
+ PlayerStats.CurNotes = [];
+
+ var noteSuccess = Savekeeper.ParseArray(
+ RunSaveValues.NoteIds.ToString(),
+ loadRun,
+ idx,
+ int.TryParse
+ );
+ if (!noteSuccess.Success)
+ return false;
+ foreach (int noteId in noteSuccess.Value)
+ {
+ PlayerStats.AddNote(Scribe.NoteDictionary[noteId]);
+ }
+ idx = noteSuccess.NextIdx;
+
+ var relicSuccess = Savekeeper.ParseArray(
+ RunSaveValues.RelicIds.ToString(),
+ loadRun,
+ idx,
+ int.TryParse
+ );
+ if (!relicSuccess.Success)
+ return false;
+ foreach (int relicId in relicSuccess.Value)
+ {
+ PlayerStats.AddRelic(Scribe.RelicDictionary[relicId]);
+ }
+ idx = relicSuccess.NextIdx;
+
+ intSuccess = Savekeeper.Parse(
+ RunSaveValues.PlayerHealth.ToString(),
+ loadRun,
+ idx,
+ int.TryParse
+ );
+ if (!intSuccess.Success)
+ return false;
+ PlayerStats.CurrentHealth = intSuccess.Value;
+ idx = intSuccess.NextIdx;
+
+ intSuccess = Savekeeper.Parse(
+ RunSaveValues.Money.ToString(),
+ loadRun,
+ idx,
+ int.TryParse
+ );
+ if (!intSuccess.Success)
+ return false;
+ PlayerStats.Money = intSuccess.Value;
+ idx = intSuccess.NextIdx;
+
+ intSuccess = Savekeeper.Parse(
+ RunSaveValues.Shortcuts.ToString(),
+ loadRun,
+ idx,
+ int.TryParse
+ );
+ if (!intSuccess.Success)
+ return false;
+ PlayerStats.Shortcuts = intSuccess.Value;
+ idx = intSuccess.NextIdx;
+
+ intSuccess = Savekeeper.Parse(
+ RunSaveValues.PlayerMaxCombo.ToString(),
+ loadRun,
+ idx,
+ int.TryParse
+ );
+ if (!intSuccess.Success)
+ return false;
+ PlayerStats.MaxComboBar = intSuccess.Value;
+
+ return true;
}
#endregion
diff --git a/Scenes/BattleDirector/Scripts/BattleDirector.cs b/Scenes/BattleDirector/Scripts/BattleDirector.cs
index 19b14d52..1040f01e 100644
--- a/Scenes/BattleDirector/Scripts/BattleDirector.cs
+++ b/Scenes/BattleDirector/Scripts/BattleDirector.cs
@@ -238,7 +238,6 @@ public override void _UnhandledInput(InputEvent @event)
{
if (@event is InputEventKey eventKey && eventKey.Pressed && !eventKey.Echo)
{
- return;
if (eventKey.Keycode == Key.Key0)
{
DebugKillEnemy();
@@ -389,7 +388,7 @@ private void OnBattleLost()
return;
}
Audio.StreamPaused = true;
- SaveSystem.ClearSave();
+ Savekeeper.ClearRun();
AddChild(GD.Load(EndScreen.LoadPath).Instantiate());
ProcessMode = ProcessModeEnum.Disabled;
}
diff --git a/Scenes/BattleDirector/Scripts/NotePlacementBar.cs b/Scenes/BattleDirector/Scripts/NotePlacementBar.cs
index d69e5314..94c9ccff 100644
--- a/Scenes/BattleDirector/Scripts/NotePlacementBar.cs
+++ b/Scenes/BattleDirector/Scripts/NotePlacementBar.cs
@@ -230,8 +230,8 @@ public Note NotePlaced()
{
if (!CanPlaceNote())
GD.PushWarning("Note is attempting placement without a full bar!");
- string inputType = SaveSystem
- .GetConfigValue(SaveSystem.ConfigSettings.InputType)
+ string inputType = Configkeeper
+ .GetConfigValue(Configkeeper.ConfigSettings.InputType)
.ToString();
Note placedNote = GetNote(Input.IsActionPressed(inputType + "_secondaryPlacement"));
CurrentBarValue -= placedNote.CostModifier * MaxValue;
diff --git a/Scenes/BattleDirector/Tutorial/Toriel.cs b/Scenes/BattleDirector/Tutorial/Toriel.cs
index 1ab5d190..d175c80a 100644
--- a/Scenes/BattleDirector/Tutorial/Toriel.cs
+++ b/Scenes/BattleDirector/Tutorial/Toriel.cs
@@ -58,7 +58,9 @@ public override void _Process(double delta)
_nextButton?.GrabFocus();
}
UpdateInputSprites();
- string scheme = SaveSystem.GetConfigValue(SaveSystem.ConfigSettings.InputType).As();
+ string scheme = Configkeeper
+ .GetConfigValue(Configkeeper.ConfigSettings.InputType)
+ .As();
if (_waitingForPlace && Input.IsActionPressed(scheme + "_arrowRight"))
{
GetViewport().SetInputAsHandled();
@@ -68,7 +70,9 @@ public override void _Process(double delta)
private void UpdateInputSprites()
{
- string prefix = SaveSystem.GetConfigValue(SaveSystem.ConfigSettings.InputType).ToString();
+ string prefix = Configkeeper
+ .GetConfigValue(Configkeeper.ConfigSettings.InputType)
+ .ToString();
_inputSprites[0].Texture = GD.Load(
ControlSettings.GetTextureForInput(prefix + "_arrowUp")
);
diff --git a/Scenes/CustomSong/CustomScore.cs b/Scenes/CustomSong/CustomScore.cs
index 83a1c8af..99773c1c 100644
--- a/Scenes/CustomSong/CustomScore.cs
+++ b/Scenes/CustomSong/CustomScore.cs
@@ -28,9 +28,12 @@ private enum ScoringVals
public delegate void FinishedHandler();
public event FinishedHandler Finished;
+ private BattleDirector.Harbinger.NoteHitHandler _noteHitListener;
+ private BattleDirector.Harbinger.NotePlacedHandler _notePlacedListener;
+
public void ListenToDirector()
{
- BattleDirector.Harbinger.Instance.NoteHit += e =>
+ _noteHitListener = e =>
{
if (e is not BattleDirector.Harbinger.NoteHitArgs nArgs)
return;
@@ -44,10 +47,19 @@ public void ListenToDirector()
break;
}
};
- BattleDirector.Harbinger.Instance.NotePlaced += _ =>
+ _notePlacedListener = _ =>
{
score[(int)ScoringVals.NotesPlaced] += 1;
};
+
+ BattleDirector.Harbinger.Instance.NotePlaced += _notePlacedListener;
+ BattleDirector.Harbinger.Instance.NoteHit += _noteHitListener;
+ }
+
+ public override void _ExitTree()
+ {
+ BattleDirector.Harbinger.Instance.NotePlaced -= _notePlacedListener;
+ BattleDirector.Harbinger.Instance.NoteHit -= _noteHitListener;
}
public CustomScore ShowResults(BattleDirector battleDirector, float enemyPercent)
diff --git a/Scenes/EventScene/EventScene.cs b/Scenes/EventScene/EventScene.cs
index 287995c2..2de1aa6e 100644
--- a/Scenes/EventScene/EventScene.cs
+++ b/Scenes/EventScene/EventScene.cs
@@ -26,7 +26,7 @@ public partial class EventScene : Node
[Export]
private MarginContainer _continueContainer;
- public static List EventPool;
+ public static List EventPool = [];
private static readonly Theme ButtonTheme = GD.Load(
"res://Scenes/UI/Assets/GeneralTheme.tres"
diff --git a/Scenes/Maps/Scripts/Cartographer.cs b/Scenes/Maps/Scripts/Cartographer.cs
index 66e421d4..00dddba2 100644
--- a/Scenes/Maps/Scripts/Cartographer.cs
+++ b/Scenes/Maps/Scripts/Cartographer.cs
@@ -38,7 +38,7 @@ public partial class Cartographer : Node2D
public override void _Ready()
{
DrawMap();
- SaveSystem.SaveGame();
+ Savekeeper.RecordSave();
if (
StageProducer.GetCurRoom().Type == Stages.Boss
&& StageProducer.GetCurRoom().Children.Length == 0
@@ -74,10 +74,10 @@ public override void _Process(double delta)
public override void _EnterTree()
{
BgAudioPlayer.LiveInstance.PlayLevelMusic();
- if (!SaveSystem.GetConfigValue(SaveSystem.ConfigSettings.FirstTime).AsBool())
+ if (StageProducer.GetPersistantVal(StageProducer.PersistKeys.TutorialDone) == 1)
return;
BattleDirector.VerticalScroll = true;
- SaveSystem.UpdateConfig(SaveSystem.ConfigSettings.VerticalScroll, true);
+ Configkeeper.UpdateConfig(Configkeeper.ConfigSettings.VerticalScroll, true);
}
private Vector2 GetPosition(int x, int y)
diff --git a/Scenes/NoteManager/Assets/NoteWIthOutline.png b/Scenes/NoteManager/Assets/NoteWithOutline.png
similarity index 100%
rename from Scenes/NoteManager/Assets/NoteWIthOutline.png
rename to Scenes/NoteManager/Assets/NoteWithOutline.png
diff --git a/Scenes/NoteManager/Assets/NoteWIthOutline.png.import b/Scenes/NoteManager/Assets/NoteWithOutline.png.import
similarity index 69%
rename from Scenes/NoteManager/Assets/NoteWIthOutline.png.import
rename to Scenes/NoteManager/Assets/NoteWithOutline.png.import
index e9bef490..caa50296 100644
--- a/Scenes/NoteManager/Assets/NoteWIthOutline.png.import
+++ b/Scenes/NoteManager/Assets/NoteWithOutline.png.import
@@ -3,15 +3,15 @@
importer="texture"
type="CompressedTexture2D"
uid="uid://coav3xvksq4jy"
-path="res://.godot/imported/NoteWIthOutline.png-00b7213af7b9958e4dcd747d842ce073.ctex"
+path="res://.godot/imported/NoteWithOutline.png-fd6e84a72270a62aa6b38d41c0180c0f.ctex"
metadata={
"vram_texture": false
}
[deps]
-source_file="res://Scenes/NoteManager/Assets/NoteWIthOutline.png"
-dest_files=["res://.godot/imported/NoteWIthOutline.png-00b7213af7b9958e4dcd747d842ce073.ctex"]
+source_file="res://Scenes/NoteManager/Assets/NoteWithOutline.png"
+dest_files=["res://.godot/imported/NoteWithOutline.png-fd6e84a72270a62aa6b38d41c0180c0f.ctex"]
[params]
diff --git a/Scenes/NoteManager/Scripts/InputHandler.cs b/Scenes/NoteManager/Scripts/InputHandler.cs
index c61dfdb2..9d927e89 100644
--- a/Scenes/NoteManager/Scripts/InputHandler.cs
+++ b/Scenes/NoteManager/Scripts/InputHandler.cs
@@ -65,10 +65,12 @@ public override void _Ready()
public override void _Process(double delta)
{
//TODO: Add change control scheme signal, so we don't query each frame.
- string scheme = SaveSystem.GetConfigValue(SaveSystem.ConfigSettings.InputType).As();
+ string scheme = Configkeeper
+ .GetConfigValue(Configkeeper.ConfigSettings.InputType)
+ .As();
if (Input.GetConnectedJoypads().Count <= 0 && scheme == "CONTROLLER")
{
- SaveSystem.UpdateConfig(SaveSystem.ConfigSettings.InputType, "WASD");
+ Configkeeper.UpdateConfig(Configkeeper.ConfigSettings.InputType, "WASD");
}
if (BattleDirector.PlayerDisabled)
@@ -92,7 +94,7 @@ public override void _UnhandledInput(InputEvent @event)
{
if (@event is InputEventJoypadButton)
{ //Force Controller if controller was pressed
- SaveSystem.UpdateConfig(SaveSystem.ConfigSettings.InputType, "CONTROLLER");
+ Configkeeper.UpdateConfig(Configkeeper.ConfigSettings.InputType, "CONTROLLER");
}
}
@@ -127,35 +129,16 @@ private void UpdateArrowSprites()
{
if (!UseArrows)
return;
- Arrows[(int)ArrowType.Left].Node.Texture = GD.Load(
- ArrowFolderPath + "New_Arrow.png"
- );
- Arrows[(int)ArrowType.Left].Node.Outline.Texture = GD.Load(
- ArrowFolderPath + "Arrow_Outline.png"
- );
- Arrows[(int)ArrowType.Left].Node.RotationDegrees = 180f;
+ Texture2D arrowTexture = GD.Load(ArrowFolderPath + "New_Arrow.png");
+ Texture2D outlineTexture = GD.Load(ArrowFolderPath + "Arrow_Outline.png");
+ float[] rotations = [270f, 90f, 180f]; //Up, down, left
- Arrows[(int)ArrowType.Up].Node.Texture = GD.Load(
- ArrowFolderPath + "New_Arrow.png"
- );
- Arrows[(int)ArrowType.Up].Node.Outline.Texture = GD.Load(
- ArrowFolderPath + "Arrow_Outline.png"
- );
- Arrows[(int)ArrowType.Up].Node.RotationDegrees = 270f;
-
- Arrows[(int)ArrowType.Down].Node.Texture = GD.Load(
- ArrowFolderPath + "New_Arrow.png"
- );
- Arrows[(int)ArrowType.Down].Node.Outline.Texture = GD.Load(
- ArrowFolderPath + "Arrow_Outline.png"
- );
- Arrows[(int)ArrowType.Down].Node.RotationDegrees = 90f;
-
- Arrows[(int)ArrowType.Right].Node.Texture = GD.Load(
- ArrowFolderPath + "New_Arrow.png"
- );
- Arrows[(int)ArrowType.Right].Node.Outline.Texture = GD.Load(
- ArrowFolderPath + "Arrow_Outline.png"
- );
+ for (int i = 0; i < Arrows.Length; i++)
+ {
+ Arrows[i].Node.Texture = arrowTexture;
+ Arrows[i].Node.Outline.Texture = outlineTexture;
+ if (i < rotations.Length)
+ Arrows[i].Node.RotationDegrees = rotations[i];
+ }
}
}
diff --git a/Scenes/Puppets/Enemies/BossBlood/P_BossBlood.cs b/Scenes/Puppets/Enemies/BossBlood/P_BossBlood.cs
index 9198c3b9..bd4748c1 100644
--- a/Scenes/Puppets/Enemies/BossBlood/P_BossBlood.cs
+++ b/Scenes/Puppets/Enemies/BossBlood/P_BossBlood.cs
@@ -37,7 +37,7 @@ public override void _Ready()
this,
BattleEffectTrigger.OnDamageInstance,
1,
- (e, eff, val) =>
+ (e, _, _) =>
{
if (e is not BattleDirector.Harbinger.OnDamageInstanceArgs dArgs)
return;
diff --git a/Scenes/Puppets/Enemies/CyberFox/P_CyberFox.cs b/Scenes/Puppets/Enemies/CyberFox/P_CyberFox.cs
index 985adf80..d1099374 100644
--- a/Scenes/Puppets/Enemies/CyberFox/P_CyberFox.cs
+++ b/Scenes/Puppets/Enemies/CyberFox/P_CyberFox.cs
@@ -36,7 +36,7 @@ public override void _Ready()
this,
BattleEffectTrigger.OnLoop,
1,
- (e, eff, val) =>
+ (e, _, _) =>
{
e.BD.AddStatus(Targetting.First, StatusEffect.Dodge, 1);
_effectNode.TriggerGlitch(1f);
diff --git a/Scenes/Puppets/Enemies/Effigy/P_Effigy.cs b/Scenes/Puppets/Enemies/Effigy/P_Effigy.cs
index fb510cd6..8cd0e024 100644
--- a/Scenes/Puppets/Enemies/Effigy/P_Effigy.cs
+++ b/Scenes/Puppets/Enemies/Effigy/P_Effigy.cs
@@ -20,7 +20,7 @@ public override void _Ready()
this,
BattleEffectTrigger.OnDamageInstance,
1,
- (e, eff, val) =>
+ (e, _, _) =>
{
if (e is not BattleDirector.Harbinger.OnDamageInstanceArgs dArgs)
return;
@@ -35,7 +35,7 @@ public override void _Ready()
this,
BattleEffectTrigger.OnBattleEnd,
1,
- (e, eff, val) =>
+ (e, _, _) =>
{
e.BD.DealDamage(Targetting.Player, e.BD.Player.GetCurrentHealth() - 1, null);
}
@@ -44,7 +44,7 @@ public override void _Ready()
this,
BattleEffectTrigger.OnBattleStart,
1,
- (e, eff, val) =>
+ (e, _, _) =>
{
_tutorialInstance = Toriel.AttachNewToriel(e.BD);
_tutorialInstance.BossDialogue();
diff --git a/Scenes/Puppets/Enemies/Keythulu/P_Keythulu.cs b/Scenes/Puppets/Enemies/Keythulu/P_Keythulu.cs
index fb91b3ac..1f721d92 100644
--- a/Scenes/Puppets/Enemies/Keythulu/P_Keythulu.cs
+++ b/Scenes/Puppets/Enemies/Keythulu/P_Keythulu.cs
@@ -42,7 +42,7 @@ public override void _Ready()
this,
BattleEffectTrigger.OnLoop,
3,
- (e, eff, val) =>
+ (_, _, _) =>
{
_effectSprite.Position = Vector2.Zero;
_effectSprite.Visible = true;
@@ -63,7 +63,7 @@ public override void _Ready()
this,
BattleEffectTrigger.OnDamageInstance,
1,
- (e, eff, val) =>
+ (e, _, _) =>
{
if (
StageProducer.Config.RoomType == Stages.Custom
@@ -76,7 +76,7 @@ public override void _Ready()
)
{
SteamWhisperer.PopAchievement("actTwoComp");
- SaveSystem.UpdateConfig(SaveSystem.ConfigSettings.HasWon, true);
+ StageProducer.UpdatePersistantValues(StageProducer.PersistKeys.HasWon, 1);
}
}
),
diff --git a/Scenes/Puppets/Enemies/Strawman/P_Strawman.cs b/Scenes/Puppets/Enemies/Strawman/P_Strawman.cs
index cfb99b03..7e58022e 100644
--- a/Scenes/Puppets/Enemies/Strawman/P_Strawman.cs
+++ b/Scenes/Puppets/Enemies/Strawman/P_Strawman.cs
@@ -22,7 +22,7 @@ public override void _Ready()
this,
BattleEffectTrigger.OnBattleStart,
1,
- (e, eff, val) =>
+ (e, _, _) =>
{
_tutorialInstance = Toriel.AttachNewToriel(e.BD);
_tutorialInstance.IntroDialogue();
@@ -32,7 +32,7 @@ public override void _Ready()
this,
BattleEffectTrigger.OnDamageInstance,
2,
- (e, eff, val) =>
+ (e, eff, _) =>
{
if (e is not BattleDirector.Harbinger.OnDamageInstanceArgs dArgs)
return;
@@ -53,7 +53,7 @@ public override void _Ready()
this,
BattleEffectTrigger.OnLoop,
1,
- (e, eff, val) =>
+ (e, _, _) =>
{
if (e is not BattleDirector.Harbinger.LoopEventArgs lArgs)
return;
@@ -67,7 +67,7 @@ public override void _Ready()
this,
BattleEffectTrigger.NoteHit,
1,
- (e, eff, val) =>
+ (e, eff, _) =>
{
if (eff.Value == 0)
return;
@@ -83,7 +83,7 @@ public override void _Ready()
this,
BattleEffectTrigger.NotePlaced,
1,
- (e, eff, val) =>
+ (_, _, _) =>
{
_tutorialInstance.CallDeferred(nameof(_tutorialInstance.OnPlaceDialogue1));
}
@@ -92,7 +92,7 @@ public override void _Ready()
this,
BattleEffectTrigger.OnDamageInstance,
1,
- (e, eff, val) =>
+ (e, _, _) =>
{
if (e is not BattleDirector.Harbinger.OnDamageInstanceArgs dArgs)
return;
@@ -101,7 +101,10 @@ public override void _Ready()
&& dArgs.Dmg.Target.GetCurrentHealth() <= dArgs.Dmg.Damage
)
{
- SaveSystem.UpdateConfig(SaveSystem.ConfigSettings.FirstTime, false);
+ StageProducer.UpdatePersistantValues(
+ StageProducer.PersistKeys.TutorialDone,
+ 1
+ );
SteamWhisperer.PopAchievement("tutorial");
}
}
diff --git a/Scenes/Puppets/Enemies/Turtle/P_Turtle.cs b/Scenes/Puppets/Enemies/Turtle/P_Turtle.cs
index 47ad8089..70ebe332 100644
--- a/Scenes/Puppets/Enemies/Turtle/P_Turtle.cs
+++ b/Scenes/Puppets/Enemies/Turtle/P_Turtle.cs
@@ -26,12 +26,12 @@ public override void _Ready()
this,
BattleEffectTrigger.OnLoop,
1,
- (e, eff, val) =>
+ (e, _, val) =>
{
// take 1/4th of player's energy, and heal that amount
int quarterEnergy = (int)e.BD.NPB.GetCurrentBarValue() / 4;
e.BD.NPB.IncreaseCharge(-quarterEnergy);
- this.Heal(quarterEnergy);
+ Heal(quarterEnergy);
//gain block based on val
e.BD.AddStatus(Targetting.First, StatusEffect.Block, val);
diff --git a/Scenes/ShopScene/Scripts/ShopScene.cs b/Scenes/ShopScene/Scripts/ShopScene.cs
index d66c9735..672d3e7c 100644
--- a/Scenes/ShopScene/Scripts/ShopScene.cs
+++ b/Scenes/ShopScene/Scripts/ShopScene.cs
@@ -343,7 +343,7 @@ private void RemoveNote()
private bool _hasHealed;
private const int HealCost = 50;
- private int _healAmount = (StageProducer.PlayerStats.MaxHealth / 4);
+ private int HealAmount => (StageProducer.PlayerStats.MaxHealth / 4);
private void UpdateHealButton()
{
@@ -366,7 +366,7 @@ private void TryHeal()
StageProducer.PlayerStats.Money -= HealCost;
_hasHealed = true;
- _player.Heal(_healAmount);
+ _player.Heal(HealAmount);
UpdateHealButton();
UpdateMoneyLabel();
}
diff --git a/Scenes/UI/Options/HowToPlay.tscn b/Scenes/UI/Options/HowToPlay.tscn
index 04ff7993..15652baf 100644
--- a/Scenes/UI/Options/HowToPlay.tscn
+++ b/Scenes/UI/Options/HowToPlay.tscn
@@ -7,7 +7,7 @@
[ext_resource type="Texture2D" uid="uid://cr82n7aojboaw" path="res://Scenes/UI/Assets/UI_CenterFrameLight.png" id="4_4vscx"]
[ext_resource type="Texture2D" uid="uid://caw70lr5e1yiq" path="res://Classes/Notes/Assets/Note_PlayerDouble.png" id="4_m6low"]
[ext_resource type="Texture2D" uid="uid://cdf3g3174du4r" path="res://Classes/Notes/Assets/Note_PlayerHeal.png" id="5_8kiq2"]
-[ext_resource type="Texture2D" uid="uid://coav3xvksq4jy" path="res://Scenes/NoteManager/Assets/NoteWIthOutline.png" id="5_xqve7"]
+[ext_resource type="Texture2D" uid="uid://coav3xvksq4jy" path="res://Scenes/NoteManager/Assets/NoteWithOutline.png" id="5_xqve7"]
[ext_resource type="Texture2D" uid="uid://c3chrsxrulapd" path="res://Classes/Notes/Assets/Note_PlayerBasic.png" id="6_uonw3"]
[ext_resource type="Texture2D" uid="uid://dg0lmu0pip4lr" path="res://Classes/Notes/Assets/Note_PlayerVampire.png" id="7_rbdrm"]
diff --git a/Scenes/UI/Options/Scripts/HowToPlay.cs b/Scenes/UI/Options/Scripts/HowToPlay.cs
index 9fae60c5..e8a0a455 100644
--- a/Scenes/UI/Options/Scripts/HowToPlay.cs
+++ b/Scenes/UI/Options/Scripts/HowToPlay.cs
@@ -46,7 +46,7 @@ public void ReturnToPrev()
private void DoTutorial()
{
- SaveSystem.UpdateConfig(SaveSystem.ConfigSettings.FirstTime, true);
+ StageProducer.UpdatePersistantValues(StageProducer.PersistKeys.TutorialDone, 0);
StageProducer.LiveInstance.TransitionStage(Stages.Map);
}
diff --git a/Scenes/UI/Options/Scripts/LanguageSelection.cs b/Scenes/UI/Options/Scripts/LanguageSelection.cs
index 5e14c224..e300ccd0 100644
--- a/Scenes/UI/Options/Scripts/LanguageSelection.cs
+++ b/Scenes/UI/Options/Scripts/LanguageSelection.cs
@@ -25,7 +25,7 @@ public void OnLanguageSelected(int index)
private void ChangeLanguage(string language)
{
TranslationServer.SetLocale(language);
- SaveSystem.UpdateConfig(SaveSystem.ConfigSettings.LanguageKey, language);
+ Configkeeper.UpdateConfig(Configkeeper.ConfigSettings.LanguageKey, language);
}
private void PresetDropdown(string language)
diff --git a/Scenes/UI/Options/Scripts/OptionsMenu.cs b/Scenes/UI/Options/Scripts/OptionsMenu.cs
index 3e8905dd..021b28f1 100644
--- a/Scenes/UI/Options/Scripts/OptionsMenu.cs
+++ b/Scenes/UI/Options/Scripts/OptionsMenu.cs
@@ -44,8 +44,8 @@ public override void _Ready()
AudioServer.GetBusVolumeDb(AudioServer.GetBusIndex("Master"))
);
- _highContrastToggle.ButtonPressed = SaveSystem
- .GetConfigValue(SaveSystem.ConfigSettings.HighContrast)
+ _highContrastToggle.ButtonPressed = Configkeeper
+ .GetConfigValue(Configkeeper.ConfigSettings.HighContrast)
.AsBool();
_volumeSlider.DragEnded += VolumeChanged;
@@ -58,7 +58,7 @@ public override void _Ready()
_titleScreenOptions.Visible =
!StageProducer.IsInitialized
- && !SaveSystem.GetConfigValue(SaveSystem.ConfigSettings.FirstTime).AsBool();
+ && StageProducer.GetPersistantVal(StageProducer.PersistKeys.TutorialDone) == 1;
_noteSpriteToggle.ButtonPressed = InputHandler.UseArrows;
_noteSpriteToggle.Toggled += ArrowSpritesToggled;
_verticalScrollToggle.ButtonPressed = BattleDirector.VerticalScroll;
@@ -118,7 +118,7 @@ private void VolumeChanged(bool valueChanged)
if (!valueChanged)
return;
ChangeVolume((float)_volumeSlider.Value);
- SaveSystem.UpdateConfig(SaveSystem.ConfigSettings.Volume, _volumeSlider.Value);
+ Configkeeper.UpdateConfig(Configkeeper.ConfigSettings.Volume, _volumeSlider.Value);
}
public static void ChangeVolume(double value)
@@ -132,19 +132,19 @@ public static void ChangeVolume(double value)
private void ArrowSpritesToggled(bool value)
{
InputHandler.UseArrows = value;
- SaveSystem.UpdateConfig(SaveSystem.ConfigSettings.TypeIsArrow, value);
+ Configkeeper.UpdateConfig(Configkeeper.ConfigSettings.TypeIsArrow, value);
}
private void VerticalScrollToggled(bool value)
{
BattleDirector.VerticalScroll = value;
- SaveSystem.UpdateConfig(SaveSystem.ConfigSettings.VerticalScroll, value);
+ Configkeeper.UpdateConfig(Configkeeper.ConfigSettings.VerticalScroll, value);
}
private void HighContrastChanged(bool toggled)
{
StageProducer.ContrastFilter.Visible = toggled;
- SaveSystem.UpdateConfig(SaveSystem.ConfigSettings.HighContrast, toggled);
+ Configkeeper.UpdateConfig(Configkeeper.ConfigSettings.HighContrast, toggled);
}
private void OpenHowToPlay()
diff --git a/Scenes/UI/Remapping/ControlSettings.cs b/Scenes/UI/Remapping/ControlSettings.cs
index 5ae9746c..44e9f265 100644
--- a/Scenes/UI/Remapping/ControlSettings.cs
+++ b/Scenes/UI/Remapping/ControlSettings.cs
@@ -151,7 +151,7 @@ public override void _Ready()
}
_remapTabs.CurrentTab =
- SaveSystem.GetConfigValue(SaveSystem.ConfigSettings.InputType).ToString()
+ Configkeeper.GetConfigValue(Configkeeper.ConfigSettings.InputType).ToString()
== KeyboardPrefix
? 0
: 1;
@@ -251,8 +251,8 @@ private void NoNullFocus()
///
private void ChangeInputType()
{
- SaveSystem.UpdateConfig(
- SaveSystem.ConfigSettings.InputType,
+ Configkeeper.UpdateConfig(
+ Configkeeper.ConfigSettings.InputType,
_remapTabs.CurrentTab == 0 ? KeyboardPrefix : JoyPrefix
);
_remapDescription.Text = Tr(_remapTabs.CurrentTab == 0 ? _keyboardRemap : _controllerRemap);
@@ -392,46 +392,49 @@ private void HandleRemapInput(InputEvent @event)
///
private static readonly Dictionary<
string,
- (SaveSystem.ConfigSettings keyboard, SaveSystem.ConfigSettings controller)
+ (Configkeeper.ConfigSettings keyboard, Configkeeper.ConfigSettings controller)
> ConfigMap = new()
{
{
"_arrowUp",
- (SaveSystem.ConfigSettings.InputKeyboardUp, SaveSystem.ConfigSettings.InputControllerUp)
+ (
+ Configkeeper.ConfigSettings.InputKeyboardUp,
+ Configkeeper.ConfigSettings.InputControllerUp
+ )
},
{
"_arrowDown",
(
- SaveSystem.ConfigSettings.InputKeyboardDown,
- SaveSystem.ConfigSettings.InputControllerDown
+ Configkeeper.ConfigSettings.InputKeyboardDown,
+ Configkeeper.ConfigSettings.InputControllerDown
)
},
{
"_arrowLeft",
(
- SaveSystem.ConfigSettings.InputKeyboardLeft,
- SaveSystem.ConfigSettings.InputControllerLeft
+ Configkeeper.ConfigSettings.InputKeyboardLeft,
+ Configkeeper.ConfigSettings.InputControllerLeft
)
},
{
"_arrowRight",
(
- SaveSystem.ConfigSettings.InputKeyboardRight,
- SaveSystem.ConfigSettings.InputControllerRight
+ Configkeeper.ConfigSettings.InputKeyboardRight,
+ Configkeeper.ConfigSettings.InputControllerRight
)
},
{
"_secondaryPlacement",
(
- SaveSystem.ConfigSettings.InputKeyboardSecondary,
- SaveSystem.ConfigSettings.InputControllerSecondary
+ Configkeeper.ConfigSettings.InputKeyboardSecondary,
+ Configkeeper.ConfigSettings.InputControllerSecondary
)
},
{
"_inventory",
(
- SaveSystem.ConfigSettings.InputKeyboardInventory,
- SaveSystem.ConfigSettings.InputControllerInventory
+ Configkeeper.ConfigSettings.InputKeyboardInventory,
+ Configkeeper.ConfigSettings.InputControllerInventory
)
},
};
@@ -474,7 +477,7 @@ private void SaveKeyInput(string button, InputEvent key)
return;
var config = key is InputEventKey ? configPair.keyboard : configPair.controller;
- SaveSystem.UpdateConfig(config, keycode);
+ Configkeeper.UpdateConfig(config, keycode);
}
///
diff --git a/Scenes/UI/TitleScreen/Scripts/TitleScreen.cs b/Scenes/UI/TitleScreen/Scripts/TitleScreen.cs
index b6eca91a..d666b943 100644
--- a/Scenes/UI/TitleScreen/Scripts/TitleScreen.cs
+++ b/Scenes/UI/TitleScreen/Scripts/TitleScreen.cs
@@ -30,8 +30,8 @@ public override void _UnhandledInput(InputEvent @event)
if (eventKey.Keycode == Key.Key0)
{
SteamWhisperer.ResetAll();
- SaveSystem.ClearSave();
- SaveSystem.ClearConfig();
+ Savekeeper.ClearRun();
+ Configkeeper.ClearConfig();
StageProducer.LiveInstance.InitFromCfg();
}
}
@@ -48,8 +48,8 @@ public override void _Ready()
{
if (StageProducer.LiveInstance.LastStage == Stages.Custom)
OpenCustomSelection();
- _customSelectionButton.Visible = (bool)
- SaveSystem.GetConfigValue(SaveSystem.ConfigSettings.HasWon);
+ _customSelectionButton.Visible =
+ StageProducer.GetPersistantVal(StageProducer.PersistKeys.HasWon) == 1;
}
public override void _Process(double delta)
diff --git a/Scenes/UI/TitleScreen/TitleScreenEffects.tscn b/Scenes/UI/TitleScreen/TitleScreenEffects.tscn
index 670edb8d..0c883ce0 100644
--- a/Scenes/UI/TitleScreen/TitleScreenEffects.tscn
+++ b/Scenes/UI/TitleScreen/TitleScreenEffects.tscn
@@ -1,7 +1,7 @@
[gd_scene load_steps=4 format=3 uid="uid://dkaxidh7xlvfc"]
[ext_resource type="Texture2D" uid="uid://iqbqsiyjd3uq" path="res://Scenes/UI/TitleScreen/Assets/2D_Shadow_Map.webp" id="1_07rxh"]
-[ext_resource type="Texture2D" uid="uid://coav3xvksq4jy" path="res://Scenes/NoteManager/Assets/NoteWIthOutline.png" id="2_ltons"]
+[ext_resource type="Texture2D" uid="uid://coav3xvksq4jy" path="res://Scenes/NoteManager/Assets/NoteWithOutline.png" id="2_ltons"]
[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_4croe"]
particle_flag_disable_z = true
diff --git a/project.godot b/project.godot
index bd90939a..06d5742c 100644
--- a/project.godot
+++ b/project.godot
@@ -24,6 +24,7 @@ buses/default_bus_layout=""
[autoload]
+Savekeeper="*res://Globals/Savekeeper.cs"
StageProducer="*res://Globals/StageProducer.cs"
TimeKeeper="*res://Globals/TimeKeeper.cs"
Scribe="*res://Globals/Scribe.cs"