The Mines/Ore Distribution

From Stardew Valley Wiki
Jump to navigation Jump to search
Axe.png
Article Stub

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

  • Work in progress

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. The other type of resource found are large (2 by 2) stones, as well as random items. The mine difficulty can also be changed by using the Shrine of Challenge or by accepting the Qi quest Danger in the Deep. This provides 3 levels, normal (0), one of these active (1), or both of these active (2). If the mine is difficult, radioactive ore can appear, as well as large stumps and large logs. The double up of difficulty has a few affects; those relevant to this page are that it increases the chance of finding radioactive ore, monsters spawning and leapers having partners.

Floors have a chance of being a quarry level, which modifies the chances and are dealt with separately.

From random stones, for the normal mines, there is a 2.9% chance to get copper ore on floors 2-39, or gold ore on floors 81-119; and on floors 41-79, there is a 15% chance to get ice crystals and a 2.465% chance to get iron ore.

Populate Levels

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 a stoneChance as a random number (double) in the range [10,30), monsterChance as a random number in the range [0.002, 0.022), itemChance as 0.0025 and gemStoneChance as 0.003. It then calls StardewValley.Locations.MineShaft::adjustLevelChances, which will perform a few modifications including (in order)[3]:

  • For floor 1, setting all bar stone chance to 0.
  • For levels divisible by 5, setting the item and gemstone chance to 0; and setting monster chance to 0 for floors divisible by 10.
  • For infested floors, setting the stoneChance and gemStoneChance to 0, monsterChance to 0.025 and itemChance to 0.001
  • increasing monsterChance by 0.02 for each level of difficulty. (This allows monsters to spawn on level 1. Other checks prevent it on levels divisible by 10)
  • Setting monsterChance to 0 or doubling it if the appropriate buffs are active.
  • Dividing gem stone chance by 2.
  • Mofidying chances if is a quarry level so gemStoneChance is 0.001 (which has no effect as these floors cannot generate gem stone ore), itemChance is 0.0001, stoneChance is twice what it was previously so now it is in the range [20, 60) and the monster chance is 0.02
  • If you are in area 40 (floors 40 to 69), and the mine is difficult, it will scale monsterChance by a factor of 0.6600000262260437

After this setup, if the floor is not divisible by 10, it will then iterate through every square of the floor, and if it is clear for a mine object it will first try to add a stone (using stoneChance), then a monster (using monsterChance), then an item (using itemChance), then a large resource (2 by 2, see details below). If a large resource is generated, it will block the 3 tiles around it. Additionally, some monsters will spawn partners, which can also block nearby tiles resulting in less stone than expected. After iterating through all squares, it attempts to add area uniques (weeds) using the function StardewValley.Locations.MineShaft::tryToAddAreaUniques, tries to spawn extra monsters (possibly replacing stones, up to one 35th of the total stones on the level) and then it attempts to add ore clumps using the function StardewValley.Locations.MineShaft::tryToAddOreClumps, but only if the floor is greater than 2 and not divisible by 5.

If the floor is divisible by 10, then it wont add anything except the ladder down and chest if needed.

Mine Area

The Mine area is based upon which floor you are on, with the exception of quarry levels.

  • Quarry levels have an area of 77377.
  • Floors 0-10 have an area of 0.
  • Floors 11-29 have an area of 10.
  • Floors 30-39 have an area of 0.
  • Floors 40-79 have an area of 40.
  • Floors 80-120 have an area of 80.

Random ore placement (stoneChance and chooseStoneType)

The game goes through 3 stages, first if the mine area is 40, there is a 15% chance for the stone to be either an ice crystal (319, 320, 321), or if the mines are set to dangerous and it is between floor 41 and 69, then it will be a weed (313, 314, 315). Then it checks if it is a mushroom floor, and if so there is a 55% chance to not generate a stone and 25% of the time it doesn't it will generate a mushroom, being a purple mushroom 20% of the time and a red mushroom otherwise. If it fails the weed check, and the 55% chance on a mushroom floor (or isn't a mushroom floor), it then uses 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) to determine what stone to place. This code first checks for radioactive ore, then through each mine area for metal ores, then for other ores.

