diff --git a/StardewArchipelago/Goals/GoalManager.cs b/StardewArchipelago/Goals/GoalManager.cs
index b28f8616a..a2703efc4 100644
--- a/StardewArchipelago/Goals/GoalManager.cs
+++ b/StardewArchipelago/Goals/GoalManager.cs
@@ -20,6 +20,7 @@ public class GoalManager
private readonly Harmony _harmony;
private readonly StardewArchipelagoClient _archipelago;
private LocationChecker _locationChecker;
+ private GrandpaIndicators _grandpaIndicators;
public GoalManager(LogHandler logger, IModHelper modHelper, Harmony harmony, StardewArchipelagoClient archipelago, LocationChecker locationChecker)
{
@@ -28,11 +29,12 @@ public GoalManager(LogHandler logger, IModHelper modHelper, Harmony harmony, Sta
_harmony = harmony;
_archipelago = archipelago;
_locationChecker = locationChecker;
+ _grandpaIndicators = new GrandpaIndicators(logger, modHelper, archipelago);
}
public void CheckGoalCompletion(bool vanillaGoal = false)
{
- EvaluateGrandpaToday(Game1.getFarm());
+ _grandpaIndicators.EvaluateGrandpaToday(Game1.getFarm());
switch (_archipelago.SlotData.Goal)
{
case Goal.CommunityCenter:
@@ -198,85 +200,5 @@ private void InjectPerfectionGoalMethods()
postfix: new HarmonyMethod(typeof(GoalCodeInjection), nameof(GoalCodeInjection.PercentGameComplete_PerfectionGoal_Postfix))
);
}
-
- private void EvaluateGrandpaToday(Farm farm)
- {
- var score = Utility.getGrandpaScore();
- var candlesFromScore = Utility.getGrandpaCandlesFromScore(score);
- farm.grandpaScore.Value = candlesFromScore;
- for (var index = 0; index < candlesFromScore; ++index)
- {
- DelayedAction.playSoundAfterDelay("fireball", 100 * index);
- }
- farm.addGrandpaCandles();
- AddArchipelagoIconsForPoints(farm, score);
- }
-
- private void AddArchipelagoIconsForPoints(Farm farm, int score)
- {
- var preference = ModEntry.Instance.Config.ShowGrandpaShrineIndicators;
- if (preference == GrandpaShrinePreferenrce.Never)
- {
- return;
- }
- if (preference == GrandpaShrinePreferenrce.GrandpaGoal && _archipelago.SlotData.Goal != Goal.GrandpaEvaluation)
- {
- return;
- }
-
- var size = 24;
- var whiteArchipelagoIcon = ArchipelagoTextures.GetArchipelagoLogo(_logger, _modHelper, size, ArchipelagoTextures.WHITE);
- var coloredArchipelagoIcon = ArchipelagoTextures.GetArchipelagoLogo(_logger, _modHelper, size, ArchipelagoTextures.COLOR);
-
- var grandpaShrinePosition = farm.GetGrandpaShrinePosition();
- var localId = 6666 + _archipelago.SlotData.Seed.GetHashCode();
- farm.removeTemporarySpritesWithIDLocal(localId);
-
- for (var i = 1; i <= 21; i++)
- {
- var texture = whiteArchipelagoIcon;
- var textureName = $"{ArchipelagoTextures.WHITE}_{size}";
- if (score >= i)
- {
- texture = coloredArchipelagoIcon;
- textureName = $"{ArchipelagoTextures.COLOR}_{size}";
- }
-
- var sprite = new TemporaryAnimatedSprite();
- sprite.texture = texture;
- sprite.textureName = textureName;
-
- var sourceRect = new Rectangle(0, 0, size, size);
- var column = (i - 1) % 7;
- var row = (i - 1) / 7;
- var positionX = ((grandpaShrinePosition.X - 2) * 64) + 50 + (column * 32);
- var positionY = ((grandpaShrinePosition.Y - 3) * 64) + 8 + (row * 32);
- var position = new Vector2(positionX, positionY);
-
- sprite.currentParentTileIndex = 0;
- sprite.initialParentTileIndex = 0;
- sprite.position = position;
- sprite.flicker = false;
- sprite.flipped = false;
-
- sprite.sourceRect = sourceRect;
- sprite.sourceRectStartingPos = new Vector2(sourceRect.X, sourceRect.Y);
- sprite.initialPosition = position;
- sprite.alphaFade = 0.0f;
- sprite.color = Color.White;
-
- sprite.interval = 50f;
- sprite.totalNumberOfLoops = 99999;
- sprite.animationLength = 1;
- sprite.lightId = $"Farm_GrandpaArchipelagoScore_{i}";
- sprite.id = localId;
- sprite.lightRadius = 1f;
- sprite.scale = 1f;
- sprite.layerDepth = 0.03f;
- sprite.delayBeforeAnimationStart = i * 50;
-
- farm.temporarySprites.Add(sprite);
- }
- }
}
}
diff --git a/StardewArchipelago/Goals/GrandpaIndicators.cs b/StardewArchipelago/Goals/GrandpaIndicators.cs
new file mode 100644
index 000000000..50c64ef48
--- /dev/null
+++ b/StardewArchipelago/Goals/GrandpaIndicators.cs
@@ -0,0 +1,267 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using HarmonyLib;
+using Microsoft.Xna.Framework;
+using StardewArchipelago.Archipelago;
+using StardewArchipelago.Logging;
+using StardewArchipelago.Textures;
+using StardewModdingAPI;
+using StardewModdingAPI.Events;
+using StardewModdingAPI.Utilities;
+using StardewValley;
+using StardewValley.Buildings;
+using StardewValley.ItemTypeDefinitions;
+using StardewValley.Menus;
+using StardewValley.Objects;
+using StardewValley.TerrainFeatures;
+using StardewValley.TokenizableStrings;
+using Object = System.Object;
+
+namespace StardewArchipelago.Goals
+{
+ public class GrandpaIndicators
+ {
+ private const int INDICATOR_SIZE = 24;
+
+ private Vector2 _currentMousePosition;
+
+ private readonly LogHandler _logger;
+ private readonly IModHelper _modHelper;
+ private readonly StardewArchipelagoClient _archipelago;
+
+ public GrandpaIndicators(LogHandler logger, IModHelper modHelper, StardewArchipelagoClient archipelago)
+ {
+ _logger = logger;
+ _modHelper = modHelper;
+ _archipelago = archipelago;
+
+ RegisterEventHandlers();
+ }
+
+ private void RegisterEventHandlers()
+ {
+ var preference = ModEntry.Instance.Config.ShowGrandpaShrineIndicators;
+ if (preference == GrandpaShrinePreference.Never)
+ {
+ return;
+ }
+ if (preference == GrandpaShrinePreference.GrandpaGoal && _archipelago.SlotData.Goal != Goal.GrandpaEvaluation)
+ {
+ return;
+ }
+ _modHelper.Events.Display.RenderingHud += OnRenderingHud;
+ _modHelper.Events.GameLoop.UpdateTicked += OnUpdateTicked;
+ }
+
+ public void EvaluateGrandpaToday(Farm farm)
+ {
+ var score = Utility.getGrandpaScore();
+ var candlesFromScore = Utility.getGrandpaCandlesFromScore(score);
+ farm.grandpaScore.Value = candlesFromScore;
+ for (var index = 0; index < candlesFromScore; ++index)
+ {
+ DelayedAction.playSoundAfterDelay("fireball", 100 * index);
+ }
+ farm.addGrandpaCandles();
+ AddArchipelagoIconsForPoints(farm);
+ }
+
+ private void AddArchipelagoIconsForPoints(Farm farm)
+ {
+ var preference = ModEntry.Instance.Config.ShowGrandpaShrineIndicators;
+ if (preference == GrandpaShrinePreference.Never)
+ {
+ return;
+ }
+ if (preference == GrandpaShrinePreference.GrandpaGoal && _archipelago.SlotData.Goal != Goal.GrandpaEvaluation)
+ {
+ return;
+ }
+
+ var whiteArchipelagoIcon = ArchipelagoTextures.GetArchipelagoLogo(_logger, _modHelper, INDICATOR_SIZE, ArchipelagoTextures.WHITE);
+ var coloredArchipelagoIcon = ArchipelagoTextures.GetArchipelagoLogo(_logger, _modHelper, INDICATOR_SIZE, ArchipelagoTextures.COLOR);
+
+ var grandpaShrinePosition = farm.GetGrandpaShrinePosition();
+ var localId = 6666 + _archipelago.SlotData.Seed.GetHashCode();
+ farm.removeTemporarySpritesWithIDLocal(localId);
+
+ for (var i = 0; i < 21; i++)
+ {
+ var texture = whiteArchipelagoIcon;
+ var textureName = $"{ArchipelagoTextures.WHITE}_{INDICATOR_SIZE}";
+ if (_indicatorTestMethods[i]())
+ {
+ texture = coloredArchipelagoIcon;
+ textureName = $"{ArchipelagoTextures.COLOR}_{INDICATOR_SIZE}";
+ }
+
+ var sprite = new TemporaryAnimatedSprite();
+ sprite.texture = texture;
+ sprite.textureName = textureName;
+
+ var sourceRect = new Rectangle(0, 0, INDICATOR_SIZE, INDICATOR_SIZE);
+ var column = i % 7;
+ var row = i / 7;
+ var position = GetIndicatorPosition(grandpaShrinePosition, column, row);
+
+ sprite.currentParentTileIndex = 0;
+ sprite.initialParentTileIndex = 0;
+ sprite.position = position;
+ sprite.flicker = false;
+ sprite.flipped = false;
+
+ sprite.sourceRect = sourceRect;
+ sprite.sourceRectStartingPos = new Vector2(sourceRect.X, sourceRect.Y);
+ sprite.initialPosition = position;
+ sprite.alphaFade = 0.0f;
+ sprite.color = Color.White;
+
+ sprite.interval = 50f;
+ sprite.totalNumberOfLoops = 99999;
+ sprite.animationLength = 1;
+ sprite.lightId = $"Farm_GrandpaArchipelagoScore_{i}";
+ sprite.id = localId;
+ sprite.lightRadius = 1f;
+ sprite.scale = 1f;
+ sprite.layerDepth = 0.03f;
+ sprite.delayBeforeAnimationStart = i * 50;
+
+ farm.temporarySprites.Add(sprite);
+ }
+ }
+
+ private static Vector2 GetIndicatorPosition(Point grandpaShrinePosition, int column, int row)
+ {
+ var positionX = ((grandpaShrinePosition.X - 2) * 64) + 50 + (column * 32);
+ var positionY = ((grandpaShrinePosition.Y - 3) * 64) + 8 + (row * 32);
+ var position = new Vector2(positionX, positionY);
+ return position;
+ }
+
+ private static bool TryGetIndicatorIndex(Point grandpaShrinePosition, Vector2 position, out int index)
+ {
+ index = -1;
+
+ var originX = ((grandpaShrinePosition.X - 2) * 64) + 50;
+ var originY = ((grandpaShrinePosition.Y - 3) * 64) + 8;
+ var width = (7 * 32) + 24;
+ var height = (3 * 32) + 24;
+ if (position.X < originX || position.X > originX + width || position.Y < originY || position.Y > originY + height)
+ {
+ return false;
+ }
+
+ var offsetPositionX = position.X - originX;
+ var offsetPositionY = position.Y - originY;
+ if (offsetPositionX % 32 > 24 || offsetPositionY % 32 > 24)
+ {
+ return false;
+ }
+
+ var column = (int)Math.Floor(offsetPositionX / 32);
+ var row = (int)Math.Floor(offsetPositionY / 32);
+
+ index = (row * 7) + column;
+ return true;
+ }
+
+ /// Raised after the game state is updated (≈60 times per second).
+ /// The event sender.
+ /// The event arguments.
+ private void OnUpdateTicked(object? sender, UpdateTickedEventArgs e)
+ {
+ if (!e.IsMultipleOf(4))
+ {
+ return;
+ }
+
+ if (Game1.currentLocation is not Farm)
+ {
+ _currentMousePosition = new Vector2(-1, -1);
+ return;
+ }
+
+ _currentMousePosition = new Vector2(Game1.viewport.X + Game1.getOldMouseX(), Game1.viewport.Y + Game1.getOldMouseY());
+ }
+
+ ///
+ /// Raised before drawing the HUD (item toolbar, clock, etc) to the screen. The vanilla HUD may be hidden at this
+ /// point (e.g. because a menu is open).
+ ///
+ /// The event sender.
+ /// The event arguments.
+ private void OnRenderingHud(object? sender, RenderingHudEventArgs e)
+ {
+ if (Game1.activeClickableMenu != null)
+ {
+ return;
+ }
+
+ if (!TryGetIndicatorIndex(Game1.getFarm().GetGrandpaShrinePosition(), _currentMousePosition, out var indicatorIndex))
+ {
+ return;
+ }
+
+ IClickableMenu.drawHoverText(
+ Game1.spriteBatch,
+ string.Join('\n', _indicatorDescriptions[indicatorIndex]),
+ Game1.smallFont,
+ overrideX: -1,
+ overrideY: -1
+ );
+ }
+
+ private readonly Dictionary _indicatorDescriptions = new()
+ {
+ { 0, "50,000g" },
+ { 1, "100,000g" },
+ { 2, "200,000g" },
+ { 3, "300,000g" },
+ { 4, "500,000g" },
+ { 5, "1,000,000g" },
+ { 6, "1,000,000g" },
+ { 7, "30 Levels Total" },
+ { 8, "50 Levels Total" },
+ { 9, "Complete Collection" },
+ { 10, "Master Angler" },
+ { 11, "Full Shipment" },
+ { 12, "Married with two house upgrades" },
+ { 13, "5 good friends" },
+ { 14, "10 good friends" },
+ { 15, "Pet loves you" },
+ { 16, "Community Center" },
+ { 17, "Community Center Ceremony" },
+ { 18, "Community Center Ceremony" },
+ { 19, "Skull Key" },
+ { 20, "Rusty Key" },
+ };
+
+ private readonly Dictionary> _indicatorTestMethods = new()
+ {
+ { 0, () => Game1.player.totalMoneyEarned >= 50000U },
+ { 1, () => Game1.player.totalMoneyEarned >= 100000U },
+ { 2, () => Game1.player.totalMoneyEarned >= 200000U },
+ { 3, () => Game1.player.totalMoneyEarned >= 300000U },
+ { 4, () => Game1.player.totalMoneyEarned >= 500000U },
+ { 5, () => Game1.player.totalMoneyEarned >= 1000000U },
+ { 6, () => Game1.player.totalMoneyEarned >= 1000000U },
+ { 7, () => Game1.player.Level >= 15 },
+ { 8, () => Game1.player.Level >= 25 },
+ { 9, () => Game1.player.achievements.Contains(5) },
+ { 10, () => Game1.player.achievements.Contains(26) },
+ { 11, () => Game1.player.achievements.Contains(34) },
+ { 12, () => Game1.player.isMarriedOrRoommates() && Utility.getHomeOfFarmer(Game1.player).upgradeLevel >= 2 },
+ { 13, () => Utility.getNumberOfFriendsWithinThisRange(Game1.player, 1975, 999999) >= 5 },
+ { 14, () => Utility.getNumberOfFriendsWithinThisRange(Game1.player, 1975, 999999) >= 10 },
+ { 15, () => Game1.player.mailReceived.Contains("petLoveMessage") },
+ { 16, () => Game1.player.hasCompletedCommunityCenter() },
+ { 17, () => Utility.HasAnyPlayerSeenEvent("191393") },
+ { 18, () => Utility.HasAnyPlayerSeenEvent("191393") },
+ { 19, () => Game1.player.hasSkullKey },
+ { 20, () => Game1.player.hasRustyKey },
+ };
+ }
+}
\ No newline at end of file
diff --git a/StardewArchipelago/Integrations/GenericModConfigMenu/ConfigMenu.cs b/StardewArchipelago/Integrations/GenericModConfigMenu/ConfigMenu.cs
index af2818a09..55a5ff903 100644
--- a/StardewArchipelago/Integrations/GenericModConfigMenu/ConfigMenu.cs
+++ b/StardewArchipelago/Integrations/GenericModConfigMenu/ConfigMenu.cs
@@ -261,7 +261,7 @@ public void RegisterConfig()
formatValue: (value) => ((SeasonPreference)value).ToString()
);
- var grandpaShrinePreferenceValues = Enum.GetValues(typeof(GrandpaShrinePreferenrce)).Cast().ToArray();
+ var grandpaShrinePreferenceValues = Enum.GetValues(typeof(GrandpaShrinePreference)).Cast().ToArray();
var grandpaShrinePreferenceMin = grandpaShrinePreferenceValues.Min();
var grandpaShrinePreferenceMax = grandpaShrinePreferenceValues.Max();
configMenu.AddNumberOption(
@@ -272,8 +272,8 @@ public void RegisterConfig()
max: grandpaShrinePreferenceMax,
interval: 1,
getValue: () => (int)Config.ShowGrandpaShrineIndicators,
- setValue: (value) => Config.ShowGrandpaShrineIndicators = (GrandpaShrinePreferenrce)value,
- formatValue: (value) => ((GrandpaShrinePreferenrce)value).ToString()
+ setValue: (value) => Config.ShowGrandpaShrineIndicators = (GrandpaShrinePreference)value,
+ formatValue: (value) => ((GrandpaShrinePreference)value).ToString()
);
}
}
diff --git a/StardewArchipelago/ModConfig.cs b/StardewArchipelago/ModConfig.cs
index 02c4072bb..8d4c9b553 100644
--- a/StardewArchipelago/ModConfig.cs
+++ b/StardewArchipelago/ModConfig.cs
@@ -91,7 +91,7 @@ public class ModConfig
///
/// Whether to display archipelago icons on grandpa's shrine to see current points
///
- public GrandpaShrinePreferenrce ShowGrandpaShrineIndicators { get; set; } = GrandpaShrinePreferenrce.GrandpaGoal;
+ public GrandpaShrinePreference ShowGrandpaShrineIndicators { get; set; } = GrandpaShrinePreference.GrandpaGoal;
}
public enum ItemIndicatorPreference
@@ -108,7 +108,7 @@ public enum SeasonPreference
Cycle = 2,
}
- public enum GrandpaShrinePreferenrce
+ public enum GrandpaShrinePreference
{
Never = 0,
GrandpaGoal = 1,