precision() public static method

public static precision ( int s ) : int
s int
return int
Example #1
0
        public static double CalculateValue(Species species, int stat, int levelWild, int levelDom, bool dom, double tamingEff, double imprintingBonus, bool roundToIngamePrecision = true)
        {
            if (species == null)
            {
                return(0);
            }

            // if stat is generally available but level is set to -1 (== unknown), return -1 (== unknown)
            if (levelWild < 0 && species.stats[stat].IncPerWildLevel != 0)
            {
                return(-1);
            }

            double add = 0, domMult = 1, imprintingM = 1, tamedBaseHP = 1;

            if (dom)
            {
                add = species.stats[stat].AddWhenTamed;
                double domMultAffinity = species.stats[stat].MultAffinity;
                // 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 (domMultAffinity >= 0)
                {
                    domMultAffinity *= tamingEff;
                }
                domMult = (tamingEff >= 0 ? (1 + domMultAffinity) : 1) * (1 + levelDom * species.stats[stat].IncPerTamedLevel);
                if (imprintingBonus > 0 &&
                    species.statImprintMult[stat] != 0
                    )
                {
                    imprintingM = 1 + species.statImprintMult[stat] * imprintingBonus * Values.V.currentServerMultipliers.BabyImprintingStatScaleMultiplier;
                }
                if (stat == 0)
                {
                    tamedBaseHP = (float)species.TamedBaseHealthMultiplier;
                }
            }
            //double result = Math.Round((species.stats[stat].BaseValue * tamedBaseHP * (1 + species.stats[stat].IncPerWildLevel * levelWild) * imprintingM + add) * domMult, Utils.precision(stat), MidpointRounding.AwayFromZero);
            // double is too precise and results in wrong values due to rounding. float results in better values, probably ARK uses float as well.
            // or rounding first to a precision of 7, then use the rounding of the precision
            //double resultt = Math.Round((species.stats[stat].BaseValue * tamedBaseHP * (1 + species.stats[stat].IncPerWildLevel * levelWild) * imprintingM + add) * domMult, 7);
            //resultt = Math.Round(resultt, Utils.precision(stat), MidpointRounding.AwayFromZero);

            // adding an epsilon to handle rounding-errors
            double result = (species.stats[stat].BaseValue * tamedBaseHP *
                             (1 + species.stats[stat].IncPerWildLevel * levelWild) * imprintingM + add) *
                            domMult + (Utils.precision(stat) == 3 ? ROUND_UP_DELTA * 0.01 : ROUND_UP_DELTA);

            if (result <= 0)
            {
                return(0);
            }

            if (roundToIngamePrecision)
            {
                return(Math.Round(result, Utils.precision(stat), MidpointRounding.AwayFromZero));
            }

            return(result);
        }
