Merge pull request #18 from Pathoschild/simplify-config

Simplify config/data parsing using SMAPI APIs
This commit is contained in:
janavarro95 2017-08-05 16:27:18 -07:00 committed by GitHub
commit f5069f8ca5
63 changed files with 644 additions and 1210 deletions

View File

@ -1,5 +1,5 @@
using System; using System;
using System.IO; using Omegasis.AutoSpeed.Framework;
using StardewModdingAPI; using StardewModdingAPI;
using StardewModdingAPI.Events; using StardewModdingAPI.Events;
using StardewValley; using StardewValley;
@ -12,8 +12,8 @@ namespace Omegasis.AutoSpeed
/********* /*********
** Properties ** Properties
*********/ *********/
/// <summary>The speed multiplier.</summary> /// <summary>The mod configuration.</summary>
private int Speed = 5; private ModConfig Config;
/********* /*********
@ -24,13 +24,7 @@ namespace Omegasis.AutoSpeed
public override void Entry(IModHelper helper) public override void Entry(IModHelper helper)
{ {
GameEvents.UpdateTick += this.GameEvents_UpdateTick; GameEvents.UpdateTick += this.GameEvents_UpdateTick;
this.Config = helper.ReadConfig<ModConfig>();
string configLocation = Path.Combine(helper.DirectoryPath, "AutoSpeed_Data.txt");
if (!File.Exists(configLocation))
this.Speed = 1;
this.LoadConfig();
this.Monitor.Log("AutoSpeed Initialization Completed", LogLevel.Info);
} }
@ -43,32 +37,7 @@ namespace Omegasis.AutoSpeed
private void GameEvents_UpdateTick(object sender, EventArgs e) private void GameEvents_UpdateTick(object sender, EventArgs e)
{ {
if (Context.IsPlayerFree) if (Context.IsPlayerFree)
Game1.player.addedSpeed = this.Speed; Game1.player.addedSpeed = this.Config.Speed;
}
/// <summary>Load the configuration settings.</summary>
private void LoadConfig()
{
string path = Path.Combine(this.Helper.DirectoryPath, "AutoSpeed_data.txt");
if (!File.Exists(path))
this.WriteConfig();
else
{
string[] text = File.ReadAllLines(path);
this.Speed = Convert.ToInt32(text[3]);
}
}
/// <summary>Save the configuration settings.</summary>
void WriteConfig()
{
string path = Path.Combine(this.Helper.DirectoryPath, "AutoSpeed_data.txt");
string[] text = new string[20];
text[0] = "Player: AutoSpeed Config:";
text[1] = "====================================================================================";
text[2] = "Player Added Speed:";
text[3] = Speed.ToString();
File.WriteAllLines(path, text);
} }
} }
} }

View File

@ -38,6 +38,7 @@
<Link>Properties\GlobalAssemblyInfo.cs</Link> <Link>Properties\GlobalAssemblyInfo.cs</Link>
</Compile> </Compile>
<Compile Include="AutoSpeed.cs" /> <Compile Include="AutoSpeed.cs" />
<Compile Include="Framework\ModConfig.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -0,0 +1,9 @@
namespace Omegasis.AutoSpeed.Framework
{
/// <summary>The mod configuration.</summary>
internal class ModConfig
{
/// <summary>The added speed.</summary>
public int Speed { get; set; } = 1;
}
}

View File

@ -9,8 +9,8 @@ Compatible with Stardew Valley 1.2+ on Linux, Mac, and Windows.
3. Run the game using SMAPI. 3. Run the game using SMAPI.
## Usage ## Usage
Launch the game with the mod installed to generate the config file, then edit the Launch the game with the mod installed to generate the config file, then edit the `config.json` to
`AutoSpeed_data.txt` to set the speed you want (higher values are faster). set the speed you want (higher values are faster).
## Versions ## Versions
1.0 1.0
@ -23,4 +23,5 @@ Launch the game with the mod installed to generate the config file, then edit th
* Updated to Stardew Valley 1.2 and SMAPI 1.12. * Updated to Stardew Valley 1.2 and SMAPI 1.12.
1.4: 1.4:
* Switched to standard JSON config file.
* Internal refactoring. * Internal refactoring.

View File

@ -1,5 +1,4 @@
using System; using Omegasis.BillboardAnywhere.Framework;
using System.IO;
using StardewModdingAPI; using StardewModdingAPI;
using StardewModdingAPI.Events; using StardewModdingAPI.Events;
using StardewValley; using StardewValley;
@ -13,8 +12,8 @@ namespace Omegasis.BillboardAnywhere
/********* /*********
** Properties ** Properties
*********/ *********/
/// <summary>The key which shows the billboard menu.</summary> /// <summary>The mod configuration.</summary>
private string KeyBinding = "B"; private ModConfig Config;
/********* /*********
@ -24,7 +23,8 @@ namespace Omegasis.BillboardAnywhere
/// <param name="helper">Provides simplified APIs for writing mods.</param> /// <param name="helper">Provides simplified APIs for writing mods.</param>
public override void Entry(IModHelper helper) public override void Entry(IModHelper helper)
{ {
SaveEvents.AfterLoad += this.SaveEvents_AfterLoad; this.Config = helper.ReadConfig<ModConfig>();
ControlEvents.KeyPressed += this.ControlEvents_KeyPressed; ControlEvents.KeyPressed += this.ControlEvents_KeyPressed;
} }
@ -32,50 +32,14 @@ namespace Omegasis.BillboardAnywhere
/********* /*********
** Private methods ** Private methods
*********/ *********/
/// <summary>The method invoked after the player loads a save.</summary>
/// <param name="sender">The event sender.</param>
/// <param name="e">The event data.</param>
private void SaveEvents_AfterLoad(object sender, EventArgs e)
{
this.LoadConfig();
}
/// <summary>The method invoked when the presses a keyboard button.</summary> /// <summary>The method invoked when the presses a keyboard button.</summary>
/// <param name="sender">The event sender.</param> /// <param name="sender">The event sender.</param>
/// <param name="e">The event data.</param> /// <param name="e">The event data.</param>
public void ControlEvents_KeyPressed(object sender, EventArgsKeyPressed e) public void ControlEvents_KeyPressed(object sender, EventArgsKeyPressed e)
{ {
// load menu if key pressed // load menu if key pressed
if (Context.IsPlayerFree && e.KeyPressed.ToString() == this.KeyBinding) if (Context.IsPlayerFree && e.KeyPressed.ToString() == this.Config.KeyBinding)
Game1.activeClickableMenu = new Billboard(); Game1.activeClickableMenu = new Billboard();
} }
/// <summary>Load the configuration settings.</summary>
void LoadConfig()
{
string path = Path.Combine(this.Helper.DirectoryPath, "Billboard_Anywhere_Config.txt");
if (!File.Exists(path))
{
this.KeyBinding = "B";
this.WriteConfig();
}
else
{
string[] text = File.ReadAllLines(path);
this.KeyBinding = Convert.ToString(text[3]);
}
}
/// <summary>Save the configuration settings.</summary>
void WriteConfig()
{
string path = Path.Combine(Helper.DirectoryPath, "Billboard_Anywhere_Config.txt");
string[] text = new string[20];
text[0] = "Config: Billboard_Anywhere. Feel free to mess with these settings.";
text[1] = "====================================================================================";
text[2] = "Key binding for opening the billboard anywhere. Press this key to do so";
text[3] = this.KeyBinding;
File.WriteAllLines(path, text);
}
} }
} }

View File

@ -38,6 +38,7 @@
<Link>Properties\GlobalAssemblyInfo.cs</Link> <Link>Properties\GlobalAssemblyInfo.cs</Link>
</Compile> </Compile>
<Compile Include="BillboardAnywhere.cs" /> <Compile Include="BillboardAnywhere.cs" />
<Compile Include="Framework\ModConfig.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -0,0 +1,9 @@
namespace Omegasis.BillboardAnywhere.Framework
{
/// <summary>The mod configuration.</summary>
internal class ModConfig
{
/// <summary>The key which shows the billboard menu.</summary>
public string KeyBinding { get; set; } = "B";
}
}

View File

@ -9,8 +9,7 @@ Compatible with Stardew Valley 1.2+ on Linux, Mac, and Windows.
3. Run the game using SMAPI. 3. Run the game using SMAPI.
## Usage ## Usage
Press `B` while in-game to show the billboard menu. Edit the `Billboard_Anywhere_Config.txt` file Press `B` while in-game to show the billboard menu. Edit the `config.json` file to change the key.
to change the key.
## Versions ## Versions
1.0 1.0
@ -23,4 +22,5 @@ to change the key.
* Updated to Stardew Valley 1.2 and SMAPI 1.12. * Updated to Stardew Valley 1.2 and SMAPI 1.12.
1.4: 1.4:
* Switched to standard JSON config file.
* Internal refactoring. * Internal refactoring.

View File

