private void UpdateTick(object sender, UpdateTickedEventArgs e) { if (Game1.player == null) { return; } if (Game1.player.CurrentTool is FishingRod) { FishingRod currentTool = Game1.player.CurrentTool as FishingRod; if (Config.fastBite && currentTool.timeUntilFishingBite > 0) { currentTool.timeUntilFishingBite /= 2; // 快速咬钩 } if (Config.autoHit && currentTool.isNibbling && !currentTool.isReeling && !currentTool.hit && !currentTool.pullingOutOfWater && !currentTool.fishCaught) { currentTool.DoFunction(Game1.player.currentLocation, 1, 1, 1, Game1.player); // 自动咬钩 } if (Config.maxCastPower) { currentTool.castingPower = 1; } } if (Game1.activeClickableMenu is BobberBar) // 自动小游戏 { BobberBar bar = Game1.activeClickableMenu as BobberBar; float barPos = Helper.Reflection.GetField <float>(bar, "bobberBarPos").GetValue(); float barHeight = Helper.Reflection.GetField <int>(bar, "bobberBarHeight").GetValue(); float fishPos = Helper.Reflection.GetField <float>(bar, "bobberPosition").GetValue(); float treasurePos = Helper.Reflection.GetField <float>(bar, "treasurePosition").GetValue(); float distanceFromCatching = Helper.Reflection.GetField <float>(bar, "distanceFromCatching").GetValue(); bool treasureCaught = Helper.Reflection.GetField <bool>(bar, "treasureCaught").GetValue(); bool hasTreasure = Helper.Reflection.GetField <bool>(bar, "treasure").GetValue(); float treasureScale = Helper.Reflection.GetField <float>(bar, "treasureScale").GetValue(); float bobberBarSpeed = Helper.Reflection.GetField <float>(bar, "bobberBarSpeed").GetValue(); float barPosMax = 568 - barHeight; float min = barPos + barHeight / 4, max = barPos + barHeight / 1.5f; if (Config.catchTreasure && hasTreasure && !treasureCaught && (distanceFromCatching > 0.75 || catching)) { catching = true; fishPos = treasurePos; } if (catching && distanceFromCatching < 0.15) { catching = false; fishPos = Helper.Reflection.GetField <float>(bar, "bobberPosition").GetValue(); } if (fishPos < min) { bobberBarSpeed -= 0.35f + (min - fishPos) / 20; Helper.Reflection.GetField <float>(bar, "bobberBarSpeed").SetValue(bobberBarSpeed); } else if (fishPos > max) { bobberBarSpeed += 0.35f + (fishPos - max) / 20; Helper.Reflection.GetField <float>(bar, "bobberBarSpeed").SetValue(bobberBarSpeed); } else { float target = 0.1f; if (bobberBarSpeed > target) { bobberBarSpeed -= 0.1f + (bobberBarSpeed - target) / 25; if (barPos + bobberBarSpeed > barPosMax) { bobberBarSpeed /= 2; // 减小触底反弹 } if (bobberBarSpeed < target) { bobberBarSpeed = target; } } else { bobberBarSpeed += 0.1f + (target - bobberBarSpeed) / 25; if (barPos + bobberBarSpeed < 0) { bobberBarSpeed /= 2; // 减小触顶反弹 } if (bobberBarSpeed > target) { bobberBarSpeed = target; } } Helper.Reflection.GetField <float>(bar, "bobberBarSpeed").SetValue(bobberBarSpeed); } } else { catching = false; } }
/// <summary> /// Update mod state. Try to keep processing quick here. /// </summary> public void OnUpdate() { if (!(Game1.player.CurrentTool is FishingRod)) { return; } FishingRod currentTool = Game1.player.CurrentTool as FishingRod; // Could set up a state machine to track this, but for now just check either in the minigame or not. if (Game1.activeClickableMenu is BobberBar && currentTool.isFishing) { PlayFishMinigame(); } else { // Do everything else the mod does outside of the fishing game. // If this is the first time out of the fishing game, clear the data. if (this.inFishingMenu) { log.Silly("Left Fishing minigame, clearing memory"); this.UnloadSVReflectionObjects(); this.inFishingMenu = false; IsButtonDownHack.simulateDown = false; } // This might be where a state machine might help, as an extra check, (e.g can't set power if you're not done casting, etc...) // but the SV tool API seems to give us enough data to have a go at it just checking conditionals. // Sequential steps to automate fishing if (config.autoCast && ShouldDoAutoCast(currentTool)) { log.Trace("Attempting to cast for the user"); currentTool.beginUsing(Game1.currentLocation, Game1.player.getStandingX(), Game1.player.getStandingY(), Game1.player); } if (config.maxCastPower && ShouldSetCastingPower(currentTool)) { log.Trace("Modifying cast to max cast power"); // Apparently for max to be registered it needs to be > 1.0, but anything over increases the // power bar past the UI, so make it a small number. Also, 1.001F is too small. currentTool.castingPower = 1.01F; } if (config.quickHook && ShouldSetQuickHook(currentTool)) { log.Trace("Modifying cast so fish will bite quickly."); // Game uses fishingBiteAccumulator as the value that gets modified so we should only modify that one // and let the game increase it and handle logic as they become equal. Change the gap if it doesn't // generate a quick hit quick enough. currentTool.fishingBiteAccumulator = currentTool.timeUntilFishingBite - fishingBiteAccumulatorGap; } if (config.autoHook && ShouldDoAutoHook(currentTool)) { log.Trace("Executing hook function for FishingRod"); currentTool.DoFunction(Game1.currentLocation, Game1.player.getStandingX(), Game1.player.getStandingY(), (int)currentTool.castingPower, Game1.player); } // Click away the catched fish. The conditionals are ordered here in a way // the check for the popup happens before the config check so the code can // always check the treasure chest. See the variable doneCaughtFish for more // info. if (ShouldDoDismissCaughtPopup(currentTool)) { log.Trace("Tool is sitting at caught fish popup"); doneCaughtFish = true; if (config.autoFinish && config.HarmonyLoad) { log.Trace("Closing popup with Harmony"); ClickAtAllHack.simulateClick = true; } } else { if (ClickAtAllHack.simulateClick) { log.Trace("Turning off Harmony injection for caught fish popup"); ClickAtAllHack.simulateClick = false; } } // Deal with any treasure that has popped up if (ShouldDoProcessTreasure(currentTool) && doneCaughtFish) { log.Trace("Found treasure after the caught fish popup"); doneCaughtFish = false; if (config.autoFinish) { log.Trace("Acquiring treasure"); ItemGrabMenu m = Game1.activeClickableMenu as ItemGrabMenu; if (m.ItemsToGrabMenu != null && m.ItemsToGrabMenu.actualInventory != null) { if (AcquireTreasure(m.ItemsToGrabMenu.actualInventory)) { m.exitThisMenu(true); } else { HandleItemGrabMenuError(m, "might be full inventory"); } } else { HandleItemGrabMenuError(m, "treasure chest is open, but inventory is null"); } } } } }