Example #2
0
        public static double calculateValue(Species species, int stat, int levelWild, int levelDom, bool dom, double tamingEff, double imprintingBonus)
        {
            // if stat is generally available but level is set to -1 (== unknown), return -1 (== unknown)
            if (levelWild < 0 && species != null && species.stats[stat].IncPerWildLevel != 0)
            {
                return(-1);
            }
            if (species != null)
            {
                double add = 0, domMult = 1, imprintingM = 1, tamedBaseHP = 1;
                if (dom)
                {
                    add = species.stats[stat].AddWhenTamed;
                    double domMultAffinity = species.stats[stat].MultAffinity;
                    // 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 (domMultAffinity >= 0)
                    {
                        domMultAffinity *= tamingEff;
                    }
                    domMult = (tamingEff >= 0 ? (1 + domMultAffinity) : 1) * (1 + levelDom * species.stats[stat].IncPerTamedLevel);
                    if (imprintingBonus > 0 && stat != (int)StatNames.Stamina && stat != (int)StatNames.Oxygen && (stat != (int)StatNames.SpeedMultiplier || species.NoImprintingForSpeed == false))
                    {
                        imprintingM = 1 + 0.2 * imprintingBonus * Values.V.imprintingStatScaleMultiplier;
                    }
                    if (stat == 0)
                    {
                        tamedBaseHP = (float)species.TamedBaseHealthMultiplier;
                    }
                }
                //double result = Math.Round((species.stats[stat].BaseValue * tamedBaseHP * (1 + species.stats[stat].IncPerWildLevel * levelWild) * imprintingM + add) * domMult, Utils.precision(stat), MidpointRounding.AwayFromZero);
                // double is too precise and results in wrong values due to rounding. float results in better values, probably ARK uses float as well.
                // or rounding first to a precision of 7, then use the rounding of the precision
                //double resultt = Math.Round((species.stats[stat].BaseValue * tamedBaseHP * (1 + species.stats[stat].IncPerWildLevel * levelWild) * imprintingM + add) * domMult, 7);
                //resultt = Math.Round(resultt, Utils.precision(stat), MidpointRounding.AwayFromZero);

                // adding an epsilon to handle rounding-errors
                double result = Math.Round((species.stats[stat].BaseValue * tamedBaseHP *
                                            (1 + species.stats[stat].IncPerWildLevel * levelWild) * imprintingM + add) *
                                           domMult + roundupDelta, Utils.precision(stat), MidpointRounding.AwayFromZero);

                return(result >= 0 ? result : 0);
            }
            return(0);
        }
        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;
                    }
                }
            }
        }