@ -1,7 +1,6 @@
using System; using System;
using System.IO; using System.IO;
using System.Text; using System.Linq;
using Newtonsoft.Json;
using Omegasis.BuildEndurance.Framework; using Omegasis.BuildEndurance.Framework;
using StardewModdingAPI; using StardewModdingAPI;
using StardewModdingAPI.Events; using StardewModdingAPI.Events;
@ -15,45 +14,30 @@ namespace Omegasis.BuildEndurance
/********* /*********
** Properties ** Properties
*********/ *********/
/// <summary>The mod settings and player data.</summary> /// <summary>The relative path for the current player's data file.</summary>
private string DataFilePath => Path.Combine("data", $"{Constants.SaveFolderName}.json");
/// <summary>The absolute path for the current player's legacy data file.</summary>
private string LegacyDataFilePath => Path.Combine(this.Helper.DirectoryPath, "PlayerData", $"BuildEndurance_data_{Game1.player.name}.txt");
/// <summary>The mod settings.</summary>
private ModConfig Config; private ModConfig Config;
/// <summary>The data for the current player.</summary>
private PlayerData PlayerData;
/// <summary>Whether the player has been exhausted today.</summary> /// <summary>Whether the player has been exhausted today.</summary>
private bool WasExhausted; private bool WasExhausted;
/// <summary>Whether the player has collapsed today.</summary> /// <summary>Whether the player has collapsed today.</summary>
private bool WasCollapsed; private bool WasCollapsed;
/// <summary>The XP points needed to reach the next endurance level.</summary>
private double ExpToNextLevel = 20;
/// <summary>The player's current endurance XP points.</summary>
private double CurrentExp;
/// <summary>The player's current endurance level.</summary>
private int CurrentLevel;
/// <summary>The stamina points to add to the player's base stamina due to their current endurance level.</summary>
private int CurrentLevelStaminaBonus;
/// <summary>The initial stamina bonus to apply regardless of the player's endurance level, from the config file.</summary>
private int BaseStaminaBonus;
/// <summary>Whether to reset all changes by the mod to the default values (i.e. start over).</summary>
private bool ClearModEffects;
/// <summary>The player's original stamina value, excluding mod effects.</summary>
private int OriginalStamina;
/// <summary>Whether the player recently gained XP for tool use.</summary> /// <summary>Whether the player recently gained XP for tool use.</summary>
private bool HasRecentToolExp; private bool HasRecentToolExp;
/// <summary>Whether the player was eating last time we checked.</summary> /// <summary>Whether the player was eating last time we checked.</summary>
private bool WasEating; private bool WasEating;
/// <summary>The player's stamina last time they slept.</summary>
private int NightlyStamina;
/********* /*********
** Public methods ** Public methods
@ -62,46 +46,22 @@ namespace Omegasis.BuildEndurance
/// <param name="helper">Provides simplified APIs for writing mods.</param> /// <param name="helper">Provides simplified APIs for writing mods.</param>
public override void Entry(IModHelper helper) public override void Entry(IModHelper helper)
{ {
this.Config = helper.ReadConfig<ModConfig>();
GameEvents.UpdateTick += this.GameEvents_UpdateTick; GameEvents.UpdateTick += this.GameEvents_UpdateTick;
GameEvents.OneSecondTick += this.GameEvents_OneSecondTick; GameEvents.OneSecondTick += this.GameEvents_OneSecondTick;
SaveEvents.AfterLoad += this.SaveEvents_AfterLoad; SaveEvents.AfterLoad += this.SaveEvents_AfterLoad;
TimeEvents.AfterDayStarted += this.TimeEvents_AfterDayStarted; SaveEvents.BeforeSave += this.SaveEvents_BeforeSave;
string configPath = Path.Combine(helper.DirectoryPath, "BuildEnduranceConfig.json");
if (!File.Exists(configPath))
{
this.Monitor.Log("Initial configuration file setup.");
this.Config = new ModConfig
{
CurrentLevel = 0,
MaxLevel = 100,
StaminaIncreasePerLevel = 1,
CurrentExp = 0,
ExpToNextLevel = 20,
ExpCurve = 1.15,
ExpForEating = 2,
ExpForSleeping = 10,
ExpForToolUse = 1,
BaseStaminaBonus = 0,
CurrentLevelStaminaBonus = 0,
ExpForExhaustion = 25,
ExpForCollapsing = 50
};
File.WriteAllBytes(configPath, Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(this.Config)));
}
else
{
this.Config = JsonConvert.DeserializeObject<ModConfig>(Encoding.UTF8.GetString(File.ReadAllBytes(configPath)));
this.Monitor.Log("Found BuildEndurance config file.");
}
this.Monitor.Log("BuildEndurance Initialization Completed");
} }
/*********
** Private methods
*********/
/// <summary>The method invoked once per second during a game update.</summary> /// <summary>The method invoked once per second during a game update.</summary>
/// <param name="sender">The event sender.</param> /// <param name="sender">The event sender.</param>
/// <param name="e">The event data.</param> /// <param name="e">The event data.</param>
public void GameEvents_OneSecondTick(object sender, EventArgs e) private void GameEvents_OneSecondTick(object sender, EventArgs e)
{ {
// nerf how quickly tool xp is gained (I hope) // nerf how quickly tool xp is gained (I hope)
if (this.HasRecentToolExp) if (this.HasRecentToolExp)
@ -111,28 +71,31 @@ namespace Omegasis.BuildEndurance
/// <summary>The method invoked when the game updates (roughly 60 times per second).</summary> /// <summary>The method invoked when the game updates (roughly 60 times per second).</summary>
/// <param name="sender">The event sender.</param> /// <param name="sender">The event sender.</param>
/// <param name="e">The event data.</param> /// <param name="e">The event data.</param>
public void GameEvents_UpdateTick(object sender, EventArgs e) private void GameEvents_UpdateTick(object sender, EventArgs e)
{ {
if (!Context.IsWorldReady)
return;
// give XP when player finishes eating // give XP when player finishes eating
if (Game1.isEating) if (Game1.isEating)
this.WasEating = true; this.WasEating = true;
else if (this.WasEating) else if (this.WasEating)
{ {
this.CurrentExp += this.Config.ExpForEating; this.PlayerData.CurrentExp += this.Config.ExpForEating;
this.WasEating = false; this.WasEating = false;
} }
// give XP when player uses tool // give XP when player uses tool
if (!this.HasRecentToolExp && Game1.player.usingTool) if (!this.HasRecentToolExp && Game1.player.usingTool)
{ {
this.CurrentExp += this.Config.ExpForToolUse; this.PlayerData.CurrentExp += this.Config.ExpForToolUse;
this.HasRecentToolExp = true; this.HasRecentToolExp = true;
} }
// give XP when exhausted // give XP when exhausted
if (!this.WasExhausted && Game1.player.exhausted) if (!this.WasExhausted && Game1.player.exhausted)
{ {
this.CurrentExp += this.Config.ExpForExhaustion; this.PlayerData.CurrentExp += this.Config.ExpForExhaustion;
this.WasExhausted = true; this.WasExhausted = true;
this.Monitor.Log("The player is exhausted"); this.Monitor.Log("The player is exhausted");
} }
@ -140,7 +103,7 @@ namespace Omegasis.BuildEndurance
// give XP when player stays up too late or collapses // give XP when player stays up too late or collapses
if (!this.WasCollapsed && Game1.farmerShouldPassOut) if (!this.WasCollapsed && Game1.farmerShouldPassOut)
{ {
this.CurrentExp += this.Config.ExpForCollapsing; this.PlayerData.CurrentExp += this.Config.ExpForCollapsing;
this.WasCollapsed = true; this.WasCollapsed = true;
this.Monitor.Log("The player has collapsed!"); this.Monitor.Log("The player has collapsed!");
} }
@ -149,195 +112,100 @@ namespace Omegasis.BuildEndurance
/// <summary>The method invoked after the player loads a save.</summary> /// <summary>The method invoked after the player loads a save.</summary>
/// <param name="sender">The event sender.</param> /// <param name="sender">The event sender.</param>
/// <param name="e">The event data.</param> /// <param name="e">The event data.</param>
public void SaveEvents_AfterLoad(object sender, EventArgs e) private void SaveEvents_AfterLoad(object sender, EventArgs e)
{ {
// initialise // load player data
this.LoadConfig(); this.MigrateLegacyData();
this.WriteConfig(); this.PlayerData = this.Helper.ReadJsonFile<PlayerData>(this.DataFilePath) ?? new PlayerData();
if (this.PlayerData.OriginalMaxStamina == 0)
// grab initial stamina this.PlayerData.OriginalMaxStamina = Game1.player.MaxStamina;
var player = Game1.player;
if (this.OriginalStamina == 0)
this.OriginalStamina = player.MaxStamina;
// set nightly stamina
player.MaxStamina = this.NightlyStamina;
if (this.NightlyStamina == 0)
player.MaxStamina = this.BaseStaminaBonus + this.CurrentLevelStaminaBonus + this.OriginalStamina;
// reset if needed // reset if needed
if (this.ClearModEffects) if (this.PlayerData.ClearModEffects)
player.MaxStamina = this.OriginalStamina; {
Game1.player.MaxStamina = this.PlayerData.OriginalMaxStamina;
this.PlayerData.ExpToNextLevel = this.Config.ExpToNextLevel;
this.PlayerData.CurrentExp = this.Config.CurrentExp;
this.PlayerData.CurrentLevelStaminaBonus = 0;
this.PlayerData.OriginalMaxStamina = Game1.player.MaxStamina;
this.PlayerData.BaseStaminaBonus = 0;
this.PlayerData.CurrentLevel = 0;
this.PlayerData.ClearModEffects = false;
}
// save config // else apply stamina
this.LoadConfig(); else
this.WriteConfig(); {
Game1.player.MaxStamina = this.PlayerData.NightlyStamina <= 0
? this.PlayerData.BaseStaminaBonus + this.PlayerData.CurrentLevelStaminaBonus + this.PlayerData.OriginalMaxStamina
: this.PlayerData.NightlyStamina;
}
} }
/// <summary>The method invoked when a new day starts.</summary> /// <summary>The method invoked just before the game is saved.</summary>
/// <param name="sender">The event sender.</param> /// <param name="sender">The event sender.</param>
/// <param name="e">The event data.</param> /// <param name="e">The event data.</param>
public void TimeEvents_AfterDayStarted(object sender, EventArgs e) private void SaveEvents_BeforeSave(object sender, EventArgs e)
{ {
// reset data // reset data
this.WasExhausted = false; this.WasExhausted = false;
this.WasCollapsed = false; this.WasCollapsed = false;
// update settings // update player data
this.Monitor.Log(this.CurrentExp.ToString()); this.PlayerData.CurrentExp += this.Config.ExpForSleeping;
this.UpdateClearSetting(); if (this.PlayerData.OriginalMaxStamina == 0)
this.Monitor.Log(this.ClearModEffects.ToString()); this.PlayerData.OriginalMaxStamina = Game1.player.MaxStamina; //grab the initial stamina value
var player = Game1.player; if (this.PlayerData.CurrentLevel < this.Config.MaxLevel)
this.CurrentExp += this.Config.ExpForSleeping;
if (this.OriginalStamina == 0)
this.OriginalStamina = player.MaxStamina; //grab the initial stamina value
if (this.ClearModEffects)
{ {
this.LoadClearSettings(); while (this.PlayerData.CurrentExp >= this.PlayerData.ExpToNextLevel)
player.MaxStamina = this.OriginalStamina;
this.ExpToNextLevel = this.Config.ExpToNextLevel;
this.CurrentExp = this.Config.CurrentExp;
this.CurrentLevelStaminaBonus = 0;
this.OriginalStamina = player.MaxStamina;
this.BaseStaminaBonus = 0;
this.CurrentLevel = 0;
}
if (!this.ClearModEffects && this.CurrentLevel < this.Config.MaxLevel)
{
while (this.CurrentExp >= this.ExpToNextLevel)
{ {
this.CurrentLevel += 1; this.PlayerData.CurrentLevel += 1;
this.CurrentExp = this.CurrentExp - this.ExpToNextLevel; this.PlayerData.CurrentExp = this.PlayerData.CurrentExp - this.PlayerData.ExpToNextLevel;
this.ExpToNextLevel = (this.Config.ExpCurve * this.ExpToNextLevel); this.PlayerData.ExpToNextLevel = (this.Config.ExpCurve * this.PlayerData.ExpToNextLevel);
player.MaxStamina += this.Config.StaminaIncreasePerLevel; Game1.player.MaxStamina += this.Config.StaminaIncreasePerLevel;
this.CurrentLevelStaminaBonus += this.Config.StaminaIncreasePerLevel; this.PlayerData.CurrentLevelStaminaBonus += this.Config.StaminaIncreasePerLevel;
} }
} }
this.ClearModEffects = false; this.PlayerData.ClearModEffects = false;
this.NightlyStamina = Game1.player.maxStamina; this.PlayerData.NightlyStamina = Game1.player.maxStamina;
this.WriteConfig();
// save data
this.Helper.WriteJsonFile(this.DataFilePath, this.PlayerData);
} }
/// <summary>Update the settings needed for <see cref="ClearModEffects"/> from the latest config file on disk.</summary> /// <summary>Migrate the legacy settings for the current player.</summary>
void LoadClearSettings() private void MigrateLegacyData()
{ {
this.LoadConfig(); // skip if no legacy data or new data already exists
this.WriteConfig(); if (!File.Exists(this.LegacyDataFilePath) || File.Exists(this.DataFilePath))
return;
if (!Directory.Exists(Path.Combine(Helper.DirectoryPath, "PlayerData"))) // migrate to new file
Directory.CreateDirectory(Path.Combine(Helper.DirectoryPath, "PlayerData")); try
string path = Path.Combine(Helper.DirectoryPath, "PlayerData", $"BuildEndurance_data_{Game1.player.name}.txt");
if (!File.Exists(path))
{ {
this.Monitor.Log("Clear Data Loaded could not find the correct file.")); string[] text = File.ReadAllLines(this.LegacyDataFilePath);
this.Helper.WriteJsonFile(this.DataFilePath, new PlayerData
{
CurrentLevel = Convert.ToInt32(text[3]),
CurrentExp = Convert.ToDouble(text[5]),
ExpToNextLevel = Convert.ToDouble(text[7]),
BaseStaminaBonus = Convert.ToInt32(text[9]),
CurrentLevelStaminaBonus = Convert.ToInt32(text[11]),
ClearModEffects = Convert.ToBoolean(text[14]),
OriginalMaxStamina = Convert.ToInt32(text[16]),
NightlyStamina = Convert.ToInt32(text[18])
});
this.ClearModEffects = false; FileInfo file = new FileInfo(this.LegacyDataFilePath);
this.OriginalStamina = 0; file.Delete();
this.BaseStaminaBonus = 0; if (!file.Directory.EnumerateFiles().Any())
file.Directory.Delete();
} }
else catch (Exception ex)
{ {
string[] text = File.ReadAllLines(path); this.Monitor.Log($"Error migrating data from the legacy 'PlayerData' folder for the current player. Technical details:\n {ex}", LogLevel.Error);
this.BaseStaminaBonus = Convert.ToInt32(text[9]);
this.ClearModEffects = Convert.ToBoolean(text[14]);
this.OriginalStamina = Convert.ToInt32(text[16]);
} }
} }
/// <summary>Update <see cref="ClearModEffects"/> based on the latest config file on disk.</summary>
private void UpdateClearSetting()
{
if (!Directory.Exists(Path.Combine(Helper.DirectoryPath, "PlayerData")))
Directory.CreateDirectory(Path.Combine(Helper.DirectoryPath, "PlayerData"));
string path = Path.Combine(Helper.DirectoryPath, "PlayerData", $"BuildEndurance_data_{Game1.player.name}.txt");
if (!File.Exists(path))
{
this.Monitor.Log("Clear Data Loaded could not find the correct file.");
this.ClearModEffects = false;
this.OriginalStamina = 0;
this.BaseStaminaBonus = 0;
}
else
{
string[] text = File.ReadAllLines(path);
this.ClearModEffects = Convert.ToBoolean(text[14]);
}
}
/// <summary>Load the configuration settings.</summary>
void LoadConfig()
{
if (!Directory.Exists(Path.Combine(Helper.DirectoryPath, "PlayerData")))
Directory.CreateDirectory(Path.Combine(Helper.DirectoryPath, "PlayerData"));
string path = Path.Combine(Helper.DirectoryPath, "PlayerData", $"BuildEndurance_data_{Game1.player.name}.txt");
if (!File.Exists(path))
{
this.ExpToNextLevel = this.Config.ExpToNextLevel;
this.CurrentExp = this.Config.CurrentExp;
this.CurrentLevel = this.Config.CurrentLevel;
this.BaseStaminaBonus = this.Config.BaseStaminaBonus;
this.CurrentLevelStaminaBonus = this.Config.CurrentLevelStaminaBonus;
this.ClearModEffects = false;
this.OriginalStamina = 0;
}
else
{
string[] text = File.ReadAllLines(path);
this.CurrentLevel = Convert.ToInt32(text[3]);
this.ExpToNextLevel = Convert.ToDouble(text[7]);
this.CurrentExp = Convert.ToDouble(text[5]);
this.BaseStaminaBonus = Convert.ToInt32(text[9]);
this.CurrentLevelStaminaBonus = Convert.ToInt32(text[11]);
this.ClearModEffects = Convert.ToBoolean(text[14]);
this.OriginalStamina = Convert.ToInt32(text[16]);
this.NightlyStamina = Convert.ToInt32(text[18]);
}
}
/// <summary>Save the configuration settings.</summary>
void WriteConfig()
{
if (!Directory.Exists(Path.Combine(Helper.DirectoryPath, "PlayerData")))
Directory.CreateDirectory(Path.Combine(Helper.DirectoryPath, "PlayerData"));
string path = Path.Combine(Helper.DirectoryPath, "PlayerData", $"BuildEndurance_data_{Game1.player.name}.txt");
string[] text = new string[20];
text[0] = "Player: Build Endurance Data. Modification can cause errors. Edit at your own risk.";
text[1] = "====================================================================================";
text[2] = "Player Current Level:";
text[3] = this.CurrentLevel.ToString();
text[4] = "Player Current XP:";
text[5] = this.CurrentExp.ToString();
text[6] = "Xp to next Level:";
text[7] = this.ExpToNextLevel.ToString();
text[8] = "Initial Stam Bonus:";
text[9] = this.BaseStaminaBonus.ToString();
text[10] = "Additional Stam Bonus:";
text[11] = this.CurrentLevelStaminaBonus.ToString();
text[12] = "=======================================================================================";
text[13] = "RESET ALL MOD EFFECTS? This will effective start you back at square 1. Also good if you want to remove this mod.";
text[14] = this.ClearModEffects.ToString();
text[15] = "OLD STAMINA AMOUNT: This is the initial value of the Player's Stamina before this mod took over.";
text[16] = this.OriginalStamina.ToString();
text[17] = "Nightly Stamina Value: This is the value of the player's stamina that was saved when the player slept.";
text[18] = this.NightlyStamina.ToString();
File.WriteAllLines(path, text);
}
} }
} }

View File

@ -30,10 +30,6 @@
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
</ItemGroup> </ItemGroup>
@ -43,6 +39,7 @@
</Compile> </Compile>
<Compile Include="BuildEndurance.cs" /> <Compile Include="BuildEndurance.cs" />
<Compile Include="Framework\ModConfig.cs" /> <Compile Include="Framework\ModConfig.cs" />
<Compile Include="Framework\PlayerData.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -4,7 +4,7 @@ namespace Omegasis.BuildEndurance.Framework
internal class ModConfig internal class ModConfig
{ {
/// <summary>The XP points needed to reach the next endurance level.</summary> /// <summary>The XP points needed to reach the next endurance level.</summary>
public double ExpToNextLevel { get; set; } public double ExpToNextLevel { get; set; } = 20;
/// <summary>The player's current endurance XP points.</summary> /// <summary>The player's current endurance XP points.</summary>
public double CurrentExp { get; set; } public double CurrentExp { get; set; }
@ -19,27 +19,27 @@ namespace Omegasis.BuildEndurance.Framework
public int CurrentLevelStaminaBonus { get; set; } public int CurrentLevelStaminaBonus { get; set; }
/// <summary>The multiplier for the experience points to need to reach an endurance level relative to the previous one.</summary> /// <summary>The multiplier for the experience points to need to reach an endurance level relative to the previous one.</summary>
public double ExpCurve { get; set; } public double ExpCurve { get; set; } = 1.15;
/// <summary>The maximum endurance level the player can reach.</summary> /// <summary>The maximum endurance level the player can reach.</summary>
public int MaxLevel { get; set; } public int MaxLevel { get; set; } = 100;
/// <summary>The amount of stamina the player should gain for each endurance level.</summary> /// <summary>The amount of stamina the player should gain for each endurance level.</summary>
public int StaminaIncreasePerLevel { get; set; } public int StaminaIncreasePerLevel { get; set; } = 1;
/// <summary>The experience points to gain for using a tool.</summary> /// <summary>The experience points to gain for using a tool.</summary>
public int ExpForToolUse { get; set; } public int ExpForToolUse { get; set; } = 1;
/// <summary>The experience points to gain for eating or drinking.</summary> /// <summary>The experience points to gain for eating or drinking.</summary>
public int ExpForEating { get; set; } public int ExpForEating { get; set; } = 2;
/// <summary>The experience points to gain for sleeping.</summary> /// <summary>The experience points to gain for sleeping.</summary>
public int ExpForSleeping { get; set; } public int ExpForSleeping { get; set; } = 10;
/// <summary>The experience points to gain for reaching a state of exhaustion for the day.</summary> /// <summary>The experience points to gain for reaching a state of exhaustion for the day.</summary>
public int ExpForExhaustion { get; set; } public int ExpForExhaustion { get; set; } = 25;
/// <summary>The experience points to gain for collapsing for the day.</summary> /// <summary>The experience points to gain for collapsing for the day.</summary>
public int ExpForCollapsing { get; set; } public int ExpForCollapsing { get; set; } = 50;
} }
} }

View File

@ -0,0 +1,30 @@
namespace Omegasis.BuildEndurance.Framework
{
/// <summary>The data for the current player.</summary>
internal class PlayerData
{
/// <summary>The player's current endurance level.</summary>
public int CurrentLevel { get; set; }
/// <summary>The player's current endurance XP points.</summary>
public double CurrentExp { get; set; }
/// <summary>The XP points needed to reach the next endurance level.</summary>
public double ExpToNextLevel { get; set; } = 20;
/// <summary>The initial stamina bonus to apply regardless of the player's endurance level, from the config file.</summary>
public int BaseStaminaBonus { get; set; }
/// <summary>The stamina points to add to the player's base stamina due to their current endurance level.</summary>
public int CurrentLevelStaminaBonus { get; set; }
/// <summary>Whether to reset all changes by the mod to the default values (i.e. start over).</summary>
public bool ClearModEffects { get; set; }
/// <summary>The player's original max stamina value, excluding mod effects.</summary>
public int OriginalMaxStamina { get; set; }
/// <summary>The player's stamina last time they slept.</summary>
public int NightlyStamina { get; set; }
}
}

View File

