calculateValue() public static method

public static calculateValue ( int speciesIndex, int stat, int levelWild, int levelDom, bool dom, double tamingEff, double imprintingBonus ) : double
speciesIndex int
stat int
levelWild int
levelDom int
dom bool
tamingEff double
imprintingBonus double
return double
Example #1
0
        private void listViewSpeciesBP_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (listViewSpeciesBP.SelectedIndices.Count > 0)
            {
                determineBestBreeding();

                if (bestLevels.Count > 6)
                {
                    // display top levels in species
                    int?     levelStep = creatureCollection.getWildLevelStep();
                    Creature crB       = new Creature(currentSpecies, "", "", "", 0, new int[8], null, 100, true, levelStep: levelStep);
                    crB.name = "Best possible levels (" + currentSpecies + ")";
                    bool totalLevelUnknown = false;
                    for (int s = 0; s < 7; s++)
                    {
                        crB.levelsWild[s]     = bestLevels[s];
                        crB.valuesBreeding[s] = Stats.calculateValue(speciesIndex, s, crB.levelsWild[s], 0, true, 1, 0);
                        if (crB.levelsWild[s] == -1)
                        {
                            totalLevelUnknown = true;
                        }
                        crB.topBreedingStats[s] = (crB.levelsWild[s] > 0);
                    }
                    crB.levelsWild[7] = crB.levelsWild.Sum();
                    crB.recalculateCreatureValues(levelStep);
                    pedigreeCreatureBestPossibleInSpecies.totalLevelUnknown = totalLevelUnknown;
                    pedigreeCreatureBestPossibleInSpecies.Creature          = crB;
                }
            }
        }
Example #2
0
        public static int durationAfterFirstFeeding(int speciesIndex, int level, double foodDepletion)
        {
            int s = 0;

            if (speciesIndex >= 0 && speciesIndex < Values.V.species.Count && Values.V.species[speciesIndex].taming != null && Values.V.species[speciesIndex].taming.nonViolent)
            {
                s = (int)(0.1 * Stats.calculateValue(speciesIndex, 3, (int)Math.Ceiling(level / 7d), 0, false, 0, 0) / foodDepletion);
            }
            return(s);
        }
Example #3
0
        private void setParents(int comboIndex)
        {
            if (comboIndex < 0 || comboIndex > combinedTops[0].Count)
            {
                pedigreeCreatureBest.Clear();
                pedigreeCreatureWorst.Clear();
                labelInfo.Visible         = false;
                labelProbabilityBest.Text = "";
                return;
            }

            Creature crB    = new Creature(currentSpecies, "", "", 0, new int[8], null, 100, true);
            Creature crW    = new Creature(currentSpecies, "", "", 0, new int[8], null, 100, true);
            Creature mother = females[combinedTops[0][comboIndex]];
            Creature father = males[combinedTops[1][comboIndex]];

            crB.Mother = mother;
            crB.Father = father;
            crW.Mother = mother;
            crW.Father = father;
            double probabilityBest   = 1;
            bool   totalLevelUnknown = false; // if stats are unknown, total level is as well (==> oxygen, speed)

            for (int s = 0; s < 7; s++)
            {
                crB.levelsWild[s]       = Math.Max(mother.levelsWild[s], father.levelsWild[s]);
                crB.valuesBreeding[s]   = Stats.calculateValue(speciesIndex, s, crB.levelsWild[s], 0, true, 1, 0);
                crB.topBreedingStats[s] = (crB.levelsWild[s] == bestLevels[s]);
                crW.levelsWild[s]       = Math.Min(mother.levelsWild[s], father.levelsWild[s]);
                crW.valuesBreeding[s]   = Stats.calculateValue(speciesIndex, s, crW.levelsWild[s], 0, true, 1, 0);
                crW.topBreedingStats[s] = (crW.levelsWild[s] == bestLevels[s]);
                if (crB.levelsWild[s] == -1 || crW.levelsWild[s] == -1)
                {
                    totalLevelUnknown = true;
                }
                if (crB.levelsWild[s] > crW.levelsWild[s])
                {
                    probabilityBest *= .7;
                }
            }
            crB.levelsWild[7] = crB.levelsWild.Sum();
            crW.levelsWild[7] = crW.levelsWild.Sum();
            crB.name          = "Best Possible (" + crB.levelHatched + (totalLevelUnknown ? "+" : "") + ")";
            crW.name          = "Worst Possible (" + crW.levelHatched + (totalLevelUnknown ? "+" : "") + ")";
            pedigreeCreatureBest.setCreature(crB);
            pedigreeCreatureWorst.setCreature(crW);
            labelProbabilityBest.Text = "Probability for this Best Possible outcome: " + Math.Round(100 * probabilityBest, 1).ToString() + "%";
            // highlight parents
            int hiliId = comboOrder.IndexOf(comboIndex) * 2;

            for (int i = 0; i < pcs.Count; i++)
            {
                pcs[i].highlight = (i == hiliId || i == hiliId + 1);
            }
        }
Example #4
0
        public static int durationAfterFirstFeeding(Species species, int level, double foodDepletion)
        {
            int s = 0;

            if (species != null &&
                species.taming != null &&
                species.taming.nonViolent)
            {
                s = (int)(0.1 * Stats.calculateValue(species, (int)StatNames.Food, (int)Math.Ceiling(level / 7d), 0, false, 0, 0) / foodDepletion);
            }
            return(s);
        }
Example #5
0
        /// <summary>
        /// call this function to recalculate all stat-values of Creature c according to its levels
        /// </summary>
        public void recalculateCreatureValues(int?levelStep)
        {
            int speciesIndex = Values.V.speciesNames.IndexOf(species);

            if (speciesIndex >= 0)
            {
                for (int s = 0; s < 8; s++)
                {
                    valuesBreeding[s] = Stats.calculateValue(speciesIndex, s, levelsWild[s], 0, true, 1, 0);
                    valuesDom[s]      = Stats.calculateValue(speciesIndex, s, levelsWild[s], levelsDom[s], true, tamingEff, imprintingBonus);
                }
            }
            calculateLevelFound(levelStep);
        }
