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.IO;
using Omegasis.AutoSpeed.Framework;
using StardewModdingAPI;
using StardewModdingAPI.Events;
using StardewValley;
@ -12,8 +12,8 @@ namespace Omegasis.AutoSpeed
/*********
** Properties
*********/
/// <summary>The speed multiplier.</summary>
private int Speed = 5;
/// <summary>The mod configuration.</summary>
private ModConfig Config;
/*********
@ -24,13 +24,7 @@ namespace Omegasis.AutoSpeed
public override void Entry(IModHelper helper)
{
GameEvents.UpdateTick += this.GameEvents_UpdateTick;
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);
this.Config = helper.ReadConfig<ModConfig>();
}
@ -43,32 +37,7 @@ namespace Omegasis.AutoSpeed
private void GameEvents_UpdateTick(object sender, EventArgs e)
{
if (Context.IsPlayerFree)
Game1.player.addedSpeed = this.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);
Game1.player.addedSpeed = this.Config.Speed;
}
}
}

View File

@ -38,6 +38,7 @@
<Link>Properties\GlobalAssemblyInfo.cs</Link>
</Compile>
<Compile Include="AutoSpeed.cs" />
<Compile Include="Framework\ModConfig.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</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.
## Usage
Launch the game with the mod installed to generate the config file, then edit the
`AutoSpeed_data.txt` to set the speed you want (higher values are faster).
Launch the game with the mod installed to generate the config file, then edit the `config.json` to
set the speed you want (higher values are faster).
## Versions
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.
1.4:
* Switched to standard JSON config file.
* Internal refactoring.

View File

@ -1,5 +1,4 @@
using System;
using System.IO;
using Omegasis.BillboardAnywhere.Framework;
using StardewModdingAPI;
using StardewModdingAPI.Events;
using StardewValley;
@ -13,8 +12,8 @@ namespace Omegasis.BillboardAnywhere
/*********
** Properties
*********/
/// <summary>The key which shows the billboard menu.</summary>
private string KeyBinding = "B";
/// <summary>The mod configuration.</summary>
private ModConfig Config;
/*********
@ -24,7 +23,8 @@ namespace Omegasis.BillboardAnywhere
/// <param name="helper">Provides simplified APIs for writing mods.</param>
public override void Entry(IModHelper helper)
{
SaveEvents.AfterLoad += this.SaveEvents_AfterLoad;
this.Config = helper.ReadConfig<ModConfig>();
ControlEvents.KeyPressed += this.ControlEvents_KeyPressed;
}
@ -32,50 +32,14 @@ namespace Omegasis.BillboardAnywhere
/*********
** 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>
/// <param name="sender">The event sender.</param>
/// <param name="e">The event data.</param>
public void ControlEvents_KeyPressed(object sender, EventArgsKeyPressed e)
{
// 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();
}
/// <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>
</Compile>
<Compile Include="BillboardAnywhere.cs" />
<Compile Include="Framework\ModConfig.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</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.
## Usage
Press `B` while in-game to show the billboard menu. Edit the `Billboard_Anywhere_Config.txt` file
to change the key.
Press `B` while in-game to show the billboard menu. Edit the `config.json` file to change the key.
## Versions
1.0
@ -23,4 +22,5 @@ to change the key.
* Updated to Stardew Valley 1.2 and SMAPI 1.12.
1.4:
* Switched to standard JSON config file.
* Internal refactoring.

View File

@ -1,7 +1,6 @@
using System;
using System.IO;
using System.Text;
using Newtonsoft.Json;
using System.Linq;
using Omegasis.BuildEndurance.Framework;
using StardewModdingAPI;
using StardewModdingAPI.Events;
@ -15,45 +14,30 @@ namespace Omegasis.BuildEndurance
/*********
** 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;
/// <summary>The data for the current player.</summary>
private PlayerData PlayerData;
/// <summary>Whether the player has been exhausted today.</summary>
private bool WasExhausted;
/// <summary>Whether the player has collapsed today.</summary>
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>
private bool HasRecentToolExp;
/// <summary>Whether the player was eating last time we checked.</summary>
private bool WasEating;
/// <summary>The player's stamina last time they slept.</summary>
private int NightlyStamina;
/*********
** Public methods
@ -62,46 +46,22 @@ namespace Omegasis.BuildEndurance
/// <param name="helper">Provides simplified APIs for writing mods.</param>
public override void Entry(IModHelper helper)
{
this.Config = helper.ReadConfig<ModConfig>();
GameEvents.UpdateTick += this.GameEvents_UpdateTick;
GameEvents.OneSecondTick += this.GameEvents_OneSecondTick;
SaveEvents.AfterLoad += this.SaveEvents_AfterLoad;
TimeEvents.AfterDayStarted += this.TimeEvents_AfterDayStarted;
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.");
SaveEvents.BeforeSave += this.SaveEvents_BeforeSave;
}
this.Monitor.Log("BuildEndurance Initialization Completed");
}
/*********
** Private methods
*********/
/// <summary>The method invoked once per second during a game update.</summary>
/// <param name="sender">The event sender.</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)
if (this.HasRecentToolExp)
@ -111,28 +71,31 @@ namespace Omegasis.BuildEndurance
/// <summary>The method invoked when the game updates (roughly 60 times per second).</summary>
/// <param name="sender">The event sender.</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
if (Game1.isEating)
this.WasEating = true;
else if (this.WasEating)
{
this.CurrentExp += this.Config.ExpForEating;
this.PlayerData.CurrentExp += this.Config.ExpForEating;
this.WasEating = false;
}
// give XP when player uses tool
if (!this.HasRecentToolExp && Game1.player.usingTool)
{
this.CurrentExp += this.Config.ExpForToolUse;
this.PlayerData.CurrentExp += this.Config.ExpForToolUse;
this.HasRecentToolExp = true;
}
// give XP when exhausted
if (!this.WasExhausted && Game1.player.exhausted)
{
this.CurrentExp += this.Config.ExpForExhaustion;
this.PlayerData.CurrentExp += this.Config.ExpForExhaustion;
this.WasExhausted = true;
this.Monitor.Log("The player is exhausted");
}
@ -140,7 +103,7 @@ namespace Omegasis.BuildEndurance
// give XP when player stays up too late or collapses
if (!this.WasCollapsed && Game1.farmerShouldPassOut)
{
this.CurrentExp += this.Config.ExpForCollapsing;
this.PlayerData.CurrentExp += this.Config.ExpForCollapsing;
this.WasCollapsed = true;
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>
/// <param name="sender">The event sender.</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
this.LoadConfig();
this.WriteConfig();
// grab initial stamina
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;
// load player data
this.MigrateLegacyData();
this.PlayerData = this.Helper.ReadJsonFile<PlayerData>(this.DataFilePath) ?? new PlayerData();
if (this.PlayerData.OriginalMaxStamina == 0)
this.PlayerData.OriginalMaxStamina = Game1.player.MaxStamina;
// reset if needed
if (this.ClearModEffects)
player.MaxStamina = this.OriginalStamina;
// save config
this.LoadConfig();
this.WriteConfig();
if (this.PlayerData.ClearModEffects)
{
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;
}
/// <summary>The method invoked when a new day starts.</summary>
// else apply stamina
else
{
Game1.player.MaxStamina = this.PlayerData.NightlyStamina <= 0
? this.PlayerData.BaseStaminaBonus + this.PlayerData.CurrentLevelStaminaBonus + this.PlayerData.OriginalMaxStamina
: this.PlayerData.NightlyStamina;
}
}
/// <summary>The method invoked just before the game is saved.</summary>
/// <param name="sender">The event sender.</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
this.WasExhausted = false;
this.WasCollapsed = false;
// update settings
this.Monitor.Log(this.CurrentExp.ToString());
this.UpdateClearSetting();
this.Monitor.Log(this.ClearModEffects.ToString());
// update player data
this.PlayerData.CurrentExp += this.Config.ExpForSleeping;
if (this.PlayerData.OriginalMaxStamina == 0)
this.PlayerData.OriginalMaxStamina = Game1.player.MaxStamina; //grab the initial stamina value
var player = Game1.player;
this.CurrentExp += this.Config.ExpForSleeping;
if (this.OriginalStamina == 0)
this.OriginalStamina = player.MaxStamina; //grab the initial stamina value
if (this.ClearModEffects)
if (this.PlayerData.CurrentLevel < this.Config.MaxLevel)
{
this.LoadClearSettings();
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.PlayerData.CurrentExp >= this.PlayerData.ExpToNextLevel)
{
while (this.CurrentExp >= this.ExpToNextLevel)
{
this.CurrentLevel += 1;
this.CurrentExp = this.CurrentExp - this.ExpToNextLevel;
this.ExpToNextLevel = (this.Config.ExpCurve * this.ExpToNextLevel);
player.MaxStamina += this.Config.StaminaIncreasePerLevel;
this.CurrentLevelStaminaBonus += this.Config.StaminaIncreasePerLevel;
this.PlayerData.CurrentLevel += 1;
this.PlayerData.CurrentExp = this.PlayerData.CurrentExp - this.PlayerData.ExpToNextLevel;
this.PlayerData.ExpToNextLevel = (this.Config.ExpCurve * this.PlayerData.ExpToNextLevel);
Game1.player.MaxStamina += this.Config.StaminaIncreasePerLevel;
this.PlayerData.CurrentLevelStaminaBonus += this.Config.StaminaIncreasePerLevel;
}
}
this.ClearModEffects = false;
this.NightlyStamina = Game1.player.maxStamina;
this.WriteConfig();
this.PlayerData.ClearModEffects = false;
this.PlayerData.NightlyStamina = Game1.player.maxStamina;
// 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>
void LoadClearSettings()
/// <summary>Migrate the legacy settings for the current player.</summary>
private void MigrateLegacyData()
{
this.LoadConfig();
this.WriteConfig();
// skip if no legacy data or new data already exists
if (!File.Exists(this.LegacyDataFilePath) || File.Exists(this.DataFilePath))
return;
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))
// migrate to new file
try
{
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;
this.OriginalStamina = 0;
this.BaseStaminaBonus = 0;
FileInfo file = new FileInfo(this.LegacyDataFilePath);
file.Delete();
if (!file.Directory.EnumerateFiles().Any())
file.Directory.Delete();
}
else
catch (Exception ex)
{
string[] text = File.ReadAllLines(path);
this.BaseStaminaBonus = Convert.ToInt32(text[9]);
this.ClearModEffects = Convert.ToBoolean(text[14]);
this.OriginalStamina = Convert.ToInt32(text[16]);
this.Monitor.Log($"Error migrating data from the legacy 'PlayerData' folder for the current player. Technical details:\n {ex}", LogLevel.Error);
}
}
/// <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>
</PropertyGroup>
<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.Xml" />
</ItemGroup>
@ -43,6 +39,7 @@
</Compile>
<Compile Include="BuildEndurance.cs" />
<Compile Include="Framework\ModConfig.cs" />
<Compile Include="Framework\PlayerData.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>

