Skull Cavern/Ore Distribution

From Stardew Valley Wiki
Revision as of 13:22, 21 April 2023 by JackBlack69 (talk | contribs) (Corrected typo, moved graphs and added links to desmos)
Jump to navigation Jump to search
Axe.png
Article Stub

This article is marked as a stub for the following reason:

  • Need info about how charts were generated, more supporting evidence for percentages and claims about luck

Small minable stones and ores can appear as random stones throughout the floor, or rarely as small clumps. These have different distributions[1][2]. On average there will be less than 0.67 small resource clumps on each floor with neutral luck, and less than 1 for the largest possible luck. These clumps have a 25% chance to be a dark grey rock (stone ore), a 1.5% chance to be iridium, and a 73.5% chance to be gold.

The distribution for random stones is more complex and varies with depth and best understood in a few stages.

If a Qi quest is in progress which makes the mine more dangerous, there is a small chance for a stone to be replaced with a radioactive ore. This is very dependent upon luck, with the luck boost from the special charm being worth 192 floors, and the worst luck requiring a depth of floor 550 to have any chance ore will drop. This is also dependent on luck buffs, with each level of luck worth 15 floors. This will replace any of the below stones.

The chance for a stone to be a metal ore (copper, iron, gold or iridium) will vary depending on floor, starting at 2% on floor 1, rapidly increasing to 16% on floor 100, and then increasing to 100% on floor 1780. Luck has no affect on this chance, or on the ore distribution. Copper and iron have the same distribution. From floor 2010 only gold and iridium ore will be found, and from floor 5700 only iridium ore will be found from this generation.

If the stone is not a metal ore, there is a chance for it to be a a gem stone ore (diamond, emerald, aquamarine, ruby, amethyst, topaz and jade), a gem node (the round purple stone), a mystic stone or a dark grey rock. This means that the chance can decrease as you go deeper as more of the stone is metal ore, and above floor 1780 these will not be found. Luck and mining level only play a significant role for mystic stones and gem nodes. For others the contribution is negligible.

For gem stone ores, diamond is slightly rarer than most, and jade is half as rare as most. The chance initially increases, peaking at a chance of ~0.35% (~0.18% for jade) at a depth of ~800, before dropping back down.

Dark grey rocks, start with their maximum chance at floor 1 (9.73% for dark grey rocks, 0.005% for mystic stones, 0.059% for gem nodes for best chances), and drop proportionally as ores take their place.


Code Details

The main code for populating the floor is found in the function StardewValley.Locations.MineShaft::populateLevel. In setting up to populate the floor, it initially defines stoneChance as a random number (double) in the range [10,30), and gemStoneChance as 0.003. It then calls StardewValley.Locations.MineShaft::adjustLevelChances, which will perform a few checks including setting the chance to find stone to 0 for infested floors and dividing gem stone chance by 2[3]. After this setup, it will then iterate through every square of the floor, and if it passes a few checks it will add a stone selected using the function StardewValley.Locations.MineShaft::chooseStoneType, passing the gemstone chance from above and the magic numbers 0.001 and 5e-5 for gem nodes (internally chanceForPurpleStone) and mystic stones (internally chanceForMysticStone). In the same sweep, if it does not add a stone there is a chance for it to add a large resource clump, which are 2 possible variants of a 2 by 2 boulder.

After iterating through every square, and performing a few other tasks, it will attempt to add ore clumps using the function StardewValley.Locations.MineShaft::tryToAddOreClumps.

Ore Clumps

In the StardewValley.Locations.MineShaft::tryToAddOreClumps[4] function, a try will only be made if a random number is less than 0.55 plus the average daily luck. The maximum possible average daily luck is 0.1 from random luck and 0.025 from the special charm[5]. This means with neutral luck there is a 55% chance to try, and with the best possible luck there is a 67.5% chance. It will try once, and then generate a random number and keep going if that random number is less than 0.25 plus the average daily luck. This means there will be 1 chance, plus a 25% chance with neutral luck or a 37.5% chance with best possible luck.

This gives an expected value of 1.3 recurring or 1.6 attempts to generate a clump, which when combined with the base chance to try gives an expected amount of 0.67 or 1.

However, each try chooses a random tile on the map and will only place an ore clump there if the tile is free, resulting in less than these numbers.

To choose which type of ore to add it calls the function StardewValley.Locations.MineShaft::getAppropriateOre[6], which just before returning has a 25% chance (if it is not in hard mode) to set the ore to 668 or 670, which are the dark grey rocks (stone ore). Otherwise, the ore is set as 764, gold ore, with a 2% chance to set it to 765, iridium ore. This results in total chances of 25% for dark grey rocks, 1.5% chance for iridium ore, and 73.5% for gold.

