Ejemplo n.º 1
0
 private void initLocalization()
 {
     Loc.LoadResourceFile();
     Utils.InitializeLocalizations();
 }
        /// <summary>
        /// Extracts possible level combinations for the given values.
        /// </summary>
        /// <param name="species"></param>
        /// <param name="level">Total level of the creature.</param>
        /// <param name="statIOs">Controls that display the stats</param>
        /// <param name="lowerTEBound">Lowest possible taming effectiveness</param>
        /// <param name="upperTEBound">Highest possible taming effectiveness</param>
        /// <param name="tamed"></param>
        /// <param name="bred"></param>
        /// <param name="imprintingBonusRounded"></param>
        /// <param name="adjustImprinting"></param>
        /// <param name="allowMoreThanHundredImprinting"></param>
        /// <param name="imprintingBonusMultiplier"></param>
        /// <param name="cuddleIntervalMultiplier"></param>
        /// <param name="considerWildLevelSteps"></param>
        /// <param name="wildLevelSteps"></param>
        /// <param name="highPrecisionInputs">If true, the input is expected to be a float value from an export file.
        /// If false, it's assumed to be a displayed value from the game with one decimal digit.</param>
        /// <param name="imprintingChanged"></param>
        public void ExtractLevels(Species species, int level, List<StatIO> statIOs, double lowerTEBound, double upperTEBound,
            bool tamed, bool bred, double imprintingBonusRounded, bool adjustImprinting, bool allowMoreThanHundredImprinting, double imprintingBonusMultiplier, double cuddleIntervalMultiplier,
            bool considerWildLevelSteps, int wildLevelSteps, bool highPrecisionInputs, 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 imprintingMultiplierRanges = new MinMaxDouble[Values.STATS_COUNT];
                for (int s = 0; s < Values.STATS_COUNT; s++)
                {
                    imprintingMultiplierRanges[s] = species.statImprintMult[s] != 0
                        ? new MinMaxDouble(1 + imprintingBonusRange.Min * imprintingBonusMultiplier * species.statImprintMult[s],
                                           1 + imprintingBonusRange.Max * imprintingBonusMultiplier * species.statImprintMult[s])
                        : new MinMaxDouble(1);
                }

                var levelWildSumRange = new MinMaxInt((int)Math.Round((statIOs[(int)StatNames.Torpidity].Input / imprintingMultiplierRanges[(int)StatNames.Torpidity].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 / imprintingMultiplierRanges[(int)StatNames.Torpidity].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;
                    if (lowerTEBound < 0) lowerTEBound = 0;
                    upperTEBound += 0.0006;
                }

                // check all possible level-combinations
                for (int s = 0; s < Values.STATS_COUNT; s++)
                {
                    if (!species.UsesStat(s))
                    {
                        results[s].Add(new StatResult(0, 0));
                        continue;
                    }
                    if (statIOs[s].Input <= 0) // if stat is unknown (e.g. oxygen sometimes is not shown)
                    {
                        results[s].Add(new StatResult(-1, 0));
                        continue;
                    }

                    statIOs[s].postTame = postTamed;

                    // determine the precision of the input value
                    // ARK displays one decimal digit, so the minimal error of a given number is assumed to be 0.06.
                    // the theoretical value of a maximal error of 0.05 is too low.
                    const float ARKDISPLAYVALUEERROR = 0.06f;
                    // If an export file is used, the full float precision of the stat value is given, the precision is calculated then.
                    // For values > 1e6 the float precision error is larger than 0.06

                    // always consider at least an error of. When using only the float-precision often the stat-calculations increase the resulting error to be much larger.
                    const float MINVALUEERROR = 0.001f;

                    // the error can increase due to the stat-calculation. Assume a factor of 10 for now, values lower than 6 were too low.
                    const float CALCULATIONERRORFACTOR = 10f;

                    float toleranceForThisStat = highPrecisionInputs || statIOs[s].Input * (Utils.precision(s) == 3 ? 100 : 1) > 1e6
                            ? Math.Max(MINVALUEERROR, ((float)statIOs[s].Input).FloatPrecision() * CALCULATIONERRORFACTOR)
                            : ARKDISPLAYVALUEERROR * (Utils.precision(s) == 3 ? .01f : 1)
                        ;
                    //Console.WriteLine($"Precision stat {s}: {toleranceForThisStat}");

                    MinMaxDouble inputValue = new MinMaxDouble(statIOs[s].Input - toleranceForThisStat, statIOs[s].Input + toleranceForThisStat);
                    double statBaseValue = stats[s].BaseValue;
                    if (postTamed && s == (int)StatNames.Health) 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;
                    int maxLW;
                    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 && species.DisplaysStat(s) && 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 (StatValueCalculation.CalculateValue(species, s, ww, 0, true, lowerTEBound, 0, false) <= 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 && species.statImprintMult[s] != 0)
                        statImprintingMultiplierRange = imprintingMultiplierRanges[s].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 (stats[s].IncPerWildLevel == 0)
                        {
                            // check if the input value is valid
                            MinMaxDouble possibleStatValues = new MinMaxDouble(StatValueCalculation.CalculateValue(species, s, 0, 0, postTamed, lowerTEBound, imprintingBonusRange.Min, false),
                                StatValueCalculation.CalculateValue(species, s, 0, 0, postTamed, upperTEBound, imprintingBonusRange.Max, false));
                            if (inputValue.Overlaps(possibleStatValues))
                                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(Creature.CalculatePreTameWildLevel(levelPostTame, tamingEffectiveness.Max),
                                                                           Creature.CalculatePreTameWildLevel(levelPostTame, tamingEffectiveness.Min));

                                    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));
                            }
                        }
                    }
                }
                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;
                    }
                }
            }
        }