Example #6
0
 public void setLevel(int speciesIndex, int wildLevel)
 {
     if (levelGraphMax > 0)
     {
         SuspendLayout();
         labelWildLevels.Width    = 60 + 68 * (wildLevel > levelGraphMax ? levelGraphMax : wildLevel) / levelGraphMax;
         labelImprinting.Width    = 60;
         labelDomLevels.Width     = 60;
         labelImprinting.Location = new Point(33 + labelWildLevels.Width, 0);
         labelDomLevels.Location  = new Point(35 + labelWildLevels.Width + labelImprinting.Width, 0);
         labelWildLevels.Text     = (Stats.calculateValue(speciesIndex, statIndex, wildLevel, 0, true, 1, 0) * (percent ? 100 : 1)).ToString() + (percent ? "%" : "");
         labelImprinting.Text     = (Stats.calculateValue(speciesIndex, statIndex, wildLevel, 0, true, 1, 1) * (percent ? 100 : 1)).ToString() + (percent ? "%" : "");
         labelDomLevels.Text      = (Stats.calculateValue(speciesIndex, statIndex, wildLevel, maxDomLevel, true, 1, 1) * (percent ? 100 : 1)).ToString() + (percent ? "%" : "");
         ResumeLayout();
     }
 }
        public void extractLevels(Species species, int level, List <StatIO> statIOs, double lowerTEBound, double upperTEBound, bool autoDetectTamed,
                                  bool tamed, bool bred, double imprintingBonusRounded, bool adjustImprinting, bool allowMoreThanHundredImprinting, double imprintingBonusMultiplier, double cuddleIntervalMultiplier,
                                  bool considerWildLevelSteps, int wildLevelSteps, out bool imprintingChanged)
        {
            List <CreatureStat> stats = species.stats;

            validResults           = true;
            imprintingChanged      = false;
            considerWildLevelSteps = considerWildLevelSteps &&
                                     !bred &&
                                     species.name.Substring(0, 3) != "Tek" &&
                                     species.name != "Jerboa"
            ;

            this.bred = bred;
            postTamed = bred || tamed;

            List <MinMaxDouble> imprintingBonusList = new List <MinMaxDouble> {
                new MinMaxDouble(0)
            };

            if (bred)
            {
                if (!adjustImprinting)
                {
                    imprintingBonusList[0] = new MinMaxDouble(imprintingBonusRounded);
                }
                else
                {
                    imprintingBonusList = CalculateImprintingBonus(species, imprintingBonusRounded, imprintingBonusMultiplier, cuddleIntervalMultiplier, statIOs[(int)StatNames.Torpidity].Input, statIOs[(int)StatNames.Food].Input);
                }
            }

            for (int IBi = 0; IBi < imprintingBonusList.Count; IBi++)
            {
                imprintingBonusRange = imprintingBonusList[IBi];
                imprintingBonusRange.SetToIntersectionWith(0, (allowMoreThanHundredImprinting ? 5 : 1)); // it's assumed that a valid IB will not be larger than 500%

                var imprintingMultiplierRange = new MinMaxDouble(1 + imprintingBonusRange.Min * imprintingBonusMultiplier * .2, 1 + imprintingBonusRange.Max * imprintingBonusMultiplier * .2);

                var levelWildSumRange = new MinMaxInt((int)Math.Round((statIOs[(int)StatNames.Torpidity].Input / imprintingMultiplierRange.Max - (postTamed ? stats[(int)StatNames.Torpidity].AddWhenTamed : 0) - stats[(int)StatNames.Torpidity].BaseValue) / (stats[(int)StatNames.Torpidity].BaseValue * stats[(int)StatNames.Torpidity].IncPerWildLevel)),
                                                      (int)Math.Round((statIOs[(int)StatNames.Torpidity].Input / imprintingMultiplierRange.Min - (postTamed ? stats[(int)StatNames.Torpidity].AddWhenTamed : 0) - stats[(int)StatNames.Torpidity].BaseValue) / (stats[(int)StatNames.Torpidity].BaseValue * stats[(int)StatNames.Torpidity].IncPerWildLevel)));
                var levelDomSumRange = new MinMaxInt(Math.Max(0, level - 1 - levelWildSumRange.Max),
                                                     Math.Max(0, level - 1 - levelWildSumRange.Min));

                levelWildSum = levelWildSumRange.Min;
                levelDomSum  = levelDomSumRange.Min; // TODO implement range-mechanic

                levelsUndeterminedWild = levelWildSum;
                levelsUndeterminedDom  = levelDomSum;

                if (bred)
                {
                    // bred creatures always have 100% TE
                    lowerTEBound = 1;
                    upperTEBound = 1;
                }
                else
                {
                    // sometimes it fails due to double-precision errors, e.g.
                    // Pteranodon (Lvl 34, TE: 80%): HP: 415.9 (6, 0); St: 195 (6, 0); Ox: 240 (6, 0); Fo: 2150.4 (6, 0); We: 134.4 (6, 0); Dm: 141.6% (3, 0); Sp: 135% (0, 0); To: 358.1 (33);
                    // will fail the extraction with a lowerTEBound of 0.8, it only extracts with a lowerTEBound of 0.79, then displays 0.8 as result for the TE. Adding these margins make it work as expected.
                    lowerTEBound -= 0.0006;
                    upperTEBound += 0.0006;
                }

                // check all possible level-combinations
                for (int s = 0; s < statsCount; s++)
                {
                    if (stats[s].BaseValue > 0 && statIOs[s].Input > 0) // if stat is used (oxygen sometimes is not)
                    {
                        statIOs[s].postTame = postTamed;
                        // double precision makes it necessary to give a bit more tolerance (hence 0.050001 instead of just 0.05 etc.)
                        // the rounding still makes issues, trying +-0.1 in the input often helps. setting the tolerance from the expected 0.05 to 0.06
                        MinMaxDouble inputValue    = new MinMaxDouble(statIOs[s].Input - (Utils.precision(s) == 3 ? 0.00060001 : 0.060001), statIOs[s].Input + (Utils.precision(s) == 3 ? 0.00060001 : 0.060001));
                        double       statBaseValue = stats[s].BaseValue;
                        if (postTamed && s == 0)
                        {
                            statBaseValue *= (double)species.TamedBaseHealthMultiplier;                     // + 0.00000000001; // todo double-precision handling
                        }
                        bool withTEff = (postTamed && stats[s].MultAffinity > 0);
                        if (withTEff)
                        {
                            statsWithTE.Add(s);
                        }
                        int minLW = 0, maxLW = 0;
                        if (stats[s].IncPerWildLevel > 0)
                        {
                            double multAffinityFactor = stats[s].MultAffinity;
                            if (postTamed)
                            {
                                // the multiplicative bonus is only multiplied with the TE if it is positive (i.e. negative boni won't get less bad if the TE is low)
                                if (multAffinityFactor > 0)
                                {
                                    multAffinityFactor *= lowerTEBound;
                                }
                                multAffinityFactor += 1;
                            }
                            else
                            {
                                multAffinityFactor = 1;
                            }
                            maxLW = (int)Math.Round(((inputValue.Max / multAffinityFactor - (postTamed ? stats[s].AddWhenTamed : 0)) / statBaseValue - 1) / stats[s].IncPerWildLevel); // floor is too unprecise
                        }
                        else
                        {
                            minLW = -1;
                            maxLW = -1;
                        }
                        if (maxLW > levelWildSum)
                        {
                            maxLW = levelWildSum;
                        }

                        double maxLD = 0;
                        if (!statIOs[s].DomLevelLockedZero && postTamed && stats[s].BaseValue > 0 && stats[s].IncPerTamedLevel > 0)
                        {
                            int ww = 0; // base wild level for the tamed creature needed to be alive
                            if (statBaseValue + stats[s].AddWhenTamed < 0)
                            {
                                // e.g. Griffin
                                // get lowest wild level at which the creature is alive
                                while (Stats.calculateValue(species, s, ww, 0, true, lowerTEBound, 0) <= 0)
                                {
                                    ww++;
                                }
                            }
                            maxLD = Math.Round((inputValue.Max / ((statBaseValue * (1 + stats[s].IncPerWildLevel * ww) + stats[s].AddWhenTamed) * (1 + lowerTEBound * stats[s].MultAffinity)) - 1) / stats[s].IncPerTamedLevel); //floor is sometimes too low
                        }
                        if (maxLD > levelsUndeterminedDom)
                        {
                            maxLD = levelsUndeterminedDom;
                        }
                        if (maxLD < 0)
                        {
                            maxLD = 0;
                        }

                        MinMaxDouble statImprintingMultiplierRange = new MinMaxDouble(1);
                        // only use imprintingMultiplier for stats that use them. Stamina and Oxygen don't use ist. Sometimes speed neither.
                        if (bred && s != (int)StatNames.Stamina && s != (int)StatNames.Oxygen && s != (int)StatNames.CraftingSpeedMultiplier && (s != (int)StatNames.SpeedMultiplier || species.NoImprintingForSpeed == false))
                        {
                            statImprintingMultiplierRange = imprintingMultiplierRange.Clone();
                        }

                        // if dom levels have no effect, just calculate the wild level
                        // for flyers (without mods) this means for speed, no wild levels at all (i.e. not unknown, but 0)
                        // for the Diplodocus this means 0 wild levels in melee
                        if (stats[s].IncPerTamedLevel == 0)
                        {
                            if (minLW == -1)
                            {
                                //results[s].Add(new StatResult(-1, 0, inputValue.Mean));
                                results[s].Add(new StatResult(0, 0, inputValue.Mean));
                            }
                            else
                            {
                                MinMaxDouble lwRange = new MinMaxDouble(((inputValue.Min / (postTamed ? 1 + stats[s].MultAffinity : 1) - (postTamed ? stats[s].AddWhenTamed : 0)) / (statBaseValue * statImprintingMultiplierRange.Max) - 1) / stats[s].IncPerWildLevel,
                                                                        ((inputValue.Max / (postTamed ? 1 + stats[s].MultAffinity : 1) - (postTamed ? stats[s].AddWhenTamed : 0)) / (statBaseValue * statImprintingMultiplierRange.Min) - 1) / stats[s].IncPerWildLevel);
                                int lw = (int)Math.Round(lwRange.Mean);
                                if (lwRange.Includes(lw) && lw >= 0 && lw <= maxLW)
                                {
                                    results[s].Add(new StatResult(lw, 0, inputValue.Mean));
                                }
                            }
                            // even if no result was found, there is no other valid
                            continue;
                        }

                        for (int lw = minLW; lw < maxLW + 1; lw++)
                        {
                            // imprinting bonus is applied to all stats except stamina (s==1) and oxygen (s==2) and speed (s==6)
                            MinMaxDouble valueWODomRange = new MinMaxDouble(statBaseValue * (1 + stats[s].IncPerWildLevel * lw) * statImprintingMultiplierRange.Min + (postTamed ? stats[s].AddWhenTamed : 0),
                                                                            statBaseValue * (1 + stats[s].IncPerWildLevel * lw) * statImprintingMultiplierRange.Max + (postTamed ? stats[s].AddWhenTamed : 0)); // value without domesticated levels
                            if (!withTEff)
                            {
                                // calculate the only possible Ld, if it's an integer, take it.
                                if (stats[s].IncPerTamedLevel > 0)
                                {
                                    MinMaxDouble ldRange = new MinMaxDouble((inputValue.Min / (valueWODomRange.Max * (postTamed ? 1 + stats[s].MultAffinity : 1)) - 1) / stats[s].IncPerTamedLevel,
                                                                            (inputValue.Max / (valueWODomRange.Min * (postTamed ? 1 + stats[s].MultAffinity : 1)) - 1) / stats[s].IncPerTamedLevel);
                                    int ld = (int)Math.Round(ldRange.Mean);
                                    if (ldRange.Includes(ld) && ld >= 0 && ld <= maxLD)
                                    {
                                        results[s].Add(new StatResult(lw, ld, inputValue.Mean));
                                    }
                                }
                                else
                                {
                                    results[s].Add(new StatResult(lw, 0, inputValue.Mean));
                                }
                            }
                            else
                            {
                                for (int ld = 0; ld <= maxLD; ld++)
                                {
                                    // taming bonus is dependant on taming-effectiveness
                                    // get tamingEffectiveness-possibility
                                    // calculate rounding-error thresholds. Here it's assumed that the displayed ingame value is maximal 0.5 off of the true ingame value
                                    MinMaxDouble tamingEffectiveness = new MinMaxDouble((inputValue.Min / (1 + stats[s].IncPerTamedLevel * ld) - valueWODomRange.Max) / (valueWODomRange.Max * stats[s].MultAffinity),
                                                                                        (inputValue.Max / (1 + stats[s].IncPerTamedLevel * ld) - valueWODomRange.Min) / (valueWODomRange.Min * stats[s].MultAffinity));

                                    if (tamingEffectiveness.Min > upperTEBound)
                                    {
                                        continue;
                                    }
                                    if (tamingEffectiveness.Max < lowerTEBound)
                                    {
                                        break; // if tamingEff < lowerBound: break, in this d-loop it's getting only smaller
                                    }
                                    // here it's ensured the TE overlaps the bounds, so we can clamp it to the bounds
                                    if (tamingEffectiveness.Min < lowerTEBound)
                                    {
                                        tamingEffectiveness.Min = lowerTEBound;
                                    }
                                    if (tamingEffectiveness.Max > upperTEBound)
                                    {
                                        tamingEffectiveness.Max = upperTEBound;
                                    }

                                    if (!bred)
                                    {
                                        // check if the totalLevel and the TE is possible by using the TE-levelbonus (credits for this check which sorts out more impossible results: https://github.com/VolatilePulse , thanks!)
                                        int       levelPostTame     = levelWildSum + 1;
                                        MinMaxInt levelPreTameRange = new MinMaxInt((int)Math.Ceiling(levelPostTame / (1 + tamingEffectiveness.Max / 2)),
                                                                                    (int)Math.Ceiling(levelPostTame / (1 + tamingEffectiveness.Min / 2)));

                                        bool impossibleTE = true;
                                        for (int wildLevel = levelPreTameRange.Min; wildLevel <= levelPreTameRange.Max; wildLevel++)
                                        {
                                            MinMaxInt levelPostTameRange = new MinMaxInt((int)Math.Floor(wildLevel * (1 + tamingEffectiveness.Min / 2)),
                                                                                         (int)Math.Floor(wildLevel * (1 + tamingEffectiveness.Max / 2)));
                                            if (levelPostTameRange.Includes(levelPostTame))
                                            {
                                                impossibleTE = false;
                                                break;
                                            }
                                        }
                                        if (impossibleTE)
                                        {
                                            continue;
                                        }

                                        // test if TE with torpor-level of tamed-creatures results in a valid wild-level according to the possible levelSteps
                                        if (considerWildLevelSteps)
                                        {
                                            bool validWildLevel = false;
                                            for (int wildLevel = levelPreTameRange.Min; wildLevel <= levelPreTameRange.Max; wildLevel++)
                                            {
                                                if (wildLevel % wildLevelSteps == 0)
                                                {
                                                    validWildLevel = true;
                                                    break;
                                                }
                                            }
                                            if (!validWildLevel)
                                            {
                                                continue;
                                            }
                                        }

                                        // if another stat already is dependant on TE, check if this TE overlaps any of their TE-ranges. If not, TE is not possible (a creature can only have the same TE for all TE-dependant stats)
                                        if (statsWithTE.Count > 1)
                                        {
                                            bool TEExistant = false;
                                            for (int er = 0; er < results[statsWithTE[0]].Count; er++)
                                            {
                                                if (tamingEffectiveness.Overlaps(results[statsWithTE[0]][er].TE))
                                                {
                                                    TEExistant = true;
                                                    break;
                                                }
                                            }
                                            if (!TEExistant)
                                            {
                                                continue;
                                            }
                                        }
                                    }

                                    results[s].Add(new StatResult(lw, ld, inputValue.Mean, tamingEffectiveness));
                                }
                            }
                        }
                    }
                    else
                    {
                        results[s].Add(new StatResult(-1, 0));
                    }
                }
                if (bred)
                {
                    // if each stat has at least one result, assume the extraction was valid with the chosen IB
                    if (EveryStatHasAtLeastOneResult)
                    {
                        // all stats have a result, don't test the other possible IBs
                        imprintingChanged = (Math.Abs(imprintingBonusRounded - imprintingBonus) > 0.01);
                        break;
                    }
                    else if (IBi < imprintingBonusList.Count - 1)
                    {
                        // not all stats got a result, clear results for the next round
                        Clear();
                        validResults = true;
                    }
                }
            }
        }
        private List <MinMaxDouble> CalculateImprintingBonus(Species species, double imprintingBonusRounded, double imprintingBonusMultiplier, double cuddleIntervalMultiplier, double torpor, double food)
        {
            List <MinMaxDouble> imprintingBonusList = new List <MinMaxDouble>();

            if (species.stats[(int)StatNames.Torpidity].BaseValue == 0 || species.stats[(int)StatNames.Torpidity].IncPerWildLevel == 0)
            {
                return(imprintingBonusList);                                                                                                                        // invalid species-data
            }
            // classic way to calculate the ImprintingBonus, this is the most exact value, but will not work if the imprinting-gain was different (e.g. events, mods (S+Nanny))
            double imprintingBonusFromGainPerCuddle = 0;

            if (species.breeding != null)
            {
                double imprintingGainPerCuddle = Utils.imprintingGainPerCuddle(species.breeding.maturationTimeAdjusted, cuddleIntervalMultiplier);
                imprintingBonusFromGainPerCuddle = Math.Round(imprintingBonusRounded / imprintingGainPerCuddle) * imprintingGainPerCuddle;
            }

            MinMaxInt wildLevelsFromImprintedTorpor = new MinMaxInt(
                (int)Math.Round(((((torpor / (1 + species.stats[(int)StatNames.Torpidity].MultAffinity)) - species.stats[(int)StatNames.Torpidity].AddWhenTamed) / ((1 + (imprintingBonusRounded + 0.005) * 0.2 * imprintingBonusMultiplier) * species.stats[(int)StatNames.Torpidity].BaseValue)) - 1) / species.stats[(int)StatNames.Torpidity].IncPerWildLevel),
                (int)Math.Round(((((torpor / (1 + species.stats[(int)StatNames.Torpidity].MultAffinity)) - species.stats[(int)StatNames.Torpidity].AddWhenTamed) / ((1 + (imprintingBonusRounded - 0.005) * 0.2 * imprintingBonusMultiplier) * species.stats[(int)StatNames.Torpidity].BaseValue)) - 1) / species.stats[(int)StatNames.Torpidity].IncPerWildLevel));

            // assuming food has no dom-levels, extract the exact imprinting from this stat. If the range is in the range of the torpor-dependant IB, take this more precise value for the imprinting. (food has higher values and yields more precise results)
            MinMaxInt wildLevelsFromImprintedFood = new MinMaxInt(
                (int)Math.Round(((((food / (1 + species.stats[(int)StatNames.Food].MultAffinity)) - species.stats[(int)StatNames.Food].AddWhenTamed) / ((1 + (imprintingBonusRounded + 0.005) * 0.2 * imprintingBonusMultiplier) * species.stats[(int)StatNames.Food].BaseValue)) - 1) / species.stats[(int)StatNames.Food].IncPerWildLevel),
                (int)Math.Round(((((food / (1 + species.stats[(int)StatNames.Food].MultAffinity)) - species.stats[(int)StatNames.Food].AddWhenTamed) / ((1 + (imprintingBonusRounded - 0.005) * 0.2 * imprintingBonusMultiplier) * species.stats[(int)StatNames.Food].BaseValue)) - 1) / species.stats[(int)StatNames.Food].IncPerWildLevel));

            List <int> otherStatsSupportIB = new List <int>(); // the number of other stats that support this IB-range

            // for high-level creatures the bonus from imprinting is so high, that a displayed and rounded value of the imprinting bonus can be possible with multiple torpor-levels, i.e. 1 %point IB results in a larger change than a level in torpor.
            for (int torporLevel = wildLevelsFromImprintedTorpor.Min; torporLevel <= wildLevelsFromImprintedTorpor.Max; torporLevel++)
            {
                int          support = 0;
                MinMaxDouble imprintingBonusRange = new MinMaxDouble(
                    (((torpor - 0.05) / (1 + species.stats[(int)StatNames.Torpidity].MultAffinity) - species.stats[(int)StatNames.Torpidity].AddWhenTamed) / Stats.calculateValue(species, (int)StatNames.Torpidity, torporLevel, 0, false, 0, 0) - 1) / (0.2 * imprintingBonusMultiplier),
                    (((torpor + 0.05) / (1 + species.stats[(int)StatNames.Torpidity].MultAffinity) - species.stats[(int)StatNames.Torpidity].AddWhenTamed) / Stats.calculateValue(species, (int)StatNames.Torpidity, torporLevel, 0, false, 0, 0) - 1) / (0.2 * imprintingBonusMultiplier));

                // check for each possible food-level the IB-range and if it can narrow down the range derived from the torpor (deriving from food is more precise, due to the higher values)
                for (int foodLevel = wildLevelsFromImprintedFood.Min; foodLevel <= wildLevelsFromImprintedFood.Max; foodLevel++)
                {
                    MinMaxDouble imprintingBonusFromFood = new MinMaxDouble(
                        (((food - 0.05) / (1 + species.stats[(int)StatNames.Food].MultAffinity) - species.stats[(int)StatNames.Food].AddWhenTamed) / Stats.calculateValue(species, (int)StatNames.Food, foodLevel, 0, false, 0, 0) - 1) / (0.2 * imprintingBonusMultiplier),
                        (((food + 0.05) / (1 + species.stats[(int)StatNames.Food].MultAffinity) - species.stats[(int)StatNames.Food].AddWhenTamed) / Stats.calculateValue(species, (int)StatNames.Food, foodLevel, 0, false, 0, 0) - 1) / (0.2 * imprintingBonusMultiplier));


                    // NOTE. it's assumed if the IB-food is in the range of IB-torpor, the values are correct. This doesn't have to be true, but is very probable. If extraction-issues appear, this assumption could be the reason.
                    //if (imprintingBonusFromTorpor.Includes(imprintingBonusFromFood)
                    if (imprintingBonusRange.Overlaps(imprintingBonusFromFood))
                    {
                        MinMaxDouble intersectionIB = new MinMaxDouble(imprintingBonusRange);
                        intersectionIB.SetToIntersectionWith(imprintingBonusFromFood);
                        if (Stats.calculateValue(species, (int)StatNames.Torpidity, torporLevel, 0, true, 1, intersectionIB.Min) <= torpor &&
                            Stats.calculateValue(species, (int)StatNames.Torpidity, torporLevel, 0, true, 1, intersectionIB.Max) >= torpor)
                        {
                            //imprintingBonusFromTorpor = imprintingBonusFromFood;
                            imprintingBonusRange.SetToIntersectionWith(imprintingBonusFromFood);
                            support++;
                        }
                    }
                }

                // if classic method results in value in the possible range, take this, probably most exact value
                if (imprintingBonusRange.Includes(imprintingBonusFromGainPerCuddle) &&
                    Stats.calculateValue(species, (int)StatNames.Torpidity, torporLevel, 0, true, 1, imprintingBonusFromGainPerCuddle) == torpor)
                {
                    imprintingBonusRange.MinMax = imprintingBonusFromGainPerCuddle;
                    support++;
                }

                // TODO check if this range has already been added to avoid double loops in the extraction. if existant, update support
                imprintingBonusList.Add(imprintingBonusRange);
                otherStatsSupportIB.Add(support);
            }

            // sort IB according to the support they got by other stats, then return the distinct means of the possible ranges.
            return(imprintingBonusList.OrderByDescending(i => otherStatsSupportIB[imprintingBonusList.IndexOf(i)]).ToList());
        }
