diff --git a/Almanac/Almanac.csproj b/Almanac/Almanac.csproj
index 46c5492..c1365fb 100644
--- a/Almanac/Almanac.csproj
+++ b/Almanac/Almanac.csproj
@@ -4,11 +4,16 @@
Almanac
0.18.1
Leclair.Stardew.Almanac
-
true
true
+ net6.0
+ Crafting;BCInventory;Inventory;GMCM;Mutex;Overlay;UI;SimpleLayout;Flow;SpookyAction;ThemeManager
-
-
+
+
+
+
+
+
diff --git a/Almanac/AssetManager.cs b/Almanac/AssetManager.cs
index 10b63aa..9591d15 100644
--- a/Almanac/AssetManager.cs
+++ b/Almanac/AssetManager.cs
@@ -146,18 +146,18 @@ private void Load(string? locale) {
Locale = locale;
}
-public struct EventData {
- public static readonly Regex I18N_SPLITTER = new(@"{{(.+?)}}", RegexOptions.Compiled);
+ public struct EventData {
+ public static readonly Regex I18N_SPLITTER = new(@"{{(.+?)}}", RegexOptions.Compiled);
- public string Id { get; set; }
- public string[] Conditions { get; set; }
- public string[] Script { get; set; }
+ public string Id { get; set; }
+ public string[] Conditions { get; set; }
+ public string[] Script { get; set; }
- public string Key => $"{Id}/{string.Join("/", Conditions)}";
- public string RealScript => string.Join("/", Script);
+ public string Key => $"{Id}/{string.Join("/", Conditions)}";
+ public string RealScript => string.Join("/", Script);
- public string Localize(ITranslationHelper helper) {
- string id = Id;
+ public string Localize(ITranslationHelper helper) {
+ string id = Id;
return I18N_SPLITTER.Replace(RealScript, match => {
string key = match.Groups[1].Value;
diff --git a/Almanac/Crops/CropPage.cs b/Almanac/Crops/CropPage.cs
index 5efa34b..e9edbd7 100644
--- a/Almanac/Crops/CropPage.cs
+++ b/Almanac/Crops/CropPage.cs
@@ -263,7 +263,7 @@ public CropPage(AlmanacMenu menu, ModEntry mod) : base(menu, mod) {
rightNeighborID = ClickableComponent.SNAP_AUTOMATIC
};
tabSeedsSprite = Game1.random.Next(2 * AlmanacMenu.TABS.Length);
- spriteSeeds = SpriteHelper.GetSprite(InventoryHelper.CreateItemById("(O)495", 1));
+ spriteSeeds = SpriteHelper.GetSprite(ItemRegistry.Create("(O)495"));
// Cache Agriculturist status.
Agriculturist = Game1.player.professions.Contains(Farmer.agriculturist);
@@ -350,7 +350,7 @@ public override void Update() {
break;
}
- spriteSeeds = SpriteHelper.GetSprite(InventoryHelper.CreateItemById(seasonSeeds, 1));
+ spriteSeeds = SpriteHelper.GetSprite(ItemRegistry.Create(seasonSeeds));
LastDays = new List[ModEntry.DaysPerMonth];
diff --git a/Almanac/FishHelper.cs b/Almanac/FishHelper.cs
index 89546f7..044fc2e 100644
--- a/Almanac/FishHelper.cs
+++ b/Almanac/FishHelper.cs
@@ -122,7 +122,7 @@ public static Dictionary>> GetFishLoca
//Dictionary
Dictionary>> result = new();
//Dictionary
- var locations = Game1.content.Load>("Data\\Locations");
+ var locations = Game1.content.Load>(@"Data\Locations");
foreach (var lp in locations) {
if (SkipLocation(lp.Key))
@@ -164,7 +164,7 @@ public static Dictionary>> GetFishLoca
public static Dictionary> GetFishLocations(int season) {
Dictionary> result = new();
- var locations = Game1.content.Load>("Data\\Locations");
+ var locations = Game1.content.Load>(@"Data\Locations");
foreach (var lp in locations) {
if (SkipLocation(lp.Key))
continue;
@@ -197,7 +197,7 @@ public static Dictionary> GetLocationFish(string key, int s
if (key == "BeachNightMarket")
key = "Beach";
- locations ??= Game1.content.Load>("Data\\Locations");
+ locations ??= Game1.content.Load>(@"Data\Locations");
Dictionary> result;
GameLocation loc;
if (locations.ContainsKey(key) && ContainsFish(locations[key]))
@@ -262,7 +262,7 @@ public static Dictionary> GetLocationFish(string key, int s
}
}
try{
- GetLocationFish(season, locations[Game1.GetFarmTypeKey()], result);
+ GetLocationFish(season, locations[Game1.GetFarmTypeID()], result);
} catch {
ModEntry.Instance.Log($"Error at {getLocName(locations[Game1.GetFarmTypeKey()])}, farm key section.", LogLevel.Warn);
}
@@ -288,10 +288,10 @@ public static Dictionary> GetLocationFish(int season, Locat
if (data.Equals(null))
return existing;
- string name = getLocName(data);
+ string name = data.DisplayName;
List entries = data.Fish;
- if (!data.Equals(Game1.content.Load>("Data\\Locations")["Default"])) {
- LocationData Default = Game1.content.Load>("Data\\Locations")["Default"];
+ if (!data.Equals(DataLoader.Locations(Game1.content)["Default"])) {
+ LocationData Default = DataLoader.Locations(Game1.content)["Default"];
foreach (SpawnFishData f in Default.Fish)
if (!entries.Contains(f))
entries.Add(f);
@@ -316,8 +316,19 @@ public static bool ContainsFish(LocationData loc) {
return false;
}
private static string getLocName(LocationData data) {
- string name = data.DisplayName == null ? "No DisplayName" : data.DisplayName;
+ string name = data.DisplayName ?? "No DisplayName";
string endCheck = name.Substring(name.Length - 7);
+ switch (name) {
+ case "Farm_Standard":
+ case "Farm_Forest":
+ case "Farm_FourCorners":
+ case "Farm_Hilltop":
+ case "Farm_Riverland":
+ case "Farm_Wilderness":
+ case "Farm_Beach":
+ name = "Farm";
+ break;
+ }
switch (endCheck) {
case "Name]]]":
name = "Farm";
@@ -344,7 +355,7 @@ private static string getLocName(LocationData data) {
name = "Woods";
break;
}
- if (name.Length > 25) name = endCheck;
+ //if (name.Length > 25) name = endCheck;
return name;
}
private static bool canAddFish(SpawnFishData fish, int season, LocationData data) {
diff --git a/Almanac/Managers/LuckManager.cs b/Almanac/Managers/LuckManager.cs
index a2c67d4..7df9c89 100644
--- a/Almanac/Managers/LuckManager.cs
+++ b/Almanac/Managers/LuckManager.cs
@@ -19,6 +19,7 @@
using StardewValley;
using Leclair.Stardew.Almanac.Models;
+using StardewValley.TokenizableStrings;
namespace Leclair.Stardew.Almanac.Managers;
@@ -183,7 +184,7 @@ public void RegisterHook(IManifest mod, Func GetEventsForDate(ulong seed, WorldDate date) {
Load();
- var state = new Common.GameStateQuery.GameState(
- Random: Game1.random,
- Date: date,
- TimeOfDay: 600,
- Ticks: 0,
- Farmer: Game1.player,
- Location: null,
- Item: null,
- Monitor: Mod.Monitor,
- DoTrace: false
- );
if (DataEvents != null)
foreach (var entry in DataEvents) {
- IRichEvent? hydrated = HydrateEvent(entry.Value, date, state, entry.Key);
+ IRichEvent? hydrated = HydrateEvent(entry.Value, date, entry.Key);
if (hydrated != null)
yield return hydrated;
}
@@ -451,7 +441,7 @@ public IEnumerable GetEventsForDate(ulong seed, WorldDate date) {
public static IRichEvent? GetTrashEvent(ulong seed, WorldDate date) {
for (int i = 0; i < 8; i++) {
- Random rnd = new((date.TotalDays + 1) + ((int)seed / 2) + 777 + i * 77);
+ Random rnd = new((date.TotalDays + 1) + ((int) seed / 2) + 777 + i * 77);
int prewarm = rnd.Next(0, 100);
for (int j = 0; j < prewarm; j++)
@@ -466,7 +456,7 @@ public IEnumerable GetEventsForDate(ulong seed, WorldDate date) {
if (rnd.NextDouble() >= 0.002)
continue;
- Item? item = InventoryHelper.CreateItemById("(H)66", 1);
+ Item? item = ItemRegistry.Create("(H)66", 1);
SpriteInfo? sprite = SpriteHelper.GetSprite(item);
return new RichEvent(
@@ -485,7 +475,7 @@ public IEnumerable GetEventsForDate(ulong seed, WorldDate date) {
if (days == 31)
return null;
- Random rnd = new(days + (int)seed / 2);
+ Random rnd = new(days + (int) seed / 2);
// Don't track any of the Community Center / Joja events because
// those all rely on game state and are not random based on the
@@ -535,10 +525,11 @@ public IEnumerable GetEventsForDate(ulong seed, WorldDate date) {
I18n.Page_Fortune_Event_Ufo(),
null,
SpriteHelper.GetSprite(new SObject(Vector2.Zero, 96))
- );*/
+ );
+ */
- return null;
- }
+ return null;
+ }
private static IRichEvent? GetLuckSkillEventForDate(ulong seed, WorldDate date) {
int days = date.TotalDays + 1 + 999999;
@@ -596,12 +587,10 @@ public IEnumerable GetEventsForDate(ulong seed, WorldDate date) {
SpriteHelper.GetSprite(new SObject(Vector2.Zero, "95"))
);
- // Don't track Strange Capsule, because that relies on whether
- // or not the player has already seen it.
-
return null;
}
- #endregion
+#endregion
}
+
diff --git a/Almanac/Managers/NoticesManager.cs b/Almanac/Managers/NoticesManager.cs
index d2c9b8e..d5e0ad5 100644
--- a/Almanac/Managers/NoticesManager.cs
+++ b/Almanac/Managers/NoticesManager.cs
@@ -25,6 +25,7 @@
using StardewValley.GameData.Shops;
using StardewValley.Internal;
using StardewValley.GameData;
+using StardewValley.TokenizableStrings;
namespace Leclair.Stardew.Almanac.Managers;
@@ -54,7 +55,7 @@ public void Invalidate() {
[Subscriber]
private void OnAssetInvalidated(object? sender, AssetsInvalidatedEventArgs e) {
- foreach(var name in e.Names)
+ foreach (var name in e.Names)
if (name.IsEquivalentTo(AssetManager.LocalNoticesPath)) {
Loaded = false;
DataEvents = null;
@@ -109,699 +110,689 @@ private Dictionary LoadEvents() {
}
[MemberNotNull(nameof(DataEvents))]
- private void Load() {
- if (Loaded && DataEvents != null)
- return;
+private void Load() {
+ if (Loaded && DataEvents != null)
+ return;
- DataEvents = Mod.Helper.GameContent.Load>(AssetManager.LocalNoticesPath);
- Loaded = true;
- }
-
- #endregion
-
- #region Mod Management
+ DataEvents = Mod.Helper.GameContent.Load>(AssetManager.LocalNoticesPath);
+ Loaded = true;
+}
- public void ClearHook(IManifest mod) {
- if (InterfaceHooks.ContainsKey(mod))
- InterfaceHooks.Remove(mod);
+#endregion
- if (ModHooks.ContainsKey(mod))
- ModHooks.Remove(mod);
- }
+#region Mod Management
- public void RegisterHook(IManifest mod, Func>> hook) {
- if (InterfaceHooks.ContainsKey(mod))
- InterfaceHooks.Remove(mod);
+public void ClearHook(IManifest mod) {
+ if (InterfaceHooks.ContainsKey(mod))
+ InterfaceHooks.Remove(mod);
- if (hook == null && ModHooks.ContainsKey(mod))
- ModHooks.Remove(mod);
- else if (hook != null)
- ModHooks[mod] = hook;
- }
+ if (ModHooks.ContainsKey(mod))
+ ModHooks.Remove(mod);
+}
- public void RegisterHook(IManifest mod, Func> hook) {
- if (ModHooks.ContainsKey(mod))
- ModHooks.Remove(mod);
+public void RegisterHook(IManifest mod, Func>> hook) {
+ if (InterfaceHooks.ContainsKey(mod))
+ InterfaceHooks.Remove(mod);
- if (hook == null && InterfaceHooks.ContainsKey(mod))
- InterfaceHooks.Remove(mod);
- else if (hook != null)
- InterfaceHooks[mod] = hook;
- }
+ if (hook == null && ModHooks.ContainsKey(mod))
+ ModHooks.Remove(mod);
+ else if (hook != null)
+ ModHooks[mod] = hook;
+}
- #endregion
+public void RegisterHook(IManifest mod, Func> hook) {
+ if (ModHooks.ContainsKey(mod))
+ ModHooks.Remove(mod);
- #region Events
+ if (hook == null && InterfaceHooks.ContainsKey(mod))
+ InterfaceHooks.Remove(mod);
+ else if (hook != null)
+ InterfaceHooks[mod] = hook;
+}
- public IRichEvent? HydrateEvent(LocalNotice notice, WorldDate date, Common.GameStateQuery.GameState state, string? key = null) {
- if (notice == null)
- return null;
+#endregion
- // Year Validation
- if (notice.FirstYear > date.Year || notice.LastYear < date.Year)
- return null;
+#region Events
- if (notice.ValidYears != null && !notice.ValidYears.Contains(date.Year))
- return null;
+public IRichEvent? HydrateEvent(LocalNotice notice, WorldDate date, string? key = null) {
+ if (notice == null)
+ return null;
- // Season Validation
- if (notice.ValidSeasons != null && !notice.ValidSeasons.Contains(Common.Enums.Season.All) && !notice.ValidSeasons.Contains((Common.Enums.Season) date.SeasonIndex))
- return null;
+ // Year Validation
+ if (notice.FirstYear > date.Year || notice.LastYear < date.Year)
+ return null;
- // Date Range Validation
- int day;
-
- bool first = true;
-
- switch(notice.Period) {
- case TimeScale.Year:
- day = date.TotalDays % (WorldDate.MonthsPerYear * ModEntry.DaysPerMonth);
- break;
- case TimeScale.Season:
- day = date.DayOfMonth;
- break;
- case TimeScale.Week:
- day = date.DayOfMonth % 7;
- break;
- default:
- day = -1;
- break;
- }
+ if (notice.ValidYears != null && !notice.ValidYears.Contains(date.Year))
+ return null;
- if (notice.Ranges != null) {
- bool matched = false;
- first = false;
- foreach (var range in notice.Ranges) {
- if (range.Start <= day && range.End >= day && (range.Valid == null || range.Valid.Contains(day))) {
- if (range.Start == day)
- first = true;
- matched = true;
- }
- }
+ // Season Validation
+ if (notice.ValidSeasons != null && !notice.ValidSeasons.Contains(Common.Enums.Season.All) && !notice.ValidSeasons.Contains((Common.Enums.Season) date.SeasonIndex))
+ return null;
- if (!matched)
- return null;
- }
+ // Date Range Validation
+ int day;
- // Condition Validation
- if (!string.IsNullOrEmpty(notice.Condition) && !Common.GameStateQuery.CheckConditions(notice.Condition, state))
- return null;
+ bool first = true;
- // Get icon
- Item? item = null;
- SpriteInfo? sprite;
+ switch (notice.Period) {
+ case TimeScale.Year:
+ day = date.TotalDays % (WorldDate.MonthsPerYear * ModEntry.DaysPerMonth);
+ break;
+ case TimeScale.Season:
+ day = date.DayOfMonth;
+ break;
+ case TimeScale.Week:
+ day = date.DayOfMonth % 7;
+ break;
+ default:
+ day = -1;
+ break;
+ }
- // Try parsing the item.
- // This will change in 1.6
- if (!string.IsNullOrEmpty(notice.Item)) {
- try {
- item = InventoryHelper.CreateItemById(notice.Item, 1);
- } catch(Exception ex) {
- Log($"Unable to get item instance for: {notice.Item}", LogLevel.Warn, ex);
- item = null;
+ if (notice.Ranges != null) {
+ bool matched = false;
+ first = false;
+ foreach (var range in notice.Ranges) {
+ if (range.Start <= day && range.End >= day && (range.Valid == null || range.Valid.Contains(day))) {
+ if (range.Start == day)
+ first = true;
+ matched = true;
}
}
- if (notice.IconType == NoticeIconType.Item) {
- sprite = item == null ? null : SpriteHelper.GetSprite(item);
-
- } else if (notice.IconType == NoticeIconType.ModTexture) {
- Texture2D? tex;
- if (!string.IsNullOrEmpty(notice.IconPath) && notice.ModContent != null)
- tex = notice.ModContent.Load(notice.IconPath);
- else
- tex = null;
-
- sprite = tex == null ? null : new SpriteInfo(
- tex,
- notice.IconSourceRect ?? tex.Bounds
- );
-
- } else if (notice.IconType == NoticeIconType.Texture) {
- Texture2D? tex;
- if (!string.IsNullOrEmpty(notice.IconPath))
- tex = Mod.Helper.GameContent.Load(notice.IconPath);
- else if (notice.IconSource.HasValue)
- tex = SpriteHelper.GetTexture(notice.IconSource.Value);
- else
- tex = null;
-
- sprite = tex == null ? null : new SpriteInfo(
- tex,
- notice.IconSourceRect ?? tex.Bounds
- );
+ if (!matched)
+ return null;
+ }
- } else {
+ // Condition Validation
+ if (!string.IsNullOrEmpty(notice.Condition) && !GameStateQuery.CheckConditions(notice.Condition))
+ return null;
+
+ // Get icon
+ Item? item = null;
+ SpriteInfo? sprite;
+
+ // Try parsing the item.
+ // This will change in 1.6
+ if (!string.IsNullOrEmpty(notice.Item)) {
+ try {
+ item = ItemRegistry.Create(notice.Item, 1);
+ } catch (Exception ex) {
+ Log($"Unable to get item instance for: {notice.Item}", LogLevel.Warn, ex);
item = null;
- sprite = null;
}
+ }
+
+ if (notice.IconType == NoticeIconType.Item) {
+ sprite = item == null ? null : SpriteHelper.GetSprite(item);
- if (notice.Translation != null && ! string.IsNullOrEmpty(notice.I18nKey))
- notice.Description = notice.Translation.Get(notice.I18nKey).ToString();
+ } else if (notice.IconType == NoticeIconType.ModTexture) {
+ Texture2D? tex;
+ if (!string.IsNullOrEmpty(notice.IconPath) && notice.ModContent != null)
+ tex = notice.ModContent.Load(notice.IconPath);
+ else
+ tex = null;
- string? desc = string.IsNullOrEmpty(notice.Description) ? null : StringTokenizer.ParseString(notice.Description, state);
- if (desc != null && Mod.Config.DebugMode && !string.IsNullOrEmpty(key))
- desc = $"{desc} @C@c@h(#{key})";
+ sprite = tex == null ? null : new SpriteInfo(
+ tex,
+ notice.IconSourceRect ?? tex.Bounds
+ );
- return new RichEvent(
- (first || notice.ShowEveryDay) ? desc : null,
- null,
- sprite,
- item
+ } else if (notice.IconType == NoticeIconType.Texture) {
+ Texture2D? tex;
+ if (!string.IsNullOrEmpty(notice.IconPath))
+ tex = Mod.Helper.GameContent.Load(notice.IconPath);
+ else if (notice.IconSource.HasValue)
+ tex = SpriteHelper.GetTexture(notice.IconSource.Value);
+ else
+ tex = null;
+
+ sprite = tex == null ? null : new SpriteInfo(
+ tex,
+ notice.IconSourceRect ?? tex.Bounds
);
+
+ } else {
+ item = null;
+ sprite = null;
}
- public IEnumerable GetEventsForDate(int seed, WorldDate date) {
+ if (notice.Translation != null && !string.IsNullOrEmpty(notice.I18nKey))
+ notice.Description = notice.Translation.Get(notice.I18nKey).ToString();
- Load();
+ string? desc = string.IsNullOrEmpty(notice.Description) ? null : TokenParser.ParseText(notice.Description);
+ if (desc != null && Mod.Config.DebugMode && !string.IsNullOrEmpty(key))
+ desc = $"{desc} @C@c@h(#{key})";
- var state = new Common.GameStateQuery.GameState(
- Random: Game1.random,
- Date: date,
- TimeOfDay: 600,
- Ticks: 0,
- Farmer: Game1.player,
- Location: null,
- Item: null,
- Monitor: Mod.Monitor,
- DoTrace: false
- );
+ return new RichEvent(
+ (first || notice.ShowEveryDay) ? desc : null,
+ null,
+ sprite,
+ item
+ );
+}
- if (DataEvents != null)
- foreach(var entry in DataEvents) {
- IRichEvent? hydrated = HydrateEvent(entry.Value, date, state, entry.Key);
- if (hydrated != null)
- yield return hydrated;
- }
+public IEnumerable GetEventsForDate(int seed, WorldDate date) {
- foreach (var ihook in InterfaceHooks.Values) {
- if (ihook != null)
- foreach (var entry in ihook(seed, date)) {
- if (entry == null)
- continue;
+ Load();
- yield return entry;
- }
+ if (DataEvents != null)
+ foreach (var entry in DataEvents) {
+ IRichEvent? hydrated = HydrateEvent(entry.Value, date, entry.Key);
+ if (hydrated != null)
+ yield return hydrated;
}
- foreach (var hook in ModHooks.Values) {
- if (hook != null)
- foreach (var entry in hook(seed, date)) {
- if (entry == null || string.IsNullOrEmpty(entry.Item1))
- continue;
+ foreach (var ihook in InterfaceHooks.Values) {
+ if (ihook != null)
+ foreach (var entry in ihook(seed, date)) {
+ if (entry == null)
+ continue;
- SpriteInfo? sprite;
-
- if (entry.Item3.HasValue && entry.Item3.Value == Rectangle.Empty)
- sprite = null;
- else if (entry.Item2 != null)
- sprite = new(
- entry.Item2,
- entry.Item3 ?? entry.Item2.Bounds
- );
- else if (entry.Item4 != null)
- sprite = SpriteHelper.GetSprite(entry.Item4);
- else
- sprite = null;
+ yield return entry;
+ }
+ }
- yield return new RichEvent(
- entry.Item1,
- null,
- sprite,
- entry.Item4
- );
- }
- }
+ foreach (var hook in ModHooks.Values) {
+ if (hook != null)
+ foreach (var entry in hook(seed, date)) {
+ if (entry == null || string.IsNullOrEmpty(entry.Item1))
+ continue;
- foreach (var evt in GetVanillaEventsForDate(date)) {
- if (evt != null)
- yield return evt;
- }
- }
+ SpriteInfo? sprite;
- #endregion
+ if (entry.Item3.HasValue && entry.Item3.Value == Rectangle.Empty)
+ sprite = null;
+ else if (entry.Item2 != null)
+ sprite = new(
+ entry.Item2,
+ entry.Item3 ?? entry.Item2.Bounds
+ );
+ else if (entry.Item4 != null)
+ sprite = SpriteHelper.GetSprite(entry.Item4);
+ else
+ sprite = null;
- #region Vanilla Events
+ yield return new RichEvent(
+ entry.Item1,
+ null,
+ sprite,
+ entry.Item4
+ );
+ }
+ }
- public IEnumerable GetVanillaEventsForDate(WorldDate date) {
+ foreach (var evt in GetVanillaEventsForDate(date)) {
+ if (evt != null)
+ yield return evt;
+ }
+}
- // Berry Season
- bool gathering = Mod.Config.NoticesShowGathering;
+#endregion
- if (gathering && bush == null)
- bush = new();
+#region Vanilla Events
- if (gathering && IsBlooming(bush!, date.Season, date.DayOfMonth)) {
- Item? berry = null;
- if (date.SeasonIndex == 0)
- berry = ItemRegistry.Create("(O)296", 1); // Salmonberry
+public IEnumerable GetVanillaEventsForDate(WorldDate date) {
- else if (date.SeasonIndex == 2)
- berry = ItemRegistry.Create("(O)410", 1); // Blackberry
+ // Berry Season
+ bool gathering = Mod.Config.NoticesShowGathering;
- if (berry != null) {
- bool first_day = date.DayOfMonth == 1 || !IsBlooming(bush!, date.Season, date.DayOfMonth - 1);
- int last = date.DayOfMonth;
+ if (gathering && bush == null)
+ bush = new();
- // If it's the first day, then we also need the last day
- // so we can display a nice string to the user.
- if (first_day)
- for (int d = date.DayOfMonth + 1; d <= ModEntry.DaysPerMonth; d++) {
- if (IsBlooming(bush!, date.Season, d))
- last = d;
- else
- break;
- }
+ if (gathering && IsBlooming(bush!, date.Season, date.DayOfMonth)) {
+ Item? berry = null;
+ if (date.SeasonIndex == 0)
+ berry = ItemRegistry.Create("(O)296", 1); // Salmonberry
- yield return new RichEvent(
- null,
- first_day ?
- FlowHelper.Translate(
- Mod.Helper.Translation.Get("page.notices.season"),
- new {
- item = berry.DisplayName,
- start = new SDate(date.DayOfMonth, date.Season).ToLocaleString(withYear: false),
- end = new SDate(last, date.Season).ToLocaleString(withYear: false)
- },
- align: Alignment.VCenter
- ) : null,
- SpriteHelper.GetSprite(berry),
- berry
- );
- }
- }
+ else if (date.SeasonIndex == 2)
+ berry = ItemRegistry.Create("(O)410", 1); // Blackberry
- // Festivals
- if (Mod.Config.NoticesShowFestivals && Utility.isFestivalDay(date.DayOfMonth, date.Season)) {
- var data = Game1.temporaryContent.Load>("Data\\Festivals\\" + date.SeasonKey + date.DayOfMonth);
- if (data.ContainsKey("name") && data.ContainsKey("conditions")) {
- string name = data["name"];
- string[] conds = data["conditions"].Split('/');
- string? where = conds.Length >= 1 ? conds[0] : null;
-
- int start = -1;
- int end = -1;
-
- if (conds.Length >= 2) {
- string[] bits = conds[1].Split(' ');
- if (bits.Length >= 2) {
- start = Convert.ToInt32(bits[0]);
- end = Convert.ToInt32(bits[1]);
- }
- }
+ if (berry != null) {
+ bool first_day = date.DayOfMonth == 1 || !IsBlooming(bush!, date.Season, date.DayOfMonth - 1);
+ int last = date.DayOfMonth;
- foreach (GameLocation loc in Game1.locations) {
- if (loc?.Name == where) {
- where = Mod.GetLocationName(loc) ?? where;
+ // If it's the first day, then we also need the last day
+ // so we can display a nice string to the user.
+ if (first_day)
+ for (int d = date.DayOfMonth + 1; d <= ModEntry.DaysPerMonth; d++) {
+ if (IsBlooming(bush!, date.Season, d))
+ last = d;
+ else
break;
- }
}
- yield return new RichEvent(
- null,
+ yield return new RichEvent(
+ null,
+ first_day ?
FlowHelper.Translate(
- Mod.Helper.Translation.Get("page.notices.festival"),
+ Mod.Helper.Translation.Get("page.notices.season"),
new {
- name,
- where,
- start = Mod.FormatTime(start),
- end = Mod.FormatTime(end)
+ item = berry.DisplayName,
+ start = new SDate(date.DayOfMonth, date.Season).ToLocaleString(withYear: false),
+ end = new SDate(last, date.Season).ToLocaleString(withYear: false)
},
align: Alignment.VCenter
- ),
- new SpriteInfo(
- Game1.temporaryContent.Load("LooseSprites\\Billboard"),
- new Rectangle(
- 1, 398,
- 84, 12
- ),
- baseFrames: 6
- )
- );
+ ) : null,
+ SpriteHelper.GetSprite(berry),
+ berry
+ );
+ }
+ }
+
+ // Festivals
+ if (Mod.Config.NoticesShowFestivals && Utility.isFestivalDay(date.DayOfMonth, date.Season)) {
+ var data = Game1.temporaryContent.Load>("Data\\Festivals\\" + date.SeasonKey + date.DayOfMonth);
+ if (data.ContainsKey("name") && data.ContainsKey("conditions")) {
+ string name = data["name"];
+ string[] conds = data["conditions"].Split('/');
+ string? where = conds.Length >= 1 ? conds[0] : null;
+
+ int start = -1;
+ int end = -1;
+
+ if (conds.Length >= 2) {
+ string[] bits = conds[1].Split(' ');
+ if (bits.Length >= 2) {
+ start = Convert.ToInt32(bits[0]);
+ end = Convert.ToInt32(bits[1]);
+ }
+ }
+
+ foreach (GameLocation loc in Game1.locations) {
+ if (loc?.Name == where) {
+ where = Mod.GetLocationName(loc) ?? where;
+ break;
+ }
}
+
+ yield return new RichEvent(
+ null,
+ FlowHelper.Translate(
+ Mod.Helper.Translation.Get("page.notices.festival"),
+ new {
+ name,
+ where,
+ start = Mod.FormatTime(start),
+ end = Mod.FormatTime(end)
+ },
+ align: Alignment.VCenter
+ ),
+ new SpriteInfo(
+ Game1.temporaryContent.Load("LooseSprites\\Billboard"),
+ new Rectangle(
+ 1, 398,
+ 84, 12
+ ),
+ baseFrames: 6
+ )
+ );
}
+ }
- if (Mod.Config.NoticesShowFestivals && Utility.TryGetPassiveFestivalDataForDay(date.DayOfMonth, date.Season, null, out string id, out PassiveFestivalData passFestData)) {
- string displayDate = Utility.getDateStringFor(date.DayOfMonth, date.SeasonIndex, date.Year);
- if (passFestData.StartDay <= date.DayOfMonth && passFestData.EndDay >= date.DayOfMonth) {
- string festName = id;
- try {
- Dictionary content = Game1.content.Load>("Strings\\1_6_Strings");
- if (content.ContainsKey(id))
- festName = content[id];
- //These festivals aren't in 1_6_Strings
- switch (id) {
- case "NightMarket": {
+ if (Mod.Config.NoticesShowFestivals && Utility.TryGetPassiveFestivalDataForDay(date.DayOfMonth, date.Season, null, out string id, out PassiveFestivalData passFestData)) {
+ string displayDate = Utility.getDateStringFor(date.DayOfMonth, date.SeasonIndex, date.Year);
+ if (passFestData.StartDay <= date.DayOfMonth && passFestData.EndDay >= date.DayOfMonth) {
+ string festName = id;
+ try {
+ Dictionary content = Game1.content.Load>("Strings\\1_6_Strings");
+ if (content.ContainsKey(id))
+ festName = content[id];
+ //These festivals aren't in 1_6_Strings
+ switch (id) {
+ case "NightMarket": {
festName = "Night Market";
break;
}
- case "DesertFestival": {
+ case "DesertFestival": {
festName = "Desert Festival";
break;
}
- }
- } catch {
- ModEntry.Instance.Log("Cannot get festival name.", LogLevel.Warn);
}
- yield return new RichEvent(
- null,
- passFestData.StartDay == date.DayOfMonth? FlowHelper.Translate(
- Mod.Helper.Translation.Get("page.notices.passive-festival"),
- new {
- name = festName,
- startTime = Mod.FormatTime(passFestData.StartTime),
- startDay = Utility.getDateStringFor(passFestData.StartDay, Utility.getSeasonNumber(Utility.getSeasonKey(passFestData.Season)), 1),
- endDay = Utility.getDateStringFor(passFestData.EndDay, Utility.getSeasonNumber(Utility.getSeasonKey(passFestData.Season)), 1)
- },
- align: Alignment.VCenter
- ) : null,
- new SpriteInfo(
- Game1.mouseCursors,
- new Rectangle(346, 392, 8, 8)
- )
- );
- } else ModEntry.Instance.Log("Adding festival failed.", LogLevel.Warn);
- }
-
- // Weddings / Anniversaries / Children
- foreach (var who in Game1.getAllFarmers()) {
- // Children
- // TODO: This.
-
- if (!Mod.Config.NoticesShowAnniversaries)
- continue;
-
- // Player Weddings and Anniversaries
- // TODO: This.
-
- // NPC Weddings and Anniversaries
- if ((who.isEngaged() || who.isMarriedOrRoommates()) && who.friendshipData != null) {
- foreach (var entry in who.friendshipData.Pairs) {
- if (entry.Value == null || entry.Value.WeddingDate == null)
- continue;
+ } catch {
+ ModEntry.Instance.Log("Cannot get festival name.", LogLevel.Warn);
+ }
+ yield return new RichEvent(
+ null,
+ passFestData.StartDay == date.DayOfMonth ? FlowHelper.Translate(
+ Mod.Helper.Translation.Get("page.notices.passive-festival"),
+ new {
+ name = festName,
+ startTime = Mod.FormatTime(passFestData.StartTime),
+ startDay = Utility.getDateStringFor(passFestData.StartDay, Utility.getSeasonNumber(Utility.getSeasonKey(passFestData.Season)), 1),
+ endDay = Utility.getDateStringFor(passFestData.EndDay, Utility.getSeasonNumber(Utility.getSeasonKey(passFestData.Season)), 1)
+ },
+ align: Alignment.VCenter
+ ) : null,
+ new SpriteInfo(
+ Game1.mouseCursors,
+ new Rectangle(346, 392, 8, 8)
+ )
+ );
+ } else ModEntry.Instance.Log("Adding festival failed.", LogLevel.Warn);
+ }
- if (entry.Value.IsDivorced())
- continue;
+ // Weddings / Anniversaries / Children
+ foreach (var who in Game1.getAllFarmers()) {
+ // Children
+ // TODO: This.
- WorldDate? wedding = entry.Value.WeddingDate;
- if (wedding == null || wedding.SeasonIndex != date.SeasonIndex || wedding.DayOfMonth != date.DayOfMonth)
- continue;
+ if (!Mod.Config.NoticesShowAnniversaries)
+ continue;
- NPC? spouse = Game1.getCharacterFromName(entry.Key);
- if (spouse == null)
- continue;
-
- char last = spouse.displayName.Last();
-
- bool no_s = last == 's' ||
- LocalizedContentManager.CurrentLanguageCode ==
- LocalizedContentManager.LanguageCode.de &&
- (last == 'x' || last == 'ß' || last == 'z');
-
- var pendant = InventoryHelper.CreateItemById("(O)460", 1); // Mermaid Pendant
- var sprite = SpriteHelper.GetSprite(pendant);
-
- // Wedding?
- if (date.Year == wedding.Year) {
- yield return new RichEvent(
- null,
- FlowHelper.Translate(
- Mod.Helper.Translation.Get(
- no_s ?
- "page.notices.wedding.no-s"
- : "page.notices.wedding.s"
- ),
- new {
- name = who.displayName,
- spouse = spouse.displayName
- },
- align: Alignment.VCenter
- ),
- sprite
- );
- } else {
- yield return new RichEvent(
- null,
- FlowHelper.Translate(
- Mod.Helper.Translation.Get(
- no_s ?
- "page.notices.anniversary.no-s"
- : "page.notices.anniversary.s"
- ),
- new {
- name = who.displayName,
- spouse = spouse.displayName
- },
- align: Alignment.VCenter
- ),
- sprite
- );
- }
- }
- }
- }
+ // Player Weddings and Anniversaries
+ // TODO: This.
- // Trains
- if (Mod.Config.NoticesShowTrains) {
- int time = TrainHelper.GetTrainTime(date);
- if (time >= 0)
- yield return new RichEvent(
- null,
- FlowHelper.Translate(
- Mod.Helper.Translation.Get("page.notices.train"),
- new {
- time = Mod.FormatTime(time)
- },
- align: Alignment.VCenter
- ),
- new SpriteInfo(
- Game1.mouseCursors,
- TrainHelper.TRAIN
- )
- );
- }
+ // NPC Weddings and Anniversaries
+ if ((who.isEngaged() || who.isMarriedOrRoommates()) && who.friendshipData != null) {
+ foreach (var entry in who.friendshipData.Pairs) {
+ if (entry.Value == null || entry.Value.WeddingDate == null)
+ continue;
- // Spring
- if (date.SeasonIndex == 0) {
+ if (entry.Value.IsDivorced())
+ continue;
- }
+ WorldDate? wedding = entry.Value.WeddingDate;
+ if (wedding == null || wedding.SeasonIndex != date.SeasonIndex || wedding.DayOfMonth != date.DayOfMonth)
+ continue;
- // Summer
- else if (date.SeasonIndex == 1) {
+ NPC? spouse = Game1.getCharacterFromName(entry.Key);
+ if (spouse == null)
+ continue;
- // Extra Foragables
- if (gathering && date.DayOfMonth >= 12 && date.DayOfMonth <= 14) {
- yield return new RichEvent(
- date.DayOfMonth == 12 ?
- I18n.Page_Notices_Summer() : null,
- null,
- SpriteHelper.GetSprite(
- InventoryHelper.CreateItemById("(O)394", 1) // Rainbow Shell
- )
- );
- }
- }
+ char last = spouse.displayName.Last();
- // Fall
- else if (date.SeasonIndex == 2) {
+ bool no_s = last == 's' ||
+ LocalizedContentManager.CurrentLanguageCode ==
+ LocalizedContentManager.LanguageCode.de &&
+ (last == 'x' || last == 'ß' || last == 'z');
- if (gathering && date.DayOfMonth >= 15 && date.DayOfMonth <= 28) {
- Item? nut = InventoryHelper.CreateItemById("(O)408", 1);
+ var pendant = ItemRegistry.Create("(O)460", 1); // Mermaid Pendant
+ var sprite = SpriteHelper.GetSprite(pendant);
- // Should never be null but just in case.
- if (nut != null)
+ // Wedding?
+ if (date.Year == wedding.Year) {
yield return new RichEvent(
null,
- date.DayOfMonth == 15 ?
FlowHelper.Translate(
- Mod.Helper.Translation.Get("page.notices.season"),
+ Mod.Helper.Translation.Get(
+ no_s ?
+ "page.notices.wedding.no-s"
+ : "page.notices.wedding.s"
+ ),
new {
- item = nut.DisplayName,
- start = new SDate(15, date.Season).ToLocaleString(withYear: false),
- end = new SDate(28, date.Season).ToLocaleString(withYear: false),
+ name = who.displayName,
+ spouse = spouse.displayName
},
align: Alignment.VCenter
- ) : null,
- SpriteHelper.GetSprite(nut),
- nut
+ ),
+ sprite
+ );
+ } else {
+ yield return new RichEvent(
+ null,
+ FlowHelper.Translate(
+ Mod.Helper.Translation.Get(
+ no_s ?
+ "page.notices.anniversary.no-s"
+ : "page.notices.anniversary.s"
+ ),
+ new {
+ name = who.displayName,
+ spouse = spouse.displayName
+ },
+ align: Alignment.VCenter
+ ),
+ sprite
);
+ }
}
}
+ }
- // Winter
- else if (date.SeasonIndex == 3) {
+ // Trains
+ if (Mod.Config.NoticesShowTrains) {
+ int time = TrainHelper.GetTrainTime(date);
+ if (time >= 0)
+ yield return new RichEvent(
+ null,
+ FlowHelper.Translate(
+ Mod.Helper.Translation.Get("page.notices.train"),
+ new {
+ time = Mod.FormatTime(time)
+ },
+ align: Alignment.VCenter
+ ),
+ new SpriteInfo(
+ Game1.mouseCursors,
+ TrainHelper.TRAIN
+ )
+ );
+ }
+ // Spring
+ if (date.SeasonIndex == 0) {
+ }
+
+ // Summer
+ else if (date.SeasonIndex == 1) {
+
+ // Extra Foragables
+ if (gathering && date.DayOfMonth >= 12 && date.DayOfMonth <= 14) {
+ yield return new RichEvent(
+ date.DayOfMonth == 12 ?
+ I18n.Page_Notices_Summer() : null,
+ null,
+ SpriteHelper.GetSprite(
+ ItemRegistry.Create("(O)394", 1) // Rainbow Shell
+ )
+ );
}
+ }
+ // Fall
+ else if (date.SeasonIndex == 2) {
- // Traveling Merchant
- if (Mod.Config.NoticesShowMerchant != MerchantMode.Disabled && date.DayOfMonth % 7 % 5 == 0) {
-
- var sprite = new SpriteInfo(
- Game1.mouseCursors,
- new Rectangle(193, 1412, 18, 18)
- );
+ if (gathering && date.DayOfMonth >= 15 && date.DayOfMonth <= 28) {
+ Item? nut = ItemRegistry.Create("(O)408", 1);
- if (Mod.Config.NoticesShowMerchant == MerchantMode.Visit)
+ // Should never be null but just in case.
+ if (nut != null)
yield return new RichEvent(
null,
- FlowHelper.Builder()
- .FormatText(I18n.Page_Notices_Merchant(), align: Alignment.VCenter)
- .Build(),
- sprite
+ date.DayOfMonth == 15 ?
+ FlowHelper.Translate(
+ Mod.Helper.Translation.Get("page.notices.season"),
+ new {
+ item = nut.DisplayName,
+ start = new SDate(15, date.Season).ToLocaleString(withYear: false),
+ end = new SDate(28, date.Season).ToLocaleString(withYear: false),
+ },
+ align: Alignment.VCenter
+ ) : null,
+ SpriteHelper.GetSprite(nut),
+ nut
);
+ }
+ }
- else {
- var stock = ShopBuilder.GetShopStock(Game1.shop_travelingCart);
- if (stock.Count > 0) {
- var builder = FlowHelper.Builder()
- .FormatText(I18n.Page_Notices_Merchant_Stock(), align: Alignment.VCenter)
- .Text("\n ");
+ // Winter
+ else if (date.SeasonIndex == 3) {
- bool first = true;
- foreach (var pair in stock) {
- var item = pair.Key;
- if (item.Stack < 1 && !item.IsInfiniteStock())
- continue;
+ }
- if (first)
- first = false;
- else
- builder.Text(", ", shadow: false);
- if (item is SObject sobj)
- builder
- .Sprite(SpriteHelper.GetSprite(sobj), scale: 2, align: Alignment.VCenter)
- .Text(" ");
+ // Traveling Merchant
+ if (Mod.Config.NoticesShowMerchant != MerchantMode.Disabled && date.DayOfMonth % 7 % 5 == 0) {
- builder.Text(item.DisplayName, shadow: false);
- }
+ var sprite = new SpriteInfo(
+ Game1.mouseCursors,
+ new Rectangle(193, 1412, 18, 18)
+ );
+ if (Mod.Config.NoticesShowMerchant == MerchantMode.Visit)
+ yield return new RichEvent(
+ null,
+ FlowHelper.Builder()
+ .FormatText(I18n.Page_Notices_Merchant(), align: Alignment.VCenter)
+ .Build(),
+ sprite
+ );
- yield return new RichEvent(
- null,
- builder.Build(),
- sprite: sprite
- );
+ else {
+ var stock = ShopBuilder.GetShopStock(Game1.shop_travelingCart);
+ if (stock.Count > 0) {
+ var builder = FlowHelper.Builder()
+ .FormatText(I18n.Page_Notices_Merchant_Stock(), align: Alignment.VCenter)
+ .Text("\n ");
+
+ bool first = true;
+
+ foreach (var pair in stock) {
+ var item = pair.Key;
+ if (item.Stack < 1 && !item.IsInfiniteStock())
+ continue;
+
+ if (first)
+ first = false;
+ else
+ builder.Text(", ", shadow: false);
+
+ if (item is SObject sobj)
+ builder
+ .Sprite(SpriteHelper.GetSprite(sobj), scale: 2, align: Alignment.VCenter)
+ .Text(" ");
+
+ builder.Text(item.DisplayName, shadow: false);
}
- }
- }
- //Bookseller
- if (Mod.Config.NoticesShowBookseller != MerchantMode.Disabled && IsBooksellerVisiting(date)) {
- var sprite = new SpriteInfo(
- Game1.mouseCursors_1_6,
- new Rectangle(177, 488, 18, 24)
- );
- if (Mod.Config.NoticesShowBookseller == MerchantMode.Visit)
+
yield return new RichEvent(
null,
- FlowHelper.Builder()
- .FormatText(I18n.Page_Notices_Bookseller(), align: Alignment.VCenter)
- .Build(),
- sprite
+ builder.Build(),
+ sprite: sprite
);
+ }
+ }
+ }
+ //Bookseller
+ if (Mod.Config.NoticesShowBookseller != MerchantMode.Disabled && IsBooksellerVisiting(date)) {
+ var sprite = new SpriteInfo(
+ Game1.mouseCursors_1_6,
+ new Rectangle(177, 488, 18, 24)
+ );
- else {
- var stock = ShopBuilder.GetShopStock(Game1.shop_bookseller);
- if (stock.Count > 0) {
- var builder = FlowHelper.Builder()
- .FormatText(I18n.Page_Notices_Bookseller_Stock(), align: Alignment.VCenter)
- .Text("\n ");
-
- bool first = true;
+ if (Mod.Config.NoticesShowBookseller == MerchantMode.Visit)
+ yield return new RichEvent(
+ null,
+ FlowHelper.Builder()
+ .FormatText(I18n.Page_Notices_Bookseller(), align: Alignment.VCenter)
+ .Build(),
+ sprite
+ );
- foreach (var pair in stock) {
- var item = pair.Key;
- if (item.Stack < 1 && !item.IsInfiniteStock())
- continue;
+ else {
+ var stock = ShopBuilder.GetShopStock(Game1.shop_bookseller);
+ if (stock.Count > 0) {
+ var builder = FlowHelper.Builder()
+ .FormatText(I18n.Page_Notices_Bookseller_Stock(), align: Alignment.VCenter)
+ .Text("\n ");
- if (first)
- first = false;
- else
- builder.Text(", ", shadow: false);
+ bool first = true;
- if (item is SObject sobj)
- builder
- .Sprite(SpriteHelper.GetSprite(sobj,Game1.objectSpriteSheet_2), scale: 2, align: Alignment.VCenter)
- .Text(" ");
+ foreach (var pair in stock) {
+ var item = pair.Key;
+ if (item.Stack < 1 && !item.IsInfiniteStock())
+ continue;
- builder.Text(item.DisplayName, shadow: false);
- }
+ if (first)
+ first = false;
+ else
+ builder.Text(", ", shadow: false);
+ if (item is SObject sobj)
+ builder
+ //Keeping for texture reference .Sprite(SpriteHelper.GetSprite(sobj, Game1.objectSpriteSheet_2), scale: 2, align: Alignment.VCenter)
+ .Sprite(SpriteHelper.GetSprite(sobj), scale: 2, align: Alignment.VCenter)
+ .Text(" ");
- yield return new RichEvent(
- null,
- builder.Build(),
- sprite: sprite
- );
+ builder.Text(item.DisplayName, shadow: false);
}
+
+
+ yield return new RichEvent(
+ null,
+ builder.Build(),
+ sprite: sprite
+ );
}
}
}
- #endregion
+}
+#endregion
- #region Utility methods
- //Copied IsBloom from Bush.cs and switched calls for current season & day to passed values
- public bool IsBlooming(Bush bush, StardewValley.Season season, int dayOfMonth) {
- if (bush.size.Value == 4) {
- return bush.tileSheetOffset.Value == 1;
- }
- if (bush.size.Value == 3) {
- bool inBloom = bush.getAge() >= 20 && dayOfMonth >= 22 && (season != StardewValley.Season.Winter || bush.IsSheltered());
- if (inBloom && bush.Location != null && bush.Location.IsFarm) {
- foreach (Farmer allFarmer in Game1.getAllFarmers()) {
- allFarmer.autoGenerateActiveDialogueEvent("cropMatured_815");
- }
+#region Utility methods
+//Copied IsBloom from Bush.cs and switched calls for current season & day to passed values
+public bool IsBlooming(Bush bush, StardewValley.Season season, int dayOfMonth) {
+ if (bush.size.Value == 4) {
+ return bush.tileSheetOffset.Value == 1;
+ }
+ if (bush.size.Value == 3) {
+ bool inBloom = bush.getAge() >= 20 && dayOfMonth >= 22 && (season != StardewValley.Season.Winter || bush.IsSheltered());
+ if (inBloom && bush.Location != null && bush.Location.IsFarm) {
+ foreach (Farmer allFarmer in Game1.getAllFarmers()) {
+ allFarmer.autoGenerateActiveDialogueEvent("cropMatured_815");
}
- return inBloom;
- }
- switch (season) {
- case StardewValley.Season.Spring:
- if (dayOfMonth > 14) {
- return dayOfMonth < 19;
- }
- return false;
- case StardewValley.Season.Fall:
- if (dayOfMonth > 7) {
- return dayOfMonth < 12;
- }
- return false;
- default:
- return false;
}
+ return inBloom;
}
- //Copied from Utility.cs and switched calls for current date info to passed value
- public static List GetDaysOfBooksellerThisSeason(WorldDate date) {
- Random r = Utility.CreateRandom(date.Year * 11, Game1.uniqueIDForThisGame, date.SeasonIndex);
- int[]? possible_days = null;
- List days = new List();
- switch (date.Season) {
- case StardewValley.Season.Spring:
- possible_days = new int[5] { 11, 12, 21, 22, 25 };
- break;
- case StardewValley.Season.Summer:
- possible_days = new int[5] { 9, 12, 18, 25, 27 };
- break;
- case StardewValley.Season.Fall:
- possible_days = new int[8] { 4, 7, 8, 9, 12, 19, 22, 25 };
- break;
- case StardewValley.Season.Winter:
- possible_days = new int[6] { 5, 11, 12, 19, 22, 24 };
- break;
- }
- int index1 = r.Next(possible_days!.Length);
- days.Add(possible_days[index1]);
- days.Add(possible_days[(index1 + possible_days.Length / 2) % possible_days.Length]);
- return days;
+ switch (season) {
+ case StardewValley.Season.Spring:
+ if (dayOfMonth > 14) {
+ return dayOfMonth < 19;
+ }
+ return false;
+ case StardewValley.Season.Fall:
+ if (dayOfMonth > 7) {
+ return dayOfMonth < 12;
+ }
+ return false;
+ default:
+ return false;
}
- public static bool IsBooksellerVisiting(WorldDate date) {
- List visitDays = GetDaysOfBooksellerThisSeason(date);
- foreach(int day in visitDays) if(day==date.DayOfMonth) return true;
- return false;
+}
+//Copied from Utility.cs and switched calls for current date info to passed value
+public static List GetDaysOfBooksellerThisSeason(WorldDate date) {
+ Random r = Utility.CreateRandom(date.Year * 11, Game1.uniqueIDForThisGame, date.SeasonIndex);
+ int[]? possible_days = null;
+ List days = new List();
+ switch (date.Season) {
+ case StardewValley.Season.Spring:
+ possible_days = new int[5] { 11, 12, 21, 22, 25 };
+ break;
+ case StardewValley.Season.Summer:
+ possible_days = new int[5] { 9, 12, 18, 25, 27 };
+ break;
+ case StardewValley.Season.Fall:
+ possible_days = new int[8] { 4, 7, 8, 9, 12, 19, 22, 25 };
+ break;
+ case StardewValley.Season.Winter:
+ possible_days = new int[6] { 5, 11, 12, 19, 22, 24 };
+ break;
}
+ int index1 = r.Next(possible_days!.Length);
+ days.Add(possible_days[index1]);
+ days.Add(possible_days[(index1 + possible_days.Length / 2) % possible_days.Length]);
+ return days;
+}
+public static bool IsBooksellerVisiting(WorldDate date) {
+ List visitDays = GetDaysOfBooksellerThisSeason(date);
+ foreach (int day in visitDays) if (day == date.DayOfMonth) return true;
+ return false;
+}
#endregion
}
+
diff --git a/Almanac/Menus/BookCollectionMenu.cs b/Almanac/Menus/BookCollectionMenu.cs
index 3ee08f0..b57ccb8 100644
--- a/Almanac/Menus/BookCollectionMenu.cs
+++ b/Almanac/Menus/BookCollectionMenu.cs
@@ -101,7 +101,7 @@ private void DiscoverBooks() {
if (value == null || !value.Enable)
continue;
- bool locked = !string.IsNullOrEmpty(value.Condition) && !Common.GameStateQuery.CheckConditions(value.Condition);
+ bool locked = !string.IsNullOrEmpty(value.Condition) && !GameStateQuery.CheckConditions(value.Condition);
if (value.Secret && locked)
continue;
@@ -520,7 +520,7 @@ public override void draw(SpriteBatch b) {
if (LockedBooks[book])
continue;
- var sprite = SpriteHelper.GetSprite(InventoryHelper.CreateItemById($"(O){idx}", 1));
+ var sprite = SpriteHelper.GetSprite(ItemRegistry.Create($"(O){idx}"));
idx++;
float scale = cmp.scale - 1;
diff --git a/Almanac/ModAPI.cs b/Almanac/ModAPI.cs
index 0c552bf..e809728 100644
--- a/Almanac/ModAPI.cs
+++ b/Almanac/ModAPI.cs
@@ -27,8 +27,8 @@ public interface IAlmanacAPI {
int DaysPerMonth { get; }
#region Custom Pages
-
- /*void RegisterPage(
+ /*
+ void RegisterPage(
IManifest manifest,
string id,
// State
@@ -74,9 +74,11 @@ public interface IAlmanacAPI {
Action, Action- > onCellHover = null
);
- void UnregisterPage(IManifest manifest, string id);*/
-
+ void UnregisterPage(IManifest manifest, string id);
+ */
#endregion
+
+
#region Crops Page
@@ -174,6 +176,7 @@ IReadOnlyCollection phaseSprites
#endregion
+
#region Fortunes Page
///
@@ -289,6 +292,7 @@ IReadOnlyCollection phaseSprites
string GetWeatherForDate(WorldDate date, string context = "Default");
#endregion
+
}
public class ModAPI : IAlmanacAPI {
@@ -568,7 +572,7 @@ public string GetWeatherForDate(WorldDate date, GameLocation location) {
public string GetWeatherForDate(WorldDate date, string context = "Default") {
LocationContextData ctx;
- switch(context) {
+ switch (context) {
case "Default":
ctx = Game1.locationContextData["Default"];
break;
@@ -584,6 +588,7 @@ public string GetWeatherForDate(WorldDate date, string context = "Default") {
string weather = Mod.Weather.GetWeatherForDate(Mod.GetBaseWorldSeed(), date, ctx, context);
return weather;
+
}
#endregion
diff --git a/Almanac/ModEntry.cs b/Almanac/ModEntry.cs
index c2ab690..b39500d 100644
--- a/Almanac/ModEntry.cs
+++ b/Almanac/ModEntry.cs
@@ -21,6 +21,7 @@
using StardewValley;
using StardewValley.Locations;
using StardewValley.Menus;
+using StardewValley.BellsAndWhistles;
using Leclair.Stardew.Almanac.Crops;
using Leclair.Stardew.Almanac.Fish;
@@ -100,8 +101,8 @@ public override void Entry(IModHelper helper) {
Harmony = new Harmony(ModManifest.UniqueID);
// Patches
- // Patches.GameMenu_Patches.Patch(this);
- Common_SpriteText_Patches.Patch(Harmony, Monitor);
+ Patches.GameMenu_Patches.Patch(this);
+ //Patches.Workbench_Patches.Patch(this);
Assets = new(this);
@@ -323,7 +324,7 @@ private void OnGameLaunched(object? sender, GameLaunchedEventArgs e) {
string input = string.Join(' ', args);
Log($" Input: {input}");
- Log($"Result: {StringTokenizer.ParseString(input, item: Game1.player?.CurrentItem, monitor: Monitor, trace: true)}");
+ // Log($"Result: {StringTokenizer.ParseString(input, item: Game1.player?.CurrentItem, monitor: Monitor, trace: true)}");
});
Helper.ConsoleCommands.Add("al_gsq", "Run a GameStateQuery", (name, args) => {
@@ -343,7 +344,7 @@ private void OnGameLaunched(object? sender, GameLaunchedEventArgs e) {
Log($" Query: {query}");
if (seed != -1)
Log($" Seed: {seed}");
- Log($"Result: {Common.GameStateQuery.CheckConditions(query, rnd: rnd, item: Game1.player.CurrentItem, monitor: Monitor, trace: true)}");
+ //Log($"Result: {GameStateQuery.CheckConditions(query, random: rnd, item: Game1.player.CurrentItem, monitor: Monitor, trace: true)}");
});
Helper.ConsoleCommands.Add("al_update", "Invalidate cached data.", (name, args) => {
@@ -371,25 +372,25 @@ private void OnGameLaunched(object? sender, GameLaunchedEventArgs e) {
}
});
- Helper.ConsoleCommands.Add("al_now", "Print information about the in-game time.", (_, _) => {
- Log($"Date: {Game1.Date.Localize()}", LogLevel.Info);
- Log($"- Year: {Game1.year}", LogLevel.Info);
- Log($"- Season: {Game1.currentSeason}", LogLevel.Info);
- Log($"- DayOf: {Game1.dayOfMonth}", LogLevel.Info);
- Log($"- TDays: {Game1.Date.TotalDays}", LogLevel.Info);
- Log($"DaysPlayed: {Game1.stats.DaysPlayed}", LogLevel.Info);
- });
-
- Helper.ConsoleCommands.Add("al_forecast", "Get the forecast for the loaded save.", (name, args) => {
- ulong seed = GetBaseWorldSeed();
- WorldDate date = new(Game1.Date);
- for (int i = 0; i < 4 * 28; i++) {
- string weather = Weather.GetWeatherForDate(seed, date, Game1.locationContextData["Default"], "Default");
- Log($"Date: {date.Localize()} -- Weather: {weather}");
- date.TotalDays++;
- }
- });
- }
+ Helper.ConsoleCommands.Add("al_now", "Print information about the in-game time.", (_, _) => {
+ Log($"Date: {Game1.Date.Localize()}", LogLevel.Info);
+ Log($"- Year: {Game1.year}", LogLevel.Info);
+ Log($"- Season: {Game1.currentSeason}", LogLevel.Info);
+ Log($"- DayOf: {Game1.dayOfMonth}", LogLevel.Info);
+ Log($"- TDays: {Game1.Date.TotalDays}", LogLevel.Info);
+ Log($"DaysPlayed: {Game1.stats.DaysPlayed}", LogLevel.Info);
+ });
+
+ Helper.ConsoleCommands.Add("al_forecast", "Get the forecast for the loaded save.", (name, args) => {
+ ulong seed = GetBaseWorldSeed();
+ WorldDate date = new(Game1.Date);
+ for (int i = 0; i < 4 * 28; i++) {
+ string weather = Weather.GetWeatherForDate(seed, date, Game1.locationContextData["Default"], "Default");
+ Log($"Date: {date.Localize()} -- Weather: {weather}");
+ date.TotalDays++;
+ }
+ });
+ }
[Subscriber]
private void OnMenuChanged(object sender, MenuChangedEventArgs e) {
@@ -883,7 +884,7 @@ public ulong GetBaseWorldSeed() {
}
public bool DoesTranslationExist(string key) {
- return Helper.Translation.ContainsKey(key);
+ return Helper.Translation.Get(key).HasValue();
}
public string GetSubLocationName(Models.SubLocation sub) {
@@ -904,6 +905,8 @@ public string GetSubLocationName(Models.SubLocation sub) {
return I18n.Location_Forest_River();
if (sub.Area == "Pond")
return I18n.Location_Forest_Pond();
+ if (sub.Area == "Lake")
+ return I18n.Location_Forest_Lake();
break;
case "IslandWest":
@@ -912,6 +915,11 @@ public string GetSubLocationName(Models.SubLocation sub) {
if (sub.Area == "Freshwater")
return I18n.Location_Island_Freshwater();
break;
+
+ case "Desert":
+ if (sub.Area == "TopPond")
+ return I18n.Location_Desert_TopPond();
+ break;
}
return sub.Area.ToString();
@@ -1023,6 +1031,13 @@ public string GetSubLocationName(Models.SubLocation sub) {
case "Deluxe Barn":
case "Deluxe Coop":
case "Farm":
+ case "Farm_Standard":
+ case "Farm_Forest":
+ case "Farm_FourCorners":
+ case "Farm_Hilltop":
+ case "Farm_Riverland":
+ case "Farm_Wilderness":
+ case "Farm_Beach":
case "FarmCave":
case "FarmHouse":
case "Greenhouse":
diff --git a/Almanac/Pages/FortunePage.cs b/Almanac/Pages/FortunePage.cs
index 12f3c5c..f885aab 100644
--- a/Almanac/Pages/FortunePage.cs
+++ b/Almanac/Pages/FortunePage.cs
@@ -1,3 +1,4 @@
+
#nullable enable
using System;
@@ -104,7 +105,7 @@ public override void Update() {
if (has_line) {
db.Text("\n");
if (evt.Item != null)
- onHover = (_,_,_) => {
+ onHover = (_, _, _) => {
Menu.HoveredItem = evt.Item;
return true;
};
@@ -207,7 +208,7 @@ public void DrawUnderCell(SpriteBatch b, WorldDate date, Rectangle bounds) {
}
public void DrawOverCell(SpriteBatch b, WorldDate date, Rectangle bounds) {
-
+
}
public bool ReceiveCellLeftClick(int x, int y, WorldDate date, Rectangle bounds) {
@@ -227,7 +228,7 @@ public bool ReceiveCellRightClick(int x, int y, WorldDate date, Rectangle bounds
}
public void PerformCellHover(int x, int y, WorldDate date, Rectangle bounds) {
- if (Luck == null || ! Luck[date.DayOfMonth - 1].HasValue)
+ if (Luck == null || !Luck[date.DayOfMonth - 1].HasValue)
return;
double luck = Luck[date.DayOfMonth - 1]!.Value;
@@ -235,10 +236,11 @@ public void PerformCellHover(int x, int y, WorldDate date, Rectangle bounds) {
Menu.HoverMagic = true;
Menu.HoverText = Mod.Config.ShowExactLuck
- ? $"{fortune} ({(luck*100):F1}%)"
+ ? $"{fortune} ({(luck * 100):F1}%)"
: fortune;
}
#endregion
}
+
diff --git a/Almanac/Pages/MinesPage.cs b/Almanac/Pages/MinesPage.cs
index a1c3a7d..de33107 100644
--- a/Almanac/Pages/MinesPage.cs
+++ b/Almanac/Pages/MinesPage.cs
@@ -40,15 +40,15 @@ public MinesPage(AlmanacMenu menu, ModEntry mod) : base(menu, mod) {
Sprites = new();
Sprites[LevelType.Mushroom] = SpriteHelper.GetSprite(
- InventoryHelper.CreateItemById("(O)420", 1) // Red Mushroom
+ ItemRegistry.Create("(O)420", 1) // Red Mushroom
);
Sprites[LevelType.InfestedMonster] = SpriteHelper.GetSprite(
- InventoryHelper.CreateItemById("(W)0", 1) // Rusty Sword
+ ItemRegistry.Create("(W)0", 1) // Rusty Sword
);
Sprites[LevelType.InfestedSlime] = SpriteHelper.GetSprite(
- InventoryHelper.CreateItemById("(O)766", 1) // Slime
+ ItemRegistry.Create("(O)766", 1) // Slime
);
Sprites[LevelType.Quarry] = new SpriteInfo(
@@ -62,7 +62,7 @@ public MinesPage(AlmanacMenu menu, ModEntry mod) : base(menu, mod) {
);
Sprites[LevelType.Dino] = SpriteHelper.GetSprite(
- InventoryHelper.CreateItemById("(O)107", 1) // Dino Egg
+ ItemRegistry.Create("(O)107", 1) // Dino Egg
);
Update();
diff --git a/Almanac/Pages/NoticesPage.cs b/Almanac/Pages/NoticesPage.cs
index 8510146..edc20e2 100644
--- a/Almanac/Pages/NoticesPage.cs
+++ b/Almanac/Pages/NoticesPage.cs
@@ -1,3 +1,4 @@
+
#nullable enable
using System;
@@ -37,7 +38,7 @@ public class NoticesPage : BasePage, ICalendarPage {
#region Lifecycle
public static NoticesPage? GetPage(AlmanacMenu menu, ModEntry mod) {
- if (! mod.Config.ShowNotices)
+ if (!mod.Config.ShowNotices)
return null;
return new(menu, mod);
@@ -67,7 +68,7 @@ public void LoadOverrides() {
Texture2D texture;
try {
texture = Game1.content.Load(@"Characters\" + npc.getTextureName());
- } catch(Exception) {
+ } catch (Exception) {
texture = npc.Sprite.Texture;
}
@@ -147,7 +148,7 @@ public override void Update() {
List? chars = null;
try {
chars = Utility.getAllCharacters();
- } catch(Exception ex) {
+ } catch (Exception ex) {
Mod.Log($"Unable to load list of characters: {ex}", StardewModdingAPI.LogLevel.Error);
builder
.Text("\n\n")
@@ -187,11 +188,11 @@ public override void Update() {
date.DayOfMonth = day;
List sprites = new();
- foreach(var evt in Mod.Notices.GetEventsForDate(0, date)) {
+ foreach (var evt in Mod.Notices.GetEventsForDate(0, date)) {
if (evt == null)
continue;
- bool has_simple = ! string.IsNullOrEmpty(evt.SimpleLabel);
+ bool has_simple = !string.IsNullOrEmpty(evt.SimpleLabel);
bool has_line = has_simple || evt.AdvancedLabel != null;
Func? onHover = null;
@@ -199,7 +200,7 @@ public override void Update() {
if (has_line) {
db.Text("\n");
if (evt.Item != null)
- onHover = (_,_,_) => {
+ onHover = (_, _, _) => {
Menu.HoveredItem = evt.Item;
return true;
};
@@ -339,7 +340,7 @@ public void DrawUnderCell(SpriteBatch b, WorldDate date, Rectangle bounds) {
} else {
int to_show = Math.Min(sprites.Count, bdays == null ? 3 : 1);
- int idx = (int) (ms / Mod.Config.CycleTime) % (int)Math.Ceiling(sprites.Count / (float) to_show) * to_show;
+ int idx = (int) (ms / Mod.Config.CycleTime) % (int) Math.Ceiling(sprites.Count / (float) to_show) * to_show;
for (int i = 0; i < to_show; i++) {
if (i + idx >= sprites.Count)
@@ -376,7 +377,7 @@ public void DrawUnderCell(SpriteBatch b, WorldDate date, Rectangle bounds) {
}
public void DrawOverCell(SpriteBatch b, WorldDate date, Rectangle bounds) {
-
+
}
public bool ReceiveCellLeftClick(int x, int y, WorldDate date, Rectangle bounds) {
@@ -411,3 +412,4 @@ public void PerformCellHover(int x, int y, WorldDate date, Rectangle bounds) {
#endregion
}
+
diff --git a/Almanac/Pages/WeatherPage.cs b/Almanac/Pages/WeatherPage.cs
index e621c8e..9bcda12 100644
--- a/Almanac/Pages/WeatherPage.cs
+++ b/Almanac/Pages/WeatherPage.cs
@@ -1,3 +1,4 @@
+
#nullable enable
using System;
@@ -23,11 +24,11 @@ public class WeatherPage : BasePage, ICalendarPage {
public static readonly Rectangle WEATHER_ICON = new(384, 352, 16, 16);
- private readonly ulong Seed;
- private IFlowNode[] Nodes;
- private string[] Forecast;
- private bool[] Festivals;
- private bool[] Pirates;
+ private readonly ulong Seed;
+ private IFlowNode[] Nodes;
+ private string[] Forecast;
+ private bool[] Festivals;
+ private bool[] Pirates;
readonly bool IsIsland;
readonly bool IsDesert;
@@ -112,13 +113,13 @@ public override void Update() {
for (int day = 1; day <= ModEntry.DaysPerMonth; day++) {
date.DayOfMonth = day;
bool shown = forecastLength == -1 || date.TotalDays - today <= forecastLength;
- string weather = Forecast[day - 1] = shown ? Mod.Weather.GetWeatherForDate(Seed, date, context, contextID): "";
+ string weather = Forecast[day - 1] = shown ? Mod.Weather.GetWeatherForDate(Seed, date, context, contextID) : "";
if (IsIsland) {
- bool pirates = Pirates![day - 1] = shown && day % 2 == 0 && ! WeatherHelper.IsRainOrSnow(weather);
+ bool pirates = Pirates![day - 1] = shown && day % 2 == 0 && !WeatherHelper.IsRainOrSnow(weather);
if (pirates)
pirateDays!.Add(day);
- } else if ( Utility.isFestivalDay(day, date.Season)) {
+ } else if (Utility.isFestivalDay(day, date.Season)) {
SDate sdate = new(day, date.Season);
var data = Game1.temporaryContent.Load>("Data\\Festivals\\" + date.Season + day);
@@ -142,7 +143,7 @@ public override void Update() {
}
}
- foreach(GameLocation loc in Game1.locations) {
+ foreach (GameLocation loc in Game1.locations) {
if (loc?.Name == where) {
where = Mod.GetLocationName(loc);
break;
@@ -155,7 +156,7 @@ public override void Update() {
font: Game1.dialogueFont,
shadow: true
),
- onClick: (_,_,_) => false
+ onClick: (_, _, _) => false
);
Nodes[day - 1] = node;
@@ -333,3 +334,4 @@ public void PerformCellHover(int x, int y, WorldDate date, Rectangle bounds) {
#endregion
}
+
diff --git a/Almanac/Patches/Game1_Patches.cs b/Almanac/Patches/Game1_Patches.cs
index 8830b35..0e32cac 100644
--- a/Almanac/Patches/Game1_Patches.cs
+++ b/Almanac/Patches/Game1_Patches.cs
@@ -18,7 +18,7 @@ internal static class Game1_Patches {
internal static void Patch(ModEntry mod) {
Monitor = mod.Monitor;
-
+ /*
try {
mod.Harmony.Patch(
original: AccessTools.Method(typeof(Game1), nameof(Game1.UpdateWeatherForNewDay)),
@@ -27,9 +27,9 @@ internal static void Patch(ModEntry mod) {
} catch(Exception ex) {
mod.Log("An error occurred while registering a harmony patch for Game1.", LogLevel.Error, ex);
- }
+ }*/
}
-
+
public static void UpdateWeatherForNewDay_Postfix() {
try {
ModEntry.Instance.Weather.UpdateForNewDay();
diff --git a/Almanac/i18n/default.json b/Almanac/i18n/default.json
index 8887ac0..3b07ab6 100644
--- a/Almanac/i18n/default.json
+++ b/Almanac/i18n/default.json
@@ -351,27 +351,31 @@
"location.Forest.River": "River",
"location.Forest.Pond": "Pond",
+ "location.Forest.Lake": "Lake",
"location.Island.Ocean": "Ocean",
"location.Island.Freshwater": "Freshwater",
-
+ "Location.Desert.TopPond": "TopPond",
// Maps: Stardew Aquarium
"location.Custom_ExteriorMuseum": "Stardew Aquarium",
// Maps: Stardew Valley Expanded
"location.Custom_AdventurerSummit": "Adventurer Summit",
"location.Custom_BlueMoonVineyard": "Blue Moon Vineyard",
- "location.Custom_BlueMoonVineyard.0": "Ocean",
- "location.Custom_BlueMoonVineyard.1": "River",
+ "location.Custom_BlueMoonVineyard.Ocean": "Ocean",
+ "location.Custom_BlueMoonVineyard.River": "River",
"location.Custom_CrimsonBadlands": "Crimson Badlands",
"location.Custom_FableReef": "Fable Reef",
"location.Custom_ForestWest": "West Cindersap Forest",
"location.Custom_Highlands": "The Highlands",
- "location.Custom_Highlands.0": "Ruins",
- "location.Custom_Highlands.1": "River",
+ "location.Custom_Highlands.Pond": "Pond",
+ "location.Custom_Highlands.River": "River",
"location.Custom_HighlandsCavern": "The Highlands (Cavern)",
"location.Custom_JunimoWoods": "Junimo Woods",
- //"location.Custom_MorrisProperty": "",
+ "location.Custom_MorrisProperty": "Morris Property",
+ "location.Custom_HenchmanBackyard": "Henchman Backyard",
+ "location.Custom_ForbiddenMaze": "Forbidden Maze",
+ "location.Custom_DiamondCavern": "Diamond Cavern",
"location.Custom_ShearwaterBridge": "Shearwater Bridge",
"location.Custom_SpriteSpring2": "Sprite Spring",
"location.Custom_GrampletonSuburbs": "Grampleton Suburbs",
diff --git a/Almanac/i18n/zh.json b/Almanac/i18n/zh.json
index ce29dc4..df9fe2a 100644
--- a/Almanac/i18n/zh.json
+++ b/Almanac/i18n/zh.json
@@ -21,7 +21,16 @@
"crop.last-day": "最后一天:",
"crop.toggle": "切换{{mode}}",
- "crop.paddy": "水稻奖金",
+ "crop.paddy": "水稻灌溉加成",
+
+ "crop.crop.none": "没有作物符合你现在的筛选。",
+
+ "page.crop.seed-filter": "按种子筛选",
+ "page.crop.seed-filter.disabled": "关闭",
+ "page.crop.seed-filter.inventory": "背包中",
+ "page.crop.seed-filter.owned": "拥有的",
+
+ "crop.seed-filter": "只展示拥有的种子",
"crop.using-none": "以下的生长时间和日期假设你没有肥料或技能。",
"crop.using-agri": "以下的生长时间和日期假设你是一个{{agriculturist}}。",
@@ -54,9 +63,10 @@
"weather.sunny": "晴天",
"weather.rain": "雨天",
"weather.debris": "多云",
- "weather.lightning": "雷雨天",
+ "weather.lightning": "雷雨",
"weather.festival": "晴天",
- "weather.snow": "下雪天",
+ "weather.snow": "雪天",
+ "weather.green": "绿雨",
"page.train": "火车时刻表",
"page.train.about": "@B警告:@b 火车将在以下时间经过星露谷火车站。 为了您的安全,当有火车出现时,请保持与轨道的距离。",
@@ -124,8 +134,8 @@
"page.fish.size": "你钓到过的最大尺寸是@B{{big_cm}}\"厘米@b。",
"page.fish.size.range": "它的尺寸范围为@B{{min_cm}}\"厘米@b至@B{{max_cm}}\"厘米@b。",
- "page.fish.weather.Sunny": "{{fish}}只在@Bsunny@b的天气可钓到。",
- "page.fish.weather.Rainy": "{{fish}}只在@Brainy@b的天气可钓到。",
+ "page.fish.weather.Sunny": "{{fish}}只在@B晴朗@b的天气可钓到。",
+ "page.fish.weather.Rainy": "{{fish}}只在@B下雨@b的天气可钓到。",
"page.fish.weather.Any": "{{fish}}任何天气都能钓,风雨无阻。 ",
"page.fish.level": "你需要{{skill}}的@B{{level}}@b级别才能钓到这种鱼。",
"page.fish.legendary": "{{fish}}是传说鱼类。",
@@ -157,6 +167,13 @@
"page.fish.location.fresh": "{{fish}}生活在淡水区域。",
"page.fish.location.ocean": "{{fish}}生活在海水区域。",
+ "page.fish.filter.aquarium": "按水族馆捐赠筛选",
+ "page.fish.aquarium.true": "已捐赠",
+ "page.fish.aquarium.false": "未捐赠",
+
+ "page.fish.aquarium.donated": "你已经捐给了星露谷水族馆。",
+ "page.fish.aquarium.not-donated": "你还没有捐给星露谷水族馆。",
+
// Settings
"settings.button": "显示年历按钮",
@@ -272,7 +289,7 @@
// Locations
- "location.WitchSwamp": "女巫的沼泽",
+ "location.WitchSwamp": "女巫沼泽",
"location.BugLand": "突变虫穴",
"location.Caldera": "姜岛(火山地牢)",
@@ -282,34 +299,43 @@
"location.IslandSouthEast": "姜岛东南部",
"location.IslandSouthEastCave": "姜岛东南部(洞穴)",
"location.IslandEast": "姜岛东部",
+ "location.Submarine": "潜艇",
"location.sub-any": "任何地点",
"location.sub-floor": "{{floor}}层",
"location.Forest.River": "河边",
"location.Forest.Pond": "池塘",
+ "location.Forest.Lake": "湖泊",
"location.Island.Ocean": "海边",
"location.Island.Freshwater": "淡水区",
+ "Location.Desert.TopPond": "池塘",
+
// Maps: Stardew Aquarium
"location.Custom_ExteriorMuseum": "星露谷水族馆",
"location.ExteriorMuseum": "星露谷水族馆",
// Maps: Stardew Valley Expanded
- "location.Custom_AdventurerSummit": "冒险家公会",
+ "location.Custom_AdventurerSummit": "探险家山峰",
"location.Custom_BlueMoonVineyard": "蓝月亮葡萄园",
- "location.Custom_BlueMoonVineyard.0": "海边",
- "location.Custom_BlueMoonVineyard.1": "河边",
- "location.Custom_CrimsonBadlands": "猩红荒地",
- "location.Custom_FableReef": "寓言礁石",
+ "location.Custom_BlueMoonVineyard.Ocean": "海边",
+ "location.Custom_BlueMoonVineyard.River": "河边",
+ "location.Custom_CrimsonBadlands": "绯红荒地",
+ "location.Custom_FableReef": "寓言礁",
"location.Custom_ForestWest": "煤矿森林西",
"location.Custom_Highlands": "高地",
- "location.Custom_Highlands.0": "废墟",
- "location.Custom_Highlands.1": "河边",
- "location.Custom_HighlandsCavern": "高地(洞穴)",
+ "location.Custom_Highlands.Pond": "池塘",
+ "location.Custom_Highlands.River": "河边",
+ "location.Custom_HighlandsCavern": "高地洞穴",
"location.Custom_JunimoWoods": "祝尼魔森林",
- //"location.Custom_MorrisProperty": "",
- "location.Custom_ShearwaterBridge": "海鸥栈桥",
- "location.Custom_SpriteSpring2": "精灵温泉"
+ "location.Custom_MorrisProperty": "莫里斯地产",
+ "location.Custom_HenchmanBackyard": "仆从后院",
+ "location.Custom_ForbiddenMaze": "禁忌迷宫",
+ "location.Custom_DiamondCavern": "钻石洞穴",
+ "location.Custom_ShearwaterBridge": "海鸥桥",
+ "location.Custom_SpriteSpring2": "精灵泉",
+ "location.Custom_GrampletonSuburbs": "郊区",
+ "location.Custom_GrampletonSuburbsTrainStation": "郊区火车站"
}
diff --git a/Almanac/manifest.json b/Almanac/manifest.json
index f30096e..18a3320 100644
--- a/Almanac/manifest.json
+++ b/Almanac/manifest.json
@@ -12,7 +12,8 @@
"Author": "Khloe Leclair",
"Version": "0.18.1-Debug",
"Description": "Adds an Almanac for the player, with forecasts, planting dates, and other calendar information useful for a farmer.",
- "MinimumApiVersion": "3.17.0",
+ "MinimumApiVersion": "4.1.0",
+ "MinimumGameVersion": "1.6.15",
"EntryDll": "Almanac.dll",
"Dependencies": [
{