Random ore placement (chooseStoneType)

Changing distribution of radioactive ore with luck (daily luck and luff buffs).

This will first produce radioactive ore, with the following check:

   if (this.GetAdditionalDifficulty() > 0 && this.mineLevel % 5 != 0 && this.mineRandom.NextDouble() < (double)this.GetAdditionalDifficulty() * 0.001 + (double)((float)this.mineLevel / 100000f) + Game1.player.team.AverageDailyLuck() / 13.0 + Game1.player.team.AverageLuckLevel() * 0.0001500000071246177)

For this, the luck boost from the special charm (0.025, contribution to AverageDailyLuck) is equivalent to an additional 192.3 floors (2500/13), and a single point of luck (such as from a food buff) is worth ~15 floors.

After this, it will go through the different areas, and for skull cavern, it will set the base stone type to 32, 38, 40 or 42 (equally), and then calculate several variables, in a few stages to give different definitions for different floor ranges chanceForOre is defined in 2 parts, including using a min, and then compared to a random double to give 4 different regions:

   double chanceForOre = 0.02 + (double)skullCavernMineLevel * 0.0005;
   if (this.mineLevel >= 130) {
       chanceForOre += 0.01 * (double)((float)(Math.Min(100, skullCavernMineLevel) - 10) / 10f);
   }

This ends up being defined as either 0.02 + skullCavernMineLevel * 0.0005 for floors 1-10, 0.01 + skullCavernMineLevel * 0.0015 for levels 10 to 100 (when skullCavernMineLevel <= 100), and 0.11 + skullCavernMineLevel * 0.0005 for levels 100 and up(when skullCavernMineLevel >= 100). This means the chance for ore will increase by 0.05% for each floor, except between levels 10 and 100 where it increases by 0.15% each floor. This reaches 100% at floor 1780, providing the 4th region. At the crossover point of floor 10 the 2 chances are equal as the extra term is 0. This means the function is continuous.

Changing distribution of metal ore with floor.

If this ore check passes it will return an ore, with it first checking for iridium, then gold, then iron, then returning copper. As an example, this means for a stone to be gold ore it must pass the ore check, then fail the iridium check, then pass the gold check. This means in order to get an ore, the chance for the previous ore must be less than 100%, so once iridium ore reaches 100%, no other metal ores can be made. The probability to get each ore (from a random stone) is therefore:

   iridium = chanceForOre*chanceForIridium
   gold = chanceForOre*(1-chanceForIridium)*chanceForGold
   iron = chanceForOre*(1-chanceForIridium)*(1-chanceForGold)*chanceForIron
   copper = chanceForOre*(1-chanceForIridium)*(1-chanceForGold)*(1-chanceForIron)

These probabilities are defined in the following code:

   double iridiumBoost = 0.0;
   if (this.mineLevel >= 130) {
       iridiumBoost += 0.001 * (double)((float)(skullCavernMineLevel - 10) / 10f);
   }
   iridiumBoost = Math.Min(iridiumBoost, 0.004);
   if (skullCavernMineLevel > 100) {
        iridiumBoost += (double)skullCavernMineLevel / 1000000.0;
   }
   double chanceForIridium = (double)Math.Min(100, skullCavernMineLevel) * (0.0003 + iridiumBoost);
   double chanceForGold = 0.01 + (double)(this.mineLevel - Math.Min(150, skullCavernMineLevel)) * 0.0005;
   double chanceForIron = Math.Min(0.5, 0.1 + (double)(this.mineLevel - Math.Min(200, skullCavernMineLevel)) * 0.005);

The chance to find iridium relies upon an iridiumBoost variable which is split into four regions, floors 0-10, where there is no boost; floors 10 to 50, where the boost increases from 0 to 0.004; floors 50 to 99 where the boost remains constant at 0.004; and floor 100 and up, where there is a discontinuity with the boost jumping to 0.004 + 0.000001 * skullCavernMineLevel (an increase of 0.0001). This results in the overall function for the chance to find iridium being non-linear, and having 5 regions; importantly reaching 100% at floor 5700. The gold ore chance variable is more straight forward, starting at a value of 7%, and once level 150 is reached, increasing linearly until it reaches 100% at floor 2130. The iron ore chance results in a value of 50%. Additional floors of note are floor 30 where iridium ore becomes more common than gold ore, floor 74 where iridium ore becomes more common than iron and copper ore, floor 677 where gold ore becomes more common than iron and copper ore, floor 1081 where iridium ore becomes more common than non-metal ores, floor 1332 where gold ore becomes more common than non-metal ores, and floor 1725 where iron and copper ore becomes more common than non-metal ores.

