I've been seeing a ton of misinformation as to how breeding works, both within this server and even in some guides. I don't claim to be an all-knowing guru in this topic, but in June of last year, someone made a reddit post containing pseudocode of ARK's breeding code, gotten from a disassembly of ARK.
https://www.reddit.com/r/playark/comments/6gsk84/
Findings
- 55% chance of inheriting the stronger stat.
- Only stats that can be leveled have a chance for random mutations.
- Three random mutation rolls each with a 2.5% probability and adding +2 stat points. These values are set per species but currently all species have the same values.
- On each roll a stat is selected at random. Multiple random mutations on the same stat are possible.
- On each roll a parent is selected at random with a 55% chance of it being the parent with the stronger stat. It affects the paternal/maternal mutation count and;
- Once the total random mutation count of a parent reaches 20 all rolls tied to that parent automatically fail.
- Stat values are capped at 255 levels.
- There is a color mutation for every stat mutation.
I'd also like like to step through that pseudocode so as to further make it clear how the process works. This assumes you have at least a passing knowledge on the general ideas of breeding (stat levels vs stat values and such), as well as knowing a little bit about reading code.
/// <summary>
/// Simulate when two ARK Creatures are mated
/// </summary>
public PrimalDinoCharacter DoMate(PrimalDinoCharacter withMate)
{
The DoMate
method is run on a PrimalDinoCharacter
object, and takes another PrimalDinoCharacter
object as its only parameter. Throughout the code, this
refers to the initiating dino, and withMate
refers to its mate. I don't know how ARK determines who is who, but it's not important to understand the rest of the process.
if (this.Gender == withMate.Gender)
{
return null;
}
If the dino is the same gender as its mate, the mating process fails entirely.
var randomMutationCount = this.RandomMutationsMale + this.RandomMutationsFemale;
var randomMutationCountMate = withMate.RandomMutationsMale + withMate.RandomMutationsFemale;
var offspring = new PrimalDinoCharacter
{
RandomMutationsFemale = this.Gender == Gender.Female ? randomMutationCount : randomMutationCountMate,
RandomMutationsMale = this.Gender == Gender.Male ? randomMutationCount : randomMutationCountMate
};
Here's where Matrilineal and Patrilineal mutations are calculated. The offspring's mutations for either side are the sum of that parent's patrilineal and matrilineal mutations. So an offspring whose dad has 2/20 and 3/20, and mom has 4/20 and 5/20, the offspring will have 5/20 and 9/20.
// Inherited colors (there is a 50/50 chance the color is inherited from each respective parent)
for (var i = 0; i < 6; i++)
{
offspring.ColorSetIndices[i] = NewRandom() <= 0.5 ? withMate.ColorSetIndices[i] : this.ColorSetIndices[i];
}
Just like the comment says, for each of the 6 color regions, pick the color from either parent for that color region, randomly between the two parents.
// Inherited stats (there is a 55/45 chance to inherit the best stat)
var mutatableStatIndices = new List<int>();
for (var i = 0; i < 12; i++)
{
var chanceToInheritStat = this.NumberOfLevelUpPointsApplied[i] <= withMate.NumberOfLevelUpPointsApplied[i] ? 0.55000001f : 0.44999999f;
offspring.NumberOfLevelUpPointsApplied[i] = NewRandom() <= chanceToInheritStat ? withMate.NumberOfLevelUpPointsApplied[i] : this.NumberOfLevelUpPointsApplied[i];
if (this.CanLevelUpValue[i] && !this.DontUseValue[i]) mutatableStatIndices.Add(i);
}
For each of the 12 stats (0: health, 1: stamina, 2: torpor, 3: oxygen, 4: food, 5: water, 6: temperature, 7: weight, 8: melee damage, 9: movement speed, 10: fortitude, 11: crafting speed. Some of these aren't used for some (or all) dinos, but they're inherited anyway), pick one from the two parents. The higher stat has a 55% chance of being inherited. This is also where which stats are eligible for mutation is calculated. These stats are the ones that can be leveled normally.
And now here's the fun part, mutations.
// Random mutations
if (mutatableStatIndices.Count > 0)
{
Mutations only occur for dinos who have stats that can be leveled. I don't know what dino would need this check but here it is anyway.
for (var i = 0; i < this.RandomMutationRolls; i++)
{
Loop through 3 times to try for mutations. Any time a mutation fails, that try is over.
// A random stat is selected
var randomStatIndex = mutatableStatIndices[NewBoundedRandom(mutatableStatIndices.Count)];
The mutated stat is completely random, chosen only from those stats that are valid for mutations.
// Mutation is tied to one parent (there is a 55/45 chance for it to be the parent with the best stat)
var chanceForParent = this.NumberOfLevelUpPointsApplied[randomStatIndex] <= withMate.NumberOfLevelUpPointsApplied[randomStatIndex] ? 0.55000001f : 0.44999999f;
var randomParentRoll = NewRandom();
var randomMutationIsFromMate = randomParentRoll <= chanceForParent;
Pick the parent that this mutation is coming from, with a 55% chance it's coming from the parent with the higher of the chosen mutation stat. Note that which parent the offspring inherited the stat from has no bearing on this check, this is only for counting mutations.
// If the selected parent have exceeded the random mutation limit skip this roll
if ((randomMutationIsFromMate ? randomMutationCountMate : randomMutationCount) >= this.RandomMutationCountLimit)
{
continue;
}
If the parent that the mutation is coming from has a combined total of mutations greater than the mutation limit of 20, the mutation fails.
// Roll for a random mutation to this stat
if (NewRandom() >= this.RandomMutationChance)
{
continue;
}
Roll the dice to determine if you got lucky and this mutation even occurs. By default this is a 2.5% chance, but using a mutator, that pushes it up to 100% for the first mutation.
var newStatValue = offspring.NumberOfLevelUpPointsApplied[randomStatIndex] + this.RandomMutationGivePoints;
Add 2 to the chosen stat. If using mutators, the first mutation will add to the chosen stat based on the number of stacks of the mutator buff. Our server limits this to an increase of 20 per mutation at 9 stacks.
// All stats are limited to 255
if (newStatValue > 255.0)
{
continue;
}
If after adding the stat increase, the stat is over 255, the mutation fails.
// Update offspring
offspring.NumberOfLevelUpPointsApplied[randomStatIndex] = (int)Math.Floor(newStatValue);
if ((randomMutationIsFromMate ? withMate : this).Gender == Gender.Male)
{
offspring.RandomMutationsMale++;
}
else
{
offspring.RandomMutationsFemale++;
}
The offspring's mutated stat is updated, and either its patrilineal or matrilineal mutation count is increased by one, depending on which parent the mutation came from.
// Random color mutation code simplified (may not be perfectly accurate):
// 1. Make sure the species have customizable colors
// 2. Create an array with all color regions that are not disallowed (->PreventColorizationRegions)
// 3. Roll a random color from the available ones
// 4. Roll a random color index from the available ones
var colors = 56;
var colorIndices = Enumerable.Range(0, 6).Select(x => this.PreventColorizationRegions[i] ? null : (int?)x).Where(x => x.HasValue).Select(x => x.Value).ToArray();
var randomColor = NewBoundedRandom(colors) + 1;
var randomColorIndex = colorIndices[NewBoundedRandom(colorIndices.Length)];
offspring.ColorSetIndices[randomColorIndex] = randomColor;
Pick a random color from the 56 available, pick a random color region from the 6 available less any regions that aren't allowed, and apply that color to that region.
It is worth noting that PreventColorizationRegions
is likely not set at all on newer dinos. I've had both Lightning Wyverns and Otters get color mutations on regions that they don't actually have.
So that's it in a nutshell. If anything is unclear please let me know and I'll do my best to explain it. It took me a while to get my head around this and I do this professionally.