Example #9
0
        private void setParents(int comboIndex)
        {
            if (comboIndex < 0 || comboIndex >= breedingPairs.Count)
            {
                pedigreeCreatureBest.Clear();
                pedigreeCreatureWorst.Clear();
                lbBreedingPlanInfo.Visible = false;
                lbBPProbabilityBest.Text   = "";
                return;
            }

            int?     levelStep = creatureCollection.getWildLevelStep();
            Creature crB       = new Creature(currentSpecies, "", "", "", 0, new int[8], null, 100, true, levelStep: levelStep);
            Creature crW       = new Creature(currentSpecies, "", "", "", 0, new int[8], null, 100, true, levelStep: levelStep);
            Creature mother    = breedingPairs[comboIndex].Female;
            Creature father    = breedingPairs[comboIndex].Male;

            crB.Mother = mother;
            crB.Father = father;
            crW.Mother = mother;
            crW.Father = father;
            double probabilityBest   = 1;
            bool   totalLevelUnknown = false; // if stats are unknown, total level is as well (==> oxygen, speed)

            for (int s = 0; s < 7; s++)
            {
                crB.levelsWild[s]       = statWeights[s] < 0 ? Math.Min(mother.levelsWild[s], father.levelsWild[s]) : Math.Max(mother.levelsWild[s], father.levelsWild[s]);
                crB.valuesBreeding[s]   = Stats.calculateValue(speciesIndex, s, crB.levelsWild[s], 0, true, 1, 0);
                crB.topBreedingStats[s] = (crB.levelsWild[s] == bestLevels[s]);
                crW.levelsWild[s]       = statWeights[s] < 0 ? Math.Max(mother.levelsWild[s], father.levelsWild[s]) : Math.Min(mother.levelsWild[s], father.levelsWild[s]);
                crW.valuesBreeding[s]   = Stats.calculateValue(speciesIndex, s, crW.levelsWild[s], 0, true, 1, 0);
                crW.topBreedingStats[s] = (crW.levelsWild[s] == bestLevels[s]);
                if (crB.levelsWild[s] == -1 || crW.levelsWild[s] == -1)
                {
                    totalLevelUnknown = true;
                }
                if (crB.levelsWild[s] > crW.levelsWild[s])
                {
                    probabilityBest *= .7;
                }
            }
            crB.levelsWild[7] = crB.levelsWild.Sum();
            crW.levelsWild[7] = crW.levelsWild.Sum();
            crB.name          = Loc.s("BestPossible");
            crW.name          = Loc.s("WorstPossible");
            crB.recalculateCreatureValues(levelStep);
            crW.recalculateCreatureValues(levelStep);
            pedigreeCreatureBest.totalLevelUnknown  = totalLevelUnknown;
            pedigreeCreatureWorst.totalLevelUnknown = totalLevelUnknown;
            int mutationCounterMaternal = mother.Mutations;
            int mutationCounterPaternal = father.Mutations;

            crB.mutationsMaternal          = mutationCounterMaternal;
            crB.mutationsPaternal          = mutationCounterPaternal;
            crW.mutationsMaternal          = mutationCounterMaternal;
            crW.mutationsPaternal          = mutationCounterPaternal;
            pedigreeCreatureBest.Creature  = crB;
            pedigreeCreatureWorst.Creature = crW;
            lbBPProbabilityBest.Text       = Loc.s("ProbabilityForBest") + ": " + Math.Round(100 * probabilityBest, 1).ToString() + "%";

            // set probability barChart
            offspringPossibilities1.wildLevels1 = mother.levelsWild;
            offspringPossibilities1.wildLevels2 = father.levelsWild;
            offspringPossibilities1.calculate();

            // highlight parents
            int hiliId = comboIndex * 2;

            for (int i = 0; i < pcs.Count; i++)
            {
                pcs[i].highlight = (i == hiliId || i == hiliId + 1);
            }
        }
