This wiki is a read-only version of the Stardew Valley Wiki. The official editable wiki maintained by ConcernedApe can be found at stardewvalleywiki.com

User talk:Alleria

From Stardew Valley Wiki
Jump to: navigation, search
This is Alleria's talk page, where you can send messages and comments to Alleria.
  • Sign and date your posts by typing four tildes (~~~~).
  • Put new text below old text.
  • Be polite.
  • Assume good faith.
  • Don't delete discussions.

Fishing

Hello Alleria! First off, let me say we both have the same goal, which is to make the wiki accurate and complete. The worst mistakes made on the wiki were assumptions based on experiential data when RNG was involved.

It may or may not be true that you can catch only trash with a fishing pole on the standard farm pond, but you need to provide a code reference showing that. In fact, I think you may be right, but if you find that code reference, you need to specify "with a fishing pole", since the edit to the Farm Pond page stated that only trash could be caught, right next to an image of crab pots full of fish.

The amount of trash you catch on different maps and the occurrence of bubbles may be very different than someone else's experience of them. Again, a code reference is impossible to argue with.

Quality of fish is determined by a combination of fishing level and casting distance (specifically, how far from the nearest land tile the bobber lands). This is valuable information, but I don't think it belongs in the short summary table on the Farm Maps page. Instead, it's already stated on the Fishing Strategy page -- a page which already contains the information you added to the Cindersap Forest page.

I agree that the mechanics of fish quality could use more emphasis/elaboration on the wiki, but I think that belongs on Fish, Fishing and/or Fishing Strategy instead of the short summary table on the Farm Maps page.

A small side note -- please remember to sign your posts by typing 4 tildes, so I know who to respond to when reading comments on my talk page. Thanks! margotbean (talk) 16:31, 15 May 2019 (BST)


Hello Margotbean!

Thank you for replying, and sorry for not signing my previous message, I am a bit new to editing wikis.

I believe you are right in your comments, especially regarding the role played by RNG! I went with personal testing instead of finding the appropriate code reference for the data as none of this information is included in neither the locations.xnb nor fish.xnb files - and I haven't been able to find another file providing relevant information. My thought was that with a sufficient sampling size, it would be definitely possible to roughly assess if trash catching chances and quality of fishes would vastly differ between fishing in the farm and fishing elsewhere. Though this methodology would not be sufficiently precise to give the exact chances. Anyway, I understand that it currently is not precise enough for the wiki.

Regarding fishing in the Farm Pond, you are right that my edition should have been "Only trash can be caught with a fishing pole on the Standard Farm map". Though I indeed have no data to back this up, hundreds of attempts on different save files with different fishing skills and during different seasons never yield anything but trash. I would be very surprised if that was not the case.

Alleria (talk) 20:47, 15 May 2019 (BST)

The following code is relates to how fishing on the farm works. This is found in Farm.cs:
    public override Object getFish(
      float millisecondsAfterNibble,
      int bait,
      int waterDepth,
      Farmer who,
      double baitPotency)
    {
      switch (Game1.whichFarm)
      {
        case 1:
          if (Game1.random.NextDouble() < 0.3)
            return this.getFish(millisecondsAfterNibble, bait, waterDepth, who, baitPotency, "Forest");
          return this.getFish(millisecondsAfterNibble, bait, waterDepth, who, baitPotency, "Town");
        case 2:
          if (Game1.random.NextDouble() < 0.05 + Game1.dailyLuck)
            return new Object(734, 1, false, -1, 0);
          if (Game1.random.NextDouble() < 0.45)
            return this.getFish(millisecondsAfterNibble, bait, waterDepth, who, baitPotency, "Forest");
          break;
        case 3:
          if (Game1.random.NextDouble() < 0.5)
            return this.getFish(millisecondsAfterNibble, bait, waterDepth, who, baitPotency, "Forest");
          break;
        case 4:
          if (Game1.random.NextDouble() <= 0.35)
            return this.getFish(millisecondsAfterNibble, bait, waterDepth, who, baitPotency, "Mountain");
          break;
      }
      return base.getFish(millisecondsAfterNibble, bait, waterDepth, who, baitPotency);
    }
The default farm returns the base, which looks up the locations file for "Farm", which has no fishing information, so can only return trash.
Case 1 is the River Farm. The river farm has a 30% chance of returning Forest fish, and a default (70%) chance of returning Town fish.
Case 2 is the Forest Farm. The forest farm has a 5 + (-10 - 10)% chance of finding a woodskip, otherwise a 45% chance of returnng Forest fish, defaulting to "Farm" which only returns trash
Case 3 is the Mountain Farm. The mountain farm has a 50% chance of returning Forest fish defaulting to "Farm"
Case 4 is the "Combat" Farm. This has a 35% chance of returning "Mountain" fish, defaulting to "Farm"
When the call is overridden with a location, there is still a chance of getting trash, as you would if you were actually fishing from that location
Regarding bubbles, The farm is excluded from getting bubbles, except for the River Farm
GameLocation:performTenMinuteUpdate
Point point1 = this.fishSplashPoint.Value;
if (point1.Equals(Point.Zero) && random.NextDouble() < 0.5 && (!(this is Farm) || Game1.whichFarm == 1))
BlaDe (talk) 02:45, 16 May 2019 (BST)



