diff options
author | Jesse Plamondon-Willard <github@jplamondonw.com> | 2017-06-07 02:08:20 -0400 |
---|---|---|
committer | Jesse Plamondon-Willard <github@jplamondonw.com> | 2017-06-07 02:08:20 -0400 |
commit | 2a9c8d43df156ba2b6eb32c690eba4a80167a549 (patch) | |
tree | c3d90e9aafa1b2aa55a9dffc42bf9313a0392ffa /src/StardewModdingAPI | |
parent | 57d20614b8dd3a6e468e81dafb611064119087ad (diff) | |
download | SMAPI-2a9c8d43df156ba2b6eb32c690eba4a80167a549.tar.gz SMAPI-2a9c8d43df156ba2b6eb32c690eba4a80167a549.tar.bz2 SMAPI-2a9c8d43df156ba2b6eb32c690eba4a80167a549.zip |
add date utility
Diffstat (limited to 'src/StardewModdingAPI')
-rw-r--r-- | src/StardewModdingAPI/StardewModdingAPI.csproj | 3 | ||||
-rw-r--r-- | src/StardewModdingAPI/Utilities/SDate.cs | 131 |
2 files changed, 133 insertions, 1 deletions
diff --git a/src/StardewModdingAPI/StardewModdingAPI.csproj b/src/StardewModdingAPI/StardewModdingAPI.csproj index ae454a35..7cc537ac 100644 --- a/src/StardewModdingAPI/StardewModdingAPI.csproj +++ b/src/StardewModdingAPI/StardewModdingAPI.csproj @@ -202,6 +202,7 @@ <Compile Include="IReflectionHelper.cs" /> <Compile Include="SemanticVersion.cs" /> <Compile Include="Translation.cs" /> + <Compile Include="Utilities\SDate.cs" /> </ItemGroup> <ItemGroup> <None Include="App.config"> @@ -273,4 +274,4 @@ <!-- Somehow this makes Visual Studio for Mac recognise the previous section. --> <!-- Nobody knows why. --> <PropertyGroup Condition="'$(RunConfiguration)' == 'Default'" /> -</Project> +</Project>
\ No newline at end of file diff --git a/src/StardewModdingAPI/Utilities/SDate.cs b/src/StardewModdingAPI/Utilities/SDate.cs new file mode 100644 index 00000000..4729bfb9 --- /dev/null +++ b/src/StardewModdingAPI/Utilities/SDate.cs @@ -0,0 +1,131 @@ +using System; +using System.Linq; +using StardewValley; + +namespace StardewModdingAPI.Utilities +{ + /// <summary>Represents a Stardew Valley date.</summary> + public class SDate + { + /********* + ** Properties + *********/ + /// <summary>The internal season names in order.</summary> + private readonly string[] Seasons = { "spring", "summer", "fall", "winter" }; + + /// <summary>The number of days in a season.</summary> + private readonly int DaysInSeason = 28; + + + /********* + ** Accessors + *********/ + /// <summary>The day of month.</summary> + public int Day { get; } + + /// <summary>The season name.</summary> + public string Season { get; } + + /// <summary>The year.</summary> + public int Year { get; } + + + /********* + ** Public methods + *********/ + /// <summary>Construct an instance.</summary> + /// <param name="day">The day of month.</param> + /// <param name="season">The season name.</param> + /// <exception cref="ArgumentException">One of the arguments has an invalid value (like day 35).</exception> + public SDate(int day, string season) + : this(day, season, Game1.year) { } + + /// <summary>Construct an instance.</summary> + /// <param name="day">The day of month.</param> + /// <param name="season">The season name.</param> + /// <param name="year">The year.</param> + /// <exception cref="ArgumentException">One of the arguments has an invalid value (like day 35).</exception> + public SDate(int day, string season, int year) + { + // validate + if (season == null) + throw new ArgumentNullException(nameof(season)); + if (!this.Seasons.Contains(season)) + throw new ArgumentException($"Unknown season '{season}', must be one of [{string.Join(", ", this.Seasons)}]."); + if (day < 1 || day > this.DaysInSeason) + throw new ArgumentException($"Invalid day '{day}', must be a value from 1 to {this.DaysInSeason}."); + if (year < 1) + throw new ArgumentException($"Invalid year '{year}', must be at least 1."); + + // initialise + this.Day = day; + this.Season = season; + this.Year = year; + } + + /// <summary>Get a new date with the given number of days added.</summary> + /// <param name="offset">The number of days to add.</param> + /// <returns>Returns the resulting date.</returns> + /// <exception cref="ArithmeticException">The offset would result in an invalid date (like year 0).</exception> + public SDate AddDays(int offset) + { + // simple case + int day = this.Day + offset; + string season = this.Season; + int year = this.Year; + + // handle season transition + if (day > this.DaysInSeason || day < 1) + { + // get current season index + int curSeasonIndex = Array.IndexOf(this.Seasons, this.Season); + if (curSeasonIndex == -1) + throw new InvalidOperationException($"The current season '{this.Season}' wasn't recognised."); + + // get season offset + int seasonOffset = day / this.DaysInSeason; + if (day < 1) + seasonOffset -= 1; + + // get new date + day = this.GetWrappedIndex(day, this.DaysInSeason); + season = this.Seasons[this.GetWrappedIndex(curSeasonIndex + seasonOffset, this.Seasons.Length)]; + year += seasonOffset / this.Seasons.Length; + } + + // validate + if(year < 1) + throw new ArithmeticException($"Adding {offset} days to {this} would result in invalid date {day:00} {season} {year}."); + + // return new date + return new SDate(day, season, year); + } + + /// <summary>Get a string representation of the date. This is mainly intended for debugging or console messages.</summary> + public override string ToString() + { + return $"{this.Day:00} {this.Season} Y{this.Year}"; + } + + /// <summary>Get the current in-game date.</summary> + public static SDate Now() + { + return new SDate(Game1.dayOfMonth, Game1.currentSeason, Game1.year); + } + + + /********* + ** Private methods + *********/ + /// <summary>Get the real index in an array which should be treated as a two-way loop.</summary> + /// <param name="index">The index in the looped array.</param> + /// <param name="length">The number of elements in the array.</param> + private int GetWrappedIndex(int index, int length) + { + int wrapped = index % length; + if (wrapped < 0) + wrapped += length; + return wrapped; + } + } +} |