@ -8,8 +8,8 @@ Compatible with Stardew Valley 1.2+ on Linux, Mac, and Windows.
2. Install [this mod from Nexus mods](http://www.nexusmods.com/stardewvalley/mods/445). 2. Install [this mod from Nexus mods](http://www.nexusmods.com/stardewvalley/mods/445).
3. Run the game using SMAPI. 3. Run the game using SMAPI.
**NOTE:** to undo the mod's changes to your player, edit the `PlayerData\BuildEndurance_data_*.txt` **NOTE:** to undo the mod's changes to your player, edit the `data\*.json` file for your save and
file and change the "RESET ALL MOD EFFECTS?" field to `True`. change the "ClearModEffects" field to `true`.
## Usage ## Usage
You'll automatically get XP for... You'll automatically get XP for...
@ -22,7 +22,7 @@ You'll automatically get XP for...
Get enough XP, and your endurance will level up. Get enough XP, and your endurance will level up.
Edit `BuildEnduranceConfig.json` to configure the mod settings. Edit `config.json` to configure the mod settings.
## Versions ## Versions
1.0 1.0
@ -36,4 +36,6 @@ Edit `BuildEnduranceConfig.json` to configure the mod settings.
1.4: 1.4:
* Updated for SMAPI 2.0. * Updated for SMAPI 2.0.
* Switched to standard JSON config & data files.
* Fixed issue where saves with the same name would overwrite each other's endurance level data.
* Internal refactoring. * Internal refactoring.

View File

@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="Newtonsoft.Json" version="10.0.3" targetFramework="net45" />
<package id="Pathoschild.Stardew.ModBuildConfig" version="1.7.0" targetFramework="net45" /> <package id="Pathoschild.Stardew.ModBuildConfig" version="1.7.0" targetFramework="net45" />
</packages> </packages>

View File

@ -1,7 +1,6 @@
using System; using System;
using System.IO; using System.IO;
using System.Text; using System.Linq;
using Newtonsoft.Json;
using Omegasis.BuildHealth.Framework; using Omegasis.BuildHealth.Framework;
using StardewModdingAPI; using StardewModdingAPI;
using StardewModdingAPI.Events; using StardewModdingAPI.Events;
@ -15,29 +14,17 @@ namespace Omegasis.BuildHealth
/********* /*********
** Properties ** Properties
*********/ *********/
/// <summary>The relative path for the current player's data file.</summary>
private string DataFilePath => Path.Combine("data", $"{Constants.SaveFolderName}.json");
/// <summary>The absolute path for the current player's legacy data file.</summary>
private string LegacyDataFilePath => Path.Combine(this.Helper.DirectoryPath, "PlayerData", $"BuildHealth_data_{Game1.player.name}.txt");
/// <summary>The mod settings and player data.</summary> /// <summary>The mod settings and player data.</summary>
private ModConfig Config; private ModConfig Config;
/// <summary>The XP points needed to reach the next level.</summary> /// <summary>The data for the current player.</summary>
private double ExpToNextLevel = 20; private PlayerData PlayerData;
/// <summary>The player's current XP points.</summary>
private double CurrentExp;
/// <summary>The player's current level.</summary>
private int CurrentLevel;
/// <summary>The health points to add to the player's base health due to their current level.</summary>
private int CurrentLevelHealthBonus;
/// <summary>The initial health bonus to apply regardless of the player's level, from the config file.</summary>
private int BaseHealthBonus;
/// <summary>Whether to reset all changes by the mod to the default values (i.e. start over).</summary>
private bool ClearModEffects;
/// <summary>The player's original max health value, excluding mod effects.</summary>
private int OriginalMaxHealth;
/// <summary>Whether the player recently gained XP for tool use.</summary> /// <summary>Whether the player recently gained XP for tool use.</summary>
private bool HasRecentToolExp; private bool HasRecentToolExp;
@ -61,42 +48,20 @@ namespace Omegasis.BuildHealth
{ {
GameEvents.UpdateTick += this.GameEvents_UpdateTick; GameEvents.UpdateTick += this.GameEvents_UpdateTick;
GameEvents.OneSecondTick += this.GameEvents_OneSecondTick; GameEvents.OneSecondTick += this.GameEvents_OneSecondTick;
TimeEvents.AfterDayStarted += this.SaveEvents_BeforeSave;
TimeEvents.AfterDayStarted += this.TimeEvents_AfterDayStarted;
SaveEvents.AfterLoad += this.SaveEvents_AfterLoaded; SaveEvents.AfterLoad += this.SaveEvents_AfterLoaded;
var configPath = Path.Combine(helper.DirectoryPath, "BuildHealthConfig.json"); this.Config = helper.ReadConfig<ModConfig>();
if (!File.Exists(configPath))
{
this.Config = new ModConfig
{
CurrentLevel = 0,
MaxLevel = 100,
HealthIncreasePerLevel = 1,
CurrentExp = 0,
ExpToNextLevel = 20,
ExpCurve = 1.15,
ExpForEating = 2,
ExpForSleeping = 10,
ExpForToolUse = 1,
BaseHealthBonus = 0,
CurrentLevelHealthBonus = 0
};
File.WriteAllBytes(configPath, Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(this.Config)));
}
else
{
this.Config = JsonConvert.DeserializeObject<ModConfig>(Encoding.UTF8.GetString(File.ReadAllBytes(configPath)));
this.Monitor.Log("Found BuildHealth config file.");
}
this.Monitor.Log("BuildHealth Initialization Completed");
} }
/*********
** Private methods
*********/
/// <summary>The method invoked once per second during a game update.</summary> /// <summary>The method invoked once per second during a game update.</summary>
/// <param name="sender">The event sender.</param> /// <param name="sender">The event sender.</param>
/// <param name="e">The event data.</param> /// <param name="e">The event data.</param>
public void GameEvents_OneSecondTick(object sender, EventArgs e) private void GameEvents_OneSecondTick(object sender, EventArgs e)
{ {
// nerf how quickly tool xp is gained (I hope) // nerf how quickly tool xp is gained (I hope)
if (this.HasRecentToolExp) if (this.HasRecentToolExp)
@ -106,21 +71,24 @@ namespace Omegasis.BuildHealth
/// <summary>The method invoked when the game updates (roughly 60 times per second).</summary> /// <summary>The method invoked when the game updates (roughly 60 times per second).</summary>
/// <param name="sender">The event sender.</param> /// <param name="sender">The event sender.</param>
/// <param name="e">The event data.</param> /// <param name="e">The event data.</param>
public void GameEvents_UpdateTick(object sender, EventArgs e) private void GameEvents_UpdateTick(object sender, EventArgs e)
{ {
if (!Context.IsWorldReady)
return;
// give XP when player finishes eating // give XP when player finishes eating
if (Game1.isEating) if (Game1.isEating)
this.WasEating = true; this.WasEating = true;
else if (this.WasEating) else if (this.WasEating)
{ {
this.CurrentExp += this.Config.ExpForEating; this.PlayerData.CurrentExp += this.Config.ExpForEating;
this.WasEating = false; this.WasEating = false;
} }
// give XP when player uses tool // give XP when player uses tool
if (!this.HasRecentToolExp && Game1.player.usingTool) if (!this.HasRecentToolExp && Game1.player.usingTool)
{ {
this.CurrentExp += this.Config.ExpForToolUse; this.PlayerData.CurrentExp += this.Config.ExpForToolUse;
this.HasRecentToolExp = true; this.HasRecentToolExp = true;
} }
@ -128,7 +96,7 @@ namespace Omegasis.BuildHealth
var player = Game1.player; var player = Game1.player;
if (this.LastHealth > player.health) if (this.LastHealth > player.health)
{ {
this.CurrentExp += this.LastHealth - player.health; this.PlayerData.CurrentExp += this.LastHealth - player.health;
this.LastHealth = player.health; this.LastHealth = player.health;
} }
else if (this.LastHealth < player.health) else if (this.LastHealth < player.health)
@ -137,195 +105,107 @@ namespace Omegasis.BuildHealth
// give XP when player stays up too late or collapses // give XP when player stays up too late or collapses
if (!this.WasCollapsed && Game1.farmerShouldPassOut) if (!this.WasCollapsed && Game1.farmerShouldPassOut)
{ {
this.CurrentExp += this.Config.ExpForCollapsing; this.PlayerData.CurrentExp += this.Config.ExpForCollapsing;
this.WasCollapsed = true; this.WasCollapsed = true;
this.Monitor.Log("The player has collapsed!"); this.Monitor.Log("The player has collapsed!");
} }
} }
/// <summary>The method invoked after a new day starts.</summary> /// <summary>The method invoked after the player loads a save.</summary>
/// <param name="sender">The event sender.</param> /// <param name="sender">The event sender.</param>
/// <param name="e">The event data.</param> /// <param name="e">The event data.</param>
public void TimeEvents_AfterDayStarted(object sender, EventArgs e) private void SaveEvents_AfterLoaded(object sender, EventArgs e)
{
// load player data
this.MigrateLegacyData();
this.PlayerData = this.Helper.ReadJsonFile<PlayerData>(this.DataFilePath) ?? new PlayerData();
if (this.PlayerData.OriginalMaxHealth == 0)
this.PlayerData.OriginalMaxHealth = Game1.player.maxHealth;
// reset if needed
if (this.PlayerData.ClearModEffects)
{
Game1.player.maxHealth = this.PlayerData.OriginalMaxHealth;
this.PlayerData.ExpToNextLevel = this.Config.ExpToNextLevel;
this.PlayerData.CurrentExp = this.Config.CurrentExp;
this.PlayerData.CurrentLevelHealthBonus = 0;
this.PlayerData.OriginalMaxHealth = Game1.player.maxHealth;
this.PlayerData.BaseHealthBonus = 0;
this.PlayerData.CurrentLevel = 0;
this.PlayerData.ClearModEffects = false;
}
// else apply health
else
{
Game1.player.maxHealth = this.PlayerData.BaseHealthBonus + this.PlayerData.CurrentLevelHealthBonus + this.PlayerData.OriginalMaxHealth;
this.LastHealth = Game1.player.health;
}
}
/// <summary>The method invoked just before the game saves.</summary>
/// <param name="sender">The event sender.</param>
/// <param name="e">The event data.</param>
private void SaveEvents_BeforeSave(object sender, EventArgs e)
{ {
// reset data // reset data
this.LastHealth = Game1.player.maxHealth; this.LastHealth = Game1.player.maxHealth;
this.WasCollapsed = false; this.WasCollapsed = false;
// update settings // update settings
this.UpdateClearSetting();
var player = Game1.player; var player = Game1.player;
this.CurrentExp += this.Config.ExpForSleeping; this.PlayerData.CurrentExp += this.Config.ExpForSleeping;
if (this.OriginalMaxHealth == 0) if (this.PlayerData.OriginalMaxHealth == 0)
this.OriginalMaxHealth = player.maxHealth; //grab the initial Health value this.PlayerData.OriginalMaxHealth = player.maxHealth; //grab the initial Health value
if (this.ClearModEffects) if (this.PlayerData.CurrentLevel < this.Config.MaxLevel)
{ {
this.LoadClearSettings(); while (this.PlayerData.CurrentExp >= this.PlayerData.ExpToNextLevel)
//This will run when the character goes to sleep. It will increase their sleeping skill.
player.maxHealth = this.OriginalMaxHealth;
this.ExpToNextLevel = this.Config.ExpToNextLevel;
this.CurrentExp = this.Config.CurrentExp;
this.CurrentLevelHealthBonus = 0;
this.OriginalMaxHealth = player.maxHealth;
this.BaseHealthBonus = 0;
this.CurrentLevel = 0;
this.Monitor.Log("BuildHealth Reset!");
}
if (!this.ClearModEffects && this.CurrentLevel < this.Config.MaxLevel)
{
while (this.CurrentExp >= this.ExpToNextLevel)
{ {
this.CurrentLevel += 1; this.PlayerData.CurrentLevel += 1;
this.CurrentExp = this.CurrentExp - this.ExpToNextLevel; this.PlayerData.CurrentExp = this.PlayerData.CurrentExp - this.PlayerData.ExpToNextLevel;
this.ExpToNextLevel = this.PlayerData.ExpToNextLevel =
(this.Config.ExpCurve * this.ExpToNextLevel); (this.Config.ExpCurve * this.PlayerData.ExpToNextLevel);
player.maxHealth += this.Config.HealthIncreasePerLevel; player.maxHealth += this.Config.HealthIncreasePerLevel;
this.CurrentLevelHealthBonus += this.Config.HealthIncreasePerLevel; this.PlayerData.CurrentLevelHealthBonus += this.Config.HealthIncreasePerLevel;
} }
} }
this.ClearModEffects = false;
this.WriteConfig(); // save data
this.Helper.WriteJsonFile(this.DataFilePath, this.PlayerData);
} }
/// <summary>The method invoked after the player loads a save.</summary> /// <summary>Migrate the legacy settings for the current player.</summary>
/// <param name="sender">The event sender.</param> private void MigrateLegacyData()
/// <param name="e">The event data.</param>
public void SaveEvents_AfterLoaded(object sender, EventArgs e)
{ {
// initialise // skip if no legacy data or new data already exists
this.LoadConfig(); if (!File.Exists(this.LegacyDataFilePath) || File.Exists(this.DataFilePath))
this.WriteConfig(); return;
// grab initial health // migrate to new file
var player = Game1.player; try
if (this.OriginalMaxHealth == 0)
this.OriginalMaxHealth = player.maxHealth;
// set max health
player.maxHealth = this.BaseHealthBonus + this.CurrentLevelHealthBonus + this.OriginalMaxHealth;
// reset if needed
if (this.ClearModEffects)
{ {
player.maxHealth = this.OriginalMaxHealth; string[] text = File.ReadAllLines(this.LegacyDataFilePath);
this.Monitor.Log("BuildHealth Reset!"); this.Helper.WriteJsonFile(this.DataFilePath, new PlayerData
{
CurrentLevel = Convert.ToInt32(text[3]),
CurrentExp = Convert.ToDouble(text[5]),
ExpToNextLevel = Convert.ToDouble(text[7]),
BaseHealthBonus = Convert.ToInt32(text[9]),
CurrentLevelHealthBonus = Convert.ToInt32(text[11]),
ClearModEffects = Convert.ToBoolean(text[14]),
OriginalMaxHealth = Convert.ToInt32(text[16])
});
FileInfo file = new FileInfo(this.LegacyDataFilePath);
file.Delete();
if (!file.Directory.EnumerateFiles().Any())
file.Directory.Delete();
} }
catch (Exception ex)
// save config
this.LastHealth = Game1.player.maxHealth;
this.LoadConfig();
this.WriteConfig();
}
/// <summary>Update the settings needed for <see cref="ClearModEffects"/> from the latest config file on disk.</summary>
void LoadClearSettings()
{
if (!Directory.Exists(Path.Combine(Helper.DirectoryPath, "PlayerData")))
Directory.CreateDirectory(Path.Combine(Helper.DirectoryPath, "PlayerData"));
string path = Path.Combine(Helper.DirectoryPath, "PlayerData", $"BuildHealth_data_{Game1.player.name}.txt");
if (!File.Exists(path))
{ {
this.ClearModEffects = false; this.Monitor.Log($"Error migrating data from the legacy 'PlayerData' folder for the current player. Technical details:\n {ex}", LogLevel.Error);
this.OriginalMaxHealth = 0;
this.BaseHealthBonus = 0;
} }
else
{
string[] text = File.ReadAllLines(path);
this.BaseHealthBonus = Convert.ToInt32(text[9]);
this.ClearModEffects = Convert.ToBoolean(text[14]);
this.OriginalMaxHealth = Convert.ToInt32(text[16]);
}
}
/// <summary>Update <see cref="ClearModEffects"/> based on the latest config file on disk.</summary>
private void UpdateClearSetting()
{
if (!Directory.Exists(Path.Combine(Helper.DirectoryPath, "PlayerData")))
Directory.CreateDirectory(Path.Combine(Helper.DirectoryPath, "PlayerData"));
string path = Path.Combine(Helper.DirectoryPath, "PlayerData", $"BuildHealth_data_{Game1.player.name}.txt");
if (!File.Exists(path))
{
this.ClearModEffects = false;
this.OriginalMaxHealth = 0;
this.BaseHealthBonus = 0;
}
else
{
string[] text = File.ReadAllLines(path);
this.ClearModEffects = Convert.ToBoolean(text[14]);
}
}
/// <summary>Load the configuration settings.</summary>
private void LoadConfig()
{
if (!Directory.Exists(Path.Combine(Helper.DirectoryPath, "PlayerData")))
Directory.CreateDirectory(Path.Combine(Helper.DirectoryPath, "PlayerData"));
string path = Path.Combine(Helper.DirectoryPath, "PlayerData", $"BuildHealth_data_{Game1.player.name}.txr");
if (!File.Exists(path))
{
this.ExpToNextLevel = this.Config.ExpToNextLevel;
this.CurrentExp = this.Config.CurrentExp;
this.CurrentLevel = this.Config.CurrentLevel;
this.BaseHealthBonus = this.Config.BaseHealthBonus;
this.CurrentLevelHealthBonus = this.Config.CurrentLevelHealthBonus;
this.ClearModEffects = false;
this.OriginalMaxHealth = 0;
}
else
{
string[] text = File.ReadAllLines(path);
this.CurrentLevel = Convert.ToInt32(text[3]);
this.ExpToNextLevel = Convert.ToDouble(text[7]);
this.CurrentExp = Convert.ToDouble(text[5]);
this.BaseHealthBonus = Convert.ToInt32(text[9]);
this.CurrentLevelHealthBonus = Convert.ToInt32(text[11]);
this.ClearModEffects = Convert.ToBoolean(text[14]);
this.OriginalMaxHealth = Convert.ToInt32(text[16]);
}
}
/// <summary>Save the configuration settings.</summary>
private void WriteConfig()
{
if (!Directory.Exists(Path.Combine(Helper.DirectoryPath, "PlayerData")))
Directory.CreateDirectory(Path.Combine(Helper.DirectoryPath, "PlayerData"));
string path = Path.Combine(Helper.DirectoryPath, "PlayerData", $"BuildHealth_data_{Game1.player.name}.txt");
string[] text = new string[20];
text[0] = "Player: Build Health Data. Modification can cause errors. Edit at your own risk.";
text[1] = "====================================================================================";
text[2] = "Player Current Level:";
text[3] = this.CurrentLevel.ToString();
text[4] = "Player Current XP:";
text[5] = this.CurrentExp.ToString();
text[6] = "Xp to next Level:";
text[7] = this.ExpToNextLevel.ToString();
text[8] = "Initial Health Bonus:";
text[9] = this.BaseHealthBonus.ToString();
text[10] = "Additional Health Bonus:";
text[11] = this.CurrentLevelHealthBonus.ToString();
text[12] = "=======================================================================================";
text[13] = "RESET ALL MOD EFFECTS? This will effective start you back at square 1. Also good if you want to remove this mod.";
text[14] = this.ClearModEffects.ToString();
text[15] = "OLD Health AMOUNT: This is the initial value of the Player's Health before this mod took over.";
text[16] = this.OriginalMaxHealth.ToString();
File.WriteAllLines(path, text);
} }
} }
} }