Hello Blade!

This information is perfectly what we needed, excellent!

However, I am very surprised by the results on the Riverlands Farm. If I understand the data correctly, it would mean that the Riverlands Farm has a 100% chance to return a fish from another location, either the forest (30%) or the town (70%), but thus would never default to "Farm". Though this contradicts my personal testing with respect to the number of trashes I get when I fish in the Riverlands Farm, which is higher than when fishing in the river (either Town or Forest), this is not what is the most surprising. According to this data, this could mean that you could potentially get Chub in all seasons and Dorado in Summer, which I am positive is not true.

I ran some testing this morning to try to test this code-data against in-game experiment. Here were the parameters for that experiment.

Experiment 1

  • Year: 1
  • Month: Spring
  • Day: 3
  • Weather: Rain
  • Luck: Good Humor (+0.02 to +0.07) - probably in the higher end of the bracket, UI Info Suite 1.7.23 by Cdaragorn displaying the green dice for luck and "You're feelin' lucky!!"
  • Fishing level: 3-5 (progressing during the day)
  • Fishing location on the farm: Deep water, various
  • Casting distance: max
  • Pole: Iridium Rod
  • Bait: Bait
  • Tackle: Cork Bobber
  • Time: 6:00 am - 8:50 am (available fishes: Smallmouth Bass, Catfish, Chub?)

The results are as follows:

Image Name Standard quality Silver quality Gold quality Total
Smallmouth Bass.png
Smallmouth Bass 2 23 7 32
Catfish.png
Catfish 0 9 1 10
Chub.png
Chub 0 0 0 0
Green Algae.png
Green Algae 20 0 0 20
Trash (item).png
Trash (all) 11 0 0 11


So, not accounting for the irrelevant data points from catch originating from both the Cindersap Forest and the Pelican Town (Catfish, Green Algae, Trash), we are left with 32 Smallmouth Bass. Using the 70% catch rate of Pelican Town fishes vs the 30% catch rate of Cindersap Forest fishes, not catching a single Chub against 32 Smallmouth Bass in a row has a probability of 0.7^32=0.00001, or in other words 1 chance out of 100,000. Yes, it may be RNG, this but we are looking at some rather unlikely numbers here.

Experiment 2

  • Year: 1
  • Month: Summer
  • Day: 8
  • Weather: Rain
  • Luck: Very happy (+0.07 to +0.1)
  • Fishing level: 5-6 (progressing during the day)
  • Fishing location on the farm: Deep water, various
  • Casting distance: max
  • Pole: Iridium Rod
  • Bait: Bait
  • Tackle: Cork Bobber
  • Time: 6:00 am - 8:50 am (available fishes: Pike, Dorado?, Chub?)

The results are as follows:

Image Name Standard quality Silver quality Gold quality Total
Pike.png
Pike 0 33 2 35
Dorado.png
Dorado 0 0 0 0
Chub.png
Chub 0 0 0 0
Green Algae.png
Green Algae 23 0 0 23
Trash (item).png
Trash (all) 16 0 0 16

Calculating the probability not to get any Chub or Dorado is difficult here as the Pike spawns both in the Cindersap Forest and in the Pelican Town rivers, but considering their spawn rate (Respectively .45, .15, and .4), it appears to be very unlikely that 0 Chub nor Dorado were caught.

Considering my previous experience with this game and the present experiments, I am pretty confident that there is something amiss as you cannot catch Cindersap Forest river fishes in the Riverlands Farm. Having said that, i can't help but notice that both the Forest Farm and the Hill-top farm return "Forest" as their fish spawn list. Yet, we have established that the Forest Farm actually yields forest pond fishes, while the Hill-top farm yields forest river fishes. Thus, in the Riverlands Farm, it may be possible that the 30% chances of catching a "Forest" fish is actually a forest pond fish, and not a forest river fish. We'll probably have to believe the code on that as it would be very hard to test, since all forest pond fishes (Smallmouth Bass, Pike, Perch and Walleye) also spawn in the Pelican Town. Still, I wonder where is the code reflecting when the list of fishes for the forest river or the forest pond is returned.

--Alleria (talk) 10:23, 16 May 2019 (BST)


OK, lets go deeper into the code to see what is happening here. I'm going to type this up as I am looking for it, so it may be a bit train of thoughty...