This means overall on a mushroom floor, not in area 40, the default stone has a 45% chance of becoming a stone, a 2.75% chance of becoming a purple mushroom, a 11% chance of becoming a red mushroom, and a 41.25% chance of being nothing; and in area 40 the default stone has a 15% chance of becoming a weed, a 38.25% chance of becoming a stone, a 2.3375% chance of becoming a purple mushroom, a 9.35% chance of becoming a red mushroom, and a 35.0625% chance of being nothing. The below calculations and graphs will include weeds in area 40, but not mushroom floors.

Metal Ores - Normal Mines

An extract of the code for the normal mines (difficulty 0) is below. It goes through each area, setting a default stone, and then checking for ore. Note that after this it will add 1 to the whichStone variable if it is odd, which has the effect of changing the normal rock for the area.

	if (this.getMineArea() == 0 || this.getMineArea() == 10) {
		whichStone = this.mineRandom.Next(31, 42);
		if (this.mineLevel % 40 < 30 && whichStone >= 33 && whichStone < 38) {
			whichStone = ((this.mineRandom.NextDouble() < 0.5) ? 32 : 38);
		} else if (this.mineLevel % 40 >= 30) {
			whichStone = ((this.mineRandom.NextDouble() < 0.5) ? 34 : 36);
		}
		if (this.mineLevel != 1 && this.mineLevel % 5 != 0 && this.mineRandom.NextDouble() < 0.029) {
			return new Object(tile, 751, "Stone", canBeSetDown: true, canBeGrabbed: false, isHoedirt: false, isSpawnedObject: false) //Copper
		}
	} else if (this.getMineArea() == 40) {
		whichStone = this.mineRandom.Next(47, 54);
		if (this.mineLevel % 5 != 0 && this.mineRandom.NextDouble() < 0.029) {
			return new Object(tile, 290, "Stone", canBeSetDown: true, canBeGrabbed: false, isHoedirt: false, isSpawnedObject: false) //Iron
		}
	} else if (this.getMineArea() == 80) {
		whichStone = ((this.mineRandom.NextDouble() < 0.3 && !this.isDarkArea()) ? ((!(this.mineRandom.NextDouble() < 0.5)) ? 32 : 38) : ((this.mineRandom.NextDouble() < 0.3) ? this.mineRandom.Next(55, 58) : ((!(this.mineRandom.NextDouble() < 0.5)) ? 762 : 760)));
		if (this.mineLevel % 5 != 0 && this.mineRandom.NextDouble() < 0.029) {
			return new Object(tile, 764, "Stone", canBeSetDown: true, canBeGrabbed: false, isHoedirt: false, isSpawnedObject: false)//Gold
		}
	}

In each area, there is a 2.9% chance for the stone to be ore, with the ore selected matching the area (copper below floor 40, iron between floor 40 and 80, and gold above that). However, the floor must not be divisible by 5, and cannot be floor 1. Also, if it is in area 40, there is a 15% chance it wont reach this point, bringing the total chance for iron ore from random stones down to 2.465%. If it is a metal ore, the function returns. Otherwise it continues to determine if it should be one of the other ores (e.g. diamond ore node), discussed below.

While there are many different types for normal rocks, they can be divided into 2 broad types: those with the index 40 or 42, and the rest. These types affect the likelihood of obtaining ore when breaking the rock (see below). If the type is 40 or 42 it has a multiplier of 1.2; otherwise it has a multiplier of 0.8. The only floors these high ore chance rock can occur on are 1-29. On these floors there is a 3 in 11 chance 27% of being a high ore chance rock.

Metal Ores - Dangerous Mines