Additionally, up until this point, luck has not factored into the calculation. However, if it does not pass the ore chance check (this means the final chances for these will need 1-chanceForOre included), it moves on to gemstone ores, dark grey rocks (stone ore), purple stones and mystic stones. This is done in the following complex code (some unneeded sections related to coloured rocks have been removed, and additional comments added):

   double averageDailyLuck = Game1.player.team.AverageDailyLuck(Game1.currentLocation);
   double averageMiningLevel = Game1.player.team.AverageSkillLevel(3, Game1.currentLocation);
   double chanceModifier = averageDailyLuck + averageMiningLevel * 0.005;
   if (this.mineLevel > 50 && this.mineRandom.NextDouble() < 0.00025 + (double)this.mineLevel / 120000.0 + 0.0005 * chanceModifier / 2.0) { //diamond
       whichStone = 2;
       stoneHealth = 10;
   }
   else if (gemStoneChance != 0.0 && this.mineRandom.NextDouble() < gemStoneChance + gemStoneChance * chanceModifier + (double)this.mineLevel / 24000.0) { //gemstones
       return new Object(tile, this.getRandomGemRichStoneForThisLevel(this.mineLevel), "Stone", canBeSetDown: true, canBeGrabbed: false, isHoedirt: false, isSpawnedObject: false) {
           MinutesUntilReady = 5
       };
   }
   if (this.mineRandom.NextDouble() < chanceForPurpleStone / 2.0 + chanceForPurpleStone * averageMiningLevel * 0.008 + chanceForPurpleStone * (averageDailyLuck / 2.0)) { //gem node
       whichStone = 44;
   }
   if (this.mineLevel > 100 && this.mineRandom.NextDouble() < chanceForMysticStone + chanceForMysticStone * averageMiningLevel * 0.008 + chanceForMysticStone * (averageDailyLuck / 2.0)) { //mystic stone
       whichStone = 46;
   }
   whichStone += whichStone % 2;
   if (this.mineRandom.NextDouble() < 0.1 && this.getMineArea() != 40) { //dark grey rock (stone ore)
       return new Object(tile, (this.mineRandom.NextDouble() < 0.5) ? 668 : 670, "Stone", canBeSetDown: true, canBeGrabbed: false, isHoedirt: false, isSpawnedObject: false)
       {
           MinutesUntilReady = 2,
           Flipped = (this.mineRandom.NextDouble() < 0.5)
       };
   }
   return new Object(tile, whichStone, "Stone", canBeSetDown: true, canBeGrabbed: false, isHoedirt: false, isSpawnedObject: false)	{
       MinutesUntilReady = stoneHealth
   };
Changing distribution of diamond nodes with floor, luck and mining level

Before analysing in full, it is worth noting the impact of luck. Diamonds and Gemstones both use chanceModifier. As daily luck ranges from a minimum of -0.1 to a maximum of 0.125 (with special charm), and farmer level ranges from 0 to 14, the lowest this can be is -0.1, and the highest is 0.195. For diamonds this is multiplied by 0.0005 and divided by 2 making its effect range from -0.0025% to 0.004875%, or by approximately 0.007%, equivalent to 8.85 floors. For a farmer with the special charm and level 10 mining, the range is reduced to 0.005%, equivalent to 6.6 floors. This is also quite small compared to the base of 0.126% for floor 1 with 0 luck and 0 mining levels. For gemstone ores, the range works out to be 0.044% for the entire range, or 0.033% for the reduced range; equivalent to 10.62 and 7.92 floors, and still small compared to the 0.654% at floor 1. The chance for gem nodes and mystic stones don't directly use the floor, and the multiplier for the chance is used in all parts of the calculation. Now the range for averageDailyLuck/2 (0.1125) is quite large, over 20% of the base 0.5 chance, making this much more dependent upon luck. Likewise, the 14 levels from mining contribute 0.112, over 10%, but the 4 gained from food buffs only contribute 0.032, much less significant. Likewise, for Mystic Stones the contribution from luck is over 10% of the base of 1, with the mining levels having a similarly reduced impact.

This can be better understood by considering the exit points. The first way to return from this function is by failing the diamond check and passing the gem stone check. The second way is if it fails the above, but passes the dark grey rock check. Otherwise it exits as whatever stone it was last set to (so mystic first, then purple, then diamond, then regular stone). This can be understood as (where each check is if they pass the check for meeting the chance):

   if (!diamondCheck && gemCheck){
       return gem
   }
   if (stoneCheck) {
       return grey rock
   }
   if (mysticCheck) {
       return mystic stone
   }
   if (purpleCheck) {
       return gem node
   }
   if (diamondCheck) {
       return diamond
   }
   return rock