View File

@ -30,10 +30,6 @@
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
</ItemGroup> </ItemGroup>
@ -43,6 +39,7 @@
</Compile> </Compile>
<Compile Include="BuildHealth.cs" /> <Compile Include="BuildHealth.cs" />
<Compile Include="Framework\ModConfig.cs" /> <Compile Include="Framework\ModConfig.cs" />
<Compile Include="Framework\PlayerData.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -4,7 +4,7 @@
internal class ModConfig internal class ModConfig
{ {
/// <summary>The XP points needed to reach the next level.</summary> /// <summary>The XP points needed to reach the next level.</summary>
public double ExpToNextLevel { get; set; } public double ExpToNextLevel { get; set; } = 20;
/// <summary>The player's current XP points.</summary> /// <summary>The player's current XP points.</summary>
public double CurrentExp { get; set; } public double CurrentExp { get; set; }
@ -19,22 +19,22 @@
public int CurrentLevelHealthBonus { get; set; } public int CurrentLevelHealthBonus { get; set; }
/// <summary>The multiplier for the experience points to need to reach an endurance level relative to the previous one.</summary> /// <summary>The multiplier for the experience points to need to reach an endurance level relative to the previous one.</summary>
public double ExpCurve { get; set; } public double ExpCurve { get; set; } = 1.15;
/// <summary>The maximum endurance level the player can reach.</summary> /// <summary>The maximum endurance level the player can reach.</summary>
public int MaxLevel { get; set; } public int MaxLevel { get; set; } = 100;
/// <summary>The amount of stamina the player should gain for each endurance level.</summary> /// <summary>The amount of stamina the player should gain for each endurance level.</summary>
public int HealthIncreasePerLevel { get; set; } public int HealthIncreasePerLevel { get; set; } = 1;
/// <summary>The experience points to gain for using a tool.</summary> /// <summary>The experience points to gain for using a tool.</summary>
public int ExpForToolUse { get; set; } public int ExpForToolUse { get; set; } = 1;
/// <summary>The experience points to gain for eating or drinking.</summary> /// <summary>The experience points to gain for eating or drinking.</summary>
public int ExpForEating { get; set; } public int ExpForEating { get; set; } = 2;
/// <summary>The experience points to gain for sleeping.</summary> /// <summary>The experience points to gain for sleeping.</summary>
public int ExpForSleeping { get; set; } public int ExpForSleeping { get; set; } = 10;
/// <summary>The experience points to gain for collapsing for the day.</summary> /// <summary>The experience points to gain for collapsing for the day.</summary>
public int ExpForCollapsing { get; set; } public int ExpForCollapsing { get; set; }

View File

@ -0,0 +1,27 @@
namespace Omegasis.BuildHealth.Framework
{
/// <summary>The data for the current player.</summary>
internal class PlayerData
{
/// <summary>The player's current endurance level.</summary>
public int CurrentLevel { get; set; }
/// <summary>The player's current endurance XP points.</summary>
public double CurrentExp { get; set; }
/// <summary>The XP points needed to reach the next endurance level.</summary>
public double ExpToNextLevel { get; set; } = 20;
/// <summary>The initial health bonus to apply regardless of the player's endurance level, from the config file.</summary>
public int BaseHealthBonus { get; set; }
/// <summary>The health points to add to the player's base health due to their current endurance level.</summary>
public int CurrentLevelHealthBonus { get; set; }
/// <summary>Whether to reset all changes by the mod to the default values (i.e. start over).</summary>
public bool ClearModEffects { get; set; }
/// <summary>The player's original maximum health value, excluding mod effects.</summary>
public int OriginalMaxHealth { get; set; }
}
}

View File

@ -8,8 +8,8 @@ Compatible with Stardew Valley 1.2+ on Linux, Mac, and Windows.
2. Install [this mod from Nexus mods](http://www.nexusmods.com/stardewvalley/mods/445). 2. Install [this mod from Nexus mods](http://www.nexusmods.com/stardewvalley/mods/445).
3. Run the game using SMAPI. 3. Run the game using SMAPI.
**NOTE:** to undo the mod's changes to your player, edit the `PlayerData\BuildEndurance_data_*.txt` **NOTE:** to undo the mod's changes to your player, edit the `data\*.json` file for your save and
file and change the "RESET ALL MOD EFFECTS?" field to `True`. change the "ClearModEffects" field to `true`.
## Usage ## Usage
You'll automatically get XP for... You'll automatically get XP for...
@ -23,7 +23,7 @@ You'll automatically get XP for...
Get enough XP, and your health will level up. Get enough XP, and your health will level up.
Edit `BuildHealthConfig.json` to configure the mod settings. Edit `config.json` to configure the mod settings.
## Versions ## Versions
1.0 1.0
@ -37,4 +37,6 @@ Edit `BuildHealthConfig.json` to configure the mod settings.
1.4: 1.4:
* Updated for SMAPI 2.0. * Updated for SMAPI 2.0.
* Switched to standard JSON config & data files.
* Fixed issue where saves with the same name would overwrite each other's endurance level data.
* Internal refactoring. * Internal refactoring.

View File

@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="Newtonsoft.Json" version="10.0.3" targetFramework="net45" />
<package id="Pathoschild.Stardew.ModBuildConfig" version="1.7.0" targetFramework="net45" /> <package id="Pathoschild.Stardew.ModBuildConfig" version="1.7.0" targetFramework="net45" />
</packages> </packages>

View File

@ -1,6 +1,4 @@
using System; using Omegasis.BuyBackCollectables.Framework;
using System.IO;
using Omegasis.BuyBackCollectables.Framework;
using StardewModdingAPI; using StardewModdingAPI;
using StardewModdingAPI.Events; using StardewModdingAPI.Events;
using StardewValley; using StardewValley;
@ -13,11 +11,8 @@ namespace Omegasis.BuyBackCollectables
/********* /*********
** Properties ** Properties
*********/ *********/
/// <summary>The key which shows the menu.</summary> /// <summary>The mod configuration.</summary>
private string KeyBinding = "B"; private ModConfig Config;
/// <summary>The multiplier applied to the cost of buying back a collectable.</summary>
private double CostMultiplier = 3.0;
/********* /*********
@ -27,7 +22,8 @@ namespace Omegasis.BuyBackCollectables
/// <param name="helper">Provides simplified APIs for writing mods.</param> /// <param name="helper">Provides simplified APIs for writing mods.</param>
public override void Entry(IModHelper helper) public override void Entry(IModHelper helper)
{ {
SaveEvents.AfterLoad += this.SaveEvents_AfterLoad; this.Config = helper.ReadConfig<ModConfig>();
ControlEvents.KeyPressed += this.ControlEvents_KeyPressed; ControlEvents.KeyPressed += this.ControlEvents_KeyPressed;
} }
@ -35,55 +31,13 @@ namespace Omegasis.BuyBackCollectables
/********* /*********
** Private methods ** Private methods
*********/ *********/
/// <summary>The method invoked after the player loads a save.</summary>
/// <param name="sender">The event sender.</param>
/// <param name="e">The event data.</param>
public void SaveEvents_AfterLoad(object sender, EventArgs e)
{
this.LoadConfig();
this.WriteConfig();
}
/// <summary>The method invoked when the presses a keyboard button.</summary> /// <summary>The method invoked when the presses a keyboard button.</summary>
/// <param name="sender">The event sender.</param> /// <param name="sender">The event sender.</param>
/// <param name="e">The event data.</param> /// <param name="e">The event data.</param>
public void ControlEvents_KeyPressed(object sender, EventArgsKeyPressed e) public void ControlEvents_KeyPressed(object sender, EventArgsKeyPressed e)
{ {
if (Context.IsPlayerFree && e.KeyPressed.ToString() == this.KeyBinding) if (Context.IsPlayerFree && e.KeyPressed.ToString() == this.Config.KeyBinding)
Game1.activeClickableMenu = new BuyBackMenu(this.CostMultiplier); Game1.activeClickableMenu = new BuyBackMenu(this.Config.CostMultiplier);
}
/// <summary>Load the configuration settings.</summary>
private void LoadConfig()
{
//loads the data to the variables upon loading the game.
string path = Path.Combine(Helper.DirectoryPath, "BuyBack_Config.txt");
if (!File.Exists(path))
{
this.KeyBinding = "B";
this.CostMultiplier = 3.0;
}
else
{
string[] text = File.ReadAllLines(path);
this.KeyBinding = Convert.ToString(text[3]);
this.CostMultiplier = Convert.ToDouble(text[5]);
}
}
/// <summary>Save the configuration settings.</summary>
private void WriteConfig()
{
//write all of my info to a text file.
string path = Path.Combine(Helper.DirectoryPath, "BuyBack_Config.txt");
string[] text = new string[20];
text[0] = "Config: Buy Back Collections. Feel free to mess with these settings.";
text[1] = "====================================================================================";
text[2] = "Key binding";
text[3] = this.KeyBinding;
text[4] = "Collectables Multiplier Cost: Sell Value * value listed below";
text[5] = this.CostMultiplier.ToString();
File.WriteAllLines(path, text);
} }
} }
} }

View File

@ -38,6 +38,7 @@
<Link>Properties\GlobalAssemblyInfo.cs</Link> <Link>Properties\GlobalAssemblyInfo.cs</Link>
</Compile> </Compile>
<Compile Include="BuyBackCollectables.cs" /> <Compile Include="BuyBackCollectables.cs" />
<Compile Include="Framework\ModConfig.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Framework\BuyBackMenu.cs" /> <Compile Include="Framework\BuyBackMenu.cs" />
</ItemGroup> </ItemGroup>

View File

@ -0,0 +1,12 @@
namespace Omegasis.BuyBackCollectables.Framework
{
/// <summary>The mod configuration.</summary>
internal class ModConfig
{
/// <summary>The key which shows the menu.</summary>
public string KeyBinding { get; set; } = "B";
/// <summary>The multiplier applied to the cost of buying back a collectable.</summary>
public double CostMultiplier { get; set; } = 3.0;
}
}

View File