The first step is to check if the stone should be 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), making radioactive ore more likely on floor 1 with a special charm than floor 100 without it. A single point of luck (such as from a food buff) is worth ~15 floors. With the best possible luck 1.2% of stones will be radioactive ore. With the worst possible luck no radioactive ore will appear in the mines at all, and the worst possible daily luck would require a luck buff of 24 along with the special charm to be able to have any chance to find radioactive ore. Also note that radioactive ore will not appear on any floor divisible by 5.

If the mines are doubly difficult (Qi quest "Danger in the Deep" while the Shrine of Challenge is active), it will contribute an extra 0.1%. This is not used in the below calculations.

After this, it will go through the different areas, picking a default stone, and checking for ores, returning if one is found.

	if (this.getMineArea() == 0 || this.getMineArea() == 10) {
        whichStone = this.mineRandom.Next(33, 37);
        if (Game1.random.NextDouble() < 0.33) {
            whichStone = 846; //Stone ore
        } else {
            stoneColor = new Color(Game1.random.Next(60, 90), Game1.random.Next(150, 200), Game1.random.Next(190, 240));
        }
        if (this.isDarkArea()) { //Level 30+
            whichStone = this.mineRandom.Next(32, 39);
            int tone = Game1.random.Next(130, 160);
            stoneColor = new Color(tone, tone, tone);
        }
        if (this.mineLevel != 1 && this.mineLevel % 5 != 0 && this.mineRandom.NextDouble() < 0.029) {
            return new Object(tile, 849, "Stone", canBeSetDown: true, canBeGrabbed: false, isHoedirt: false, isSpawnedObject: false) { //Copper
                MinutesUntilReady = 6
            };
        }
        if (stoneColor.Equals(Color.White)) { //Only happens for stone ore on floors less than 30. Otherwise stone colour is changed.
            return new Object(tile, whichStone, "Stone", canBeSetDown: true, canBeGrabbed: false, isHoedirt: false, isSpawnedObject: false) {
                MinutesUntilReady = stoneHealth
            };
        }
	} else if (this.getMineArea() == 40) {
		whichStone = this.mineRandom.Next(47, 54);
		stoneHealth = 3;
		if (this.GetAdditionalDifficulty() > 0 && this.mineLevel % 40 < 30) {
			whichStone = this.mineRandom.Next(39, 42);
			if (this.mineRandom.NextDouble() < 0.15) {
				return new ColoredObject(294 + ((this.mineRandom.NextDouble() < 0.5) ? 1 : 0), 1, new Color(170, 140, 155)) //Twig
			}
			if (this.mineLevel != 1 && this.mineLevel % 5 != 0 && this.mineRandom.NextDouble() < 0.029) {
				return new ColoredObject(290, 1, new Color(150, 225, 160)) //IRON
			}
		}
		else if (this.mineLevel % 5 != 0 && this.mineRandom.NextDouble() < 0.029) {
			return new Object(tile, 290, "Stone", canBeSetDown: true, canBeGrabbed: false, isHoedirt: false, isSpawnedObject: false) { //Iron
				MinutesUntilReady = 4
			};
		}
	} else if (this.getMineArea() == 80) {
        whichStone = ((!(this.mineRandom.NextDouble() < 0.5)) ? 32 : 38);
        if (this.isDarkArea()) {
            whichStone = this.mineRandom.Next(32, 39);
        }
        if (this.mineLevel != 1 && this.mineLevel % 5 != 0 && this.mineRandom.NextDouble() < 0.029) {
            return new Object(tile, 764, "Stone", canBeSetDown: true, canBeGrabbed: false, isHoedirt: false, isSpawnedObject: false) { //GOLD
                MinutesUntilReady = 7
            };
        }
	}