Changing distribution of gemstone nodes with floor with neutral base luck, the special charm and level 10 mining.
Changing distribution of gem nodes with floor luck and mining level.

However the use of diamondCheck twice means you cannot just use the chance for it twice, as it will either pass both times or fail both times, making calculations of chances more complex. The simplest to understand is the gemstone ore. In order to return the gemstone ore, the diamond check must fail, and the gem check must pass. This is equivalent to:

   (1-chanceForOre)*(1-chanceForDiamond)*chanceForGem.

Additionally, this returns a random gem using the function MineShaft::getRandomGemRichStoneForThisLevel[7]. This relies upon the code:

   int whichGem = this.mineRandom.Next(59, 70);
   whichGem += whichGem % 2;

Which will randomly select an integer in the range [59,70), and then add 1 if it is odd. This has the effect of randomly selecting an even integer from 60 to 70 inclusive, with the integers from 60 to 68 inclusive having an equal likelihood and 70 being half as likely. This is because the mineRandom.Next(a,b) will return an integer greater than or equal to a and less than b, from internally generating a random number from 0 to 1, scaling it and offsetting it to be a random decimal number from 59 to 70, and then rounding down. This means that the range 59 to just below 61 will round to 59 or 60, which is then both forced to 60; while the numbers from 69 to 70 will round to 69 and then be converted to 70, meaning 70 has half the range. This means that the chance for jade (from 70) will be:

   (1-chanceForOre)*(1-chanceForDiamond)*chanceForGem/11

And the chance for the other gems (emerald, aquamarine, ruby, amethyst & topaz) will be:

   (1-chanceForOre)*(1-chanceForDiamond)*chanceForGem*2/11

The chance to not be a gem stone ore, and be some other option (other than diamond) relies upon either passing the diamond check, or failing the diamond check and failing the gemstone check. This chance is equal to:

   chanceForDiamond+(1-chanceForDiamond)*(1-chanceForGem) = 1-(1-chanceForDiamond)*chanceForGem

Then going through each return statement we have the final chances being:

   stone = (1-chanceForOre)*(1-(1-chanceForDiamond)*chanceForGem)*chanceForStone
   mystic = (1-chanceForOre)*(1-(1-chanceForDiamond)*chanceForGem)*(1-chanceForStone)*chanceForMystic
   purple = (1-chanceForOre)*(1-(1-chanceForDiamond)*chanceForGem)*(1-chanceForStone)*(1-chanceForMystic)*chanceForPurple

The next one to consider is is Diamond. As passing the diamond check skips the gem stone ore check, so it cannot be included in the chance. To be a diamond, it must pass the diamond check, which skips the gem check, and it must fail every other check. This gives:

   diamond = (1-chanceForOre)*(chanceForDiamond)*(1-chanceForPurple)*(1-chanceForMystic)*(1-chanceForStone)

And finally, the only other option is a normal rock. This could be calculated as whatever is left over, but for completeness, it must fail every check.

   rock = (1-chanceForOre)*(1-chanceForDiamond)*(1-chanceForGem)*(1-chanceForPurple)*(1-chanceForMystic)*(1-chanceForStone)

Links to Desmos Graphs

You can access an interactive graph on Desmos, which can be presented in a variety of ways.
To see the metal ores: https://www.desmos.com/calculator/uwi9hfdjvv
To see the gemstones, gem nodes, dark grey rocks (stone ore) and mystic stones with a daily luck of 0.025 (neutral with special charm) and mining level 10 (Note, for easy of viewing some of these have been scaled): https://www.desmos.com/calculator/iopaqgwsvs
To see the effect of daily luck (including special charm) on the chance, relative to the chance at a daily luck of 0.025, with mining level 10 and floor 100: https://www.desmos.com/calculator/ngyjsb1b0m
To see the effect of mining level (including buffs) on the chance, relative to a mining level of 10, with a luck of 0.025 and floor 100: https://www.desmos.com/calculator/72efyqudvu

These include sliders for mining level, daily luck and floor which you can adjust to shift the references above.


References

  1. See MineShaft::populateLevel in the game code.
  2. See MineShaft::chooseStoneType in the game code.
  3. See MineShaft::adjustLevelChances in the game code.
  4. See MineShaft::tryToAddOreClumps in the game code.
  5. See FarmerTeam::AverageDailyLuck in the game code.
  6. See FarmerTeam::getAppropriateOre in the game code.
  7. See MineShaft::getRandomGemRichStoneForThisLevel in the game code.