Ejemplo n.º 3
0
        private void setLocalizations(bool init = true)
        {
            if (init)
                initLocalization();

            // menu
            Loc.ControlText(fileToolStripMenuItem);
            Loc.ControlText(newToolStripMenuItem);
            Loc.ControlText(loadToolStripMenuItem);
            Loc.ControlText(loadAndAddToolStripMenuItem);
            Loc.ControlText(saveToolStripMenuItem);
            Loc.ControlText(saveAsToolStripMenuItem);
            Loc.ControlText(importingFromSavegameToolStripMenuItem);
            Loc.ControlText(importingFromSavegameEmptyToolStripMenuItem);
            //Loc.ControlText(runDefaultExtractionAndImportFileToolStripMenuItem);
            //Loc.ControlText(runDefaultExtractionToolStripMenuItem);
            //Loc.ControlText(importCreatedJsonfileToolStripMenuItem);
            Loc.ControlText(importExportedCreaturesToolStripMenuItem);
            //Loc.ControlText(runDefaultExtractionAndImportFileToolStripMenuItem);
            //Loc.ControlText(runDefaultExtractionToolStripMenuItem);
            //Loc.ControlText(importCreatedJsonfileToolStripMenuItem);
            Loc.ControlText(modValueManagerToolStripMenuItem);
            Loc.ControlText(settingsToolStripMenuItem);
            Loc.ControlText(openSettingsToolStripMenuItem);
            Loc.ControlText(quitToolStripMenuItem);
            Loc.ControlText(editToolStripMenuItem);
            Loc.ControlText(exportValuesToClipboardToolStripMenuItem);
            Loc.ControlText(importValuesFromClipboardToolStripMenuItem);
            Loc.ControlText(setStatusToolStripMenuItem);
            Loc.ControlText(multiSetterToolStripMenuItem);
            Loc.ControlText(deleteSelectedToolStripMenuItem);
            Loc.ControlText(findDuplicatesToolStripMenuItem);
            Loc.ControlText(copyCreatureToolStripMenuItem);
            Loc.ControlText(pasteCreatureToolStripMenuItem);
            Loc.ControlText(libraryFilterToolStripMenuItem);
            Loc.ControlText(helpToolStripMenuItem);
            Loc.ControlText(aboutToolStripMenuItem);
            Loc.ControlText(onlinehelpToolStripMenuItem);
            Loc.ControlText(BreedingPlanHelpToolStripMenuItem);
            Loc.ControlText(extractionIssuesToolStripMenuItem);
            Loc.ControlText(checkForUpdatedStatsToolStripMenuItem);
            Loc.ControlText(toolStripButtonCopy2Tester);
            Loc.ControlText(toolStripButtonCopy2Extractor);
            Loc.ControlText(toolStripButtonClear);
            Loc.ControlText(toolStripButtonAddNote);
            Loc.ControlText(toolStripButtonRemoveNote);
            Loc.ControlText(toolStripButtonDeleteExpiredIncubationTimers);
            Loc.ControlText(toolStripButtonSaveCreatureValuesTemp);
            Loc.ControlText(toolStripButtonDeleteTempCreature);
            Loc.ControlText(tsBtAddAsExtractionTest);
            Loc.ControlText(copyToMultiplierTesterToolStripButton);

            // top bar
            Loc.ControlText(cbGuessSpecies, _tt);
            Loc.ControlText(btReadValuesFromArk, _tt);
            Loc.ControlText(btImportLastExported, _tt);
            Loc.ControlText(cbToggleOverlay);

            // tester
            Loc.ControlText(tabPageStatTesting, "statTesting");
            Loc.ControlText(rbWildTester, "wild");
            Loc.ControlText(rbTamedTester, "tamed");
            Loc.ControlText(rbBredTester, "bred");
            Loc.ControlText(lbTesterWildLevel, "wildLvl");
            Loc.ControlText(lbTesterDomLevel, "domLvl");
            Loc.ControlText(lbCurrentValue, "currentValue");
            Loc.ControlText(lbBreedingValueTester, "breedingValue");
            Loc.ControlText(lbNotYetTamed);
            Loc.ControlText(gpPreviewEdit);
            Loc.ControlText(lbTestingInfo);
            Loc.ControlText(gbStatChart, "statChart");
            Loc.ControlText(lbCurrentCreature, "CurrentCreature");
            Loc.SetToolTip(lbImprintedCount, _tt);
            Loc.SetToolTip(lbTesterDomLevel, "domLevelExplanation", _tt);
            Loc.SetToolTip(lbTesterWildLevel, "wildLevelExplanation", _tt);

            // extractor
            Loc.ControlText(tabPageExtractor, "extractor");
            Loc.ControlText(lbCurrentStatEx, "currentStatValue");
            Loc.ControlText(lbExtractorWildLevel, "wildLvl");
            Loc.ControlText(lbExtractorDomLevel, "domLvl");
            Loc.ControlText(lbSum);
            Loc.ControlText(lbShouldBe);
            Loc.ControlText(lbImprintingFailInfo);
            Loc.ControlText(cbExactlyImprinting, _tt);
            Loc.ControlText(btExtractLevels);
            Loc.ControlText(cbQuickWildCheck, _tt);
            Loc.ControlText(rbWildExtractor, "wild");
            Loc.ControlText(rbTamedExtractor, "tamed");
            Loc.ControlText(rbBredExtractor, "bred");
            Loc.SetToolTip(lbImprintingCuddleCountExtractor, _tt);
            Loc.SetToolTip(lbSumWild, _tt);
            Loc.SetToolTip(lbSumDom, _tt);
            Loc.SetToolTip(lbSumDomSB, _tt);
            Loc.SetToolTip(lbListening, _tt);
            Loc.SetToolTip(lbExtractorDomLevel, "domLevelExplanation", _tt);
            Loc.SetToolTip(lbExtractorWildLevel, "wildLevelExplanation", _tt);
            var statNames = speciesSelector1.SelectedSpecies?.statNames;
            for (int si = 0; si < _statIOs.Count; si++)
            {
                _statIOs[si].Title = Utils.StatName(si, false, statNames);
                _testingIOs[si].Title = Utils.StatName(si, false, statNames);
            }

            // library
            Loc.ControlText(tabPageLibrary, "library");
            columnHeaderName.Text = Loc.S("Name");
            columnHeaderOwner.Text = Loc.S("Owner");
            columnHeaderTribe.Text = Loc.S("Tribe");
            columnHeaderNote.Text = Loc.S("Note");
            columnHeaderServer.Text = Loc.S("Server");
            columnHeaderHP.Text = Utils.StatName(StatNames.Health, true);
            columnHeaderSt.Text = Utils.StatName(StatNames.Stamina, true);
            columnHeaderOx.Text = Utils.StatName(StatNames.Oxygen, true);
            columnHeaderFo.Text = Utils.StatName(StatNames.Food, true);
            columnHeaderWe.Text = Utils.StatName(StatNames.Weight, true);
            columnHeaderDm.Text = Utils.StatName(StatNames.MeleeDamageMultiplier, true);
            columnHeaderSp.Text = Utils.StatName(StatNames.SpeedMultiplier, true);
            columnHeaderTo.Text = Utils.StatName(StatNames.Torpidity, true);
            columnHeaderWa.Text = Utils.StatName(StatNames.CraftingSpeedMultiplier, true);
            columnHeaderTemp.Text = Utils.StatName(StatNames.Temperature, true);
            columnHeaderCr.Text = Utils.StatName(StatNames.Water, true);
            columnHeaderFr.Text = Utils.StatName(StatNames.TemperatureFortitude, true);
            columnHeaderTopStatsNr.Text = Loc.S("Top");
            columnHeaderTopness.Text = Loc.S("topPercentage");
            columnHeaderGen.Text = Loc.S("Generation_Abb");
            columnHeaderLW.Text = Loc.S("LevelWild_Abb");
            columnHeaderMutations.Text = Loc.S("Mutations_Abb");
            columnHeaderAdded.Text = Loc.S("added");
            columnHeaderCooldown.Text = Loc.S("cooldownGrowing");
            columnHeaderColor0.Text = Loc.S("C0");
            columnHeaderColor1.Text = Loc.S("C1");
            columnHeaderColor2.Text = Loc.S("C2");
            columnHeaderColor3.Text = Loc.S("C3");
            columnHeaderColor4.Text = Loc.S("C4");
            columnHeaderColor5.Text = Loc.S("C5");

            // other tabs
            Loc.ControlText(tabPagePedigree, "pedigree");
            Loc.ControlText(tabPageTaming, "Taming");
            Loc.ControlText(tabPageBreedingPlan, "BreedingPlan");
            Loc.ControlText(tabPageRaising, "Raising");
            Loc.ControlText(tabPagePlayerTribes, "Player");

            // other controls
            creatureInfoInputTester.SetLocalizations();
            creatureInfoInputExtractor.SetLocalizations();
            pedigree1.SetLocalizations();
            tamingControl1.SetLocalizations();
            breedingPlan1.SetLocalizations();
        }
        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) * species.statImprintMult[(int)StatNames.Torpidity] * 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) * species.statImprintMult[(int)StatNames.Torpidity] * 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) * species.statImprintMult[(int)StatNames.Food] * 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) * species.statImprintMult[(int)StatNames.Food] * 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;
                double imprintingProductTorpor = species.statImprintMult[(int)StatNames.Torpidity] * imprintingBonusMultiplier;
                double imprintingProductFood = species.statImprintMult[(int)StatNames.Food] * imprintingBonusMultiplier;
                if (imprintingProductTorpor == 0 || imprintingProductFood == 0) break;
                MinMaxDouble imprintingBonusRange = new MinMaxDouble(
                    (((torpor - 0.05) / (1 + species.stats[(int)StatNames.Torpidity].MultAffinity) - species.stats[(int)StatNames.Torpidity].AddWhenTamed) / StatValueCalculation.CalculateValue(species, (int)StatNames.Torpidity, torporLevel, 0, false, 0, 0) - 1) / imprintingProductTorpor,
                    (((torpor + 0.05) / (1 + species.stats[(int)StatNames.Torpidity].MultAffinity) - species.stats[(int)StatNames.Torpidity].AddWhenTamed) / StatValueCalculation.CalculateValue(species, (int)StatNames.Torpidity, torporLevel, 0, false, 0, 0) - 1) / imprintingProductTorpor);

                // 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) / StatValueCalculation.CalculateValue(species, (int)StatNames.Food, foodLevel, 0, false, 0, 0) - 1) / imprintingProductFood,
                        (((food + 0.05) / (1 + species.stats[(int)StatNames.Food].MultAffinity) - species.stats[(int)StatNames.Food].AddWhenTamed) / StatValueCalculation.CalculateValue(species, (int)StatNames.Food, foodLevel, 0, false, 0, 0) - 1) / imprintingProductFood);


                    // 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 (StatValueCalculation.CalculateValue(species, (int)StatNames.Torpidity, torporLevel, 0, true, 1, intersectionIB.Min) <= torpor
                            && StatValueCalculation.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)
                    && StatValueCalculation.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();
        }