Example #4
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 #5
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, double imprintingBonusMultiplier, double cuddleIntervalMultiplier,
                                  bool considerWildLevelSteps, int wildLevelSteps, out bool imprintingChanged)
        {
            validResults           = true;
            imprintingChanged      = false;
            considerWildLevelSteps = considerWildLevelSteps && !bred;

            if (bred)
            {
                postTamed = true;
            }
            else if (autoDetectTamed && Values.V.species[speciesI].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(Values.V.species[speciesI].stats[7].BaseValue * (1 + Values.V.species[speciesI].stats[7].IncPerWildLevel * Math.Round((statIOs[7].Input - Values.V.species[speciesI].stats[7].BaseValue) / (Values.V.species[speciesI].stats[7].BaseValue * Values.V.species[speciesI].stats[7].IncPerWildLevel))), 3) != statIOs[7].Input);
            }
            else
            {
                postTamed = tamed;
            }

            imprintingBonus = 0;
            if (bred)
            {
                if (!adjustImprinting)
                {
                    imprintingBonus = imprintingBonusRounded;
                }
                else if (Values.V.species[speciesI].breeding != null && Values.V.species[speciesI].breeding.maturationTimeAdjusted > 0)
                {
                    imprintingBonus = Math.Round(Math.Round(imprintingBonusRounded * Values.V.species[speciesI].breeding.maturationTimeAdjusted / (14400 * cuddleIntervalMultiplier))
                                                 * 14400 * cuddleIntervalMultiplier / Values.V.species[speciesI].breeding.maturationTimeAdjusted, 5);
                    if (imprintingBonus > 1)
                    {
                        imprintingBonus = 1;
                    }
                    if (Math.Abs(imprintingBonusRounded - imprintingBonus) > 0.01)
                    {
                        imprintingChanged = true;
                    }
                }
            }
            double imprintingMultiplier = (1 + imprintingBonus * imprintingBonusMultiplier * .2);

            // needed to handle Torpor-bug
            this.justTamed = false; // Torpor-bug got fixed :)) leaving the code for a while

            // Torpor-bug: if bonus levels are added due to taming-effectiveness, torpor is too high
            // instead of giving only the TE-bonus, the original wild levels W are added a second time to the torporlevels
            // the game does this after taming: toLvl = (Math.Floor(W*TE/2) > 0 ? 2*W + Math.Min(W*TE/2) : W);
            // the game should do (and does after some while, maybe a server-restart): toLvl = W + Math.Min(W*TE/2);
            // max level for wild according to torpor (possible bug ingame: torpor is depending on taming effectiveness 5/3 - 2 times "too high" for level after taming until server-restart (not only the bonus levels are added, but also the existing levels again)
            double torporLevelTamingMultMax, torporLevelTamingMultMin;
            bool   runTorporRangeAgain;

            do
            {
                runTorporRangeAgain      = false;
                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 ? Values.V.species[speciesI].stats[7].AddWhenTamed : 0) - Values.V.species[speciesI].stats[7].BaseValue) * torporLevelTamingMultMin / (Values.V.species[speciesI].stats[7].BaseValue * Values.V.species[speciesI].stats[7].IncPerWildLevel), 0);
                levelWildFromTorporRange[1] = (int)Math.Round((statIOs[7].Input / imprintingMultiplier - (postTamed ? Values.V.species[speciesI].stats[7].AddWhenTamed : 0) - Values.V.species[speciesI].stats[7].BaseValue) * torporLevelTamingMultMax / (Values.V.species[speciesI].stats[7].BaseValue * Values.V.species[speciesI].stats[7].IncPerWildLevel), 0);

                // if level of torpor is higher than the total-level, the torporBug displayed a too high torpor. If the user didn't check the justTamed-checkbox, do it for them and recalculate the true torpor-level
                if (false && !runTorporRangeAgain && !justTamed && levelWildFromTorporRange[0] > level) // torpor bug got fixed, leaving the code for a while
                {
                    justTamed           = true;
                    this.justTamed      = true;
                    runTorporRangeAgain = true;
                }
                // if levelWildFromTorporRange[0] > level, then justTamed has to be true, then run the previous calculation again
            } while (runTorporRangeAgain);

            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 - (Values.V.speciesNames[speciesI] == "Plesiosaur" ? 34 : 0)); // creatures starts with level 1, Plesiosaur starts at level 35
                domFreeMax = Math.Max(0, level - levelWildFromTorporRange[0] - 1 - (Values.V.speciesNames[speciesI] == "Plesiosaur" ? 34 : 0)); // creatures starts with level 1, Plesiosaur starts at level 35
            }
            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 (Values.V.species[speciesI].stats[s].BaseValue > 0 && activeStats[s]) // if stat is used (oxygen sometimes is not)
                {
                    statIOs[s].postTame = postTamed;
                    double inputValue         = statIOs[s].Input;
                    double statBaseValueWild  = Values.V.species[speciesI].stats[s].BaseValue;
                    double statBaseValueTamed = statBaseValueWild * (s == 0 ? (double)Values.V.species[speciesI].TamedBaseHealthMultiplier : 1);

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

                    bool withTEff = (postTamed && Values.V.species[speciesI].stats[s].MultAffinity > 0);
                    if (withTEff)
                    {
                        statsWithEff.Add(s);
                    }
                    double maxLW = 0;
                    if (Values.V.species[speciesI].stats[s].BaseValue > 0 && Values.V.species[speciesI].stats[s].IncPerWildLevel > 0)
                    {
                        maxLW = Math.Round(((inputValue / (postTamed ? 1 + lowerTEBound * Values.V.species[speciesI].stats[s].MultAffinity : 1) - (postTamed ? Values.V.species[speciesI].stats[s].AddWhenTamed : 0)) / (postTamed ? statBaseValueTamed : statBaseValueWild) - 1) / Values.V.species[speciesI].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 && Values.V.species[speciesI].stats[s].BaseValue > 0 && Values.V.species[speciesI].stats[s].IncPerTamedLevel > 0)
                    {
                        maxLD = Math.Round((inputValue / ((statBaseValueTamed + Values.V.species[speciesI].stats[s].AddWhenTamed) * (1 + lowerTEBound * Values.V.species[speciesI].stats[s].MultAffinity)) - 1) / Values.V.species[speciesI].stats[s].IncPerTamedLevel); //floor is sometimes too unprecise
                    }
                    if (maxLD > domFreeMax)
                    {
                        maxLD = domFreeMax;
                    }

                    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 = (postTamed ? statBaseValueTamed : statBaseValueWild) * (1 + Values.V.species[speciesI].stats[s].IncPerWildLevel * w) * (s == 1 || s == 2 || (s == 6 && Values.V.species[speciesI].NoImprintingForSpeed == true) ? 1 : imprintingMultiplier) + (postTamed ? Values.V.species[speciesI].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 + Values.V.species[speciesI].stats[s].IncPerTamedLevel * d) - valueWODom) / (valueWODom * Values.V.species[speciesI].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 + Values.V.species[speciesI].stats[s].IncPerTamedLevel * d) - valueWODom) / (valueWODom * Values.V.species[speciesI].stats[s].MultAffinity), 4);
                                double tamingEffectivenessMin = Math.Round(((inputValue - (Utils.precision(s) == 3 ? 0.0006 : 0.06)) / (1 + Values.V.species[speciesI].stats[s].IncPerTamedLevel * d) - valueWODom) / (valueWODom * Values.V.species[speciesI].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
                                        double ttttt = trueTorporLevel(tamingEffectiveness);
                                        double ttt   = (trueTorporLevel(tamingEffectiveness) + 1) / (1 + tamingEffectiveness / 2);
                                        if (considerWildLevelSteps && s != 7 && tamingEffectiveness > 0)
                                        {
                                            int  preTameLevelMin = (int)((trueTorporLevel(tamingEffectiveness) + 1) / (1 + tamingEffectivenessMax / 2));
                                            int  preTameLevelMax = (int)Math.Ceiling((trueTorporLevel(tamingEffectiveness) + 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 * (1 + Values.V.species[speciesI].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 #6
0
 public double calculateValue(int speciesIndex, int stat, int levelWild, int levelDom, bool dom, double tamingEff)
 {
     if (speciesIndex > 0)
     {
         double add = 0, domMult = 1;
         if (dom)
         {
             add     = Stats.S.stats[speciesIndex][stat].AddWhenTamed;
             domMult = (tamingEff >= 0 ? (1 + tamingEff * Stats.S.stats[speciesIndex][stat].MultAffinity) : 1) * (1 + levelDom * Stats.S.stats[speciesIndex][stat].IncPerTamedLevel);
         }
         return(Math.Round((Stats.S.stats[speciesIndex][stat].BaseValue * (1 + Stats.S.stats[speciesIndex][stat].IncPerWildLevel * levelWild) + add) * domMult, Utils.precision(stat), MidpointRounding.AwayFromZero));
     }
     else
     {
         return(0);
     }
 }
Example #7
0
 public static double calculateValue(int speciesIndex, int stat, int levelWild, int levelDom, bool dom, double tamingEff, double imprintingBonus)
 {
     if (speciesIndex >= 0)
     {
         double add = 0, domMultAffinity = 0, domMult = 1, imprintingM = 1, tamedBaseHP = 1;
         if (dom)
         {
             add             = Values.V.species[speciesIndex].stats[stat].AddWhenTamed;
             domMultAffinity = Values.V.species[speciesIndex].stats[stat].MultAffinity;
             if (domMultAffinity >= 0)
             {
                 domMultAffinity *= tamingEff;
             }
             domMult = (tamingEff >= 0 ? (1 + domMultAffinity) : 1) * (1 + levelDom * Values.V.species[speciesIndex].stats[stat].IncPerTamedLevel);
             if (imprintingBonus > 0 && stat != 1 && stat != 2 && (stat != 6 || Values.V.species[speciesIndex].NoImprintingForSpeed == false))
             {
                 imprintingM = 1 + 0.2 * imprintingBonus * Values.V.imprintingStatScaleMultiplier;
             }
             if (stat == 0)
             {
                 tamedBaseHP = (float)Values.V.species[speciesIndex].TamedBaseHealthMultiplier;
             }
         }
         double result = Math.Round((Values.V.species[speciesIndex].stats[stat].BaseValue * tamedBaseHP * (1 + Values.V.species[speciesIndex].stats[stat].IncPerWildLevel * levelWild) * imprintingM + add) * domMult, Utils.precision(stat), MidpointRounding.AwayFromZero);
         return(result >= 0 ? result : 0);
     }
     else
     {
         return(0);
     }
 }
Example #8
0
        public void setCreature(Creature creature)
        {
            this.creature  = creature;
            groupBox1.Text = (!onlyLevels && creature.status != CreatureStatus.Available ? "(" + Utils.statusSymbol(creature.status) + ") " : "") + creature.name + " (" + creature.levelHatched + (totalLevelUnknown ? "+" : "") + ")";
            if (!onlyLevels && creature.status == CreatureStatus.Dead)
            {
                groupBox1.ForeColor = SystemColors.GrayText;
                tt.SetToolTip(groupBox1, "Creature has passed away");
            }
            else if (!onlyLevels && creature.status == CreatureStatus.Unavailable)
            {
                groupBox1.ForeColor = SystemColors.GrayText;
                tt.SetToolTip(groupBox1, "Creature is currently not available");
            }

            for (int s = 0; s < 7; s++)
            {
                if (creature.levelsWild[s] < 0)
                {
                    labels[s].Text      = "?";
                    labels[s].BackColor = Color.WhiteSmoke;
                    labels[s].ForeColor = Color.LightGray;
                }
                else
                {
                    labels[s].Text      = creature.levelsWild[s].ToString();
                    labels[s].BackColor = Utils.getColorFromPercent((int)(creature.levelsWild[s] * 2.5), (creature.topBreedingStats[s] ? 0.2 : 0.7));
                    labels[s].ForeColor = SystemColors.ControlText;
                    tt.SetToolTip(labels[s], Utils.statName(s) + ": " + (creature.valuesBreeding[s] * (Utils.precision(s) == 3 ? 100 : 1)).ToString() + (Utils.precision(s) == 3 ? "%" : ""));
                }
                labels[s].Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, (creature.topBreedingStats[s] ? System.Drawing.FontStyle.Bold : System.Drawing.FontStyle.Regular), System.Drawing.GraphicsUnit.Point, ((byte)(0)));
            }
            if (onlyLevels)
            {
                labelSex.Visible    = false;
                pictureBox1.Visible = false;
                plainTextcurrentValuesToolStripMenuItem.Visible = false;
                aRKChatcurrentValuesToolStripMenuItem.Visible   = false;
            }
            else
            {
                labelSex.Visible   = true;
                labelSex.Text      = Utils.sexSymbol(creature.gender);
                labelSex.BackColor = creature.neutered ? SystemColors.GrayText : Utils.sexColor(creature.gender);
                // creature Colors
                pictureBox1.Image   = CreatureColored.getColoredCreature(creature.colors, "", enabledColorRegions, 24, 22, true);
                labelSex.Visible    = true;
                pictureBox1.Visible = true;
                plainTextcurrentValuesToolStripMenuItem.Visible = true;
                aRKChatcurrentValuesToolStripMenuItem.Visible   = true;
            }
            labelMutations.BackColor = Color.FromArgb(225, 192, 255);
            labelMutations.Text      = creature.mutationCounter.ToString();
            labelMutations.Visible   = creature.mutationCounter > 0;
            contextMenuAvailable     = true;
        }
Example #9
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;
                    }
                }
            }
        }
Example #10
0
 public static double calculateValue(int speciesIndex, int stat, int levelWild, int levelDom, bool dom, double tamingEff, double imprintingBonus)
 {
     if (speciesIndex >= 0)
     {
         double add = 0, domMult = 1, imprintingM = 1;
         if (dom)
         {
             add     = Values.V.species[speciesIndex].stats[stat].AddWhenTamed;
             domMult = (tamingEff >= 0 ? (1 + tamingEff * Values.V.species[speciesIndex].stats[stat].MultAffinity) : 1) * (1 + levelDom * Values.V.species[speciesIndex].stats[stat].IncPerTamedLevel);
             if (stat != 1 && stat != 2)
             {
                 imprintingM = 1 + 0.2 * imprintingBonus * Values.V.imprintingMultiplier;
             }
         }
         return(Math.Round((Values.V.species[speciesIndex].stats[stat].BaseValue * (1 + Values.V.species[speciesIndex].stats[stat].IncPerWildLevel * levelWild) * imprintingM + add) * domMult, Utils.precision(stat), MidpointRounding.AwayFromZero));
     }
     else
     {
         return(0);
     }
 }
        /// <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;
                    }
                }
            }
        }