Example #10
0
        public void extractLevels(int speciesI, int level, List <StatIO> statIOs, double lowerTEBound, double upperTEBound, bool autoDetectTamed,
                                  bool tamed, bool justTamed, bool bred, double imprintingBonusRounded, bool adjustImprinting, bool allowMoreThanHundredImprinting, bool extractImprintingFromTorpor, double imprintingBonusMultiplier, double cuddleIntervalMultiplier,
                                  bool considerWildLevelSteps, int wildLevelSteps, out bool imprintingChanged)
        {
            List <CreatureStat> stats = Values.V.species[speciesI].stats;

            validResults           = true;
            imprintingChanged      = false;
            considerWildLevelSteps = considerWildLevelSteps && !bred;

            this.bred = bred;
            if (bred)
            {
                postTamed = true;
            }
            else if (autoDetectTamed && stats[7].AddWhenTamed > 0)
            {
                // torpor is directly proportional to wild level. Check if creature is wild or tamed (doesn't work with creatures that have no additive bonus on torpor, e.g. the Giganotosaurus)
                postTamed = (Math.Round(stats[7].BaseValue * (1 + stats[7].IncPerWildLevel * Math.Round((statIOs[7].Input - stats[7].BaseValue) / (stats[7].BaseValue * stats[7].IncPerWildLevel))), 3) != statIOs[7].Input);
            }
            else
            {
                postTamed = tamed;
            }

            imprintingBonus = 0;
            if (bred)
            {
                if (!adjustImprinting)
                {
                    imprintingBonus = imprintingBonusRounded;
                }
                else if (extractImprintingFromTorpor)
                {
                    int wildLevelsFromImprintedTorpor = (int)Math.Round(((((statIOs[7].Input / (1 + stats[7].MultAffinity)) - stats[7].AddWhenTamed) / ((1 + imprintingBonusRounded * 0.2 * imprintingBonusMultiplier) * stats[7].BaseValue)) - 1) / stats[7].IncPerWildLevel);
                    imprintingBonus = ((statIOs[7].Input / (1 + stats[7].MultAffinity) - stats[7].AddWhenTamed) / Stats.calculateValue(speciesI, 7, wildLevelsFromImprintedTorpor, 0, false, 0, 0) - 1) / (0.2 * imprintingBonusMultiplier);

                    // assuming food has no dom-levels, extract the exact imprinting from this stat. If the difference is less than 0.01, take this (probably more precise) value for the imprinting. (food has higher values and yields more precise results)
                    int    wildLevelsFromImprintedFood = (int)Math.Round(((((statIOs[3].Input / (1 + stats[3].MultAffinity)) - stats[3].AddWhenTamed) / ((1 + imprintingBonusRounded * 0.2 * imprintingBonusMultiplier) * stats[3].BaseValue)) - 1) / stats[3].IncPerWildLevel);
                    double imprintingBonusFromFood     = ((statIOs[3].Input / (1 + stats[3].MultAffinity) - stats[3].AddWhenTamed) / Stats.calculateValue(speciesI, 3, wildLevelsFromImprintedFood, 0, false, 0, 0) - 1) / (0.2 * imprintingBonusMultiplier);
                    if (Math.Abs(imprintingBonus - imprintingBonusFromFood) < 0.01)
                    {
                        imprintingBonus = imprintingBonusFromFood;
                    }
                }
                else if (Values.V.species[speciesI].breeding != null && Values.V.species[speciesI].breeding.maturationTimeAdjusted > 0)
                {
                    double imprintingGainPerCuddle = Utils.imprintingGainPerCuddle(Values.V.species[speciesI].breeding.maturationTimeAdjusted, cuddleIntervalMultiplier);
                    imprintingBonus = Math.Round(Math.Round(imprintingBonusRounded / imprintingGainPerCuddle) * imprintingGainPerCuddle, 7);
                }
                if (!allowMoreThanHundredImprinting && imprintingBonus > 1)
                {
                    imprintingBonus = 1;
                }
                if (imprintingBonus < 0)
                {
                    imprintingBonus = 0;
                }
                if (Math.Abs(imprintingBonusRounded - imprintingBonus) > 0.01)
                {
                    imprintingChanged = true;
                }
            }
            double imprintingMultiplier = (1 + imprintingBonus * imprintingBonusMultiplier * .2);
            double torporLevelTamingMultMax, torporLevelTamingMultMin;

            torporLevelTamingMultMax = 1;
            torporLevelTamingMultMin = 1;
            if (postTamed && justTamed && !bred)
            {
                torporLevelTamingMultMax = (2 + upperTEBound) / (4 + upperTEBound);
                torporLevelTamingMultMin = (2 + lowerTEBound) / (4 + lowerTEBound);
            }
            levelWildFromTorporRange[0] = (int)Math.Round((statIOs[7].Input / imprintingMultiplier - (postTamed ? stats[7].AddWhenTamed : 0) - stats[7].BaseValue) * torporLevelTamingMultMin / (stats[7].BaseValue * stats[7].IncPerWildLevel), 0);
            levelWildFromTorporRange[1] = (int)Math.Round((statIOs[7].Input / imprintingMultiplier - (postTamed ? stats[7].AddWhenTamed : 0) - stats[7].BaseValue) * torporLevelTamingMultMax / (stats[7].BaseValue * stats[7].IncPerWildLevel), 0);

            domFreeMin = 0;
            domFreeMax = 0;
            // lower/upper Bound of each stat (wild has no upper bound as wild-speed and sometimes oxygen is unknown)
            if (postTamed)
            {
                domFreeMin = Math.Max(0, level - levelWildFromTorporRange[1] - 1);
                domFreeMax = Math.Max(0, level - levelWildFromTorporRange[0] - 1);
            }
            levelDomFromTorporAndTotalRange[0] = domFreeMin;
            levelDomFromTorporAndTotalRange[1] = domFreeMax;
            wildFreeMax = levelWildFromTorporRange[1];

            if (bred)
            {
                // bred creatures always have 100% TE
                lowerTEBound = 1;
                upperTEBound = 1;
            }

            // check all possible level-combinations
            for (int s = 7; s >= 0; s--)
            {
                if (stats[s].BaseValue > 0 && activeStats[s]) // if stat is used (oxygen sometimes is not)
                {
                    statIOs[s].postTame = postTamed;
                    double inputValue    = statIOs[s].Input;
                    double statBaseValue = stats[s].BaseValue;
                    if (postTamed)
                    {
                        statBaseValue *= (s == 0 ? (double)Values.V.species[speciesI].TamedBaseHealthMultiplier : 1);
                    }

                    double tamingEffectiveness = -1;
                    double valueWODom          = 0; // value without domesticated levels

                    bool withTEff = (postTamed && stats[s].MultAffinity > 0);
                    if (withTEff)
                    {
                        statsWithEff.Add(s);
                    }
                    double maxLW = 0;
                    if (stats[s].BaseValue > 0 && stats[s].IncPerWildLevel > 0)
                    {
                        double multAffinityFactor = stats[s].MultAffinity;
                        if (postTamed)
                        {
                            // the multiplicative bonus is only multiplied with the TE if it is positive (i.e. negative boni won't get less bad if the TE is low)
                            if (multAffinityFactor > 0)
                            {
                                multAffinityFactor *= lowerTEBound;
                            }
                            multAffinityFactor += 1;
                        }
                        else
                        {
                            multAffinityFactor = 1;
                        }
                        maxLW = Math.Round(((inputValue / multAffinityFactor - (postTamed ? stats[s].AddWhenTamed : 0)) / statBaseValue - 1) / stats[s].IncPerWildLevel); // floor is too unprecise
                    }
                    if (s != 7 && maxLW > levelWildFromTorporRange[1])
                    {
                        maxLW = levelWildFromTorporRange[1];
                    }                                                                                           // torpor level can be too high right after taming (torpor bug in the game)

                    double maxLD = 0;
                    if (!statIOs[s].DomLevelZero && postTamed && stats[s].BaseValue > 0 && stats[s].IncPerTamedLevel > 0)
                    {
                        maxLD = Math.Round((inputValue / ((statBaseValue + stats[s].AddWhenTamed) * (1 + lowerTEBound * stats[s].MultAffinity)) - 1) / stats[s].IncPerTamedLevel); //floor is sometimes too unprecise
                    }
                    if (maxLD > domFreeMax)
                    {
                        maxLD = domFreeMax;
                    }
                    if (maxLD < 0)
                    {
                        maxLD = 0;
                    }

                    for (int w = 0; w < maxLW + 1; w++)
                    {
                        // imprinting bonus is applied to all stats except stamina (s==1) and oxygen (s==2) and speed (s==6)
                        valueWODom = statBaseValue * (1 + stats[s].IncPerWildLevel * w) * (s == 1 || s == 2 || (s == 6 && Values.V.species[speciesI].NoImprintingForSpeed == true) ? 1 : imprintingMultiplier) + (postTamed ? stats[s].AddWhenTamed : 0);
                        for (int d = 0; d < maxLD + 1; d++)
                        {
                            if (withTEff)
                            {
                                // taming bonus is dependant on taming-effectiveness
                                // get tamingEffectiveness-possibility
                                tamingEffectiveness = Math.Round((inputValue / (1 + stats[s].IncPerTamedLevel * d) - valueWODom) / (valueWODom * stats[s].MultAffinity), 4);

                                // calculate rounding-error thresholds. Here it's assumed that the displayed ingame value is maximal 0.6 off of the true ingame value
                                double tamingEffectivenessMax = Math.Round(((inputValue + (Utils.precision(s) == 3 ? 0.0006 : 0.06)) / (1 + stats[s].IncPerTamedLevel * d) - valueWODom) / (valueWODom * stats[s].MultAffinity), 4);
                                double tamingEffectivenessMin = Math.Round(((inputValue - (Utils.precision(s) == 3 ? 0.0006 : 0.06)) / (1 + stats[s].IncPerTamedLevel * d) - valueWODom) / (valueWODom * stats[s].MultAffinity), 4);

                                if (tamingEffectivenessMin <= 1 && tamingEffectiveness > 1)
                                {
                                    tamingEffectiveness = 1;
                                }
                                if (tamingEffectivenessMax >= lowerTEBound)
                                {
                                    if (tamingEffectivenessMin <= upperTEBound)
                                    {
                                        // test if TE with torpor-level of tamed-creatures results in a valid wild-level
                                        if (considerWildLevelSteps && s != 7 && tamingEffectiveness > 0)
                                        {
                                            int  preTameLevelMin = (int)((trueTorporLevel() + 1) / (1 + tamingEffectivenessMax / 2));
                                            int  preTameLevelMax = (int)Math.Ceiling((trueTorporLevel() + 1) / (1 + tamingEffectivenessMax / 2));
                                            bool validWildLevel  = false;
                                            for (int wl = preTameLevelMin; wl <= preTameLevelMax; wl++)
                                            {
                                                if (wl % wildLevelSteps == 0)
                                                {
                                                    validWildLevel = true;
                                                    break;
                                                }
                                            }
                                            if (!validWildLevel)
                                            {
                                                continue;
                                            }
                                        }

                                        results[s].Add(new StatResult(w, d, tamingEffectiveness, tamingEffectivenessMin, tamingEffectivenessMax));
                                    }
                                    else
                                    {
                                        continue;
                                    }
                                }
                                else
                                {
                                    // if tamingEff < lowerBound: break, in this loop it's getting only smaller
                                    break;
                                }
                            }
                            else if (Math.Abs((valueWODom * (postTamed ? 1 + stats[s].MultAffinity : 1) * (1 + stats[s].IncPerTamedLevel * d) - inputValue) * (Utils.precision(s) == 3 ? 100 : 1)) < 0.15)
                            {
                                results[s].Add(new StatResult(w, d));
                                break; // no other solution with this w possible
                            }
                        }
                    }
                }
                else
                {
                    results[s].Add(new StatResult(0, 0));
                }
            }
        }