@ -9,8 +9,8 @@ Compatible with Stardew Valley 1.2+ on Linux, Mac, and Windows.
3. Run the game using SMAPI. 3. Run the game using SMAPI.
## Usage ## Usage
Press `B` to open the buy-collectibles menu. Edit `BuildHealthConfig.json` to change the key or the Press `B` to open the buy-collectibles menu. Edit `config.json` to change the key or the price
price markup. markup.
## Versions ## Versions
1.0: 1.0:
@ -31,4 +31,5 @@ price markup.
* Updated to Stardew Valley 1.2 and SMAPI 1.12. * Updated to Stardew Valley 1.2 and SMAPI 1.12.
1.4: 1.4:
* Switched to standard JSON config file.
* Internal refactoring. * Internal refactoring.

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework;
using Omegasis.CustomShopsRedux.Framework;
using StardewModdingAPI; using StardewModdingAPI;
using StardewModdingAPI.Events; using StardewModdingAPI.Events;
using StardewValley; using StardewValley;
@ -31,17 +32,17 @@ namespace Omegasis.CustomShopsRedux
/********* /*********
** Properties ** Properties
*********/ *********/
/// <summary>The mod configuration.</summary>
private ModConfig Config;
/// <summary>The prices for the items to list.</summary> /// <summary>The prices for the items to list.</summary>
private readonly Dictionary<Item, int[]> ListPrices = new Dictionary<Item, int[]>(); private readonly Dictionary<Item, int[]> ListPrices = new Dictionary<Item, int[]>();
/// <summary>The folder path containing shop data files.</summary>
private string DataPath;
/// <summary>The configured shop options.</summary> /// <summary>The configured shop options.</summary>
private readonly List<string> Options = new List<string>(); private readonly List<string> Options = new List<string>();
/// <summary>The key which shows the menu.</summary> /// <summary>The folder path containing shop data files.</summary>
private string KeyBinding = "U"; private string DataPath => Path.Combine(this.Helper.DirectoryPath, "Custom_Shops");
/********* /*********
@ -51,7 +52,8 @@ namespace Omegasis.CustomShopsRedux
/// <param name="helper">Provides simplified APIs for writing mods.</param> /// <param name="helper">Provides simplified APIs for writing mods.</param>
public override void Entry(IModHelper helper) public override void Entry(IModHelper helper)
{ {
SaveEvents.AfterLoad += this.SaveEvents_AfterDayStarted; this.Config = helper.ReadConfig<ModConfig>();
ControlEvents.KeyPressed += this.ControlEvents_KeyPressed; ControlEvents.KeyPressed += this.ControlEvents_KeyPressed;
} }
@ -59,58 +61,20 @@ namespace Omegasis.CustomShopsRedux
/********* /*********
** Private methods ** Private methods
*********/ *********/
/// <summary>The method invoked after a new day starts.</summary>
/// <param name="sender">The event sender.</param>
/// <param name="e">The event data.</param>
private void SaveEvents_AfterDayStarted(object sender, EventArgs e)
{
this.LoadConfig();
this.WriteConfig();
}
/// <summary>The method invoked when the presses a keyboard button.</summary> /// <summary>The method invoked when the presses a keyboard button.</summary>
/// <param name="sender">The event sender.</param> /// <param name="sender">The event sender.</param>
/// <param name="e">The event data.</param> /// <param name="e">The event data.</param>
private void ControlEvents_KeyPressed(object sender, EventArgsKeyPressed e) private void ControlEvents_KeyPressed(object sender, EventArgsKeyPressed e)
{ {
if (Context.IsPlayerFree && e.KeyPressed.ToString() == this.KeyBinding) if (Context.IsPlayerFree && e.KeyPressed.ToString() == this.Config.KeyBinding)
this.OpenSelectFileMenu(); this.OpenSelectFileMenu();
} }
/// <summary>Load the configuration settings.</summary>
private void LoadConfig()
{
this.DataPath = Path.Combine(this.Helper.DirectoryPath, "Custom_Shops");
Directory.CreateDirectory(this.DataPath);
string path = Path.Combine(this.Helper.DirectoryPath, "Custom_Shop_Redux_Config.txt");
if (!File.Exists(path))
this.KeyBinding = "U";
else
{
string[] text = File.ReadAllLines(path);
this.KeyBinding = Convert.ToString(text[3]);
}
}
/// <summary>Save the configuration settings.</summary>
private void WriteConfig()
{
string path = Path.Combine(this.Helper.DirectoryPath, "Custom_Shop_Redux_Config.txt");
string[] text = new string[20];
text[0] = "Config: Custom_Shop_Redux. Feel free to mess with these settings.";
text[1] = "====================================================================================";
text[2] = "Key binding for saving anywhere. Press this key to save anywhere!";
text[3] = this.KeyBinding;
File.WriteAllLines(path, text);
}
/// <summary>Open the menu which lets the player choose a file.</summary> /// <summary>Open the menu which lets the player choose a file.</summary>
private void OpenSelectFileMenu() private void OpenSelectFileMenu()
{ {
// get mod folder // get mod folder
Directory.CreateDirectory(this.DataPath);
DirectoryInfo modFolder = new DirectoryInfo(this.DataPath); DirectoryInfo modFolder = new DirectoryInfo(this.DataPath);
this.Monitor.Log(modFolder.FullName); this.Monitor.Log(modFolder.FullName);

View File

@ -38,6 +38,7 @@
<Link>Properties\GlobalAssemblyInfo.cs</Link> <Link>Properties\GlobalAssemblyInfo.cs</Link>
</Compile> </Compile>
<Compile Include="CustomShopsRedux.cs" /> <Compile Include="CustomShopsRedux.cs" />
<Compile Include="Framework\ModConfig.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -0,0 +1,9 @@
namespace Omegasis.CustomShopsRedux.Framework
{
/// <summary>The mod configuration.</summary>
internal class ModConfig
{
/// <summary>The key which shows the menu.</summary>
public string KeyBinding { get; set; } = "U";
}
}

View File

@ -13,7 +13,7 @@ Make a custom shop by copying & editing one of the included custom shop template
[Custom Shops Creation Tool](https://myscccd-my.sharepoint.com/personal/0703280_my_scccd_edu/_layouts/15/guestaccess.aspx?guestaccesstoken=ZYxG9Cs8S0q%2bxCVV3fEnc8MI4SfVfe07919rhFUhRiA%3d&docid=0e51dae1da2eb43988f77f5c54ec3ee58) [Custom Shops Creation Tool](https://myscccd-my.sharepoint.com/personal/0703280_my_scccd_edu/_layouts/15/guestaccess.aspx?guestaccesstoken=ZYxG9Cs8S0q%2bxCVV3fEnc8MI4SfVfe07919rhFUhRiA%3d&docid=0e51dae1da2eb43988f77f5c54ec3ee58)
(see [demo video](https://youtu.be/bSvNTZmgeZE)). (see [demo video](https://youtu.be/bSvNTZmgeZE)).
You can access the custom shops by pressing `U` in-game (configurable via `Custom_Shop_Redux_Config.txt`). You can access the custom shops by pressing `U` in-game (configurable via `config.json`).
Supported item types: Supported item types:
@ -60,4 +60,5 @@ Supported item types:
1.4: 1.4:
* Updated for SMAPI 2.0. * Updated for SMAPI 2.0.
* Switched to standard JSON config file.
* Internal refactoring. * Internal refactoring.

View File

@ -1,5 +1,4 @@
using System; using Omegasis.DailyQuestAnywhere.Framework;
using System.IO;
using StardewModdingAPI; using StardewModdingAPI;
using StardewModdingAPI.Events; using StardewModdingAPI.Events;
using StardewValley; using StardewValley;
@ -13,8 +12,8 @@ namespace Omegasis.DailyQuestAnywhere
/********* /*********
** Properties ** Properties
*********/ *********/
/// <summary>The key which shows the menu.</summary> /// <summary>The mod configuration.</summary>
private string KeyBinding = "H"; private ModConfig Config;
/********* /*********
@ -24,7 +23,8 @@ namespace Omegasis.DailyQuestAnywhere
/// <param name="helper">Provides simplified APIs for writing mods.</param> /// <param name="helper">Provides simplified APIs for writing mods.</param>
public override void Entry(IModHelper helper) public override void Entry(IModHelper helper)
{ {
SaveEvents.AfterLoad += this.SaveEvents_AfterLoad; this.Config = helper.ReadConfig<ModConfig>();
ControlEvents.KeyPressed += this.ControlEvents_KeyPressed; ControlEvents.KeyPressed += this.ControlEvents_KeyPressed;
} }
@ -32,49 +32,13 @@ namespace Omegasis.DailyQuestAnywhere
/********* /*********
** Private methods ** Private methods
*********/ *********/
/// <summary>The method invoked after the player loads a save.</summary>
/// <param name="sender">The event sender.</param>
/// <param name="e">The event data.</param>
private void SaveEvents_AfterLoad(object sender, EventArgs e)
{
this.LoadConfig();
this.WriteConfig();
}
/// <summary>The method invoked when the presses a keyboard button.</summary> /// <summary>The method invoked when the presses a keyboard button.</summary>
/// <param name="sender">The event sender.</param> /// <param name="sender">The event sender.</param>
/// <param name="e">The event data.</param> /// <param name="e">The event data.</param>
private void ControlEvents_KeyPressed(object sender, EventArgsKeyPressed e) private void ControlEvents_KeyPressed(object sender, EventArgsKeyPressed e)
{ {
if (Context.IsPlayerFree && e.KeyPressed.ToString() == this.KeyBinding) if (Context.IsPlayerFree && e.KeyPressed.ToString() == this.Config.KeyBinding)
Game1.activeClickableMenu = new Billboard(true); Game1.activeClickableMenu = new Billboard(true);
} }
/// <summary>Load the configuration settings.</summary>
void LoadConfig()
{
string path = Path.Combine(Helper.DirectoryPath, "DailyQuest_Anywhere_Config.txt");
if (!File.Exists(path))
this.KeyBinding = "H";
else
{
string[] text = File.ReadAllLines(path);
this.KeyBinding = Convert.ToString(text[3]);
}
}
/// <summary>Save the configuration settings.</summary>
void WriteConfig()
{
string path = Path.Combine(Helper.DirectoryPath, "DailyQuest_Anywhere_Config.txt");
string[] text = new string[20];
text[0] = "Config: DailyQuest_Anywhere Info. Feel free to mess with these settings.";
text[1] = "====================================================================================";
text[2] = "Key binding for opening the billboard for quests anywhere. Press this key to do so";
text[3] = this.KeyBinding;
File.WriteAllLines(path, text);
}
} }
} }

View File

@ -38,6 +38,7 @@
<Link>Properties\GlobalAssemblyInfo.cs</Link> <Link>Properties\GlobalAssemblyInfo.cs</Link>
</Compile> </Compile>
<Compile Include="DailyQuestAnywhere.cs" /> <Compile Include="DailyQuestAnywhere.cs" />
<Compile Include="Framework\ModConfig.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -0,0 +1,9 @@
namespace Omegasis.DailyQuestAnywhere.Framework
{
/// <summary>The mod configuration.</summary>
internal class ModConfig
{
/// <summary>The key which shows the menu.</summary>
public string KeyBinding { get; set; } = "H";
}
}

View File

@ -9,7 +9,7 @@ Compatible with Stardew Valley 1.2+ on Linux, Mac, and Windows.
3. Run the game using SMAPI. 3. Run the game using SMAPI.
## Usage ## Usage
Press `H` to open the daily quest menu. Edit `DailyQuest_Anywhere_Config.txt` to change the key. Press `H` to open the daily quest menu. Edit `config.json` to change the key.
## Versions ## Versions
1.0: 1.0:
@ -22,4 +22,5 @@ Press `H` to open the daily quest menu. Edit `DailyQuest_Anywhere_Config.txt` to
* Updated to Stardew Valley 1.2 and SMAPI 1.12. * Updated to Stardew Valley 1.2 and SMAPI 1.12.
1.4: 1.4:
* Switched to standard JSON config file.
* Internal refactoring. * Internal refactoring.

View File

@ -0,0 +1,9 @@
namespace Omegasis.HappyBirthday.Framework
{
/// <summary>The mod configuration.</summary>
internal class ModConfig
{
/// <summary>The key which shows the menu.</summary>
public string KeyBinding { get; set; } = "O";
}
}

View File

@ -0,0 +1,12 @@
namespace Omegasis.HappyBirthday.Framework
{
/// <summary>The data for the current player.</summary>
internal class PlayerData
{
/// <summary>The player's current birthday day.</summary>
public int BirthdayDay;
/// <summary>The player's current birthday season.</summary>
public string BirthdaySeason;
}
}

View File

@ -18,11 +18,20 @@ namespace Omegasis.HappyBirthday
/********* /*********
** Properties ** Properties
*********/ *********/
/// <summary>The key which shows the menu.</summary> /// <summary>The relative path for the current player's data file.</summary>
private string KeyBinding = "O"; private string DataFilePath => Path.Combine("data", $"{Constants.SaveFolderName}.json");
/// <summary>The absolute path for the current player's legacy data file.</summary>
private string LegacyDataFilePath => Path.Combine(this.Helper.DirectoryPath, "Player_Birthdays", $"HappyBirthday_{Game1.player.name}.txt");
/// <summary>The mod configuration.</summary>
private ModConfig Config;
/// <summary>The data for the current player.</summary>
private PlayerData PlayerData;
/// <summary>Whether the player has chosen a birthday.</summary> /// <summary>Whether the player has chosen a birthday.</summary>
private bool HasChosenBirthday; private bool HasChosenBirthday => !string.IsNullOrEmpty(this.PlayerData.BirthdaySeason) && this.PlayerData.BirthdayDay != 0;
/// <summary>The queue of villagers who haven't given a gift yet.</summary> /// <summary>The queue of villagers who haven't given a gift yet.</summary>
private List<string> VillagerQueue; private List<string> VillagerQueue;
@ -38,18 +47,6 @@ namespace Omegasis.HappyBirthday
//private Dictionary<string, Dialogue> Dialogue; //private Dictionary<string, Dialogue> Dialogue;
//private bool SeenEvent; //private bool SeenEvent;
/// <summary>The name of the folder containing birthday data files.</summary>
private readonly string FolderName = "Player_Birthdays";
/// <summary>The full path to the folder containing birthday data files.</summary>
private string BirthdayFolderPath;
/// <summary>The player's current birthday day.</summary>
public int BirthdayDay;
/// <summary>The player's current birthday season.</summary>
public string BirthdaySeason;
/********* /*********
** Public methods ** Public methods
@ -58,17 +55,16 @@ namespace Omegasis.HappyBirthday
/// <param name="helper">Provides simplified APIs for writing mods.</param> /// <param name="helper">Provides simplified APIs for writing mods.</param>
public override void Entry(IModHelper helper) public override void Entry(IModHelper helper)
{ {
this.Config = helper.ReadConfig<ModConfig>();
TimeEvents.AfterDayStarted += this.TimeEvents_AfterDayStarted; TimeEvents.AfterDayStarted += this.TimeEvents_AfterDayStarted;
GameEvents.UpdateTick += this.GameEvents_UpdateTick; GameEvents.UpdateTick += this.GameEvents_UpdateTick;
SaveEvents.AfterLoad += this.SaveEvents_AfterLoad; SaveEvents.AfterLoad += this.SaveEvents_AfterLoad;
SaveEvents.BeforeSave += this.SaveEvents_BeforeSave;
ControlEvents.KeyPressed += this.ControlEvents_KeyPressed; ControlEvents.KeyPressed += this.ControlEvents_KeyPressed;
this.VillagerQueue = new List<string>(); this.VillagerQueue = new List<string>();
this.PossibleBirthdayGifts = new List<Item>(); this.PossibleBirthdayGifts = new List<Item>();
this.BirthdayFolderPath = Path.Combine(Helper.DirectoryPath, this.FolderName);
if (!Directory.Exists(this.BirthdayFolderPath))
Directory.CreateDirectory(this.BirthdayFolderPath);
} }
@ -80,9 +76,6 @@ namespace Omegasis.HappyBirthday
/// <param name="e">The event data.</param> /// <param name="e">The event data.</param>
private void TimeEvents_AfterDayStarted(object sender, EventArgs e) private void TimeEvents_AfterDayStarted(object sender, EventArgs e)
{ {
if (this.HasChosenBirthday)
this.WriteBirthday();
this.WriteConfig();
this.CheckedForBirthday = false; this.CheckedForBirthday = false;
} }
@ -92,8 +85,8 @@ namespace Omegasis.HappyBirthday
private void ControlEvents_KeyPressed(object sender, EventArgsKeyPressed e) private void ControlEvents_KeyPressed(object sender, EventArgsKeyPressed e)
{ {
// show birthday selection menu // show birthday selection menu
if (Context.IsPlayerFree && !this.HasChosenBirthday && e.KeyPressed.ToString() == this.KeyBinding) if (Context.IsPlayerFree && !this.HasChosenBirthday && e.KeyPressed.ToString() == this.Config.KeyBinding)
Game1.activeClickableMenu = new BirthdayMenu(this.BirthdaySeason, this.BirthdayDay, this.SetBirthday); Game1.activeClickableMenu = new BirthdayMenu(this.PlayerData.BirthdaySeason, this.PlayerData.BirthdayDay, this.SetBirthday);
} }
/// <summary>The method invoked after the player loads a save.</summary> /// <summary>The method invoked after the player loads a save.</summary>
@ -101,12 +94,21 @@ namespace Omegasis.HappyBirthday
/// <param name="e">The event data.</param> /// <param name="e">The event data.</param>
private void SaveEvents_AfterLoad(object sender, EventArgs e) private void SaveEvents_AfterLoad(object sender, EventArgs e)
{ {
this.LoadBirthday(); this.MigrateLegacyData();
this.LoadConfig(); this.PlayerData = this.Helper.ReadJsonFile<PlayerData>(this.DataFilePath) ?? new PlayerData();
//this.SeenEvent = false; //this.SeenEvent = false;
//this.Dialogue = new Dictionary<string, Dialogue>(); //this.Dialogue = new Dictionary<string, Dialogue>();
} }
/// <summary>The method invoked just before the game updates the saves.</summary>
/// <param name="sender">The event sender.</param>
/// <param name="e">The event data.</param>
private void SaveEvents_BeforeSave(object sender, EventArgs e)
{
if (this.HasChosenBirthday)
this.Helper.WriteJsonFile(this.DataFilePath, this.PlayerData);
}
/// <summary>The method invoked when the game updates (roughly 60 times per second).</summary> /// <summary>The method invoked when the game updates (roughly 60 times per second).</summary>
/// <param name="sender">The event sender.</param> /// <param name="sender">The event sender.</param>
/// <param name="e">The event data.</param> /// <param name="e">The event data.</param>
@ -159,9 +161,9 @@ namespace Omegasis.HappyBirthday
} }
// ask for birthday date // ask for birthday date
if (string.IsNullOrEmpty(this.BirthdaySeason) || this.BirthdayDay == 0) if (!this.HasChosenBirthday)
{ {
Game1.activeClickableMenu = new BirthdayMenu(this.BirthdaySeason, this.BirthdayDay, this.SetBirthday); Game1.activeClickableMenu = new BirthdayMenu(this.PlayerData.BirthdaySeason, this.PlayerData.BirthdayDay, this.SetBirthday);
this.CheckedForBirthday = false; this.CheckedForBirthday = false;
} }
} }
@ -223,14 +225,6 @@ namespace Omegasis.HappyBirthday
Game1.player.addItemByMenuIfNecessaryElseHoldUp(this.BirthdayGiftToReceive); Game1.player.addItemByMenuIfNecessaryElseHoldUp(this.BirthdayGiftToReceive);
this.BirthdayGiftToReceive = null; this.BirthdayGiftToReceive = null;
} }
// update settings
if (!this.HasChosenBirthday && !string.IsNullOrEmpty(this.BirthdaySeason) && this.BirthdayDay != 0)
{
this.WriteConfig();
this.WriteBirthday();
this.HasChosenBirthday = true;
}
} }
/// <summary>Set the player's birtday/</summary> /// <summary>Set the player's birtday/</summary>
@ -238,8 +232,8 @@ namespace Omegasis.HappyBirthday
/// <param name="day">The birthday day.</param> /// <param name="day">The birthday day.</param>
private void SetBirthday(string season, int day) private void SetBirthday(string season, int day)
{ {
this.BirthdaySeason = season; this.PlayerData.BirthdaySeason = season;
this.BirthdayDay = day; this.PlayerData.BirthdayDay = day;
} }
/// <summary>Reset the queue of villager names.</summary> /// <summary>Reset the queue of villager names.</summary>
@ -495,63 +489,36 @@ namespace Omegasis.HappyBirthday
private bool IsBirthday() private bool IsBirthday()
{ {
return return
this.BirthdayDay == Game1.dayOfMonth this.PlayerData.BirthdayDay == Game1.dayOfMonth
&& this.BirthdaySeason == Game1.currentSeason; && this.PlayerData.BirthdaySeason == Game1.currentSeason;
} }
/// <summary>Load the configuration settings.</summary> /// <summary>Migrate the legacy settings for the current player.</summary>
private void LoadConfig() private void MigrateLegacyData()
{ {
string path = Path.Combine(Helper.DirectoryPath, "HappyBirthday_Config.txt"); // skip if no legacy data or new data already exists
if (!File.Exists(path)) if (!File.Exists(this.LegacyDataFilePath) || File.Exists(this.DataFilePath))
this.KeyBinding = "O"; return;
else
// migrate to new file
try
{ {
string[] text = File.ReadAllLines(path); string[] text = File.ReadAllLines(this.LegacyDataFilePath);
this.KeyBinding = Convert.ToString(text[3]); this.Helper.WriteJsonFile(this.DataFilePath, new PlayerData
{
BirthdaySeason = text[3],
BirthdayDay = Convert.ToInt32(text[5])
});
FileInfo file = new FileInfo(this.LegacyDataFilePath);
file.Delete();
if (!file.Directory.EnumerateFiles().Any())
file.Directory.Delete();
} }
} catch (Exception ex)
/// <summary>Save the configuration settings.</summary>
private void WriteConfig()
{
string path = Path.Combine(Helper.DirectoryPath, "HappyBirthday_Config.txt");
string[] text = new string[20];
text[0] = "Config: HappyBirthday Info. Feel free to mess with these settings.";
text[1] = "====================================================================================";
text[2] = "Key binding for opening the birthday menu. Press this key to do so.";
text[3] = this.KeyBinding;
File.WriteAllLines(path, text);
}
/// <summary>Load the player's birthday from the config file.</summary>
private void LoadBirthday()
{
string path = Path.Combine(this.BirthdayFolderPath, $"HappyBirthday_{Game1.player.name}.txt");
if (File.Exists(path))
{ {
string[] text = File.ReadAllLines(path); this.Monitor.Log($"Error migrating data from the legacy 'Player_Birthdays' folder for the current player. Technical details:\n {ex}", LogLevel.Error);
this.BirthdaySeason = Convert.ToString(text[3]);
this.BirthdayDay = Convert.ToInt32(text[5]);
} }
} }
/// <summary>Write the player's birthday to the config file.</summary>
private void WriteBirthday()
{
string path = Path.Combine(this.BirthdayFolderPath, $"HappyBirthday_{Game1.player.name}.txt");
string[] text = new string[20];
text[0] = "Player Info: Modifying these values could be considered cheating or an exploit. Edit at your own risk.";
text[1] = "====================================================================================";
text[2] = "Player's Birthday Season";
text[3] = this.BirthdaySeason;
text[4] = "Player's Birthday Date";
text[5] = this.BirthdayDay.ToString();
File.WriteAllLines(path, text);
}
} }
} }

View File

@ -40,6 +40,8 @@
<Link>Properties\GlobalAssemblyInfo.cs</Link> <Link>Properties\GlobalAssemblyInfo.cs</Link>
</Compile> </Compile>
<Compile Include="Framework\BirthdayMenu.cs" /> <Compile Include="Framework\BirthdayMenu.cs" />
<Compile Include="Framework\ModConfig.cs" />
<Compile Include="Framework\PlayerData.cs" />
<Compile Include="HappyBirthday.cs" /> <Compile Include="HappyBirthday.cs" />
<Compile Include="Framework\Messages.cs" /> <Compile Include="Framework\Messages.cs" />
<Compile Include="Framework\ObjectUtility.cs" /> <Compile Include="Framework\ObjectUtility.cs" />

View File

@ -54,4 +54,6 @@ change based on your friendship with them. Check your mailbox for letters from y
1.4: 1.4:
* Updated for SMAPI 2.0. * Updated for SMAPI 2.0.
* Switched to standard JSON config & data files.
* Fixed issue where saves with the same name would overwrite each other's birthdays.
* Internal refactoring. * Internal refactoring.

View File

@ -0,0 +1,30 @@
namespace Omegasis.MoreRain.Framework
{
/// <summary>The mod configuration.</summary>
internal class ModConfig
{
/// <summary>The chance out of 100 that it will rain tomorrow if it's spring.</summary>
public int SpringRainChance { get; set; } = 15;
/// <summary>The chance out of 100 that it will storm tomorrow if it's spring.</summary>
public int SpringThunderChance { get; set; } = 5;
/// <summary>The chance out of 100 that it will rain tomorrow if it's summer.</summary>
public int SummerRainChance { get; set; } = 5;
/// <summary>The chance out of 100 that it will storm tomorrow if it's summer.</summary>
public int SummerThunderChance { get; set; } = 10;
/// <summary>The chance out of 100 that it will rain tomorrow if it's fall.</summary>
public int FallRainChance { get; set; } = 15;
/// <summary>The chance out of 100 that it will storm tomorrow if it's fall.</summary>
public int FallThunderChance { get; set; } = 5;
/// <summary>The chance out of 100 that it will snow tomorrow if it's winter.</summary>
public int WinterSnowChance { get; set; } = 15;
/// <summary>Whether to suppress verbose logging.</summary>
public bool SuppressLog { get; set; } = true;
}
}

View File

@ -1,6 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using Omegasis.MoreRain.Framework;
using StardewModdingAPI; using StardewModdingAPI;
using StardewModdingAPI.Events; using StardewModdingAPI.Events;
using StardewValley; using StardewValley;
@ -16,29 +16,8 @@ namespace Omegasis.MoreRain
/// <summary>The weathers that can be safely overridden.</summary> /// <summary>The weathers that can be safely overridden.</summary>
private readonly HashSet<int> NormalWeathers = new HashSet<int> { Game1.weather_sunny, Game1.weather_rain, Game1.weather_lightning, Game1.weather_debris, Game1.weather_snow }; private readonly HashSet<int> NormalWeathers = new HashSet<int> { Game1.weather_sunny, Game1.weather_rain, Game1.weather_lightning, Game1.weather_debris, Game1.weather_snow };
/// <summary>The chance out of 100 that it will rain tomorrow if it's spring.</summary> /// <summary>The mod configuration.</summary>
private int SpringRainChance; private ModConfig Config;
/// <summary>The chance out of 100 that it will storm tomorrow if it's spring.</summary>
private int SpringThunderChance;
/// <summary>The chance out of 100 that it will rain tomorrow if it's summer.</summary>
private int SummerRainChance;
/// <summary>The chance out of 100 that it will storm tomorrow if it's summer.</summary>
private int SummerThunderChance;
/// <summary>The chance out of 100 that it will rain tomorrow if it's fall.</summary>
private int FallRainChance;
/// <summary>The chance out of 100 that it will storm tomorrow if it's fall.</summary>
private int FallThunderChance;
/// <summary>The chance out of 100 that it will snow tomorrow if it's winter.</summary>
private int WinterSnowChance;
/// <summary>Whether to suppress verbose logging.</summary>
private bool SuppressLog;
/********* /*********
@ -48,9 +27,10 @@ namespace Omegasis.MoreRain
/// <param name="helper">Provides simplified APIs for writing mods.</param> /// <param name="helper">Provides simplified APIs for writing mods.</param>
public override void Entry(IModHelper helper) public override void Entry(IModHelper helper)
{ {
this.Config = helper.ReadConfig<ModConfig>();
SaveEvents.AfterLoad += this.SaveEvents_AfterLoad; SaveEvents.AfterLoad += this.SaveEvents_AfterLoad;
SaveEvents.BeforeSave += this.SaveEvents_BeforeSave; SaveEvents.BeforeSave += this.SaveEvents_BeforeSave;
this.LoadConfig();
} }
@ -95,7 +75,7 @@ namespace Omegasis.MoreRain
{ {
case "spring": case "spring":
// set rain // set rain
if (chance <= this.SpringRainChance) if (chance <= this.Config.SpringRainChance)
{ {
Game1.weatherForTomorrow = Game1.weather_rain; Game1.weatherForTomorrow = Game1.weather_rain;
this.VerboseLog("It will rain tomorrow."); this.VerboseLog("It will rain tomorrow.");
@ -109,7 +89,7 @@ namespace Omegasis.MoreRain
// set storm // set storm
if (Game1.weatherForTomorrow == Game1.weather_rain) if (Game1.weatherForTomorrow == Game1.weather_rain)
{ {
if (chance <= this.SpringThunderChance) if (chance <= this.Config.SpringThunderChance)
{ {
Game1.weatherForTomorrow = Game1.weather_lightning; Game1.weatherForTomorrow = Game1.weather_lightning;
this.VerboseLog("It will be stormy tomorrow."); this.VerboseLog("It will be stormy tomorrow.");
@ -124,7 +104,7 @@ namespace Omegasis.MoreRain
case "summer": case "summer":
// set rain // set rain
if (chance <= this.SummerRainChance) if (chance <= this.Config.SummerRainChance)
{ {
Game1.weatherForTomorrow = Game1.weather_rain; Game1.weatherForTomorrow = Game1.weather_rain;
this.VerboseLog("It will rain tomorrow."); this.VerboseLog("It will rain tomorrow.");
@ -138,7 +118,7 @@ namespace Omegasis.MoreRain
// set storm // set storm
if (Game1.weatherForTomorrow == Game1.weather_rain) if (Game1.weatherForTomorrow == Game1.weather_rain)
{ {
if (chance <= this.SummerThunderChance) if (chance <= this.Config.SummerThunderChance)
{ {
Game1.weatherForTomorrow = Game1.weather_lightning; Game1.weatherForTomorrow = Game1.weather_lightning;
this.VerboseLog("It will be stormy tomorrow."); this.VerboseLog("It will be stormy tomorrow.");
@ -154,7 +134,7 @@ namespace Omegasis.MoreRain
case "fall": case "fall":
case "autumn": case "autumn":
// set rain // set rain
if (chance <= this.FallRainChance) if (chance <= this.Config.FallRainChance)
{ {
Game1.weatherForTomorrow = Game1.weather_rain; Game1.weatherForTomorrow = Game1.weather_rain;
this.VerboseLog("It will rain tomorrow."); this.VerboseLog("It will rain tomorrow.");
@ -168,7 +148,7 @@ namespace Omegasis.MoreRain
// set storm // set storm
if (Game1.weatherForTomorrow == Game1.weather_rain) if (Game1.weatherForTomorrow == Game1.weather_rain)
{ {
if (chance <= this.FallThunderChance) if (chance <= this.Config.FallThunderChance)
{ {
Game1.weatherForTomorrow = Game1.weather_lightning; Game1.weatherForTomorrow = Game1.weather_lightning;
this.VerboseLog("It will be stormy tomorrow."); this.VerboseLog("It will be stormy tomorrow.");
@ -183,7 +163,7 @@ namespace Omegasis.MoreRain
case "winter": case "winter":
// set snow // set snow
if (chance <= this.WinterSnowChance) if (chance <= this.Config.WinterSnowChance)
{ {
Game1.weatherForTomorrow = Game1.weather_snow; Game1.weatherForTomorrow = Game1.weather_snow;
this.VerboseLog("It will snow tomorrow."); this.VerboseLog("It will snow tomorrow.");
@ -197,91 +177,11 @@ namespace Omegasis.MoreRain
} }
} }
/// <summary>Save the configuration settings.</summary>
private void SaveConfig()
{
string path = Path.Combine(Helper.DirectoryPath, "More_Rain_Config.txt");
string[] text = new string[20];
text[0] = "Player: More Rain Config. Feel free to edit.";
text[1] = "====================================================================================";
text[2] = "Spring Rain chance: The chance out of 100 that it will rain tomorrow.";
text[3] = this.SpringRainChance.ToString();
text[4] = "Spring Storm chance: The chance out of 100 that it will be stormy tomorrow.";
text[5] = this.SpringThunderChance.ToString();
text[6] = "Summer Rain chance: The chance out of 100 that it will rain tomorrow.";
text[7] = this.SummerRainChance.ToString();
text[8] = "Summer Storm chance: The chance out of 100 that it will be stormy tomorrow.";
text[9] = this.SummerThunderChance.ToString();
text[10] = "Fall Rain chance: The chance out of 100 that it will rain tomorrow.";
text[11] = this.FallRainChance.ToString();
text[12] = "Fall Storm chance: The chance out of 100 that it will be stormy tomorrow.";
text[13] = this.FallThunderChance.ToString();
text[14] = "Winter Snow chance: The chance out of 100 that it will rain tomorrow.";
text[15] = this.WinterSnowChance.ToString();
text[16] = "Supress Log: If true, the mod won't output any messages to the console.";
text[17] = this.SuppressLog.ToString();
File.WriteAllLines(path, text);
}
/// <summary>Load the configuration settings.</summary>
private void LoadConfig()
{
string path = Path.Combine(Helper.DirectoryPath, $"More_Rain_Config.txt");
if (!File.Exists(path))
{
this.SpringRainChance = 15;
this.SummerRainChance = 5;
this.FallRainChance = 15;
this.WinterSnowChance = 15;
this.SpringThunderChance = 5;
this.SummerThunderChance = 10;
this.FallThunderChance = 5;
this.SuppressLog = true;
this.SaveConfig();
}
else
{
try
{
string[] text = File.ReadAllLines(path);
this.SpringRainChance = Convert.ToInt32(text[3]);
this.SpringThunderChance = Convert.ToInt32(text[5]);
this.SummerRainChance = Convert.ToInt32(text[7]);
this.SummerThunderChance = Convert.ToInt32(text[9]);
this.FallRainChance = Convert.ToInt32(text[11]);
this.FallThunderChance = Convert.ToInt32(text[13]);
this.WinterSnowChance = Convert.ToInt32(text[15]);
this.SuppressLog = Convert.ToBoolean(text[17]);
}
catch (Exception) //something dun goofed
{
this.SpringRainChance = 15;
this.SummerRainChance = 5;
this.FallRainChance = 15;
this.WinterSnowChance = 15;
this.SpringThunderChance = 5;
this.SummerThunderChance = 10;
this.FallThunderChance = 5;
this.SuppressLog = true;
this.SaveConfig();
}
}
}
/// <summary>Log a message if <see cref="SuppressLog"/> is <c>false</c>.</summary> /// <summary>Log a message if <see cref="SuppressLog"/> is <c>false</c>.</summary>
/// <param name="message">The message to log.</param> /// <param name="message">The message to log.</param>
private void VerboseLog(string message) private void VerboseLog(string message)
{ {
if (!this.SuppressLog) if (!this.Config.SuppressLog)
this.Monitor.Log(message); this.Monitor.Log(message);
} }
} }

View File

@ -37,6 +37,7 @@
<Compile Include="..\GlobalAssemblyInfo.cs"> <Compile Include="..\GlobalAssemblyInfo.cs">
<Link>Properties\GlobalAssemblyInfo.cs</Link> <Link>Properties\GlobalAssemblyInfo.cs</Link>
</Compile> </Compile>
<Compile Include="Framework\ModConfig.cs" />
<Compile Include="MoreRain.cs" /> <Compile Include="MoreRain.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup> </ItemGroup>

View File

@ -9,8 +9,8 @@ Compatible with Stardew Valley 1.2+ on Linux, Mac, and Windows.
3. Run the game using SMAPI. 3. Run the game using SMAPI.
## Usage ## Usage
Edit `More_Rain_Config.txt` to change the chance of rain, storms, or snow. Each value is a Edit `config.json` to change the chance of rain, storms, or snow. Each value is a percentage (0
percentage (0 to 100). to 100).
It won't rain on days where a wedding or a festival would take place. It won't rain on days where a wedding or a festival would take place.
@ -29,4 +29,5 @@ It won't rain on days where a wedding or a festival would take place.
1.4: 1.4:
* Updated for SMAPI 2.0. * Updated for SMAPI 2.0.
* Switched to standard JSON config file.
* Internal refactoring. * Internal refactoring.

View File

@ -0,0 +1,12 @@
namespace Omegasis.MuseumRearranger.Framework
{
/// <summary>The mod configuration.</summary>
internal class ModConfig
{
/// <summary>The key which shows the museum rearranging menu.</summary>
public string ShowMenuKey { get; set; } = "R";
/// <summary>The key which toggles the inventory box when the menu is open.</summary>
public string ToggleInventoryKey { get; set; } = "T";
}
}

View File

@ -1,6 +1,4 @@
using System; using Omegasis.MuseumRearranger.Framework;
using System.IO;
using Omegasis.MuseumRearranger.Framework;
using StardewModdingAPI; using StardewModdingAPI;
using StardewModdingAPI.Events; using StardewModdingAPI.Events;
using StardewValley; using StardewValley;
@ -14,11 +12,8 @@ namespace Omegasis.MuseumRearranger
/********* /*********
** Properties ** Properties
*********/ *********/
/// <summary>The key which shows the museum rearranging menu.</summary> /// <summary>The mod configuration.</summary>
private string ShowMenuKey = "R"; private ModConfig Config;
/// <summary>The key which toggles the inventory box when the menu is open.</summary>
private string ToggleInventoryKey = "T";
/// <summary>The open museum menu (if any).</summary> /// <summary>The open museum menu (if any).</summary>
private NewMuseumMenu OpenMenu; private NewMuseumMenu OpenMenu;
@ -31,7 +26,8 @@ namespace Omegasis.MuseumRearranger
/// <param name="helper">Provides simplified APIs for writing mods.</param> /// <param name="helper">Provides simplified APIs for writing mods.</param>
public override void Entry(IModHelper helper) public override void Entry(IModHelper helper)
{ {
SaveEvents.AfterLoad += this.SaveEvents_AfterLoad; this.Config = helper.ReadConfig<ModConfig>();
ControlEvents.KeyPressed += this.ControlEvents_KeyPressed; ControlEvents.KeyPressed += this.ControlEvents_KeyPressed;
} }
@ -48,7 +44,7 @@ namespace Omegasis.MuseumRearranger
return; return;
// open menu // open menu
if (e.KeyPressed.ToString() == this.ShowMenuKey) if (e.KeyPressed.ToString() == this.Config.ShowMenuKey)
{ {
if (Game1.activeClickableMenu != null) if (Game1.activeClickableMenu != null)
return; return;
@ -59,48 +55,8 @@ namespace Omegasis.MuseumRearranger
} }
// toggle inventory box // toggle inventory box
if (e.KeyPressed.ToString() == this.ToggleInventoryKey) if (e.KeyPressed.ToString() == this.Config.ToggleInventoryKey)
this.OpenMenu?.ToggleInventory(); this.OpenMenu?.ToggleInventory();
} }
/// <summary>The method invoked after the player loads a save.</summary>
/// <param name="sender">The event sender.</param>
/// <param name="e">The event data.</param>
private void SaveEvents_AfterLoad(object sender, EventArgs e)
{
this.LoadConfig();
this.WriteConfig();
}
/// <summary>Load the configuration settings.</summary>
private void LoadConfig()
{
string path = Path.Combine(Helper.DirectoryPath, "Museum_Rearrange_Config.txt");
if (!File.Exists(path))
{
this.ShowMenuKey = "R";
this.ToggleInventoryKey = "T";
}
else
{
string[] text = File.ReadAllLines(path);
this.ShowMenuKey = Convert.ToString(text[3]);
this.ToggleInventoryKey = Convert.ToString(text[5]);
}
}
/// <summary>Save the configuration settings.</summary>
private void WriteConfig()
{
string path = Path.Combine(Helper.DirectoryPath, "Museum_Rearrange_Config.txt");
string[] text = new string[20];
text[0] = "Config: Museum_Rearranger. Feel free to mess with these settings.";
text[1] = "====================================================================================";
text[2] = "Key binding for rearranging the museum.";
text[3] = this.ShowMenuKey;
text[4] = "Key binding for showing the menu when rearranging the museum.";
text[5] = this.ToggleInventoryKey;
File.WriteAllLines(path, text);
}
} }
} }