This has the same 2.9% chance check for ore as for the regular mines, however there are some significant differences. Firstly there was the chance for them to be replaced by radioactive ore, which depends heavily on luck. On floors 1-39, there is a 33% chance for it to set the normal stone type to stone ore; if it is less than level 30, and it doesn't return copper ore, it will return this stone ore. This gives a 32% chance to return stone ore. On floors 41-69, there is a 15% chance to return a twig instead of a stone. This means that overall (assuming no radioactive ore) on floors 41-69, 15% of the "random stones" will be weeds, 12.75% of the time they will be twigs, 2.1% of the time they will be iron, and 70.2% of the time they will be something else. Also, on floors 41-69, the rocks that spawn will be more likely to drop ore when broken, the rocks on other floors will be less likely to drop ore.

Metal ores – Quarry levels

Quarry levels are treated as a special case, after checking for radioactive ore if the mines are dangerous, it then goes through the following (abridged) code. These probabilities are defined in the following code:

    bool foundSomething = false;
    foreach (Vector2 v in Utility.getAdjacentTileLocations(tile)) {
        if (base.objects.ContainsKey(v)) {
            foundSomething = true;
            break;
        }
    }
    if (!foundSomething && this.mineRandom.NextDouble() < 0.45) {
        return null;
    }
    bool brownSpot = false;
    for (int i = 0; i < this.brownSpots.Count; i++) {
        if (Vector2.Distance(tile, this.brownSpots[i]) < 4f) {
            brownSpot = true;
            break;
        }
        if (Vector2.Distance(tile, this.brownSpots[i]) < 6f) {
            return null;
        }
    }
    if (brownSpot) {
        whichStone = ((this.mineRandom.NextDouble() < 0.5) ? 32 : 38);
        if (this.mineRandom.NextDouble() < 0.01) {
            return new Object(tile, 751, "Stone", canBeSetDown: true, canBeGrabbed: false, isHoedirt: false, isSpawnedObject: false) //copper
        }
    } else {
        whichStone = ((this.mineRandom.NextDouble() < 0.5) ? 34 : 36);
        if (this.mineRandom.NextDouble() < 0.01) {
            return new Object(tile, 290, "Stone", canBeSetDown: true, canBeGrabbed: false, isHoedirt: false, isSpawnedObject: false) //iron
        }
    }
    return new Object(tile, whichStone, "Stone", canBeSetDown: true, canBeGrabbed: false, isHoedirt: false, isSpawnedObject: false) // normal rock

Regardless of what options are taken, this will return. This means it isn't possible to have a quarry level with gem nodes, mystic stones, or ores for gems, as they are determined after checking areas. If there isn't an adjacent stone to the location being considered, there is a 45% chance that this will return nothing. However, as the stone chance was multiplied by 2 when adjusting level chances, this doesn't result in less stone on these levels. The brown spots are generated in StardewValley.Locations.MineShaft::loadLevel, where it will randomly place brown spots so that 1% of the total map area are brown spots. Technically it is possible for these to be the same square, or for these to be outside the map and have no effect. If it is within 4 tiles of a brown spot, there is a 1% chance for copper ore, and a 99% chance to be a normal, brown coloured rock. If it is 6 or more tiles away from a brown spot, there is a 1% chance for iron ore, and a 99% chance to be a normal, grey coloured rock. (Not the dark grey rocks which are stone ores) Otherwise, if it is within 6 tiles, but outside 4 tiles, there will be no rocks. This means that multiple brown spots can connect, but there should be a gap between brown rocks and grey rocks.

Other ores