Example #11
0
        private void setParents(int comboIndex)
        {
            if (comboIndex < 0 || comboIndex > combinedTops[0].Count)
            {
                pedigreeCreatureBest.Clear();
                pedigreeCreatureWorst.Clear();
                labelInfo.Visible         = false;
                labelProbabilityBest.Text = "";
                return;
            }

            int?     levelStep = creatureCollection.getWildLevelStep();
            Creature crB       = new Creature(currentSpecies, "", "", "", 0, new int[8], null, 100, true, levelStep: levelStep);
            Creature crW       = new Creature(currentSpecies, "", "", "", 0, new int[8], null, 100, true, levelStep: levelStep);
            Creature mother    = females[combinedTops[0][comboIndex]];
            Creature father    = males[combinedTops[1][comboIndex]];

            crB.Mother = mother;
            crB.Father = father;
            crW.Mother = mother;
            crW.Father = father;
            double probabilityBest   = 1;
            bool   totalLevelUnknown = false; // if stats are unknown, total level is as well (==> oxygen, speed)

            for (int s = 0; s < 7; s++)
            {
                crB.levelsWild[s]       = Math.Max(mother.levelsWild[s], father.levelsWild[s]);
                crB.valuesBreeding[s]   = Stats.calculateValue(speciesIndex, s, crB.levelsWild[s], 0, true, 1, 0);
                crB.topBreedingStats[s] = (crB.levelsWild[s] == bestLevels[s]);
                crW.levelsWild[s]       = Math.Min(mother.levelsWild[s], father.levelsWild[s]);
                crW.valuesBreeding[s]   = Stats.calculateValue(speciesIndex, s, crW.levelsWild[s], 0, true, 1, 0);
                crW.topBreedingStats[s] = (crW.levelsWild[s] == bestLevels[s]);
                if (crB.levelsWild[s] == -1 || crW.levelsWild[s] == -1)
                {
                    totalLevelUnknown = true;
                }
                if (crB.levelsWild[s] > crW.levelsWild[s])
                {
                    probabilityBest *= .7;
                }
            }
            crB.levelsWild[7] = crB.levelsWild.Sum();
            crW.levelsWild[7] = crW.levelsWild.Sum();
            crB.name          = "Best Possible";
            crW.name          = "Worst Possible";
            crB.recalculateCreatureValues(levelStep);
            crW.recalculateCreatureValues(levelStep);
            pedigreeCreatureBest.totalLevelUnknown  = totalLevelUnknown;
            pedigreeCreatureWorst.totalLevelUnknown = totalLevelUnknown;
            int mutationCounter = mother.mutationCounter + father.mutationCounter;

            crB.mutationCounter            = mutationCounter;
            crW.mutationCounter            = mutationCounter;
            pedigreeCreatureBest.Creature  = crB;
            pedigreeCreatureWorst.Creature = crW;
            labelProbabilityBest.Text      = "Probability for this Best Possible outcome: " + Math.Round(100 * probabilityBest, 1).ToString() + "%";

            // set probability barChart
            offspringPossibilities1.wildLevels1 = mother.levelsWild;
            offspringPossibilities1.wildLevels2 = father.levelsWild;
            offspringPossibilities1.calculate();

            // highlight parents
            int hiliId = comboOrder.IndexOf(comboIndex) * 2;

            for (int i = 0; i < pcs.Count; i++)
            {
                pcs[i].highlight = (i == hiliId || i == hiliId + 1);
            }
        }