View File

@ -39,6 +39,7 @@
<Compile Include="..\GlobalAssemblyInfo.cs"> <Compile Include="..\GlobalAssemblyInfo.cs">
<Link>Properties\GlobalAssemblyInfo.cs</Link> <Link>Properties\GlobalAssemblyInfo.cs</Link>
</Compile> </Compile>
<Compile Include="Framework\ModConfig.cs" />
<Compile Include="MuseumRearranger.cs" /> <Compile Include="MuseumRearranger.cs" />
<Compile Include="Framework\NewMuseumMenu.cs" /> <Compile Include="Framework\NewMuseumMenu.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />

View File

@ -10,7 +10,7 @@ Compatible with Stardew Valley 1.2+ on Linux, Mac, and Windows.
## Usage ## Usage
Press `R` while in the museum to open the rearranging menu. Press `T` while the menu is open to Press `R` while in the museum to open the rearranging menu. Press `T` while the menu is open to
toggle the inventory box. Edit `Museum_Rearrange_Config.txt` to change the keys. toggle the inventory box. Edit `config.json` to change the keys.
## Versions ## Versions
1.0: 1.0:
@ -28,4 +28,5 @@ toggle the inventory box. Edit `Museum_Rearrange_Config.txt` to change the keys.
* Updated to Stardew Valley 1.2 and SMAPI 1.12. * Updated to Stardew Valley 1.2 and SMAPI 1.12.
1.4: 1.4:
* Switched to standard JSON config file.
* Internal refactoring. * Internal refactoring.

