From 2a9c8d43df156ba2b6eb32c690eba4a80167a549 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Wed, 7 Jun 2017 02:08:20 -0400 Subject: add date utility --- src/StardewModdingAPI/StardewModdingAPI.csproj | 3 +- src/StardewModdingAPI/Utilities/SDate.cs | 131 +++++++++++++++++++++++++ 2 files changed, 133 insertions(+), 1 deletion(-) create mode 100644 src/StardewModdingAPI/Utilities/SDate.cs (limited to 'src/StardewModdingAPI') 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 @@ + @@ -273,4 +274,4 @@ - + \ 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 +{ + /// Represents a Stardew Valley date. + public class SDate + { + /********* + ** Properties + *********/ + /// The internal season names in order. + private readonly string[] Seasons = { "spring", "summer", "fall", "winter" }; + + /// The number of days in a season. + private readonly int DaysInSeason = 28; + + + /********* + ** Accessors + *********/ + /// The day of month. + public int Day { get; } + + /// The season name. + public string Season { get; } + + /// The year. + public int Year { get; } + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// The day of month. + /// The season name. + /// One of the arguments has an invalid value (like day 35). + public SDate(int day, string season) + : this(day, season, Game1.year) { } + + /// Construct an instance. + /// The day of month. + /// The season name. + /// The year. + /// One of the arguments has an invalid value (like day 35). + 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; + } + + /// Get a new date with the given number of days added. + /// The number of days to add. + /// Returns the resulting date. + /// The offset would result in an invalid date (like year 0). + 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); + } + + /// Get a string representation of the date. This is mainly intended for debugging or console messages. + public override string ToString() + { + return $"{this.Day:00} {this.Season} Y{this.Year}"; + } + + /// Get the current in-game date. + public static SDate Now() + { + return new SDate(Game1.dayOfMonth, Game1.currentSeason, Game1.year); + } + + + /********* + ** Private methods + *********/ + /// Get the real index in an array which should be treated as a two-way loop. + /// The index in the looped array. + /// The number of elements in the array. + private int GetWrappedIndex(int index, int length) + { + int wrapped = index % length; + if (wrapped < 0) + wrapped += length; + return wrapped; + } + } +} -- cgit