Example #12
0
        public void extractLevels(int speciesI, int level, List <StatIO> statIOs, double lowerTEBound, double upperTEBound, bool autoDetectTamed, bool tamed, bool justTamed, bool bred, double imprintingBonus, double imprintingBonusMultiplier)
        {
            validResults = true;
            if (autoDetectTamed)
            {
                // torpor is directly proportional to wild level. Check if creature is wild or tamed (doesn't work with Giganotosaurus because it has no additional bonus on torpor)
                postTamed = (Math.Round(Values.V.species[speciesI].stats[7].BaseValue * (1 + Values.V.species[speciesI].stats[7].IncPerWildLevel * Math.Round((statIOs[7].Input - Values.V.species[speciesI].stats[7].BaseValue) / (Values.V.species[speciesI].stats[7].BaseValue * Values.V.species[speciesI].stats[7].IncPerWildLevel))), 3) != statIOs[7].Input);
            }
            else
            {
                postTamed = tamed;
            }

            // needed to handle Torpor-bug
            this.justTamed = justTamed;

            imprintingBonusMin = 0; // imprintingBonus - .005; //TODO add handling of imprinting
            imprintingBonusMax = 0; // imprintingBonus + .005;

            // Torpor-bug: if bonus levels are added due to taming-effectiveness, torpor is too high
            // instead of giving only the TE-bonus, the original wild levels W are added a second time to the torporlevels
            // the game does this after taming: toLvl = (Math.Floor(W*TE/2) > 0 ? 2*W + Math.Min(W*TE/2) : W);
            // the game should do (and does after some while, maybe a server-restart): toLvl = W + Math.Min(W*TE/2);
            // max level for wild according to torpor (possible bug ingame: torpor is depending on taming effectiveness 5/3 - 2 times "too high" for level after taming until server-restart (not only the bonus levels are added, but also the existing levels again)
            double torporLevelTamingMultMax, torporLevelTamingMultMin;
            bool   runTorporRangeAgain;

            do
            {
                runTorporRangeAgain      = false;
                torporLevelTamingMultMax = 1;
                torporLevelTamingMultMin = 1;
                if (postTamed && justTamed)
                {
                    torporLevelTamingMultMax = (2 + upperTEBound) / (4 + upperTEBound);
                    torporLevelTamingMultMin = (2 + lowerTEBound) / (4 + lowerTEBound);
                }
                levelWildFromTorporRange[0] = (int)Math.Round((statIOs[7].Input - (postTamed ? Values.V.species[speciesI].stats[7].AddWhenTamed : 0) - Values.V.species[speciesI].stats[7].BaseValue) * torporLevelTamingMultMin / (Values.V.species[speciesI].stats[7].BaseValue * Values.V.species[speciesI].stats[7].IncPerWildLevel), 0);
                levelWildFromTorporRange[1] = (int)Math.Round((statIOs[7].Input - (postTamed ? Values.V.species[speciesI].stats[7].AddWhenTamed : 0) - Values.V.species[speciesI].stats[7].BaseValue) * torporLevelTamingMultMax / (Values.V.species[speciesI].stats[7].BaseValue * Values.V.species[speciesI].stats[7].IncPerWildLevel), 0);
                if (!runTorporRangeAgain && !justTamed && levelWildFromTorporRange[0] > level)
                {
                    justTamed           = true;
                    this.justTamed      = true;
                    runTorporRangeAgain = true;
                }
            } while (runTorporRangeAgain);
            // if levelWildFromTorporRange[0] > level, then justTamed has to be true, then run the previous calculation again

            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 - (Values.V.speciesNames[speciesI] == "Plesiosaur" ? 34 : 0)); // creatures starts with level 1, Plesiosaur starts at level 35
                domFreeMax = Math.Max(0, level - levelWildFromTorporRange[0] - 1 - (Values.V.speciesNames[speciesI] == "Plesiosaur" ? 34 : 0)); // creatures starts with level 1, Plesiosaur starts at level 35
            }
            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 = 0; s < 8; s++)
            {
                if (Values.V.species[speciesI].stats[s].BaseValue > 0) // if stat is used (oxygen sometimes is not)
                {
                    statIOs[s].postTame = postTamed;
                    double inputValue          = statIOs[s].Input;
                    double tamingEffectiveness = -1;
                    double valueWODom          = 0; // value without domesticated levels

                    bool withTEff = (postTamed && Values.V.species[speciesI].stats[s].MultAffinity > 0);
                    if (withTEff)
                    {
                        statsWithEff.Add(s);
                    }
                    double maxLW = 0;
                    if (Values.V.species[speciesI].stats[s].BaseValue > 0 && Values.V.species[speciesI].stats[s].IncPerWildLevel > 0)
                    {
                        maxLW = Math.Round(((inputValue / (postTamed ? 1 + lowerTEBound * Values.V.species[speciesI].stats[s].MultAffinity : 1) - (postTamed ? Values.V.species[speciesI].stats[s].AddWhenTamed : 0)) / Values.V.species[speciesI].stats[s].BaseValue - 1) / Values.V.species[speciesI].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 && Values.V.species[speciesI].stats[s].BaseValue > 0 && Values.V.species[speciesI].stats[s].IncPerTamedLevel > 0)
                    {
                        maxLD = Math.Round((inputValue / ((Values.V.species[speciesI].stats[s].BaseValue + Values.V.species[speciesI].stats[s].AddWhenTamed) * (1 + lowerTEBound * Values.V.species[speciesI].stats[s].MultAffinity)) - 1) / Values.V.species[speciesI].stats[s].IncPerTamedLevel); //floor is sometimes too unprecise
                    }
                    if (maxLD > domFreeMax)
                    {
                        maxLD = domFreeMax;
                    }

                    for (int w = 0; w < maxLW + 1; w++)
                    {
                        valueWODom = Values.V.species[speciesI].stats[s].BaseValue * (1 + Values.V.species[speciesI].stats[s].IncPerWildLevel * w) * (1 + imprintingBonusMin * imprintingBonusMultiplier * .2) + (postTamed ? Values.V.species[speciesI].stats[s].AddWhenTamed : 0);
                        for (int d = 0; d < maxLD + 1; d++)
                        {
                            if (withTEff)
                            {
                                // taming bonus is dependant on taming-effectiveness
                                // get tamingEffectiveness-possibility
                                // rounding errors need to increase error-range
                                tamingEffectiveness = Math.Round((inputValue / (1 + Values.V.species[speciesI].stats[s].IncPerTamedLevel * d) - valueWODom) / (valueWODom * Values.V.species[speciesI].stats[s].MultAffinity), 3, MidpointRounding.AwayFromZero);
                                if (tamingEffectiveness < 1.005 && tamingEffectiveness > 1)
                                {
                                    tamingEffectiveness = 1;
                                }
                                if (tamingEffectiveness > lowerTEBound - 0.008)
                                {
                                    if (tamingEffectiveness <= upperTEBound)
                                    {
                                        results[s].Add(new StatResult(w, d, tamingEffectiveness));
                                    }
                                    else
                                    {
                                        continue;
                                    }
                                }
                                else
                                {
                                    // if tamingEff < lowerBound: break, in this loop it's getting only smaller
                                    break;
                                }
                            }
                            else if (Math.Abs((valueWODom * (1 + Values.V.species[speciesI].stats[s].IncPerTamedLevel * d) - inputValue) * (Utils.precision(s) == 3 ? 100 : 1)) < 0.2)
                            {
                                results[s].Add(new StatResult(w, d));
                                break; // no other solution possible
                            }
                        }
                    }
                }
                else
                {
                    results[s].Add(new StatResult(0, 0));
                }
            }
        }