View File

@ -0,0 +1,27 @@
namespace Omegasis.NightOwl.Framework
{
/// <summary>The mod configuration.</summary>
internal class ModConfig
{
/// <summary>Whether lighting should transition to day from 2am to 6am. If <c>false</c>, the world will stay dark until the player passes out or goes to bed.</summary>
public bool MorningLightTransition { get; set; } = true;
/// <summary>Whether the player can stay up until 6am.</summary>
public bool StayUp { get; set; } = true;
/// <summary>Whether to remove the mail received for collapsing like 'we charged X gold for your health fees'.</summary>
public bool SkipCollapseMail { get; set; } = true;
/// <summary>Whether to restore the player's position after they collapse.</summary>
public bool KeepPositionAfterCollapse { get; set; } = true;
/// <summary>Whether to restore the player's money after they collapse (i.e. prevent the automatic deduction).</summary>
public bool KeepMoneyAfterCollapse { get; set; } = true;
/// <summary>Whether to keep stamina as-is after the player collapses.</summary>
public bool KeepHealthAfterCollapse { get; set; } = true;
/// <summary>Whether to keep stamina as-is after the player collapses.</summary>
public bool KeepStaminaAfterCollapse { get; set; } = true;
}
}

View File

@ -2,7 +2,7 @@
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework;
using Newtonsoft.Json; using Omegasis.NightOwl.Framework;
using StardewModdingAPI; using StardewModdingAPI;
using StardewModdingAPI.Events; using StardewModdingAPI.Events;
using StardewValley; using StardewValley;
@ -24,6 +24,9 @@ namespace Omegasis.NightOwl
/********* /*********
** Properties ** Properties
*********/ *********/
/// <summary>The mod configuration.</summary>
private ModConfig Config;
/**** /****
** Context ** Context
****/ ****/
@ -57,29 +60,6 @@ namespace Omegasis.NightOwl
/// <summary>The player's health before they collapsed.</summary> /// <summary>The player's health before they collapsed.</summary>
private int PreCollapseHealth; private int PreCollapseHealth;
/****
** Settings
****/
/// <summary>Whether lighting should transition to day from 2am to 6am. If <c>false</c>, the world will stay dark until the player passes out or goes to bed.</summary>
private bool MorningLightTransition;
/// <summary>Whether the player can stay up until 6am.</summary>
private bool StayUp;
/// <summary>Whether to remove the mail received for collapsing like 'we charged X gold for your health fees'.</summary>
private bool SkipCollapseMail;
/// <summary>Whether to restore the player's position after they collapse.</summary>
private bool KeepPositionAfterCollapse;
/// <summary>Whether to restore the player's money after they collapse (i.e. prevent the automatic deduction).</summary>
private bool KeepMoneyAfterCollapse;
/// <summary>Whether to keep stamina as-is after the player collapses.</summary>
private bool KeepHealthAfterCollapse;
/// <summary>Whether to keep stamina as-is after the player collapses.</summary>
private bool KeepStaminaAfterCollapse;
/********* /*********
@ -89,6 +69,8 @@ namespace Omegasis.NightOwl
/// <param name="helper">Provides simplified APIs for writing mods.</param> /// <param name="helper">Provides simplified APIs for writing mods.</param>
public override void Entry(IModHelper helper) public override void Entry(IModHelper helper)
{ {
this.Config = helper.ReadConfig<ModConfig>();
TimeEvents.TimeOfDayChanged += this.TimeEvents_TimeOfDayChanged; TimeEvents.TimeOfDayChanged += this.TimeEvents_TimeOfDayChanged;
TimeEvents.AfterDayStarted += this.TimeEvents_AfterDayStarted; TimeEvents.AfterDayStarted += this.TimeEvents_AfterDayStarted;
SaveEvents.AfterLoad += this.SaveEvents_AfterLoad; SaveEvents.AfterLoad += this.SaveEvents_AfterLoad;
@ -107,7 +89,7 @@ namespace Omegasis.NightOwl
try try
{ {
// reset position after collapse // reset position after collapse
if (Context.IsWorldReady && this.JustStartedNewDay && this.KeepPositionAfterCollapse) if (Context.IsWorldReady && this.JustStartedNewDay && this.Config.KeepPositionAfterCollapse)
{ {
if (this.PreCollapseMap != null) if (this.PreCollapseMap != null)
Game1.warpFarmer(this.PreCollapseMap, this.PreCollapseTile.X, this.PreCollapseTile.Y, false); Game1.warpFarmer(this.PreCollapseMap, this.PreCollapseTile.X, this.PreCollapseTile.Y, false);
@ -129,8 +111,6 @@ namespace Omegasis.NightOwl
/// <param name="e">The event data.</param> /// <param name="e">The event data.</param>
public void SaveEvents_AfterLoad(object sender, EventArgs e) public void SaveEvents_AfterLoad(object sender, EventArgs e)
{ {
this.LoadConfig();
this.WriteConfig();
this.IsUpLate = false; this.IsUpLate = false;
this.JustStartedNewDay = false; this.JustStartedNewDay = false;
this.JustCollapsed = false; this.JustCollapsed = false;
@ -144,8 +124,6 @@ namespace Omegasis.NightOwl
try try
{ {
// reset data // reset data
this.LoadConfig();
this.WriteConfig();
this.IsUpLate = false; this.IsUpLate = false;
Game1.farmerShouldPassOut = false; Game1.farmerShouldPassOut = false;
@ -154,18 +132,18 @@ namespace Omegasis.NightOwl
{ {
this.ShouldResetPlayerAfterCollapseNow = false; this.ShouldResetPlayerAfterCollapseNow = false;
if (this.KeepStaminaAfterCollapse) if (this.Config.KeepStaminaAfterCollapse)
Game1.player.stamina = this.PreCollapseStamina; Game1.player.stamina = this.PreCollapseStamina;
if (this.KeepHealthAfterCollapse) if (this.Config.KeepHealthAfterCollapse)
Game1.player.health = this.PreCollapseHealth; Game1.player.health = this.PreCollapseHealth;
if (this.KeepMoneyAfterCollapse) if (this.Config.KeepMoneyAfterCollapse)
Game1.player.money = this.PreCollapseMoney; Game1.player.money = this.PreCollapseMoney;
if (this.KeepPositionAfterCollapse) if (this.Config.KeepPositionAfterCollapse)
Game1.warpFarmer(this.PreCollapseMap, this.PreCollapseTile.X, this.PreCollapseTile.Y, false); Game1.warpFarmer(this.PreCollapseMap, this.PreCollapseTile.X, this.PreCollapseTile.Y, false);
} }
// delete annoying charge messages (if only I could do this with mail IRL) // delete annoying charge messages (if only I could do this with mail IRL)
if (this.SkipCollapseMail) if (this.Config.SkipCollapseMail)
{ {
string[] validMail = Game1.mailbox string[] validMail = Game1.mailbox
.Where(p => !p.Contains("passedOut")) .Where(p => !p.Contains("passedOut"))
@ -196,14 +174,14 @@ namespace Omegasis.NightOwl
try try
{ {
// transition morning light more realistically // transition morning light more realistically
if (this.MorningLightTransition && Game1.timeOfDay > 400 && Game1.timeOfDay < 600) if (this.Config.MorningLightTransition && Game1.timeOfDay > 400 && Game1.timeOfDay < 600)
{ {
float colorMod = (1300 - Game1.timeOfDay) / 1000f; float colorMod = (1300 - Game1.timeOfDay) / 1000f;
Game1.outdoorLight = Game1.ambientLight * colorMod; Game1.outdoorLight = Game1.ambientLight * colorMod;
} }
// transition to next morning // transition to next morning
if (this.StayUp && Game1.timeOfDay == 2550) if (this.Config.StayUp && Game1.timeOfDay == 2550)
{ {
Game1.isRaining = false; // remove rain, otherwise lighting gets screwy Game1.isRaining = false; // remove rain, otherwise lighting gets screwy
Game1.updateWeatherIcon(); Game1.updateWeatherIcon();
@ -236,83 +214,24 @@ namespace Omegasis.NightOwl
} }
} }
/// <summary>Save the configuration settings.</summary>
private void WriteConfig()
{
string path = Path.Combine(Helper.DirectoryPath, "Night_Owl_Config_.txt");
string[] text = new string[20];
text[0] = "Player: Night Owl Config. Feel free to edit.";
text[1] = "====================================================================================";
text[2] = "Whether you can stay up until 6am.";
text[3] = this.StayUp.ToString();
text[4] = "Whether the lighting should transition to daytime from 2am to 6am. Setting this to false will keep the world dark until the player passes out or goes to bed.";
text[5] = this.MorningLightTransition.ToString();
text[6] = "Whether to keep your position as-is after you collapse at 6am. If false, you'll warp back home.";
text[7] = this.KeepPositionAfterCollapse.ToString();
text[8] = "Whether to prevent money from being deducted after you collapse at 6am.";
text[9] = this.KeepMoneyAfterCollapse.ToString();
text[10] = "Whether to keep your stamina as-is after you collapse at 6am.";
text[11] = this.KeepStaminaAfterCollapse.ToString();
text[12] = "Whether to keep your health as-is after you collapse at 6am.";
text[13] = this.KeepHealthAfterCollapse.ToString();
text[14] = "Whether to remove the mail you receive for collapsing like 'we charged X gold for your health fees'.";
text[15] = this.SkipCollapseMail.ToString();
File.WriteAllLines(path, text);
}
/// <summary>Load the configuration settings.</summary>
private void LoadConfig()
{
string path = Path.Combine(Helper.DirectoryPath, "Night_Owl_Config_.txt");
if (!File.Exists(path))
{
this.MorningLightTransition = true;
this.KeepPositionAfterCollapse = true;
this.StayUp = true;
this.KeepHealthAfterCollapse = true;
this.KeepStaminaAfterCollapse = true;
this.SkipCollapseMail = true;
this.KeepMoneyAfterCollapse = true;
}
else
{
string[] text = File.ReadAllLines(path);
this.StayUp = Convert.ToBoolean(text[3]);
this.MorningLightTransition = Convert.ToBoolean(text[5]);
this.KeepPositionAfterCollapse = Convert.ToBoolean(text[7]);
this.KeepMoneyAfterCollapse = Convert.ToBoolean(text[9]);
this.KeepStaminaAfterCollapse = Convert.ToBoolean(text[11]);
this.KeepHealthAfterCollapse = Convert.ToBoolean(text[13]);
this.SkipCollapseMail = text[15] == "" || Convert.ToBoolean(text[15]);
}
}
/// <summary>Write the current mod state to the error log file.</summary> /// <summary>Write the current mod state to the error log file.</summary>
private void WriteErrorLog() private void WriteErrorLog()
{ {
try var state = new
{ {
JsonSerializer serializer = new JsonSerializer this.Config,
{ this.IsUpLate,
NullValueHandling = NullValueHandling.Ignore, this.ShouldResetPlayerAfterCollapseNow,
TypeNameHandling = TypeNameHandling.All, this.JustStartedNewDay,
Formatting = Formatting.Indented, this.JustCollapsed,
ReferenceLoopHandling = ReferenceLoopHandling.Ignore this.PreCollapseMap,
}; this.PreCollapseTile,
string path = Path.Combine(this.Helper.DirectoryPath, "Error_Logs", "Mod_State.json"); this.PreCollapseMoney,
using (StreamWriter sw = new StreamWriter(path)) this.PreCollapseStamina,
{ this.PreCollapseHealth
using (JsonWriter writer2 = new JsonTextWriter(sw)) };
serializer.Serialize(writer2, this); string path = Path.Combine(this.Helper.DirectoryPath, "Error_Logs", "Mod_State.json");
} this.Helper.WriteJsonFile(path, state);
}
catch (Exception ex)
{
this.Monitor.Log(ex.ToString(), LogLevel.Error);
}
} }
} }
} }

View File

@ -30,10 +30,6 @@
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
</ItemGroup> </ItemGroup>
@ -41,6 +37,7 @@
<Compile Include="..\GlobalAssemblyInfo.cs"> <Compile Include="..\GlobalAssemblyInfo.cs">
<Link>Properties\GlobalAssemblyInfo.cs</Link> <Link>Properties\GlobalAssemblyInfo.cs</Link>
</Compile> </Compile>
<Compile Include="Framework\ModConfig.cs" />
<Compile Include="NightOwl.cs" /> <Compile Include="NightOwl.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup> </ItemGroup>

View File

@ -14,7 +14,7 @@ Simply stay up past 2am, and you won't collapse. The lighting will gradually bri
rises. At 6am you'll temporarily collapse so the game can save, but you won't lose anything and rises. At 6am you'll temporarily collapse so the game can save, but you won't lose anything and
you'll stay where you are. you'll stay where you are.
Edit the `Night_Owl_Config_.txt` to change the mod settings. Edit the `config.json` to change the mod settings.
## Versions ## Versions
1.0: 1.0:
@ -25,4 +25,5 @@ Edit the `Night_Owl_Config_.txt` to change the mod settings.
1.4: 1.4:
* Updated for SMAPI 2.0. * Updated for SMAPI 2.0.
* Switched to standard JSON config file.
* Internal refactoring. * Internal refactoring.

View File

@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="Newtonsoft.Json" version="10.0.3" targetFramework="net45" />
<package id="Pathoschild.Stardew.ModBuildConfig" version="1.7.0" targetFramework="net45" /> <package id="Pathoschild.Stardew.ModBuildConfig" version="1.7.0" targetFramework="net45" />
</packages> </packages>

View File

@ -1,7 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection;
using Omegasis.SaveAnywhere.Framework; using Omegasis.SaveAnywhere.Framework;
using StardewModdingAPI; using StardewModdingAPI;
using StardewModdingAPI.Events; using StardewModdingAPI.Events;

View File

@ -0,0 +1,9 @@
namespace Omegasis.SaveBackup.Framework
{
/// <summary>The mod configuration.</summary>
internal class ModConfig
{
/// <summary>The number of save backups to keep for each type.</summary>
public int SaveCount { get; set; } = 30;
}
}

View File

@ -24,4 +24,5 @@ configure that.
1.3: 1.3:
* Updated for SMAPI 2.0. * Updated for SMAPI 2.0.
* Switched to standard JSON config file.
* Internal refactoring. * Internal refactoring.

View File

@ -2,6 +2,7 @@
using System.IO; using System.IO;
using System.IO.Compression; using System.IO.Compression;
using System.Linq; using System.Linq;
using Omegasis.SaveBackup.Framework;
using StardewModdingAPI; using StardewModdingAPI;
using StardewModdingAPI.Events; using StardewModdingAPI.Events;
@ -25,8 +26,8 @@ namespace Omegasis.SaveBackup
/// <summary>The folder path containing nightly backups of the save.</summary> /// <summary>The folder path containing nightly backups of the save.</summary>
private static readonly string NightlyBackupsPath = Path.Combine(SaveBackup.AppDataPath, "Backed_Up_Saves", "Nightly_InGame_Saves"); private static readonly string NightlyBackupsPath = Path.Combine(SaveBackup.AppDataPath, "Backed_Up_Saves", "Nightly_InGame_Saves");
/// <summary>The number of save backups to keep for each type.</summary> /// <summary>The mod configuration.</summary>
private int SaveCount = 30; private ModConfig Config;
/********* /*********
@ -36,8 +37,7 @@ namespace Omegasis.SaveBackup
/// <param name="helper">Provides simplified APIs for writing mods.</param> /// <param name="helper">Provides simplified APIs for writing mods.</param>
public override void Entry(IModHelper helper) public override void Entry(IModHelper helper)
{ {
this.LoadConfig(); this.Config = helper.ReadConfig<ModConfig>();
this.WriteConfig();
this.BackupSaves(SaveBackup.PrePlayBackupsPath); this.BackupSaves(SaveBackup.PrePlayBackupsPath);
@ -68,33 +68,9 @@ namespace Omegasis.SaveBackup
new DirectoryInfo(folderPath) new DirectoryInfo(folderPath)
.EnumerateFiles() .EnumerateFiles()
.OrderByDescending(f => f.CreationTime) .OrderByDescending(f => f.CreationTime)
.Skip(this.SaveCount) .Skip(this.Config.SaveCount)
.ToList() .ToList()
.ForEach(file => file.Delete()); .ForEach(file => file.Delete());
} }
/// <summary>Load the configuration settings.</summary>
private void LoadConfig()
{
var path = Path.Combine(Helper.DirectoryPath, "AutoBackup_data.txt");
if (File.Exists(path))
{
string[] text = File.ReadAllLines(path);
this.SaveCount = Convert.ToInt32(text[3]);
}
}
/// <summary>Save the configuration settings.</summary>
private void WriteConfig()
{
string path = Path.Combine(Helper.DirectoryPath, "AutoBackup_data.txt");
string[] text = new string[20];
text[0] = "Player: AutoBackup Config:";
text[1] = "====================================================================================";
text[2] = "Number of Backups to Keep:";
text[3] = this.SaveCount.ToString();
File.WriteAllLines(path, text);
}
} }
} }

View File

@ -39,6 +39,7 @@
<Compile Include="..\GlobalAssemblyInfo.cs"> <Compile Include="..\GlobalAssemblyInfo.cs">
<Link>Properties\GlobalAssemblyInfo.cs</Link> <Link>Properties\GlobalAssemblyInfo.cs</Link>
</Compile> </Compile>
<Compile Include="Framework\ModConfig.cs" />
<Compile Include="SaveBackup.cs" /> <Compile Include="SaveBackup.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup> </ItemGroup>

View File

@ -0,0 +1,18 @@
namespace Omegasis.StardewSymphony.Framework
{
/// <summary>The mod configuration.</summary>
internal class ModConfig
{
/// <summary>The minimum delay (in milliseconds) to pass before playing the next song, or 0 for no delay.</summary>
public int MinSongDelay { get; set; } = 10000;
/// <summary>The maximum delay (in milliseconds) to pass before playing the next song, or 0 for no delay.</summary>
public int MaxSongDelay { get; set; } = 30000;
/// <summary>Whether to disable ambient rain audio when music is playing. If false, plays ambient rain audio alongside whatever songs are set in rain music.</summary>
public bool SilentRain { get; set; }
/// <summary>Whether to play seasonal music from the music packs, instead of defaulting to the Stardew Valley Soundtrack.</summary>
public bool PlaySeasonalMusic { get; set; } = true;
}
}

View File

@ -34,4 +34,5 @@ This won't mute the music for in-game events or festivals.
1.4: 1.4:
* Updated for SMAPI 2.0. * Updated for SMAPI 2.0.
* Switched to standard JSON config file.
* Internal refactoring. * Internal refactoring.

View File

@ -25,6 +25,9 @@ namespace Omegasis.StardewSymphony
/********* /*********
** Properties ** Properties
*********/ *********/
/// <summary>The mod configuration.</summary>
private ModConfig Config;
/// <summary>All of the music/soundbanks and their locations.</summary> /// <summary>All of the music/soundbanks and their locations.</summary>
private IList<MusicManager> MasterList = new List<MusicManager>(); private IList<MusicManager> MasterList = new List<MusicManager>();
@ -60,21 +63,6 @@ namespace Omegasis.StardewSymphony
/// <summary>A timer used to create random pauses between songs.</summary> /// <summary>A timer used to create random pauses between songs.</summary>
private Timer SongDelayTimer = new Timer(); private Timer SongDelayTimer = new Timer();
/****
** Config
****/
/// <summary>The minimum delay (in milliseconds) to pass before playing the next song, or 0 for no delay.</summary>
private int MinSongDelay;
/// <summary>The maximum delay (in milliseconds) to pass before playing the next song, or 0 for no delay.</summary>
private int MaxSongDelay;
/// <summary>Whether to disable ambient rain audio when music is playing. If false, plays ambient rain audio alongside whatever songs are set in rain music.</summary>
private bool SilentRain;
/// <summary>Whether to play seasonal music from the music packs, instead of defaulting to the Stardew Valley Soundtrack.</summary>
private bool PlaySeasonalMusic;
/********* /*********
** Public methods ** Public methods
@ -83,6 +71,7 @@ namespace Omegasis.StardewSymphony
/// <param name="helper">Provides simplified APIs for writing mods.</param> /// <param name="helper">Provides simplified APIs for writing mods.</param>
public override void Entry(IModHelper helper) public override void Entry(IModHelper helper)
{ {
this.Config = helper.ReadConfig<ModConfig>();
this.HexProcessor = new MusicHexProcessor(this.MasterList, this.Reset); this.HexProcessor = new MusicHexProcessor(this.MasterList, this.Reset);
SaveEvents.AfterLoad += this.SaveEvents_AfterLoad; SaveEvents.AfterLoad += this.SaveEvents_AfterLoad;
@ -122,7 +111,7 @@ namespace Omegasis.StardewSymphony
return; // replace with festival return; // replace with festival
if (Game1.eventUp) if (Game1.eventUp)
return; // replace with event music return; // replace with event music
if (Game1.isRaining && !this.SilentRain) if (Game1.isRaining && !this.Config.SilentRain)
return; // play the rain ambience soundtrack return; // play the rain ambience soundtrack
Game1.currentSong.Stop(AudioStopOptions.Immediate); //stop the normal songs from playing over the new songs Game1.currentSong.Stop(AudioStopOptions.Immediate); //stop the normal songs from playing over the new songs
@ -135,9 +124,6 @@ namespace Omegasis.StardewSymphony
private void TimeEvents_AfterDayStarted(object sender, EventArgs e) private void TimeEvents_AfterDayStarted(object sender, EventArgs e)
{ {
this.StopSound(); //if my music player is called and I forget to clean up sound before hand, kill the old sound. this.StopSound(); //if my music player is called and I forget to clean up sound before hand, kill the old sound.
this.LoadConfig();
this.WriteConfig();
this.SelectMusic(); this.SelectMusic();
} }
@ -146,10 +132,6 @@ namespace Omegasis.StardewSymphony
/// <param name="e">The event data.</param> /// <param name="e">The event data.</param>
private void SaveEvents_AfterLoad(object sender, EventArgs e) private void SaveEvents_AfterLoad(object sender, EventArgs e)
{ {
// init config
this.LoadConfig();
this.WriteConfig();
// init context // init context
this.Random = new Random(); this.Random = new Random();
this.MasterList = new List<MusicManager>(); this.MasterList = new List<MusicManager>();
@ -192,7 +174,7 @@ namespace Omegasis.StardewSymphony
{ {
// reset timer // reset timer
this.SongDelayTimer.Dispose(); this.SongDelayTimer.Dispose();
this.SongDelayTimer = new Timer(this.Random.Next(this.MinSongDelay, this.MaxSongDelay)); this.SongDelayTimer = new Timer(this.Random.Next(this.Config.MinSongDelay, this.Config.MaxSongDelay));
// start timer // start timer
this.SongDelayTimer.Elapsed += (sender, args) => this.SongDelayTimer.Elapsed += (sender, args) =>
@ -364,7 +346,7 @@ namespace Omegasis.StardewSymphony
if (this.HasNoMusic) //if there is valid music playing if (this.HasNoMusic) //if there is valid music playing
{ {
if (!this.PlaySeasonalMusic) if (!this.Config.PlaySeasonalMusic)
return; return;
if (this.CurrentSong != null && this.CurrentSong.IsPlaying) if (this.CurrentSong != null && this.CurrentSong.IsPlaying)
@ -1185,49 +1167,5 @@ namespace Omegasis.StardewSymphony
Game1.waveBank = this.DefaultWavebank; Game1.waveBank = this.DefaultWavebank;
Game1.soundBank = this.DefaultSoundbank; Game1.soundBank = this.DefaultSoundbank;
} }
/// <summary>Save the configuration settings.</summary>
private void WriteConfig()
{
string path = Path.Combine(Helper.DirectoryPath, "Music_Expansion_Config.txt");
string[] text = new string[20];
text[0] = "Player: Stardew Valley Music Expansion Config. Feel free to edit.";
text[1] = "====================================================================================";
text[2] = "Minimum delay time: This is the minimal amout of time(in miliseconds!!!) that will pass before another song will play. 0 means a song will play immediately, 1000 means a second will pass, etc. Used in RNG to determine a random delay between songs.";
text[3] = this.MinSongDelay.ToString();
text[4] = "Maximum delay time: This is the maximum amout of time(in miliseconds!!!) that will pass before another song will play. 0 means a song will play immediately, 1000 means a second will pass, etc. Used in RNG to determine a random delay between songs.";
text[5] = this.MaxSongDelay.ToString();
text[6] = "Silent rain? Setting this value to false plays the default ambient rain music along side whatever songs are set in rain music. Setting this to true will disable the ambient rain music. It's up to the soundpack creators wither or not they want to mix their music with rain prior to loading it in here.";
text[7] = this.SilentRain.ToString();
text[8] = "Seasonal_Music? Setting this value to true will play the seasonal music from the music packs instead of defaulting to the Stardew Valley Soundtrack.";
text[9] = this.PlaySeasonalMusic.ToString();
File.WriteAllLines(path, text);
}
/// <summary>Load the configuration settings.</summary>
void LoadConfig()
{
string path = Path.Combine(Helper.DirectoryPath, "Music_Expansion_Config.txt");
if (!File.Exists(path))
{
this.MinSongDelay = 10000;
this.MaxSongDelay = 30000;
this.SilentRain = false;
this.PlaySeasonalMusic = true;
}
else
{
string[] text = File.ReadAllLines(path);
this.MinSongDelay = Convert.ToInt32(text[3]);
this.MaxSongDelay = Convert.ToInt32(text[5]);
this.SilentRain = Convert.ToBoolean(text[7]);
this.PlaySeasonalMusic = Convert.ToBoolean(text[9]);
}
}
} }
} }

View File

@ -37,6 +37,7 @@
<Compile Include="..\GlobalAssemblyInfo.cs"> <Compile Include="..\GlobalAssemblyInfo.cs">
<Link>Properties\GlobalAssemblyInfo.cs</Link> <Link>Properties\GlobalAssemblyInfo.cs</Link>
</Compile> </Compile>
<Compile Include="Framework\ModConfig.cs" />
<Compile Include="StardewSymphony.cs" /> <Compile Include="StardewSymphony.cs" />
<Compile Include="Framework\MusicHexProcessor.cs" /> <Compile Include="Framework\MusicHexProcessor.cs" />
<Compile Include="Framework\MusicManager.cs" /> <Compile Include="Framework\MusicManager.cs" />

View File

@ -0,0 +1,12 @@
namespace Omegasis.TimeFreeze.Framework
{
/// <summary>The mod configuration.</summary>
internal class ModConfig
{
/// <summary>Whether time should be unfrozen while the player is swimming.</summary>
public bool PassTimeWhileSwimming { get; set; } = true;
/// <summary>Whether time should be unfrozen while the player is swimming in the vanilla bathhouse.</summary>
public bool PassTimeWhileSwimmingInBathhouse { get; set; } = true;
}
}

View File

@ -20,4 +20,5 @@ but you can edit `ModConfig.txt` to change that.
* Updated to Stardew Valley 1.2 and SMAPI 1.12. * Updated to Stardew Valley 1.2 and SMAPI 1.12.
1.2: 1.2:
* Switched to standard JSON config file.
* Internal refactoring. * Internal refactoring.

View File

@ -1,5 +1,5 @@
using System; using System;
using System.IO; using Omegasis.TimeFreeze.Framework;
using StardewModdingAPI; using StardewModdingAPI;
using StardewModdingAPI.Events; using StardewModdingAPI.Events;
using StardewValley; using StardewValley;
@ -13,11 +13,8 @@ namespace Omegasis.TimeFreeze
/********* /*********
** Properties ** Properties
*********/ *********/
/// <summary>Whether time should be unfrozen while the player is swimming.</summary> /// <summary>The mod configuration.</summary>
private bool PassTimeWhileSwimming = true; private ModConfig Config;
/// <summary>Whether time should be unfrozen while the player is swimming in the vanilla bathhouse.</summary>
private bool PassTimeWhileSwimmingInBathhouse = true;
/********* /*********
@ -27,8 +24,9 @@ namespace Omegasis.TimeFreeze
/// <param name="helper">Provides simplified APIs for writing mods.</param> /// <param name="helper">Provides simplified APIs for writing mods.</param>
public override void Entry(IModHelper helper) public override void Entry(IModHelper helper)
{ {
this.Config = helper.ReadConfig<ModConfig>();
GameEvents.UpdateTick += this.GameEvents_UpdateTick; GameEvents.UpdateTick += this.GameEvents_UpdateTick;
this.LoadConfig();
} }
/********* /*********
@ -55,44 +53,12 @@ namespace Omegasis.TimeFreeze
return false; return false;
if (player.swimming) if (player.swimming)
{ {
if (this.PassTimeWhileSwimmingInBathhouse && location is BathHousePool) if (this.Config.PassTimeWhileSwimmingInBathhouse && location is BathHousePool)
return false; return false;
if (this.PassTimeWhileSwimming) if (this.Config.PassTimeWhileSwimming)
return false; return false;
} }
return true; return true;
} }
/// <summary>Save the configuration settings.</summary>
private void WriteConfig()
{
string path = Path.Combine(Helper.DirectoryPath, "ModConfig.txt");
string[] text = new string[6];
text[0] = "Player: TimeFreeze Config";
text[1] = "====================================================================================";
text[2] = "Whether to unfreeze time while swimming in the vanilla bathhouse.";
text[3] = this.PassTimeWhileSwimmingInBathhouse.ToString();
text[4] = "Whether to unfreeze time while swimming anywhere.";
text[5] = this.PassTimeWhileSwimming.ToString();
File.WriteAllLines(path, text);
}
/// <summary>Load the configuration settings.</summary>
private void LoadConfig()
{
string path = Path.Combine(Helper.DirectoryPath, "ModConfig.txt");
if (!File.Exists(path))
{
this.PassTimeWhileSwimming = true;
this.PassTimeWhileSwimmingInBathhouse = true;
this.WriteConfig();
}
else
{
string[] text = File.ReadAllLines(path);
this.PassTimeWhileSwimming = Convert.ToBoolean(text[3]);
this.PassTimeWhileSwimmingInBathhouse = Convert.ToBoolean(text[5]);
}
}
} }
} }

View File

@ -37,6 +37,7 @@
<Compile Include="..\GlobalAssemblyInfo.cs"> <Compile Include="..\GlobalAssemblyInfo.cs">
<Link>Properties\GlobalAssemblyInfo.cs</Link> <Link>Properties\GlobalAssemblyInfo.cs</Link>
</Compile> </Compile>
<Compile Include="Framework\ModConfig.cs" />
<Compile Include="TimeFreeze.cs" /> <Compile Include="TimeFreeze.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup> </ItemGroup>