Example #12
0
        public void extractLevels(int speciesI, int level, List <StatIO> statIOs, double lowerTEBound, double upperTEBound, bool autoDetectTamed,
                                  bool tamed, bool bred, double imprintingBonusRounded, bool adjustImprinting, bool allowMoreThanHundredImprinting, double imprintingBonusMultiplier, double cuddleIntervalMultiplier,
                                  bool considerWildLevelSteps, int wildLevelSteps, out bool imprintingChanged)
        {
            List <CreatureStat> stats = Values.V.species[speciesI].stats;

            validResults           = true;
            imprintingChanged      = false;
            considerWildLevelSteps = considerWildLevelSteps && !bred;

            this.bred = bred;
            if (bred)
            {
                postTamed = true;
            }
            else
            {
                postTamed = tamed;
            }

            List <double> imprintingBonusList = new List <double>()
            {
                0
            };

            if (bred)
            {
                if (!adjustImprinting)
                {
                    imprintingBonusList[0] = imprintingBonusRounded;
                }
                else
                {
                    imprintingBonusList = CalculateImprintingBonus(imprintingBonusRounded, imprintingBonusMultiplier, cuddleIntervalMultiplier, stats, speciesI, statIOs[7].Input, statIOs[3].Input);
                }
            }

            for (int IBi = 0; IBi < imprintingBonusList.Count; IBi++)
            {
                imprintingBonus = imprintingBonusList[IBi];
                if (!allowMoreThanHundredImprinting && imprintingBonus > 1)
                {
                    imprintingBonus = 1;
                }
                if (imprintingBonus < 0)
                {
                    imprintingBonus = 0;
                }
                imprintingChanged = (Math.Abs(imprintingBonusRounded - imprintingBonus) > 0.01);
                double imprintingMultiplier = (1 + imprintingBonus * imprintingBonusMultiplier * .2);

                levelWildSum = (int)Math.Round((statIOs[7].Input / imprintingMultiplier - (postTamed ? stats[7].AddWhenTamed : 0) - stats[7].BaseValue) / (stats[7].BaseValue * stats[7].IncPerWildLevel), 0);
                levelDomSum  = Math.Max(0, level - 1 - levelWildSum);

                levelsUndeterminedWild = levelWildSum;
                levelsUndeterminedDom  = levelDomSum;

                if (bred)
                {
                    // bred creatures always have 100% TE
                    lowerTEBound = 1;
                    upperTEBound = 1;
                }

                // check all possible level-combinations
                for (int s = 0; s < 8; s++)
                {
                    if (stats[s].BaseValue > 0 && activeStats[s]) // if stat is used (oxygen sometimes is not)
                    {
                        statIOs[s].postTame = postTamed;
                        // double precision makes it necessary to give a bit more tolerance (hence 0.050001 instead of just 0.05 etc.)
                        MinMaxDouble inputValue    = new MinMaxDouble(statIOs[s].Input - (Utils.precision(s) == 3 ? 0.00050001 : 0.050001), statIOs[s].Input + (Utils.precision(s) == 3 ? 0.00050001 : 0.050001));
                        double       statBaseValue = stats[s].BaseValue;
                        if (postTamed)
                        {
                            statBaseValue *= (s == 0 ? (double)Values.V.species[speciesI].TamedBaseHealthMultiplier : 1);
                        }

                        bool withTEff = (postTamed && stats[s].MultAffinity > 0);
                        if (withTEff)
                        {
                            statsWithTE.Add(s);
                        }
                        int minLW = 0, maxLW = 0;
                        if (stats[s].IncPerWildLevel > 0)
                        {
                            double multAffinityFactor = stats[s].MultAffinity;
                            if (postTamed)
                            {
                                // the multiplicative bonus is only multiplied with the TE if it is positive (i.e. negative boni won't get less bad if the TE is low)
                                if (multAffinityFactor > 0)
                                {
                                    multAffinityFactor *= lowerTEBound;
                                }
                                multAffinityFactor += 1;
                            }
                            else
                            {
                                multAffinityFactor = 1;
                            }
                            maxLW = (int)Math.Round(((inputValue.Max / multAffinityFactor - (postTamed ? stats[s].AddWhenTamed : 0)) / statBaseValue - 1) / stats[s].IncPerWildLevel); // floor is too unprecise
                        }
                        else
                        {
                            minLW = -1;
                            maxLW = -1;
                        }
                        if (maxLW > levelWildSum)
                        {
                            maxLW = levelWildSum;
                        }

                        double maxLD = 0;
                        if (!statIOs[s].DomLevelLockedZero && postTamed && stats[s].BaseValue > 0 && stats[s].IncPerTamedLevel > 0)
                        {
                            int ww = 0; // base wild level for the tamed creature needed to be alive
                            if (statBaseValue + stats[s].AddWhenTamed < 0)
                            {
                                // e.g. Griffin
                                // get lowest wild level at which the creature is alive
                                while (Stats.calculateValue(speciesI, s, ww, 0, true, lowerTEBound, 0) <= 0)
                                {
                                    ww++;
                                }
                            }
                            maxLD = Math.Round((inputValue.Max / ((statBaseValue * (1 + stats[s].IncPerWildLevel * ww) + stats[s].AddWhenTamed) * (1 + lowerTEBound * stats[s].MultAffinity)) - 1) / stats[s].IncPerTamedLevel); //floor is sometimes too low
                        }
                        if (maxLD > levelsUndeterminedDom)
                        {
                            maxLD = levelsUndeterminedDom;
                        }
                        if (maxLD < 0)
                        {
                            maxLD = 0;
                        }

                        double statImprintingMultiplier = (!bred || s == 1 || s == 2 || (s == 6 && Values.V.species[speciesI].NoImprintingForSpeed == true) ? 1 : imprintingMultiplier);

                        // if dom levels have no effect, just calculate the wild level
                        if (stats[s].IncPerTamedLevel == 0)
                        {
                            if (minLW == -1)
                            {
                                results[s].Add(new StatResult(-1, 0, inputValue.Mean));
                            }
                            else
                            {
                                MinMaxDouble lwRange = new MinMaxDouble(((inputValue.Min / (postTamed ? 1 + stats[s].MultAffinity : 1) - (postTamed ? stats[s].AddWhenTamed : 0)) / (statBaseValue * statImprintingMultiplier) - 1) / stats[s].IncPerWildLevel,
                                                                        ((inputValue.Max / (postTamed ? 1 + stats[s].MultAffinity : 1) - (postTamed ? stats[s].AddWhenTamed : 0)) / (statBaseValue * statImprintingMultiplier) - 1) / stats[s].IncPerWildLevel);
                                int lw = (int)Math.Round(lwRange.Mean);
                                if (lwRange.Includes(lw) && lw >= 0 && lw <= maxLW)
                                {
                                    results[s].Add(new StatResult(lw, 0, inputValue.Mean));
                                }
                            }
                            // even if no result was found, there is no other valid
                            continue;
                        }

                        for (int lw = minLW; lw < maxLW + 1; lw++)
                        {
                            // imprinting bonus is applied to all stats except stamina (s==1) and oxygen (s==2) and speed (s==6)
                            double valueWODom = statBaseValue * (1 + stats[s].IncPerWildLevel * lw) * statImprintingMultiplier + (postTamed ? stats[s].AddWhenTamed : 0); // value without domesticated levels
                            if (!withTEff)
                            {
                                // calculate the only possible Ld, if it's an integer, take it.
                                if (stats[s].IncPerTamedLevel > 0)
                                {
                                    MinMaxDouble ldRange = new MinMaxDouble((inputValue.Min / (valueWODom * (postTamed ? 1 + stats[s].MultAffinity : 1)) - 1) / stats[s].IncPerTamedLevel,
                                                                            (inputValue.Max / (valueWODom * (postTamed ? 1 + stats[s].MultAffinity : 1)) - 1) / stats[s].IncPerTamedLevel);
                                    int ld = (int)Math.Round(ldRange.Mean);
                                    if (ldRange.Includes(ld) && ld >= 0 && ld <= maxLD)
                                    {
                                        results[s].Add(new StatResult(lw, ld, inputValue.Mean));
                                    }
                                }
                                else
                                {
                                    results[s].Add(new StatResult(lw, 0, inputValue.Mean));
                                }
                            }
                            else
                            {
                                for (int ld = 0; ld <= maxLD; ld++)
                                {
                                    // taming bonus is dependant on taming-effectiveness
                                    // get tamingEffectiveness-possibility
                                    // calculate rounding-error thresholds. Here it's assumed that the displayed ingame value is maximal 0.5 off of the true ingame value
                                    MinMaxDouble tamingEffectiveness = new MinMaxDouble((inputValue.Min / (1 + stats[s].IncPerTamedLevel * ld) - valueWODom) / (valueWODom * stats[s].MultAffinity),
                                                                                        (inputValue.Max / (1 + stats[s].IncPerTamedLevel * ld) - valueWODom) / (valueWODom * stats[s].MultAffinity));

                                    if (tamingEffectiveness.Min > upperTEBound)
                                    {
                                        continue;
                                    }
                                    if (tamingEffectiveness.Max < lowerTEBound)
                                    {
                                        break; // if tamingEff < lowerBound: break, in this d-loop it's getting only smaller
                                    }
                                    // here it's ensured the TE overlaps the bounds, so we can clamp it to the bounds
                                    if (tamingEffectiveness.Min < lowerTEBound)
                                    {
                                        tamingEffectiveness.Min = lowerTEBound;
                                    }
                                    if (tamingEffectiveness.Max > upperTEBound)
                                    {
                                        tamingEffectiveness.Max = upperTEBound;
                                    }

                                    if (!bred)
                                    {
                                        // check if the totalLevel and the TE is possible by using the TE-levelbonus (credits for this check which sorts out more impossible results: https://github.com/VolatilePulse , thanks!)
                                        int       levelPostTame     = levelWildSum + 1;
                                        MinMaxInt levelPreTameRange = new MinMaxInt((int)Math.Ceiling(levelPostTame / (1 + tamingEffectiveness.Max / 2)),
                                                                                    (int)Math.Ceiling(levelPostTame / (1 + tamingEffectiveness.Min / 2)));

                                        bool impossibleTE = true;
                                        for (int wildLevel = levelPreTameRange.Min; wildLevel <= levelPreTameRange.Max; wildLevel++)
                                        {
                                            MinMaxInt levelPostTameRange = new MinMaxInt((int)Math.Floor(wildLevel * (1 + tamingEffectiveness.Min / 2)),
                                                                                         (int)Math.Floor(wildLevel * (1 + tamingEffectiveness.Max / 2)));
                                            if (levelPostTameRange.Includes(levelPostTame))
                                            {
                                                impossibleTE = false;
                                                break;
                                            }
                                        }
                                        if (impossibleTE)
                                        {
                                            continue;
                                        }

                                        // test if TE with torpor-level of tamed-creatures results in a valid wild-level according to the possible levelSteps
                                        if (considerWildLevelSteps)
                                        {
                                            bool validWildLevel = false;
                                            for (int wildLevel = levelPreTameRange.Min; wildLevel <= levelPreTameRange.Max; wildLevel++)
                                            {
                                                if (wildLevel % wildLevelSteps == 0)
                                                {
                                                    validWildLevel = true;
                                                    break;
                                                }
                                            }
                                            if (!validWildLevel)
                                            {
                                                continue;
                                            }
                                        }

                                        // if another stat already is dependant on TE, check if this TE overlaps any of their TE-ranges. If not, TE is not possible (a creature can only have the same TE for all TE-dependant stats)
                                        if (statsWithTE.Count > 1)
                                        {
                                            bool TEExistant = false;
                                            for (int er = 0; er < results[statsWithTE[0]].Count; er++)
                                            {
                                                if (tamingEffectiveness.Overlaps(results[statsWithTE[0]][er].TE))
                                                {
                                                    TEExistant = true;
                                                    break;
                                                }
                                            }
                                            if (!TEExistant)
                                            {
                                                continue;
                                            }
                                        }
                                    }

                                    results[s].Add(new StatResult(lw, ld, inputValue.Mean, tamingEffectiveness));
                                }
                            }
                        }
                    }
                    else
                    {
                        results[s].Add(new StatResult(-1, 0));
                    }
                }
                if (bred)
                {
                    // if each stat has at least one result, assume the extraction was valid with the chosen IB
                    if (EveryStatHasAtLeastOneResult)
                    {
                        // all stats have a result, don't test the other possible IBs
                        break;
                    }
                    else if (IBi < imprintingBonusList.Count - 1)
                    {
                        // not all stats got a result, clear results for the next round
                        Clear();
                        validResults = true;
                    }
                }
            }
        }