View File

@ -4,7 +4,7 @@ namespace Omegasis.BuildEndurance.Framework
internal class ModConfig
{
/// <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>
public double CurrentExp { get; set; }
@ -19,27 +19,27 @@ namespace Omegasis.BuildEndurance.Framework
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>
public double ExpCurve { get; set; }
public double ExpCurve { get; set; } = 1.15;
/// <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>
public int StaminaIncreasePerLevel { get; set; }
public int StaminaIncreasePerLevel { get; set; } = 1;
/// <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>
public int ExpForEating { get; set; }
public int ExpForEating { get; set; } = 2;
/// <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>
public int ExpForExhaustion { get; set; }
public int ExpForExhaustion { get; set; } = 25;
/// <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).
3. Run the game using SMAPI.
**NOTE:** to undo the mod's changes to your player, edit the `PlayerData\BuildEndurance_data_*.txt`
file and change the "RESET ALL MOD EFFECTS?" field to `True`.
**NOTE:** to undo the mod's changes to your player, edit the `data\*.json` file for your save and
change the "ClearModEffects" field to `true`.
## Usage
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.
Edit `BuildEnduranceConfig.json` to configure the mod settings.
Edit `config.json` to configure the mod settings.
## Versions
1.0
@ -36,4 +36,6 @@ Edit `BuildEnduranceConfig.json` to configure the mod settings.
1.4:
* 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.

View File

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

View File

@ -1,7 +1,6 @@
using System;
using System.IO;
using System.Text;
using Newtonsoft.Json;
using System.Linq;
using Omegasis.BuildHealth.Framework;
using StardewModdingAPI;
using StardewModdingAPI.Events;
@ -15,29 +14,17 @@ namespace Omegasis.BuildHealth
/*********
** 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>
private ModConfig Config;
/// <summary>The XP points needed to reach the next level.</summary>
private double ExpToNextLevel = 20;
/// <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>The data for the current player.</summary>
private PlayerData PlayerData;
/// <summary>Whether the player recently gained XP for tool use.</summary>
private bool HasRecentToolExp;
@ -61,42 +48,20 @@ namespace Omegasis.BuildHealth
{
GameEvents.UpdateTick += this.GameEvents_UpdateTick;
GameEvents.OneSecondTick += this.GameEvents_OneSecondTick;
TimeEvents.AfterDayStarted += this.TimeEvents_AfterDayStarted;
TimeEvents.AfterDayStarted += this.SaveEvents_BeforeSave;
SaveEvents.AfterLoad += this.SaveEvents_AfterLoaded;
var configPath = Path.Combine(helper.DirectoryPath, "BuildHealthConfig.json");
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.Config = helper.ReadConfig<ModConfig>();
}
this.Monitor.Log("BuildHealth Initialization Completed");
}
/*********
** Private methods
*********/
/// <summary>The method invoked once per second during a game update.</summary>
/// <param name="sender">The event sender.</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)
if (this.HasRecentToolExp)
@ -106,21 +71,24 @@ namespace Omegasis.BuildHealth
/// <summary>The method invoked when the game updates (roughly 60 times per second).</summary>
/// <param name="sender">The event sender.</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
if (Game1.isEating)
this.WasEating = true;
else if (this.WasEating)
{
this.CurrentExp += this.Config.ExpForEating;
this.PlayerData.CurrentExp += this.Config.ExpForEating;
this.WasEating = false;
}
// give XP when player uses tool
if (!this.HasRecentToolExp && Game1.player.usingTool)
{
this.CurrentExp += this.Config.ExpForToolUse;
this.PlayerData.CurrentExp += this.Config.ExpForToolUse;
this.HasRecentToolExp = true;
}
@ -128,7 +96,7 @@ namespace Omegasis.BuildHealth
var player = Game1.player;
if (this.LastHealth > player.health)
{
this.CurrentExp += this.LastHealth - player.health;
this.PlayerData.CurrentExp += this.LastHealth - player.health;
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
if (!this.WasCollapsed && Game1.farmerShouldPassOut)
{
this.CurrentExp += this.Config.ExpForCollapsing;
this.PlayerData.CurrentExp += this.Config.ExpForCollapsing;
this.WasCollapsed = true;
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="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
this.LastHealth = Game1.player.maxHealth;
this.WasCollapsed = false;
// update settings
this.UpdateClearSetting();
var player = Game1.player;
this.CurrentExp += this.Config.ExpForSleeping;
if (this.OriginalMaxHealth == 0)
this.OriginalMaxHealth = player.maxHealth; //grab the initial Health value
this.PlayerData.CurrentExp += this.Config.ExpForSleeping;
if (this.PlayerData.OriginalMaxHealth == 0)
this.PlayerData.OriginalMaxHealth = player.maxHealth; //grab the initial Health value
if (this.ClearModEffects)
if (this.PlayerData.CurrentLevel < this.Config.MaxLevel)
{
this.LoadClearSettings();
//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.PlayerData.CurrentExp >= this.PlayerData.ExpToNextLevel)
{
while (this.CurrentExp >= this.ExpToNextLevel)
{
this.CurrentLevel += 1;
this.CurrentExp = this.CurrentExp - this.ExpToNextLevel;
this.ExpToNextLevel =
(this.Config.ExpCurve * this.ExpToNextLevel);
this.PlayerData.CurrentLevel += 1;
this.PlayerData.CurrentExp = this.PlayerData.CurrentExp - this.PlayerData.ExpToNextLevel;
this.PlayerData.ExpToNextLevel =
(this.Config.ExpCurve * this.PlayerData.ExpToNextLevel);
player.maxHealth += this.Config.HealthIncreasePerLevel;
this.CurrentLevelHealthBonus += this.Config.HealthIncreasePerLevel;
this.PlayerData.CurrentLevelHealthBonus += this.Config.HealthIncreasePerLevel;
}
}
this.ClearModEffects = false;
this.WriteConfig();
}
/// <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_AfterLoaded(object sender, EventArgs e)
// save data
this.Helper.WriteJsonFile(this.DataFilePath, this.PlayerData);
}
/// <summary>Migrate the legacy settings for the current player.</summary>
private void MigrateLegacyData()
{
// initialise
this.LoadConfig();
this.WriteConfig();
// skip if no legacy data or new data already exists
if (!File.Exists(this.LegacyDataFilePath) || File.Exists(this.DataFilePath))
return;
// grab initial health
var player = Game1.player;
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)
// migrate to new file
try
{
player.maxHealth = this.OriginalMaxHealth;
this.Monitor.Log("BuildHealth Reset!");
}
// 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()
string[] text = File.ReadAllLines(this.LegacyDataFilePath);
this.Helper.WriteJsonFile(this.DataFilePath, new PlayerData
{
if (!Directory.Exists(Path.Combine(Helper.DirectoryPath, "PlayerData")))
Directory.CreateDirectory(Path.Combine(Helper.DirectoryPath, "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])
});
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;
FileInfo file = new FileInfo(this.LegacyDataFilePath);
file.Delete();
if (!file.Directory.EnumerateFiles().Any())
file.Directory.Delete();
}
else
catch (Exception ex)
{
string[] text = File.ReadAllLines(path);
this.BaseHealthBonus = Convert.ToInt32(text[9]);
this.ClearModEffects = Convert.ToBoolean(text[14]);
this.OriginalMaxHealth = Convert.ToInt32(text[16]);
this.Monitor.Log($"Error migrating data from the legacy 'PlayerData' folder for the current player. Technical details:\n {ex}", LogLevel.Error);
}
}
/// <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>
</PropertyGroup>
<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.Xml" />
</ItemGroup>
@ -43,6 +39,7 @@
</Compile>
<Compile Include="BuildHealth.cs" />
<Compile Include="Framework\ModConfig.cs" />
<Compile Include="Framework\PlayerData.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>

View File

@ -4,7 +4,7 @@
internal class ModConfig
{
/// <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>
public double CurrentExp { get; set; }
@ -19,22 +19,22 @@
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>
public double ExpCurve { get; set; }
public double ExpCurve { get; set; } = 1.15;
/// <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>
public int HealthIncreasePerLevel { get; set; }
public int HealthIncreasePerLevel { get; set; } = 1;
/// <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>
public int ExpForEating { get; set; }
public int ExpForEating { get; set; } = 2;
/// <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>
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).
3. Run the game using SMAPI.
**NOTE:** to undo the mod's changes to your player, edit the `PlayerData\BuildEndurance_data_*.txt`
file and change the "RESET ALL MOD EFFECTS?" field to `True`.
**NOTE:** to undo the mod's changes to your player, edit the `data\*.json` file for your save and
change the "ClearModEffects" field to `true`.
## Usage
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.
Edit `BuildHealthConfig.json` to configure the mod settings.
Edit `config.json` to configure the mod settings.
## Versions
1.0
@ -37,4 +37,6 @@ Edit `BuildHealthConfig.json` to configure the mod settings.
1.4:
* 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.

View File

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

View File

@ -1,6 +1,4 @@
using System;
using System.IO;
using Omegasis.BuyBackCollectables.Framework;
using Omegasis.BuyBackCollectables.Framework;
using StardewModdingAPI;
using StardewModdingAPI.Events;
using StardewValley;
@ -13,11 +11,8 @@ namespace Omegasis.BuyBackCollectables
/*********
** Properties
*********/
/// <summary>The key which shows the menu.</summary>
private string KeyBinding = "B";
/// <summary>The multiplier applied to the cost of buying back a collectable.</summary>
private double CostMultiplier = 3.0;
/// <summary>The mod configuration.</summary>
private ModConfig Config;
/*********
@ -27,7 +22,8 @@ namespace Omegasis.BuyBackCollectables
/// <param name="helper">Provides simplified APIs for writing mods.</param>
public override void Entry(IModHelper helper)
{
SaveEvents.AfterLoad += this.SaveEvents_AfterLoad;
this.Config = helper.ReadConfig<ModConfig>();
ControlEvents.KeyPressed += this.ControlEvents_KeyPressed;
}
@ -35,55 +31,13 @@ namespace Omegasis.BuyBackCollectables
/*********
** 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>
/// <param name="sender">The event sender.</param>
/// <param name="e">The event data.</param>
public void ControlEvents_KeyPressed(object sender, EventArgsKeyPressed e)
{
if (Context.IsPlayerFree && e.KeyPressed.ToString() == this.KeyBinding)
Game1.activeClickableMenu = new BuyBackMenu(this.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);
if (Context.IsPlayerFree && e.KeyPressed.ToString() == this.Config.KeyBinding)
Game1.activeClickableMenu = new BuyBackMenu(this.Config.CostMultiplier);
}
}
}

View File

@ -38,6 +38,7 @@
<Link>Properties\GlobalAssemblyInfo.cs</Link>
</Compile>
<Compile Include="BuyBackCollectables.cs" />
<Compile Include="Framework\ModConfig.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Framework\BuyBackMenu.cs" />
</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.
## Usage
Press `B` to open the buy-collectibles menu. Edit `BuildHealthConfig.json` to change the key or the
price markup.
Press `B` to open the buy-collectibles menu. Edit `config.json` to change the key or the price
markup.
## Versions
1.0:
@ -31,4 +31,5 @@ price markup.
* Updated to Stardew Valley 1.2 and SMAPI 1.12.
1.4:
* Switched to standard JSON config file.
* Internal refactoring.

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.Xna.Framework;
using Omegasis.CustomShopsRedux.Framework;
using StardewModdingAPI;
using StardewModdingAPI.Events;
using StardewValley;
@ -31,17 +32,17 @@ namespace Omegasis.CustomShopsRedux
/*********
** Properties
*********/
/// <summary>The mod configuration.</summary>
private ModConfig Config;
/// <summary>The prices for the items to list.</summary>
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>
private readonly List<string> Options = new List<string>();
/// <summary>The key which shows the menu.</summary>
private string KeyBinding = "U";
/// <summary>The folder path containing shop data files.</summary>
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>
public override void Entry(IModHelper helper)
{
SaveEvents.AfterLoad += this.SaveEvents_AfterDayStarted;
this.Config = helper.ReadConfig<ModConfig>();
ControlEvents.KeyPressed += this.ControlEvents_KeyPressed;
}
@ -59,58 +61,20 @@ namespace Omegasis.CustomShopsRedux
/*********
** 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>
/// <param name="sender">The event sender.</param>
/// <param name="e">The event data.</param>
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();
}
/// <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>
private void OpenSelectFileMenu()
{
// get mod folder
Directory.CreateDirectory(this.DataPath);
DirectoryInfo modFolder = new DirectoryInfo(this.DataPath);
this.Monitor.Log(modFolder.FullName);

View File

@ -38,6 +38,7 @@
<Link>Properties\GlobalAssemblyInfo.cs</Link>
</Compile>
<Compile Include="CustomShopsRedux.cs" />
<Compile Include="Framework\ModConfig.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</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)
(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:
@ -60,4 +60,5 @@ Supported item types:
1.4:
* Updated for SMAPI 2.0.
* Switched to standard JSON config file.
* Internal refactoring.

View File

@ -1,5 +1,4 @@
using System;
using System.IO;
using Omegasis.DailyQuestAnywhere.Framework;
using StardewModdingAPI;
using StardewModdingAPI.Events;
using StardewValley;
@ -13,8 +12,8 @@ namespace Omegasis.DailyQuestAnywhere
/*********
** Properties
*********/
/// <summary>The key which shows the menu.</summary>
private string KeyBinding = "H";
/// <summary>The mod configuration.</summary>
private ModConfig Config;
/*********
@ -24,7 +23,8 @@ namespace Omegasis.DailyQuestAnywhere
/// <param name="helper">Provides simplified APIs for writing mods.</param>
public override void Entry(IModHelper helper)
{
SaveEvents.AfterLoad += this.SaveEvents_AfterLoad;
this.Config = helper.ReadConfig<ModConfig>();
ControlEvents.KeyPressed += this.ControlEvents_KeyPressed;
}
@ -32,49 +32,13 @@ namespace Omegasis.DailyQuestAnywhere
/*********
** 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>
/// <param name="sender">The event sender.</param>
/// <param name="e">The event data.</param>
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);
}
/// <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>
</Compile>
<Compile Include="DailyQuestAnywhere.cs" />
<Compile Include="Framework\ModConfig.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</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.
## 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
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.
1.4:
* Switched to standard JSON config file.
* 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
*********/
/// <summary>The key which shows the menu.</summary>
private string KeyBinding = "O";
/// <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, "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>
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>
private List<string> VillagerQueue;
@ -38,18 +47,6 @@ namespace Omegasis.HappyBirthday
//private Dictionary<string, Dialogue> Dialogue;
//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
@ -58,17 +55,16 @@ namespace Omegasis.HappyBirthday
/// <param name="helper">Provides simplified APIs for writing mods.</param>
public override void Entry(IModHelper helper)
{
this.Config = helper.ReadConfig<ModConfig>();
TimeEvents.AfterDayStarted += this.TimeEvents_AfterDayStarted;
GameEvents.UpdateTick += this.GameEvents_UpdateTick;
SaveEvents.AfterLoad += this.SaveEvents_AfterLoad;
SaveEvents.BeforeSave += this.SaveEvents_BeforeSave;
ControlEvents.KeyPressed += this.ControlEvents_KeyPressed;
this.VillagerQueue = new List<string>();
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>
private void TimeEvents_AfterDayStarted(object sender, EventArgs e)
{
if (this.HasChosenBirthday)
this.WriteBirthday();
this.WriteConfig();
this.CheckedForBirthday = false;
}
@ -92,8 +85,8 @@ namespace Omegasis.HappyBirthday
private void ControlEvents_KeyPressed(object sender, EventArgsKeyPressed e)
{
// show birthday selection menu
if (Context.IsPlayerFree && !this.HasChosenBirthday && e.KeyPressed.ToString() == this.KeyBinding)
Game1.activeClickableMenu = new BirthdayMenu(this.BirthdaySeason, this.BirthdayDay, this.SetBirthday);
if (Context.IsPlayerFree && !this.HasChosenBirthday && e.KeyPressed.ToString() == this.Config.KeyBinding)
Game1.activeClickableMenu = new BirthdayMenu(this.PlayerData.BirthdaySeason, this.PlayerData.BirthdayDay, this.SetBirthday);
}
/// <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>
private void SaveEvents_AfterLoad(object sender, EventArgs e)
{
this.LoadBirthday();
this.LoadConfig();
this.MigrateLegacyData();
this.PlayerData = this.Helper.ReadJsonFile<PlayerData>(this.DataFilePath) ?? new PlayerData();
//this.SeenEvent = false;
//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>
/// <param name="sender">The event sender.</param>
/// <param name="e">The event data.</param>
@ -159,9 +161,9 @@ namespace Omegasis.HappyBirthday
}
// 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;
}
}
@ -223,14 +225,6 @@ namespace Omegasis.HappyBirthday
Game1.player.addItemByMenuIfNecessaryElseHoldUp(this.BirthdayGiftToReceive);
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>
@ -238,8 +232,8 @@ namespace Omegasis.HappyBirthday
/// <param name="day">The birthday day.</param>
private void SetBirthday(string season, int day)
{
this.BirthdaySeason = season;
this.BirthdayDay = day;
this.PlayerData.BirthdaySeason = season;
this.PlayerData.BirthdayDay = day;
}
/// <summary>Reset the queue of villager names.</summary>
@ -495,63 +489,36 @@ namespace Omegasis.HappyBirthday
private bool IsBirthday()
{
return
this.BirthdayDay == Game1.dayOfMonth
&& this.BirthdaySeason == Game1.currentSeason;
this.PlayerData.BirthdayDay == Game1.dayOfMonth
&& this.PlayerData.BirthdaySeason == Game1.currentSeason;
}
/// <summary>Load the configuration settings.</summary>
private void LoadConfig()
/// <summary>Migrate the legacy settings for the current player.</summary>
private void MigrateLegacyData()
{
string path = Path.Combine(Helper.DirectoryPath, "HappyBirthday_Config.txt");
if (!File.Exists(path))
this.KeyBinding = "O";
else
// skip if no legacy data or new data already exists
if (!File.Exists(this.LegacyDataFilePath) || File.Exists(this.DataFilePath))
return;
// migrate to new file
try
{
string[] text = File.ReadAllLines(path);
this.KeyBinding = Convert.ToString(text[3]);
string[] text = File.ReadAllLines(this.LegacyDataFilePath);
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();
}
}
/// <summary>Save the configuration settings.</summary>
private void WriteConfig()
catch (Exception ex)
{
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);
this.Monitor.Log($"Error migrating data from the legacy 'Player_Birthdays' folder for the current player. Technical details:\n {ex}", LogLevel.Error);
}
/// <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.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>
</Compile>
<Compile Include="Framework\BirthdayMenu.cs" />
<Compile Include="Framework\ModConfig.cs" />
<Compile Include="Framework\PlayerData.cs" />
<Compile Include="HappyBirthday.cs" />
<Compile Include="Framework\Messages.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:
* 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.

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.Collections.Generic;
using System.IO;
using Omegasis.MoreRain.Framework;
using StardewModdingAPI;
using StardewModdingAPI.Events;
using StardewValley;
@ -16,29 +16,8 @@ namespace Omegasis.MoreRain
/// <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 };
/// <summary>The chance out of 100 that it will rain tomorrow if it's spring.</summary>
private int SpringRainChance;
/// <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;
/// <summary>The mod configuration.</summary>
private ModConfig Config;
/*********
@ -48,9 +27,10 @@ namespace Omegasis.MoreRain
/// <param name="helper">Provides simplified APIs for writing mods.</param>
public override void Entry(IModHelper helper)
{
this.Config = helper.ReadConfig<ModConfig>();
SaveEvents.AfterLoad += this.SaveEvents_AfterLoad;
SaveEvents.BeforeSave += this.SaveEvents_BeforeSave;
this.LoadConfig();
}
@ -95,7 +75,7 @@ namespace Omegasis.MoreRain
{
case "spring":
// set rain
if (chance <= this.SpringRainChance)
if (chance <= this.Config.SpringRainChance)
{
Game1.weatherForTomorrow = Game1.weather_rain;
this.VerboseLog("It will rain tomorrow.");
@ -109,7 +89,7 @@ namespace Omegasis.MoreRain
// set storm
if (Game1.weatherForTomorrow == Game1.weather_rain)
{
if (chance <= this.SpringThunderChance)
if (chance <= this.Config.SpringThunderChance)
{
Game1.weatherForTomorrow = Game1.weather_lightning;
this.VerboseLog("It will be stormy tomorrow.");
@ -124,7 +104,7 @@ namespace Omegasis.MoreRain
case "summer":
// set rain
if (chance <= this.SummerRainChance)
if (chance <= this.Config.SummerRainChance)
{
Game1.weatherForTomorrow = Game1.weather_rain;
this.VerboseLog("It will rain tomorrow.");
@ -138,7 +118,7 @@ namespace Omegasis.MoreRain
// set storm
if (Game1.weatherForTomorrow == Game1.weather_rain)
{
if (chance <= this.SummerThunderChance)
if (chance <= this.Config.SummerThunderChance)
{
Game1.weatherForTomorrow = Game1.weather_lightning;
this.VerboseLog("It will be stormy tomorrow.");
@ -154,7 +134,7 @@ namespace Omegasis.MoreRain
case "fall":
case "autumn":
// set rain
if (chance <= this.FallRainChance)
if (chance <= this.Config.FallRainChance)
{
Game1.weatherForTomorrow = Game1.weather_rain;
this.VerboseLog("It will rain tomorrow.");
@ -168,7 +148,7 @@ namespace Omegasis.MoreRain
// set storm
if (Game1.weatherForTomorrow == Game1.weather_rain)
{
if (chance <= this.FallThunderChance)
if (chance <= this.Config.FallThunderChance)
{
Game1.weatherForTomorrow = Game1.weather_lightning;
this.VerboseLog("It will be stormy tomorrow.");
@ -183,7 +163,7 @@ namespace Omegasis.MoreRain
case "winter":
// set snow
if (chance <= this.WinterSnowChance)
if (chance <= this.Config.WinterSnowChance)
{
Game1.weatherForTomorrow = Game1.weather_snow;
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>
/// <param name="message">The message to log.</param>
private void VerboseLog(string message)
{
if (!this.SuppressLog)
if (!this.Config.SuppressLog)
this.Monitor.Log(message);
}
}

View File

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

View File

@ -9,8 +9,8 @@ Compatible with Stardew Valley 1.2+ on Linux, Mac, and Windows.
3. Run the game using SMAPI.
## Usage
Edit `More_Rain_Config.txt` to change the chance of rain, storms, or snow. Each value is a
percentage (0 to 100).
Edit `config.json` to change the chance of rain, storms, or snow. Each value is a percentage (0
to 100).
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:
* Updated for SMAPI 2.0.
* Switched to standard JSON config file.
* 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 System.IO;
using Omegasis.MuseumRearranger.Framework;
using Omegasis.MuseumRearranger.Framework;
using StardewModdingAPI;
using StardewModdingAPI.Events;
using StardewValley;
@ -14,11 +12,8 @@ namespace Omegasis.MuseumRearranger
/*********
** Properties
*********/
/// <summary>The key which shows the museum rearranging menu.</summary>
private string ShowMenuKey = "R";
/// <summary>The key which toggles the inventory box when the menu is open.</summary>
private string ToggleInventoryKey = "T";
/// <summary>The mod configuration.</summary>
private ModConfig Config;
/// <summary>The open museum menu (if any).</summary>
private NewMuseumMenu OpenMenu;
@ -31,7 +26,8 @@ namespace Omegasis.MuseumRearranger
/// <param name="helper">Provides simplified APIs for writing mods.</param>
public override void Entry(IModHelper helper)
{
SaveEvents.AfterLoad += this.SaveEvents_AfterLoad;
this.Config = helper.ReadConfig<ModConfig>();
ControlEvents.KeyPressed += this.ControlEvents_KeyPressed;
}
@ -48,7 +44,7 @@ namespace Omegasis.MuseumRearranger
return;
// open menu
if (e.KeyPressed.ToString() == this.ShowMenuKey)
if (e.KeyPressed.ToString() == this.Config.ShowMenuKey)
{
if (Game1.activeClickableMenu != null)
return;
@ -59,48 +55,8 @@ namespace Omegasis.MuseumRearranger
}
// toggle inventory box
if (e.KeyPressed.ToString() == this.ToggleInventoryKey)
if (e.KeyPressed.ToString() == this.Config.ToggleInventoryKey)
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">
<Link>Properties\GlobalAssemblyInfo.cs</Link>
</Compile>
<Compile Include="Framework\ModConfig.cs" />
<Compile Include="MuseumRearranger.cs" />
<Compile Include="Framework\NewMuseumMenu.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />

