/// <summary>
        /// Reimplements (almost) the entire Farm.checkAction() logic when a player checks for an action on the tiles of grandpa's shrine.
        /// Includes new logic to add mail, grant bonus rewards, allow infinite re-evalualtions, and give each farmhand their own Statue of Perfection.
        /// </summary>
        /// <param name="tileLocation">The tile location being checked to see if an action is possible.</param>
        /// <param name="viewport">The viewport of the screen.</param>
        /// <param name="who">The player performing an action.</param>
        /// <param name="__instance">The Farm location where the player is acting on the world.</param>
        /// <param name="__result">The result returned by checkAction. Assign true if an action is possible, false if no action is possible.</param>
        /// <returns>true if the original checkAction method is allowed to run; false if blocked</returns>
        public static bool farmCheckAction_Prefix(Location tileLocation, xTile.Dimensions.Rectangle viewport, Farmer who, Farm __instance, ref bool __result)
        {
            try
            {
                Microsoft.Xna.Framework.Rectangle rect = new Microsoft.Xna.Framework.Rectangle(tileLocation.X * 64, tileLocation.Y * 64, 64, 64);
                switch (__instance.map.GetLayer("Buildings").Tiles[tileLocation] != null ? __instance.map.GetLayer("Buildings").Tiles[tileLocation].TileIndex : -1)
                {
                case 1956:
                case 1957:
                case 1958:     // Any of the three tiles that make up grandpa's shrine
                    // Clicking on grandpa's note for the first time?
                    if (!__instance.hasSeenGrandpaNote)
                    {
                        __instance.hasSeenGrandpaNote = true;
                        Game1.activeClickableMenu     = (IClickableMenu) new LetterViewerMenu(Game1.content.LoadString("Strings\\Locations:Farm_GrandpaNote", (object)Game1.player.Name).Replace('\n', '^'));
                        if (!Game1.player.mailReceived.Contains("6324grandpaNoteMail"))       // Add mail to collections
                        {
                            Game1.player.mailReceived.Insert(0, "6324grandpaNoteMail");
                        }
                        __result = true;
                        return(false);    // Alter __result, don't run original code.
                    }
                    // Check for new bonus rewards. Players must do an evaluation with this mod to activate them.
                    if (Config.BonusRewards && Game1.player.mailReceived.Contains("6324hasDoneModdedEvaluation"))
                    {
                        // Give new 1-candle reward (Ancient seed artifact)
                        if ((int)(NetFieldBase <int, NetInt>)__instance.grandpaScore >= 1 && !Game1.player.mailReceived.Contains("6324reward1candle"))
                        {
                            who.addItemByMenuIfNecessaryElseHoldUp((Item) new Object(Vector2.Zero, 114, 1), new ItemGrabMenu.behaviorOnItemSelect(grandpa1CandleCallback));
                            __result = true;
                            return(false);    // Alter __result, don't run original code.
                        }
                        // Give new 2-candle reward (Dinosaur egg)
                        if ((int)(NetFieldBase <int, NetInt>)__instance.grandpaScore >= 2 && !Game1.player.mailReceived.Contains("6324reward2candle"))
                        {
                            who.addItemByMenuIfNecessaryElseHoldUp((Item) new Object(Vector2.Zero, 107, 1), new ItemGrabMenu.behaviorOnItemSelect(grandpa2CandleCallback));
                            __result = true;
                            return(false);    // Alter __result, don't run original code.
                        }
                        // Give new 3-candle reward (Prismatic shard)
                        if ((int)(NetFieldBase <int, NetInt>)__instance.grandpaScore >= 3 && !Game1.player.mailReceived.Contains("6324reward3candle"))
                        {
                            who.addItemByMenuIfNecessaryElseHoldUp((Item) new Object(Vector2.Zero, 74, 1), new ItemGrabMenu.behaviorOnItemSelect(grandpa3CandleCallback));
                            __result = true;
                            return(false);    // Alter __result, don't run original code.
                        }
                    }
                    // Give 4-candle reward (Statue of Perfection)
                    if (Config.StatuesForFarmhands && Game1.player.mailReceived.Contains("6324hasDoneModdedEvaluation"))
                    {     // ANGRY GRANDPA LOGIC
                        if ((int)(NetFieldBase <int, NetInt>)__instance.grandpaScore >= 4 && !Game1.player.mailReceived.Contains("6324reward4candle"))
                        {
                            who.addItemByMenuIfNecessaryElseHoldUp((Item) new Object(Vector2.Zero, 160, false), new ItemGrabMenu.behaviorOnItemSelect(grandpa4CandleCallback));
                            __result = true;
                            Monitor.Log($"Used modifed logic to grant Statue of Perfection: {nameof(farmCheckAction_Prefix)}", LogLevel.Trace);
                            return(false);    // Alter __result, don't run original code.
                        }
                    }
                    else     // VANILLA LOGIC
                    {
                        if ((int)(NetFieldBase <int, NetInt>)__instance.grandpaScore >= 4 && !Utility.doesItemWithThisIndexExistAnywhere(160, true))
                        {
                            who.addItemByMenuIfNecessaryElseHoldUp((Item) new Object(Vector2.Zero, 160, false), new ItemGrabMenu.behaviorOnItemSelect(__instance.grandpaStatueCallback));
                            __result = true;
                            Monitor.Log($"Used vanilla game logic to grant Statue of Perfection: {nameof(farmCheckAction_Prefix)}", LogLevel.Trace);
                            return(false);    // Alter __result, don't run original code.
                        }
                    }
                    // Accept diamond or prompt for diamond
                    if (Game1.year > Config.YearsBeforeEvaluation && (int)(NetFieldBase <int, NetInt>)__instance.grandpaScore > 0)   // && (int)(NetFieldBase<int, NetInt>)__instance.grandpaScore < 4) // Allow endless re-evaluations
                    {
                        if (who.ActiveObject != null && (int)(NetFieldBase <int, NetInt>)who.ActiveObject.parentSheetIndex == 72)    // && (int)(NetFieldBase<int, NetInt>)__instance.grandpaScore < 4) // Allow endless re-evaluations
                        {
                            who.reduceActiveItemByOne();
                            __instance.playSound("stoneStep", NetAudio.SoundContext.Default);
                            __instance.playSound("fireball", NetAudio.SoundContext.Default);
                            DelayedAction.playSoundAfterDelay("yoba", 800, (GameLocation)__instance, -1);
                            DelayedAction.showDialogueAfterDelay(Game1.content.LoadString("Strings\\Locations:Farm_GrandpaShrine_PlaceDiamond"), 1200);
                            // Game1.multiplayer.broadcastGrandpaReevaluation(); // Re-implemented below
                            IReflectedField <Multiplayer> mp = Helper.Reflection.GetField <Multiplayer>(typeof(Game1), "multiplayer");
                            Helper.Reflection.GetMethod(mp.GetValue(), "broadcastGrandpaReevaluation").Invoke();
                            Game1.player.freezePause = 1200;
                            __result = true;
                            return(false);    // Alter __result, don't run original code.
                        }
                        if (who.ActiveObject == null || (int)(NetFieldBase <int, NetInt>)who.ActiveObject.parentSheetIndex != 72)
                        {
                            Game1.drawObjectDialogue(Game1.content.LoadString("Strings\\Locations:Farm_GrandpaShrine_DiamondSlot"));
                            __result = true;
                            return(false);    // Alter __result, don't run original code.
                        }
                        break;
                    }
                    // Uh-oh, if somehow an evaluation is needed, request one for free.
                    if ((int)(NetFieldBase <int, NetInt>)__instance.grandpaScore == 0 && Game1.year > Config.YearsBeforeEvaluation)
                    {
                        while (Game1.player.eventsSeen.Contains(558292))
                        {
                            Game1.player.eventsSeen.Remove(558292);     // Remove re-evaluation event
                        }
                        if (Game1.player.eventsSeen.Contains(558291) && // If have not seen original, can still trigger
                            !Game1.player.eventsSeen.Contains(321777))  // Re-evaluation request
                        {
                            Game1.player.eventsSeen.Add(321777);
                            break;
                        }
                        break;
                    }
                    break;     // Exit to baseMethod logic below

                default:
                    return(true);    // Run original code if not one of the shrine tiles
                }
                // return base.checkAction(tileLocation, viewport, who) || Game1.didPlayerJustRightClick(true) && __instance.CheckInspectAnimal(rect, who); // Re-implemented below.
                var baseMethod      = typeof(BuildableGameLocation).GetMethod("checkAction");
                var ftn             = baseMethod.MethodHandle.GetFunctionPointer();
                var baseCheckAction = (Func <Location, xTile.Dimensions.Rectangle, Farmer, bool>)Activator.CreateInstance(
                    typeof(Func <Location, xTile.Dimensions.Rectangle, Farmer, bool>), __instance, ftn);
                __result = baseCheckAction(tileLocation, viewport, who) || (Game1.didPlayerJustRightClick(true) && __instance.CheckInspectAnimal(rect, who));
                return(false); // Alter __result, don't run original code.
            }
            catch (Exception ex)
            {
                Monitor.Log($"Failed in {nameof(farmCheckAction_Prefix)}:\n{ex}",
                            LogLevel.Error);
                return(true); // Run original code
            }
        }