Firstly, the base implementation of getFish (the main one that accepts a location string). I don't know your background, so apologies if it seems like I am talking down to you

    public virtual Object getFish(
      float millisecondsAfterNibble,
      int bait,
      int waterDepth,
      Farmer who,
      double baitPotency,
      string locationName = null)
    {
      int parentSheetIndex = -1;
      Dictionary<string, string> dictionary1 = Game1.content.Load<Dictionary<string, string>>("Data\\Locations");
      bool flag1 = false;
      string key = locationName == null ? (string) ((NetFieldBase<string, NetString>) this.name) : locationName;
      if (this.name.Equals((object) "WitchSwamp") && !Game1.MasterPlayer.mailReceived.Contains("henchmanGone") && (Game1.random.NextDouble() < 0.25 && !Game1.player.hasItemInInventory(308, 1, 0)))
        return new Object(308, 1, false, -1, 0);
      if (dictionary1.ContainsKey(key))
      {
        string[] strArray1 = dictionary1[key].Split('/')[4 + Utility.getSeasonNumber(Game1.currentSeason)].Split(' ');
        Dictionary<string, string> dictionary2 = new Dictionary<string, string>();
        if (strArray1.Length > 1)
        {
          for (int index = 0; index < strArray1.Length; index += 2)
            dictionary2.Add(strArray1[index], strArray1[index + 1]);
        }
        string[] array = dictionary2.Keys.ToArray<string>();
        Dictionary<int, string> dictionary3 = Game1.content.Load<Dictionary<int, string>>("Data\\Fish");
        Utility.Shuffle<string>(Game1.random, array);
        for (int index1 = 0; index1 < array.Length; ++index1)
        {
          bool flag2 = true;
          string[] strArray2 = dictionary3[Convert.ToInt32(array[index1])].Split('/');
          string[] strArray3 = strArray2[5].Split(' ');
          int int32 = Convert.ToInt32(dictionary2[array[index1]]);
          if (int32 == -1 || this.getFishingLocation(who.getTileLocation()) == int32)
          {
            for (int index2 = 0; index2 < strArray3.Length; index2 += 2)
            {
              if (Game1.timeOfDay >= Convert.ToInt32(strArray3[index2]) && Game1.timeOfDay < Convert.ToInt32(strArray3[index2 + 1]))
              {
                flag2 = false;
                break;
              }
            }
          }
          if (!strArray2[7].Equals("both"))
          {
            if (strArray2[7].Equals("rainy") && !Game1.isRaining)
              flag2 = true;
            else if (strArray2[7].Equals("sunny") && Game1.isRaining)
              flag2 = true;
          }
          if (who.FishingLevel < Convert.ToInt32(strArray2[12]))
            flag2 = true;
          if (!flag2)
          {
            double num1 = Convert.ToDouble(strArray2[10]);
            double num2 = Convert.ToDouble(strArray2[11]) * num1;
            double num3 = Math.Min(num1 - (double) Math.Max(0, Convert.ToInt32(strArray2[9]) - waterDepth) * num2 + (double) who.FishingLevel / 50.0, 0.899999976158142);
            if (Game1.random.NextDouble() <= num3)
            {
              parentSheetIndex = Convert.ToInt32(array[index1]);
              break;
            }
          }
        }
      }
      bool flag3 = false;
      if (parentSheetIndex == -1)
      {
        parentSheetIndex = Game1.random.Next(167, 173);
        flag3 = true;
      }
      if ((who.fishCaught == null || who.fishCaught.Count == 0) && parentSheetIndex >= 152)
        parentSheetIndex = 145;
      if (who.hasMagnifyingGlass & flag3 && Game1.random.NextDouble() < 0.08)
      {
        Object unseenSecretNote = this.tryToCreateUnseenSecretNote(who);
        if (unseenSecretNote != null)
          return unseenSecretNote;
      }
      Object @object = new Object(parentSheetIndex, 1, false, -1, 0);
      if (flag1)
        @object.scale.X = 1f;
      return @object;
    }

So the game digs into the location file, and looks at the line for either the passed in location, or the current location if nothing was passed in. It then cross references with the fish file to find seasonal and time information, and if everything matches, does a RNG roll to see if that fish is on the line. If no roll hits, then a random piece of trash is found (Trash is index 167 - 172). This explains why you are still getting trash on the riverlands farm.

Now onto the fish themselves. There is a line jumping out at me that I have yet to investigate: if (int32 == -1 || this.getFishingLocation(who.getTileLocation()) == int32) This seems to be the line that separates fish based on water source within a location. int32 is sourced from the Locations file. -1 is any body of water, anything else is dependent on the water source. Lets see what is in Farm::getFishingLocation

    public override int getFishingLocation(Vector2 tile)
    {
      switch (Game1.whichFarm)
      {
        case 1:
        case 2:
          return 1;
        case 3:
          return 0;
        default:
          return -1;
      }
    }

There we go, River and Forest farms return 1, Mountain returns 0, everything else returns -1

Looking at Forest Location in Spring: 153 -1 145 0 143 0 137 1 132 0 706 0 702 0

Only 153 and 137 can be caught (Green Algae and Smallmouth Bass)

For Town in Spring: 137 -1 132 -1 143 -1 145 -1 153 -1 706 -1

137 132 143 145 153 706 Smallmouth, Bream, Catfish, Sunfish, Green Algae, Shad

I am running out of time, but I assume that the fish not listed in your table are due to times the fish can be caught.

So it looks like you are correct in your guess, in that it is only fish from a certain area of the locations that can be caught on the farms. BlaDe (talk) 11:26, 16 May 2019 (BST)