Other than for radioactive ore up until this point, luck has not factored into the calculation, and level has only affected what area is used and removed ores on floors divisible by 5. However, if it does not return an ore or stone above (or null for a quarry), it moves on to gemstone ores, dark grey rocks (stone ore), purple stones and mystic stones. This is done in the following complex code (code related to colour removed for simplicity, it will return a coloured object instead of an object):

    double averageDailyLuck = Game1.player.team.AverageDailyLuck(Game1.currentLocation);
    double averageMiningLevel = Game1.player.team.AverageSkillLevel(3, Game1.currentLocation);
    double chanceModifier = averageDailyLuck + averageMiningLevel * 0.005;
    // Diamond node.
    if (this.mineLevel > 50 && this.mineRandom.NextDouble() < 0.00025 + (double)this.mineLevel / 120000.0 + 0.0005 * chanceModifier / 2.0) {
        whichStone = 2;
        stoneHealth = 10;
    }
    // Gem stone nodes.
    else if (gemStoneChance != 0.0 && this.mineRandom.NextDouble() < gemStoneChance + gemStoneChance * chanceModifier + (double)this.mineLevel / 24000.0) {
        return new Object(tile, this.getRandomGemRichStoneForThisLevel(this.mineLevel), "Stone", canBeSetDown: true, canBeGrabbed: false, isHoedirt: false, isSpawnedObject: false) {
            MinutesUntilReady = 5
        };
    }
    // gem node (purple rocks).
    if (this.mineRandom.NextDouble() < chanceForPurpleStone / 2.0 + chanceForPurpleStone * averageMiningLevel * 0.008 + chanceForPurpleStone * (averageDailyLuck / 2.0)) {
        whichStone = 44;
    }
    // Mystic stones.
    if (this.mineLevel > 100 && this.mineRandom.NextDouble() < chanceForMysticStone + chanceForMysticStone * averageMiningLevel * 0.008 + chanceForMysticStone * (averageDailyLuck / 2.0)) {
        whichStone = 46;
    }
    whichStone += whichStone % 2;
    // Dark grey rock (stone ore).
    if (this.mineRandom.NextDouble() < 0.1 && this.getMineArea() != 40) {
        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(); //Return selected stone
Changing distribution of diamond nodes with floor, luck and mining level

Before analyzing 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 the 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

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[4]. This relies upon the code:

    int whichGem = this.mineRandom.Next(59, 70);
	whichGem += whichGem % 2;
	if (Game1.player.timesReachedMineBottom == 0) {
		if (level < 40 && whichGem != 66 && whichGem != 68) {
			whichGem = ((this.mineRandom.NextDouble() < 0.5) ? 66 : 68);
		}
		else if (level < 80 && (whichGem == 64 || whichGem == 60)) {
			whichGem = ((!(this.mineRandom.NextDouble() < 0.5)) ? ((this.mineRandom.NextDouble() < 0.5) ? 68 : 62) : ((this.mineRandom.NextDouble() < 0.5) ? 66 : 70));
		}
	}


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 one 11th of the chance to obtain a gem, and the other gems (emerald, aquamarine, ruby, amethyst & topaz) will be double that:

      jade = (1-chanceForDiamond)*chanceForGem/11
     other = (1-chanceForDiamond)*chanceForGem*2/11

However, if you have not yet reached the bottom of the mines, and the floor generated is less than floor 80, this distribution will be different. Until floor 40 there is an equal chance for amethyst or topaz. Between floor 40 and floor 80 there is a complex chance where the chance for emerald and ruby are replaced with amethyst, topaz, aquamarine and jade; this results in an 18.2% chance for jade, and a 27.3% chance for each of amethyst, topaz and aquamarine.

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:

  stoneore = (1-(1-chanceForDiamond)*chanceForGem)*chanceForStone
    mystic = (1-(1-chanceForDiamond)*chanceForGem)*(1-chanceForStone)*chanceForMystic
    purple = (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 = (chanceForDiamond)*(1-chanceForPurple)*(1-chanceForMystic)*(1-chanceForStone)

While calculated in quite a different way, the chance to find a diamond node is quite comparable to the chance to find a node of another gem type. 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-chanceForDiamond)*(1-chanceForGem)*(1-chanceForPurple)*(1-chanceForMystic)*(1-chanceForStone)

Due to the interaction between the different checks it is hypothetically possible for the chance for one of these to be found increasing to decrease the chance of finding others. This is observed with the increasing chance to find mystic stones on floor 100 reducing the chance to find gem nodes and gem stone ores. Additionally, the increase in chance of finding these valuable items due to luck or mining level reduces the chance of finding dark grey rocks and rocks, but does not parasitically affect each other, e.g. a higher daily luck will increase your chance of finding diamonds, gems, mystic stones and gem nodes, and will decrease the chance of finding dark grey rocks and normal rocks.

Items

After checking for stones and monsters, it attempts to add items. The chance to succeed is the itemChance defined above. By default this is 0.25%, but it is 0.1% for infested floors and 0.01% for quarry floors. This calls the function StardewValley.Locations.MineShaft::getRandomItemForThisLevel[5] to determine the item, using the following code (uneeded parts for skull Cavern removed)

	int index = 80;
	if (this.mineRandom.NextDouble() < 0.05 && level > 80) {
		index = 422;
	} else if (this.mineRandom.NextDouble() < 0.1 && level > 20 && this.getMineArea() != 40) {
		index = 420;
	} else if (this.mineRandom.NextDouble() < 0.25 || this.GetAdditionalDifficulty() > 0) {
		switch (this.getMineArea()) {
            case 0:
            case 10:
                if (this.GetAdditionalDifficulty() > 0 && !this.isDarkArea()) {
                    switch (this.mineRandom.Next(6)) {
                        case 0:
                        case 6:
                            index = 152;
                            break;
                        case 1:
                            index = 393;
                            break;
                        case 2:
                            index = 397;
                            break;
                        case 3:
                            index = 372;
                            break;
                        case 4:
                            index = 392;
                            break;
                    }
                    if (this.mineRandom.NextDouble() < 0.005) {
                        index = 797;
                    } else if (this.mineRandom.NextDouble() < 0.08) {
                        index = 394;
                    }
                } else {
                    index = 86;
                }
                break;
            case 40:
                if (this.GetAdditionalDifficulty() > 0 && this.mineLevel % 40 < 30) {
                    switch (this.mineRandom.Next(4)) {
                        case 0:
                        case 3:
                            index = 259;
                            break;
                        case 1:
                            index = 404;
                            break;
                        case 2:
                            index = 420;
                            break;
                    }
                    if (this.mineRandom.NextDouble() < 0.08) {
                        index = 422;
                    }
                } else {
                    index = 84;
                }
                break;
            case 80:
                index = 82;
                break;
		}
	}

First the item is set to 80 (quartz) which will be returned if all other checks fail. Then, if the floor is greater than 80, there is a 5% chance for it to return a purple mushroom. Otherwise, if the floor is greater than 20, it isn't area 40, there is a 10% chance to return a red mushroom. Otherwise there is a 25% chance to return an item based upon the area, or a 100% chance if the mines are set to difficult. Otherwise it will return quartz. For a quarry floor, there is no area item, so it will return a mushroom or quartz. In areas 0 and 10, if the mines are not set to dangerous or it is above floor 30, the item will be an earth crystal. If the mines are dangerous and it is below floor 30, the area item will be a pearl 0.5% of the time, otherwise a rainbow shell 8% of the time, otherwise there is a 5/6th chance for it to be one of seaweed, coral, sea urchin, clam or a nautilus shell; the remaining 1/6th will be nothing, ending up with the default quartz. For area 40, the item based upon area will be a frozen tear if the mines are not set to dangerous or it is above floor 70, otherwise there is a 50% chance to be a fiddlehead fern, a 25% chance to be a common mushroom and a 25% chance to be a red mushroom, with an 8% chance to be overridden by a purple mushroom. In area 80, the area based item is fire quartz.

Floors Item Chances Dangerous Mine Item Chances
Quarry 1-19 100% quartz 100% quartz
Quarry 21-79 10% red mushroom
90% quartz
10% red mushroom
90% quartz
Quarry 81-119 5% purple mushroom
9.5% red mushroom
85.5% quartz
5% purple mushroom
9.5% red mushroom
85.5% quartz
1-19 25% earth crystal
75% quartz
0.5% pearl
7.96% rainbow shell
15.257% seaweed
15.257% coral
15.257% sea urchin
15.257% clam
15.257% nautilus shell
15.257% quartz
21-29 10% red mushroom
22.5% earth crystal
67.5% quartz
10% red mushroom
0.45% pearl
7.164% rainbow shell
13.731% seaweed
13.731% coral
13.731% sea urchin
13.731% clam
13.731% nautilus shell
13.731% quartz
31-39 10% red mushroom
22.5% earth crystal
67.5% quartz
10% red mushroom
90% earth crystal
41-69 25% frozen tear
75% quartz
92% fiddlehead fern
46% common mushroom
46% red mushroom
8% purple mushroom
71-79 25% frozen tear
75% quartz
100% frozen tear
81-120 5% purple mushroom
9.5% red mushroom
21.375% fire quartz
64.125% quartz
5% purple mushroom
9.5% red mushroom
85.5% fire quartz

Large Resources

After checking for stones, monsters and items, it attempts to add resource clumps. This has a 0.5% chance to succeed (significantly smaller after considering above checks), and requires the mines to not be set to difficult, or for the floor to be in the range 41-69. Due to the order of iteration, this will not be stopped by a stone in one of the other 3 tiles needed for the large resource, instead it can block a stone which otherwise would have been added. Additionally, these will not generate on infested floors.

The specific resource added will depend on area (40 or not) and mine difficulty:

  • If the mine is difficult, it will add either a tree stump 90% of the time or fallen log 10% of the time.
  • Otherwise, if it is in area 40, it will add one of 2 large blue rocks (to match the level theme)
  • Otherwise, it will add one of the 2 other large rocks.

Terrain Features

If the mine is set to dangerous, then additional terrain features can be added. This occurs after checking for stones, monsters, items and large resources. If the floor is between 40 and 70, then there is a 1% chance to generate a mahogany tree. Otherwise there is a 10% chance to add grass if the floor is between 40 and 70, or above 80.

Area Uniques

In the StardewValley.Locations.MineShaft::tryToAddAreaUniques[6], it will attempt to add "weeds". Before going further in, it checks conditions with:

	if ((this.getMineArea() != 10 && this.getMineArea() != 80 && (this.getMineArea() != 40 || !(this.mineRandom.NextDouble() < 0.1))) || this.isDarkArea() || this.mustKillAllMonstersToAdvance())
	{
		return;
	}

This means it will only add weeds for floors 11-29 and 41-119, however on floors 41-39, there is only a 90% chance that it will try. Additionally, there is a later check for the mines being dangerous and the area being 80, causing it to return before adding weeds. If it is area 40 and the mine is not dangerous, or if it is dangerous and on floors 71-79, the "weeds" chosen is an ice crystal (319, 320 and 321).

It will then make a random number of tries between 7 and 23 (inclusive) to place weeds. As this requires the spot to be free and in the accessible area, on average there will be fewer weeds placed, but if all tiles were free, this would give an average of 15 clumps of weeds (or ice crystals). This would give an average of less than 13.5 clumps in area 40. However, this does not necessarily mean that there will be fewer weeds (or ice crystals) in area 40. This is because in the "stone" generation, area 40 would have 15% of "stones" generate as single weeds (or ice crystals). This means that roughly 3% of suitable squares will be weeds in area 40 before the additional weed placement.

Ore Clumps

In the StardewValley.Locations.MineShaft::tryToAddOreClumps[7] 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[8]. 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. But if successful, it will then have the possibility to expand outwards to cover multiple tiles with the ore.

To choose which type of ore to add it calls the function StardewValley.Locations.MineShaft::getAppropriateOre[9]. In this function it sets the default to 751 (copper ore) and then modifies it based upon mine area. If it is area 0 or 10, and the mines are difficult, it will change it to 849, a different type of copper ore. For area 40, if it is difficult it will be iron, otherwise, 80% of the time it will be iron. For area 80, 80% of the time it will be gold. Then just before returning if it is not area 40 and not difficult, then there is a 25% chance to set the ore to 668 or 670, which are the dark grey rocks (stone ore).

This results in the following chances for the regular mines:

  • For floors 3-39 and quarry floors, 25% chance to be stone, 75% chance to be copper.
  • For floors 41-79, 80% chance to be iron, 20% chance to be copper.
  • For floors 81-119, 25% chance to be stone, 60% chance to be gold, and 15% chance to be copper.

This results in the following chances for the dangerous mines:

  • For floors 3-39 and quarry floors, 100% chance to be copper.
  • For floors 41-79, 100% chance to be iron.
  • For floors 81-119, 80% chance to be gold, and 20% chance to be copper.

Ores From Rocks

If a normal rock is generated, there is still a chance to obtain ore from it. When the rock is broken, the code in StardewValley.Locations.MineShaft::checkStoneForItems will potentially call StardewValley.Locations.MineShaft::getOreIndexForLevel to have ore drop. The key parts of the code are[10]:

    double chanceModifier = who.DailyLuck / 2.0 + (double)who.MiningLevel * 0.005 + (double)who.LuckLevel * 0.001;
	double oreModifier = ((tileIndexOfStone == 40 || tileIndexOfStone == 42) ? 1.2 : 0.8);
    if (r.NextDouble() < 0.05 * (1.0 + chanceModifier) * oreModifier) {
		if (r.NextDouble() < 0.25 * (double)((!who.professions.Contains(21)) ? 1 : 2)) {
			Game1.createObjectDebris(382, x, y, who.UniqueMultiplayerID, this); //coal
		}
		Game1.createObjectDebris(this.getOreIndexForLevel(this.mineLevel, r), x, y, who.UniqueMultiplayerID, this);//ore
	} else if (r.NextDouble() < 0.5) {
		Game1.createDebris(14, x, y, 1, this);
	}

This results in a chance to find ore of 5.1% at worst, and 5.7% at best; with a corresponding 47.45% to 47.15% chance to obtain stone. If it would generate ore, then there is a 25% chance to obtain coal, doubled to 50% with the Prospector profession. This results in approximately a 1% chance to get coal from a rock.

Then inside StardewValley.Locations.MineShaft::getOreIndexForLevel, the following code is run to obtain the ore[11]:

	if (this.getMineArea(mineLevel) == 77377) { //Quarry levels
		return 380; //Iron
	}
	if (mineLevel < 40) {
		if (mineLevel >= 20 && r.NextDouble() < 0.1) {
			return 380; //Iron
		}
		return 378; //Copper
	}
	if (mineLevel < 80) {
		if (mineLevel >= 60 && r.NextDouble() < 0.1) {
			return 384; //Gold
		}
		if (!(r.NextDouble() < 0.75)) {
			return 378; //Copper
		}
		return 380; //Iron
	}
	if (mineLevel < 120) {
		if (!(r.NextDouble() < 0.75)) {
			if (!(r.NextDouble() < 0.75)) {
				return 378; //Copper
			}
			return 380; //Iron
		}
		return 384; //Gold
	}
Floors Copper ore Iron ore Gold ore
1-19 100% None None
21-39 90% 10% None
41-59 25% 75% None
61-79 22.5% 67.5% 10%
81-119 6.25% 18.75% 75%
Quarry levels None 100% None

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::getRandomGemRichStoneForThisLevel in the game code.
  5. See MineShaft::getRandomItemForThisLevel in the game code.
  6. See MineShaft::tryToAddAreaUniques in the game code.
  7. See MineShaft::tryToAddOreClumps in the game code.
  8. See FarmerTeam::AverageDailyLuck and Game1::_newDayAfterFade in the game code.
  9. See FarmerTeam::getAppropriateOre in the game code.
  10. See MineShaft::checkStoneForItems in the game code.
  11. See MineShaft::getOreIndexForLevel in the game code.