public CustomBobberBar(SFarmer user, int whichFish, float fishSize, bool treasure, int bobber, int waterDepth) : base(whichFish, fishSize, treasure, bobber) { this.User = user; this._origStreak = FishHelper.GetStreak(user); /* Private field hooks */ this._treasureField = ModFishing.INSTANCE.Helper.Reflection.GetPrivateField <bool>(this, "treasure"); this._treasureCaughtField = ModFishing.INSTANCE.Helper.Reflection.GetPrivateField <bool>(this, "treasureCaught"); this._treasurePositionField = ModFishing.INSTANCE.Helper.Reflection.GetPrivateField <float>(this, "treasurePosition"); this._treasureAppearTimerField = ModFishing.INSTANCE.Helper.Reflection.GetPrivateField <float>(this, "treasureAppearTimer"); this._treasureScaleField = ModFishing.INSTANCE.Helper.Reflection.GetPrivateField <float>(this, "treasureScale"); this._distanceFromCatchingField = ModFishing.INSTANCE.Helper.Reflection.GetPrivateField <float>(this, "distanceFromCatching"); this._treasureCatchLevelField = ModFishing.INSTANCE.Helper.Reflection.GetPrivateField <float>(this, "treasureCatchLevel"); this._bobberBarPosField = ModFishing.INSTANCE.Helper.Reflection.GetPrivateField <float>(this, "bobberBarPos"); this._difficultyField = ModFishing.INSTANCE.Helper.Reflection.GetPrivateField <float>(this, "difficulty"); this._fishQualityField = ModFishing.INSTANCE.Helper.Reflection.GetPrivateField <int>(this, "fishQuality"); this._perfectField = ModFishing.INSTANCE.Helper.Reflection.GetPrivateField <bool>(this, "perfect"); this._sparkleTextField = ModFishing.INSTANCE.Helper.Reflection.GetPrivateField <SparklingText>(this, "sparkleText"); this._lastDistanceFromCatching = this._distanceFromCatchingField.GetValue(); this._lastTreasureCatchLevel = this._treasureCatchLevelField.GetValue(); /* Actual code */ ConfigMain config = ModFishing.INSTANCE.Config; ConfigStrings strings = ModFishing.INSTANCE.Strings; // Choose a random fish, this time using the custom fish selector FishingRod rod = Game1.player.CurrentTool as FishingRod; //int waterDepth = rod != null ? ModEntry.INSTANCE.Helper.Reflection.GetPrivateValue<int>(rod, "clearWaterDistance") : 0; // Applies difficulty modifier, including if fish isn't paying attention float difficulty = this._difficultyField.GetValue() * config.BaseDifficultyMult; difficulty *= 1f + config.DifficultyStreakEffect * this._origStreak; double difficultyChance = config.UnawareChance + user.LuckLevel * config.UnawareLuckLevelEffect + Game1.dailyLuck * config.UnawareDailyLuckEffect; if (Game1.random.NextDouble() < difficultyChance) { Game1.showGlobalMessage(string.Format(strings.UnawareFish, 1f - config.UnawareMult)); difficulty *= config.UnawareMult; } this._difficultyField.SetValue(difficulty); // Adjusts quality to be increased by streak int fishQuality = this._fishQualityField.GetValue(); this._origQuality = fishQuality; int qualityBonus = (int)Math.Floor((double)this._origStreak / config.StreakForIncreasedQuality); fishQuality = Math.Min(fishQuality + qualityBonus, 3); if (fishQuality == 3) { fishQuality++; // Iridium-quality fish. Only possible through your perfect streak } this._fishQualityField.SetValue(fishQuality); // Increase the user's perfect streak (this will be dropped to 0 if they don't get a perfect catch) if (this._origStreak >= config.StreakForIncreasedQuality) { this._sparkleTextField.SetValue(new SparklingText(Game1.dialogueFont, string.Format(strings.StreakDisplay, this._origStreak), Color.Yellow, Color.White)); } FishHelper.SetStreak(user, this._origStreak + 1); }
public override void update(GameTime time) { // Speed warp on normal catching float distanceFromCatching = this._distanceFromCatchingField.GetValue(); float delta = distanceFromCatching - this._lastDistanceFromCatching; distanceFromCatching += (ModFishing.INSTANCE.Config.CatchSpeed - 1f) * delta; this._lastDistanceFromCatching = distanceFromCatching; this._distanceFromCatchingField.SetValue(distanceFromCatching); // Speed warp on treasure catching float treasureCatchLevel = this._treasureCatchLevelField.GetValue(); delta = treasureCatchLevel - this._lastTreasureCatchLevel; treasureCatchLevel += (ModFishing.INSTANCE.Config.TreasureCatchSpeed - 1f) * delta; this._lastTreasureCatchLevel = treasureCatchLevel; this._treasureCatchLevelField.SetValue(treasureCatchLevel); bool perfect = this._perfectField.GetValue(); bool treasure = this._treasureField.GetValue(); bool treasureCaught = this._treasureCaughtField.GetValue(); ConfigStrings strings = ModFishing.INSTANCE.Strings; // Check if still perfect, otherwise apply changes to loot if (!this._perfectChanged && !perfect) { this._perfectChanged = true; this._fishQualityField.SetValue(Math.Min(this._origQuality, 1)); FishHelper.SetStreak(this.User, 0); if (this._origStreak >= ModFishing.INSTANCE.Config.StreakForIncreasedQuality) { Game1.showGlobalMessage(treasure ? string.Format(strings.WarnStreak, this._origStreak) : string.Format(strings.LostStreak, this._origStreak)); } } if (!this._treasureChanged && !perfect && treasure && treasureCaught) { this._treasureChanged = true; int qualityBonus = (int)Math.Floor((double)this._origStreak / ModFishing.INSTANCE.Config.StreakForIncreasedQuality); int quality = this._origQuality; quality = Math.Min(quality + qualityBonus, 3); if (quality == 3) { quality++; } this._fishQualityField.SetValue(quality); } base.update(time); distanceFromCatching = this._distanceFromCatchingField.GetValue(); if (distanceFromCatching <= 0.0) { // Failed to catch fish //FishHelper.setStreak(this.user, 0); if (!this._notifiedFailOrSucceed && treasure) { this._notifiedFailOrSucceed = true; if (this._origStreak >= ModFishing.INSTANCE.Config.StreakForIncreasedQuality) { Game1.showGlobalMessage(string.Format(strings.LostStreak, this._origStreak)); } } } else if (distanceFromCatching >= 1.0) { // Succeeded in catching the fish if (!this._notifiedFailOrSucceed && !perfect && treasure && treasureCaught) { this._notifiedFailOrSucceed = true; if (this._origStreak >= ModFishing.INSTANCE.Config.StreakForIncreasedQuality) { Game1.showGlobalMessage(string.Format(strings.KeptStreak, this._origStreak)); } FishHelper.SetStreak(this.User, this._origStreak); } } }
public static void OpenTreasureMenuEndFunction(FishingRod rod, int extra) { ModFishing.INSTANCE.Monitor.Log("Successfully replaced treasure", LogLevel.Trace); ConfigMain config = ModFishing.INSTANCE.Config; SFarmer lastUser = ModFishing.INSTANCE.Helper.Reflection.GetPrivateValue <SFarmer>(rod, "lastUser"); int clearWaterDistance = 5; if (config.OverrideFishing) { if (FishingRodOverrides.ClearWaterDistances.ContainsKey(lastUser)) { clearWaterDistance = FishingRodOverrides.ClearWaterDistances[lastUser]; } else { ModFishing.INSTANCE.Monitor.Log("The bobber bar was not replaced. Fishing might not be overridden by this mod", LogLevel.Warn); } } int whichFish = ModFishing.INSTANCE.Helper.Reflection.GetPrivateValue <int>(rod, "whichFish"); int fishQuality = ModFishing.INSTANCE.Helper.Reflection.GetPrivateValue <int>(rod, "fishQuality"); lastUser.gainExperience(5, 10 * (clearWaterDistance + 1)); rod.doneFishing(lastUser, true); lastUser.completelyStopAnimatingOrDoingAction(); // REWARDS List <Item> rewards = new List <Item>(); if (extra == 1) { rewards.Add(new StardewValley.Object(whichFish, 1, false, -1, fishQuality)); } List <TreasureData> possibleLoot = new List <TreasureData>(config.PossibleLoot) .Where(treasure => treasure.IsValid(lastUser.FishingLevel, clearWaterDistance)).ToList(); // Select rewards float chance = 1f; int streak = FishHelper.GetStreak(lastUser); while (possibleLoot.Count > 0 && rewards.Count < config.MaxTreasureQuantity && Game1.random.NextDouble() <= chance) { TreasureData treasure = possibleLoot.Choose(Game1.random); int id = treasure.id + Game1.random.Next(treasure.idRange - 1); if (id == Objects.LOST_BOOK) { if (lastUser.archaeologyFound == null || !lastUser.archaeologyFound.ContainsKey(102) || lastUser.archaeologyFound[102][0] >= 21) { continue; } Game1.showGlobalMessage("You found a lost book. The library has been expanded."); } int count = Game1.random.Next(treasure.minAmount, treasure.maxAmount); Item reward; if (treasure.meleeWeapon) { reward = new MeleeWeapon(id); } else if (id >= Ring.ringLowerIndexRange && id <= Ring.ringUpperIndexRange) { reward = new Ring(id); } else if (id >= 504 && id <= 513) { reward = new Boots(id); } else { reward = new StardewValley.Object(Vector2.Zero, id, count); } rewards.Add(reward); if (!config.AllowDuplicateLoot || !treasure.allowDuplicates) { possibleLoot.Remove(treasure); } //rewards.Add(new StardewValley.Object(Vector2.Zero, Objects.BAIT, Game1.random.Next(10, 25))); } // Add bait if no rewards were selected. NOTE: This should never happen if (rewards.Count == 0) { ModFishing.INSTANCE.Monitor.Log("Could not find any valid loot for the treasure chest. Check your treasure.json?", LogLevel.Warn); rewards.Add(new StardewValley.Object(685, Game1.random.Next(2, 5) * 5, false, -1, 0)); } // Show rewards GUI Game1.activeClickableMenu = new ItemGrabMenu(rewards); (Game1.activeClickableMenu as ItemGrabMenu).source = 3; lastUser.completelyStopAnimatingOrDoingAction(); }
public static int GetRandomFish(int depth, int mineLevel = -1) => FishHelper.GetRandomFish(FishHelper.GetPossibleFish(depth, mineLevel));
public static void StartMinigameEndFunction(FishingRod rod, int extra) { ModFishing.INSTANCE.Monitor.Log("Overriding fishing minigame", LogLevel.Trace); ConfigMain config = ModFishing.INSTANCE.Config; SFarmer lastUser = ModFishing.INSTANCE.Helper.Reflection.GetPrivateValue <SFarmer>(rod, "lastUser"); Vector2 bobber = ModFishing.INSTANCE.Helper.Reflection.GetPrivateValue <Vector2>(rod, "bobber"); rod.isReeling = true; rod.hit = false; switch (lastUser.FacingDirection) { case 1: lastUser.FarmerSprite.setCurrentSingleFrame(48, 32000, false, false); break; case 3: lastUser.FarmerSprite.setCurrentSingleFrame(48, 32000, false, true); break; } lastUser.FarmerSprite.pauseForSingleAnimation = true; int clearWaterDistance = FishingRod.distanceToLand((int)(bobber.X / (double)Game1.tileSize - 1.0), (int)(bobber.Y / (double)Game1.tileSize - 1.0), lastUser.currentLocation); FishingRodOverrides.ClearWaterDistances[lastUser] = clearWaterDistance; float num = 1f * (clearWaterDistance / 5f) * (Game1.random.Next(1 + Math.Min(10, lastUser.FishingLevel) / 2, 6) / 5f); if (rod.favBait) { num *= 1.2f; } float fishSize = Math.Max(0.0f, Math.Min(1f, num * (float)(1.0 + Game1.random.Next(-10, 10) / 100.0))); bool treasure = false; double treasureChance = config.TreasureChance + lastUser.LuckLevel * config.TreasureLuckLevelEffect + (rod.getBaitAttachmentIndex() == 703 ? config.TreasureBaitEffect : 0.0) + (rod.getBobberAttachmentIndex() == 693 ? config.TreasureBobberEffect : 0.0) + Game1.dailyLuck * config.TreasureDailyLuckEffect + (lastUser.professions.Contains(9) ? config.TreasureChance : 0.0) + config.TreasureStreakEffect * FishHelper.GetStreak(lastUser); treasureChance = Math.Min(treasureChance, config.MaxTreasureChance); if (!Game1.isFestival() && lastUser.fishCaught != null && lastUser.fishCaught.Count > 1 && Game1.random.NextDouble() < treasureChance) { treasure = true; } // Override caught fish bool legendary = FishHelper.IsLegendary(extra); if (!config.UseVanillaFish && (!config.VanillaLegendaries || !legendary)) { int origExtra = extra; extra = FishHelper.GetRandomFish(clearWaterDistance); if (FishHelper.IsTrash(extra)) { if (false) // TODO: Replace this with code relating to a config option that determines the chance you'll get fish/trash { #pragma warning disable CS0162 // Unreachable code detected Game1.showGlobalMessage("No valid fish to catch! Giving junk instead."); StardewValley.Object o = new StardewValley.Object(extra, 1, false, -1, 0); rod.pullFishFromWater(extra, -1, 0, 0, false, false); return; #pragma warning restore CS0162 // Unreachable code detected } else { ModFishing.INSTANCE.Monitor.Log("No valid fish to catch! Using original fish instead.", LogLevel.Warn); extra = origExtra; } } } // Show custom bobber bar Game1.activeClickableMenu = new CustomBobberBar(lastUser, extra, fishSize, treasure, rod.attachments[1] != null ? rod.attachments[1].ParentSheetIndex : -1, clearWaterDistance); }