View File

@ -10,7 +10,7 @@ Compatible with Stardew Valley 1.2+ on Linux, Mac, and Windows.
## Usage
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
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.
1.4:
* Switched to standard JSON config file.
* 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.Linq;
using Microsoft.Xna.Framework;
using Newtonsoft.Json;
using Omegasis.NightOwl.Framework;
using StardewModdingAPI;
using StardewModdingAPI.Events;
using StardewValley;
@ -24,6 +24,9 @@ namespace Omegasis.NightOwl
/*********
** Properties
*********/
/// <summary>The mod configuration.</summary>
private ModConfig Config;
/****
** Context
****/
@ -57,29 +60,6 @@ namespace Omegasis.NightOwl
/// <summary>The player's health before they collapsed.</summary>
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>
public override void Entry(IModHelper helper)
{
this.Config = helper.ReadConfig<ModConfig>();
TimeEvents.TimeOfDayChanged += this.TimeEvents_TimeOfDayChanged;
TimeEvents.AfterDayStarted += this.TimeEvents_AfterDayStarted;
SaveEvents.AfterLoad += this.SaveEvents_AfterLoad;
@ -107,7 +89,7 @@ namespace Omegasis.NightOwl
try
{
// reset position after collapse
if (Context.IsWorldReady && this.JustStartedNewDay && this.KeepPositionAfterCollapse)
if (Context.IsWorldReady && this.JustStartedNewDay && this.Config.KeepPositionAfterCollapse)
{
if (this.PreCollapseMap != null)
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>
public void SaveEvents_AfterLoad(object sender, EventArgs e)
{
this.LoadConfig();
this.WriteConfig();
this.IsUpLate = false;
this.JustStartedNewDay = false;
this.JustCollapsed = false;
@ -144,8 +124,6 @@ namespace Omegasis.NightOwl
try
{
// reset data
this.LoadConfig();
this.WriteConfig();
this.IsUpLate = false;
Game1.farmerShouldPassOut = false;
@ -154,18 +132,18 @@ namespace Omegasis.NightOwl
{
this.ShouldResetPlayerAfterCollapseNow = false;
if (this.KeepStaminaAfterCollapse)
if (this.Config.KeepStaminaAfterCollapse)
Game1.player.stamina = this.PreCollapseStamina;
if (this.KeepHealthAfterCollapse)
if (this.Config.KeepHealthAfterCollapse)
Game1.player.health = this.PreCollapseHealth;
if (this.KeepMoneyAfterCollapse)
if (this.Config.KeepMoneyAfterCollapse)
Game1.player.money = this.PreCollapseMoney;
if (this.KeepPositionAfterCollapse)
if (this.Config.KeepPositionAfterCollapse)
Game1.warpFarmer(this.PreCollapseMap, this.PreCollapseTile.X, this.PreCollapseTile.Y, false);
}
// delete annoying charge messages (if only I could do this with mail IRL)
if (this.SkipCollapseMail)
if (this.Config.SkipCollapseMail)
{
string[] validMail = Game1.mailbox
.Where(p => !p.Contains("passedOut"))
@ -196,14 +174,14 @@ namespace Omegasis.NightOwl
try
{
// 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;
Game1.outdoorLight = Game1.ambientLight * colorMod;
}
// 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.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>
private void WriteErrorLog()
{
try
var state = new
{
JsonSerializer serializer = new JsonSerializer
{
NullValueHandling = NullValueHandling.Ignore,
TypeNameHandling = TypeNameHandling.All,
Formatting = Formatting.Indented,
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
this.Config,
this.IsUpLate,
this.ShouldResetPlayerAfterCollapseNow,
this.JustStartedNewDay,
this.JustCollapsed,
this.PreCollapseMap,
this.PreCollapseTile,
this.PreCollapseMoney,
this.PreCollapseStamina,
this.PreCollapseHealth
};
string path = Path.Combine(this.Helper.DirectoryPath, "Error_Logs", "Mod_State.json");
using (StreamWriter sw = new StreamWriter(path))
{
using (JsonWriter writer2 = new JsonTextWriter(sw))
serializer.Serialize(writer2, this);
}
}
catch (Exception ex)
{
this.Monitor.Log(ex.ToString(), LogLevel.Error);
}
this.Helper.WriteJsonFile(path, state);
}
}
}

View File

@ -30,10 +30,6 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<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.Xml" />
</ItemGroup>
@ -41,6 +37,7 @@
<Compile Include="..\GlobalAssemblyInfo.cs">
<Link>Properties\GlobalAssemblyInfo.cs</Link>
</Compile>
<Compile Include="Framework\ModConfig.cs" />
<Compile Include="NightOwl.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</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
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
1.0:
@ -25,4 +25,5 @@ Edit the `Night_Owl_Config_.txt` to change the mod settings.
1.4:
* Updated for SMAPI 2.0.
* Switched to standard JSON config file.
* Internal refactoring.

View File

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

View File

@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Omegasis.SaveAnywhere.Framework;
using StardewModdingAPI;
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:
* Updated for SMAPI 2.0.
* Switched to standard JSON config file.
* Internal refactoring.

View File

@ -2,6 +2,7 @@
using System.IO;
using System.IO.Compression;
using System.Linq;
using Omegasis.SaveBackup.Framework;
using StardewModdingAPI;
using StardewModdingAPI.Events;
@ -25,8 +26,8 @@ namespace Omegasis.SaveBackup
/// <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");
/// <summary>The number of save backups to keep for each type.</summary>
private int SaveCount = 30;
/// <summary>The mod configuration.</summary>
private ModConfig Config;
/*********
@ -36,8 +37,7 @@ namespace Omegasis.SaveBackup
/// <param name="helper">Provides simplified APIs for writing mods.</param>
public override void Entry(IModHelper helper)
{
this.LoadConfig();
this.WriteConfig();
this.Config = helper.ReadConfig<ModConfig>();
this.BackupSaves(SaveBackup.PrePlayBackupsPath);
@ -68,33 +68,9 @@ namespace Omegasis.SaveBackup
new DirectoryInfo(folderPath)
.EnumerateFiles()
.OrderByDescending(f => f.CreationTime)
.Skip(this.SaveCount)
.Skip(this.Config.SaveCount)
.ToList()
.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">
<Link>Properties\GlobalAssemblyInfo.cs</Link>
</Compile>
<Compile Include="Framework\ModConfig.cs" />
<Compile Include="SaveBackup.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</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:
* Updated for SMAPI 2.0.
* Switched to standard JSON config file.
* Internal refactoring.

View File

@ -25,6 +25,9 @@ namespace Omegasis.StardewSymphony
/*********
** Properties
*********/
/// <summary>The mod configuration.</summary>
private ModConfig Config;
/// <summary>All of the music/soundbanks and their locations.</summary>
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>
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
@ -83,6 +71,7 @@ namespace Omegasis.StardewSymphony
/// <param name="helper">Provides simplified APIs for writing mods.</param>
public override void Entry(IModHelper helper)
{
this.Config = helper.ReadConfig<ModConfig>();
this.HexProcessor = new MusicHexProcessor(this.MasterList, this.Reset);
SaveEvents.AfterLoad += this.SaveEvents_AfterLoad;
@ -122,7 +111,7 @@ namespace Omegasis.StardewSymphony
return; // replace with festival
if (Game1.eventUp)
return; // replace with event music
if (Game1.isRaining && !this.SilentRain)
if (Game1.isRaining && !this.Config.SilentRain)
return; // play the rain ambience soundtrack
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)
{
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();
}
@ -146,10 +132,6 @@ namespace Omegasis.StardewSymphony
/// <param name="e">The event data.</param>
private void SaveEvents_AfterLoad(object sender, EventArgs e)
{
// init config
this.LoadConfig();
this.WriteConfig();
// init context
this.Random = new Random();
this.MasterList = new List<MusicManager>();
@ -192,7 +174,7 @@ namespace Omegasis.StardewSymphony
{
// reset timer
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
this.SongDelayTimer.Elapsed += (sender, args) =>
@ -364,7 +346,7 @@ namespace Omegasis.StardewSymphony
if (this.HasNoMusic) //if there is valid music playing
{
if (!this.PlaySeasonalMusic)
if (!this.Config.PlaySeasonalMusic)
return;
if (this.CurrentSong != null && this.CurrentSong.IsPlaying)
@ -1185,49 +1167,5 @@ namespace Omegasis.StardewSymphony
Game1.waveBank = this.DefaultWavebank;
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">
<Link>Properties\GlobalAssemblyInfo.cs</Link>
</Compile>
<Compile Include="Framework\ModConfig.cs" />
<Compile Include="StardewSymphony.cs" />
<Compile Include="Framework\MusicHexProcessor.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.
1.2:
* Switched to standard JSON config file.
* Internal refactoring.

View File

@ -1,5 +1,5 @@
using System;
using System.IO;
using Omegasis.TimeFreeze.Framework;
using StardewModdingAPI;
using StardewModdingAPI.Events;
using StardewValley;
@ -13,11 +13,8 @@ namespace Omegasis.TimeFreeze
/*********
** Properties
*********/
/// <summary>Whether time should be unfrozen while the player is swimming.</summary>
private bool PassTimeWhileSwimming = true;
/// <summary>Whether time should be unfrozen while the player is swimming in the vanilla bathhouse.</summary>
private bool PassTimeWhileSwimmingInBathhouse = true;
/// <summary>The mod configuration.</summary>
private ModConfig Config;
/*********
@ -27,8 +24,9 @@ namespace Omegasis.TimeFreeze
/// <param name="helper">Provides simplified APIs for writing mods.</param>
public override void Entry(IModHelper helper)
{
this.Config = helper.ReadConfig<ModConfig>();
GameEvents.UpdateTick += this.GameEvents_UpdateTick;
this.LoadConfig();
}
/*********
@ -55,44 +53,12 @@ namespace Omegasis.TimeFreeze
return false;
if (player.swimming)
{
if (this.PassTimeWhileSwimmingInBathhouse && location is BathHousePool)
if (this.Config.PassTimeWhileSwimmingInBathhouse && location is BathHousePool)
return false;
if (this.PassTimeWhileSwimming)
if (this.Config.PassTimeWhileSwimming)
return false;
}
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">
<Link>Properties\GlobalAssemblyInfo.cs</Link>
</Compile>
<Compile Include="Framework\ModConfig.cs" />
<Compile Include="TimeFreeze.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>