Beispiel #1
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++)
                {
                    double statImprintingMultiplier = species.StatImprintMultipliers[s];
                    imprintingMultiplierRanges[s] = statImprintingMultiplier != 0
                        ? new MinMaxDouble(1 + imprintingBonusRange.Min * imprintingBonusMultiplier * statImprintingMultiplier,
                                           1 + imprintingBonusRange.Max * imprintingBonusMultiplier * statImprintingMultiplier)
                        : 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
                    float toleranceForThisStat = StatValueCalculation.DisplayedAberration(statIOs[s].Input, Utils.Precision(s), highPrecisionInputs);
                    //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.StatImprintMultipliers[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;
                    }
                }
            }
        }
        public void Calculate(Species species, int[] wildLevels1, int[] wildLevels2)
        {
            var    levelProbabilities = new Dictionary <int, double>();
            double maxProbability     = 0;

            if (wildLevels1 == null || wildLevels2 == null || wildLevels1.Length != Values.STATS_COUNT || wildLevels2.Length != Values.STATS_COUNT)
            {
                Clear(true);
                return;
            }

            List <int> usedStatIndicesTest = new List <int>(Values.STATS_COUNT);

            for (int s = 0; s < Values.STATS_COUNT; s++)
            {
                if (species.UsesStat(s) && s != (int)StatNames.Torpidity)
                {
                    usedStatIndicesTest.Add(s);
                }
            }
            int usedStatsCount = usedStatIndicesTest.Count;

            List <int> usedStatIndices = new List <int>(usedStatsCount);
            // first check for equal levels, these can be skipped in the all-combinations loop
            int minimumLevel = 1; // includes the base level and all levels that are equal in both parents

            for (int s = 0; s < usedStatsCount; s++)
            {
                if (wildLevels1[usedStatIndicesTest[s]] == wildLevels2[usedStatIndicesTest[s]])
                {
                    minimumLevel += wildLevels1[usedStatIndicesTest[s]];
                }
                else
                {
                    usedStatIndices.Add(usedStatIndicesTest[s]);
                }
            }
            usedStatsCount = usedStatIndices.Count;
            int totalLevelCombinations = 1 << usedStatsCount;


            // loop through all combinations the offspring can inherit stat-levels
            // each used stat multiplies the combinations by two
            for (int p = 0; p < totalLevelCombinations; p++)
            {
                int    totalLevel  = minimumLevel;
                double probability = 1;
                for (int s = 0; s < usedStatsCount; s++)
                {
                    // determine if stat-level of creature one or two should be used
                    if ((p & (1 << s)) != 0)
                    {
                        // use the stat level of creature 1
                        totalLevel  += wildLevels1[usedStatIndices[s]];
                        probability *= wildLevels1[usedStatIndices[s]] > wildLevels2[usedStatIndices[s]] ? BreedingPlan.ProbabilityHigherLevel : BreedingPlan.ProbabilityLowerLevel;
                    }
                    else
                    {
                        // use the stat level of creature 2
                        totalLevel  += wildLevels2[usedStatIndices[s]];
                        probability *= wildLevels1[usedStatIndices[s]] < wildLevels2[usedStatIndices[s]] ? BreedingPlan.ProbabilityHigherLevel : BreedingPlan.ProbabilityLowerLevel;
                    }
                }
                if (!levelProbabilities.ContainsKey(totalLevel))
                {
                    levelProbabilities[totalLevel] = 0;
                }
                levelProbabilities[totalLevel] += probability;

                if (levelProbabilities[totalLevel] > maxProbability)
                {
                    maxProbability = levelProbabilities[totalLevel];
                }
            }
            DrawBars(levelProbabilities, maxProbability);
        }
Beispiel #3
0
        private List <MinMaxDouble> CalculateImprintingBonus(Species species, double imprintingBonusRounded, double imprintingBonusMultiplier, double cuddleIntervalMultiplier, double torpor, double food)
        {
            List <MinMaxDouble> imprintingBonusList = new List <MinMaxDouble>();

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

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

            double[] statImprintMultipliers = species.StatImprintMultipliers;

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

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

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

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

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


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

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

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

            // sort IB according to the support they got by other stats, then return the distinct means of the possible ranges.
            return(imprintingBonusList.OrderByDescending(i => otherStatsSupportIB[imprintingBonusList.IndexOf(i)]).ToList());
        }
Beispiel #4
0
        /// <summary>
        /// Import exported file. Used by a fileWatcher.
        /// </summary>
        /// <param name="filePath"></param>
        private void ImportExportedAddIfPossible(string filePath)
        {
            var loadResult = ExtractExportedFileInExtractor(filePath);

            if (!loadResult.HasValue)
            {
                return;
            }

            bool alreadyExists    = loadResult.Value;
            bool addedToLibrary   = false;
            bool uniqueExtraction = _extractor.UniqueResults ||
                                    (alreadyExists && _extractor.ValidResults);
            bool copyNameToClipboard = Properties.Settings.Default.copyNameToClipboardOnImportWhenAutoNameApplied &&
                                       (Properties.Settings.Default.applyNamePatternOnAutoImportAlways ||
                                        Properties.Settings.Default.applyNamePatternOnImportIfEmptyName ||
                                        (!alreadyExists && Properties.Settings.Default.applyNamePatternOnAutoImportForNewCreatures)
                                       );
            Species  species  = speciesSelector1.SelectedSpecies;
            Creature creature = null;

            if (uniqueExtraction &&
                Properties.Settings.Default.OnAutoImportAddToLibrary)
            {
                creature = AddCreatureToCollection(true, goToLibraryTab: Properties.Settings.Default.AutoImportGotoLibraryAfterSuccess);
                SetMessageLabelText($"Successful {(alreadyExists ? "updated" : "added")} {creature.name} ({species.name}) of the exported file\n" + filePath, MessageBoxIcon.Information, filePath);
                addedToLibrary = true;
            }

            bool topLevels    = false;
            bool newTopLevels = false;

            // give feedback in overlay
            string    infoText;
            Color     textColor;
            const int colorSaturation = 200;

            if (uniqueExtraction)
            {
                var sb = new StringBuilder();
                sb.AppendLine($"{species.name} \"{creatureInfoInputExtractor.CreatureName}\" {(alreadyExists ? "updated in " : "added to")} the library.");
                if (addedToLibrary && copyNameToClipboard)
                {
                    sb.AppendLine("Name copied to clipboard.");
                }

                for (int s = 0; s < values.Values.STATS_COUNT; s++)
                {
                    int statIndex = values.Values.statsDisplayOrder[s];
                    if (!species.UsesStat(statIndex))
                    {
                        continue;
                    }

                    sb.Append($"{Utils.StatName(statIndex, true, species.statNames)}: { _statIOs[statIndex].LevelWild} ({_statIOs[statIndex].BreedingValue})");
                    if (_statIOs[statIndex].TopLevel.HasFlag(LevelStatus.NewTopLevel))
                    {
                        sb.Append($" {Loc.S("newTopLevel")}");
                        newTopLevels = true;
                    }
                    else if (_statIOs[statIndex].TopLevel.HasFlag(LevelStatus.TopLevel))
                    {
                        sb.Append($" {Loc.S("topLevel")}");
                        topLevels = true;
                    }
                    sb.AppendLine();
                }

                infoText  = sb.ToString();
                textColor = Color.FromArgb(colorSaturation, 255, colorSaturation);
            }
            else
            {
                infoText  = $"Creature \"{creatureInfoInputExtractor.CreatureName}\" couldn't be extracted uniquely, manual level selection is necessary.";
                textColor = Color.FromArgb(255, colorSaturation, colorSaturation);
            }

            if (_overlay != null)
            {
                _overlay.SetInfoText(infoText, textColor);
                if (Properties.Settings.Default.DisplayInheritanceInOverlay && creature != null)
                {
                    _overlay.SetInheritanceCreatures(creature, creature.Mother, creature.Father);
                }
            }

            if (addedToLibrary)
            {
                if (Properties.Settings.Default.DeleteAutoImportedFile)
                {
                    FileService.TryDeleteFile(filePath);
                }
                else if (Properties.Settings.Default.MoveAutoImportedFileToSubFolder || Properties.Settings.Default.AutoImportedExportFileRename)
                {
                    string newPath = Properties.Settings.Default.MoveAutoImportedFileToSubFolder
                        ? (string.IsNullOrEmpty(Properties.Settings.Default.ImportExportedArchiveFolder)
                            ? Path.Combine(Path.GetDirectoryName(filePath), "imported")
                            : Properties.Settings.Default.ImportExportedArchiveFolder)
                        : Path.GetDirectoryName(filePath);

                    if (Properties.Settings.Default.MoveAutoImportedFileToSubFolder &&
                        !FileService.TryCreateDirectory(newPath, out string errorMessage))
                    {
                        MessageBoxes.ShowMessageBox($"Subfolder\n{newPath}\ncould not be created.\n{errorMessage}");
                        return;
                    }

                    string namePattern = Properties.Settings.Default.AutoImportedExportFileRenamePattern;

                    string newFileName = Properties.Settings.Default.AutoImportedExportFileRename && !string.IsNullOrWhiteSpace(namePattern)
                        ? NamePattern.GenerateCreatureName(creature,
                                                           _creatureCollection.creatures.Where(c => c.Species == speciesSelector1.SelectedSpecies).ToArray(), null, null,
                                                           _customReplacingNamingPattern, false, -1, false, namePattern)
                        : Path.GetFileName(filePath);

                    // remove invalid characters
                    var invalidCharacters = Path.GetInvalidFileNameChars();
                    foreach (var invalidChar in invalidCharacters)
                    {
                        newFileName = newFileName.Replace(invalidChar, '_');
                    }

                    string newFileNameWithoutExtension = Path.GetFileNameWithoutExtension(newFileName);
                    string newFileNameExtension        = Path.GetExtension(newFileName);
                    string newFilePath = Path.Combine(newPath, newFileName);
                    int    fileSuffix  = 1;
                    while (File.Exists(newFilePath))
                    {
                        newFilePath = Path.Combine(newPath, $"{newFileNameWithoutExtension}_{++fileSuffix}{newFileNameExtension}");
                    }

                    if (FileService.TryMoveFile(filePath, newFilePath))
                    {
                        _librarySelectionInfoClickPath = newFilePath;
                    }
                }
            }
            else if (!uniqueExtraction && copyNameToClipboard)
            {
                // extraction failed, user might expect the name of the new creature in the clipboard
                Clipboard.SetText("Automatic extraction was not possible");
            }

            if (Properties.Settings.Default.PlaySoundOnAutoImport)
            {
                if (uniqueExtraction)
                {
                    if (alreadyExists)
                    {
                        SoundFeedback.BeepSignal(SoundFeedback.FeedbackSounds.Indifferent);
                    }
                    if (newTopLevels)
                    {
                        SoundFeedback.BeepSignal(SoundFeedback.FeedbackSounds.Great);
                    }
                    else if (topLevels)
                    {
                        SoundFeedback.BeepSignal(SoundFeedback.FeedbackSounds.Good);
                    }
                    else
                    {
                        SoundFeedback.BeepSignal(SoundFeedback.FeedbackSounds.Success);
                    }
                }
                else
                {
                    SoundFeedback.BeepSignal(SoundFeedback.FeedbackSounds.Failure);
                }
            }
        }
        /// <summary>
        /// Loads the given creature collection file.
        /// </summary>
        /// <param name="filePath">File that contains the collection</param>
        /// <param name="keepCurrentCreatures">add the creatures of the loaded file to the current ones</param>
        /// <param name="keepCurrentSelections">don't change the species selection or tab</param>
        /// <returns></returns>
        private bool LoadCollectionFile(string filePath, bool keepCurrentCreatures = false, bool keepCurrentSelections = false)
        {
            Species selectedSpecies        = speciesSelector1.SelectedSpecies;
            Species selectedlibrarySpecies = listBoxSpeciesLib.SelectedItem as Species;

            if (!File.Exists(filePath))
            {
                MessageBox.Show($"Save file with name \"{filePath}\" does not exist!", "File not found", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return(false);
            }

            List <Creature> oldCreatures = null;

            if (keepCurrentCreatures)
            {
                oldCreatures = creatureCollection.creatures;
            }

            // for the case the collectionfile has no multipliers, keep the current ones
            ServerMultipliers oldMultipliers = creatureCollection.serverMultipliers;

            // Wait until the file is readable
            const int numberOfRetries = 5;
            const int delayOnRetry    = 1000;

            FileStream fileStream = null;

            for (int i = 1; i <= numberOfRetries; ++i)
            {
                try
                {
                    if (Path.GetExtension(filePath).ToLower() == ".xml")
                    {
                        using (fileStream = File.OpenRead(filePath))
                        {
                            // use xml-serializer for old library-format
                            XmlSerializer reader = new XmlSerializer(typeof(oldLibraryFormat.CreatureCollectionOld));
                            var           creatureCollectionOld = (oldLibraryFormat.CreatureCollectionOld)reader.Deserialize(fileStream);

                            List <Mod> mods = null;
                            // first check if additional values are used, and if the according values-file is already available.
                            // if not, abort conversion and first make sure the file is available, e.g. downloaded
                            if (!string.IsNullOrEmpty(creatureCollectionOld.additionalValues))
                            {
                                // usually the old filename is equal to the mod-tag
                                bool   modFound = false;
                                string modTag   = Path.GetFileNameWithoutExtension(creatureCollectionOld.additionalValues).Replace(" ", "").ToLower().Replace("gaiamod", "gaia");
                                foreach (KeyValuePair <string, ModInfo> tmi in Values.V.modsManifest.modsByTag)
                                {
                                    if (tmi.Key.ToLower() == modTag)
                                    {
                                        modFound = true;

                                        MessageBox.Show("The library contains creatures of modded species. For a correct file-conversion the correct mod-values file is needed.\n\n"
                                                        + "If the mod-value file is not loaded, the conversion may assign wrong species to your creatures.\n"
                                                        + "If the mod-value file is not available locally, it will be tried to download it.",
                                                        "Mod values needed", MessageBoxButtons.OK, MessageBoxIcon.Information);

                                        if (Values.V.loadedModsHash != CreatureCollection.CalculateModListHash(new List <Mod>()))
                                        {
                                            LoadStatAndKibbleValues(false); // reset values to default
                                        }
                                        LoadModValueFiles(new List <string> {
                                            tmi.Value.mod.FileName
                                        }, true, true, out mods);
                                        break;
                                    }
                                }
                                if (!modFound &&
                                    MessageBox.Show("The additional-values file in the library you're loading is unknown. You should first get a values-file in the new format for that mod.\n"
                                                    + "If you're loading the library the conversion of some modded species to the new format may fail and the according creatures have to be imported again later.\n\n"
                                                    + $"File:\n{filePath}\n"
                                                    + $"unknown mod-file: {modTag}\n\n"
                                                    + "Do you want to load the library and risk losing creatures?", "Unknown mod-file",
                                                    MessageBoxButtons.YesNo, MessageBoxIcon.Warning) != DialogResult.Yes)
                                {
                                    return(false);
                                }
                            }

                            creatureCollection         = oldLibraryFormat.FormatConverter.ConvertXml2Asb(creatureCollectionOld, filePath);
                            creatureCollection.ModList = mods;

                            if (creatureCollection == null)
                            {
                                throw new Exception("Conversion failed");
                            }

                            string fileNameWOExt = Path.Combine(Path.GetDirectoryName(filePath), Path.GetFileNameWithoutExtension(filePath));
                            // check if new fileName is not yet existing
                            filePath = fileNameWOExt + COLLECTION_FILE_EXTENSION;
                            if (File.Exists(filePath))
                            {
                                int fi = 2;
                                while (File.Exists(fileNameWOExt + "_" + fi + COLLECTION_FILE_EXTENSION))
                                {
                                    fi++;
                                }
                                filePath = fileNameWOExt + "_" + fi + COLLECTION_FILE_EXTENSION;
                            }

                            // save converted library
                            SaveCollectionToFileName(filePath);
                        }
                    }
                    else
                    {
                        CreatureCollection tmpCC;
                        using (StreamReader file = File.OpenText(filePath))
                        {
                            JsonSerializer serializer = new JsonSerializer();
                            tmpCC = (CreatureCollection)serializer.Deserialize(file, typeof(CreatureCollection));
                        }
                        if (!Version.TryParse(tmpCC.FormatVersion, out Version ccVersion) ||
                            !Version.TryParse(CreatureCollection.CURRENT_FORMAT_VERSION, out Version currentVersion) ||
                            ccVersion > currentVersion)
                        {
                            throw new FormatException("Unhandled format version");
                        }
                        creatureCollection = tmpCC;
                    }

                    break;
                }
                catch (IOException)
                {
                    // if file is not readable
                    Thread.Sleep(delayOnRetry);
                }
                catch (FormatException)
                {
                    // This FormatVersion is not understood, abort
                    MessageBox.Show($"This library format is unsupported in this version of ARK Smart Breeding." +
                                    "\n\nTry updating to a newer version.",
                                    "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return(false);
                }
                catch (InvalidOperationException e)
                {
                    MessageBox.Show($"The library-file\n{filePath}\ncouldn\'t be opened, we thought you should know.\nErrormessage:\n\n{e.Message}" + (e.InnerException == null ? string.Empty : $"\n\nInnerException:\n\n{e.InnerException.Message}"),
                                    "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return(false);
                }
                finally
                {
                    fileStream?.Close();
                }
            }

            if (creatureCollection.ModValueReloadNeeded)
            {
                // load original multipliers if they were changed
                if (!LoadStatAndKibbleValues(false).statValuesLoaded)
                {
                    creatureCollection = new CreatureCollection();
                    return(false);
                }
            }
            if (creatureCollection.ModValueReloadNeeded &&
                !LoadModValuesOfCollection(creatureCollection, false, false))
            {
                creatureCollection = new CreatureCollection();
                return(false);
            }

            if (creatureCollection.serverMultipliers == null)
            {
                creatureCollection.serverMultipliers = oldMultipliers ?? Values.V.serverMultipliersPresets.GetPreset(ServerMultipliersPresets.OFFICIAL);
            }

            if (speciesSelector1.LastSpecies != null && speciesSelector1.LastSpecies.Length > 0)
            {
                tamingControl1.SetSpecies(Values.V.SpeciesByBlueprint(speciesSelector1.LastSpecies[0]));
            }

            creatureCollection.FormatVersion = CreatureCollection.CURRENT_FORMAT_VERSION;

            ApplySettingsToValues();

            bool creatureWasAdded = false;

            if (keepCurrentCreatures)
            {
                creatureWasAdded = creatureCollection.MergeCreatureList(oldCreatures);
            }
            else
            {
                currentFileName = filePath;
                fileSync.ChangeFile(currentFileName);
                creatureBoxListView.Clear();
            }

            creatureCollection.DeletedCreatureGuids = null; // no longer needed

            InitializeCollection();

            filterListAllowed = false;
            SetLibraryFilter("Dead", creatureCollection.showFlags.HasFlag(CreatureFlags.Dead));
            SetLibraryFilter("Unavailable", creatureCollection.showFlags.HasFlag(CreatureFlags.Unavailable));
            SetLibraryFilter("Neutered", creatureCollection.showFlags.HasFlag(CreatureFlags.Neutered));
            SetLibraryFilter("Obelisk", creatureCollection.showFlags.HasFlag(CreatureFlags.Obelisk));
            SetLibraryFilter("Cryopod", creatureCollection.showFlags.HasFlag(CreatureFlags.Cryopod));
            SetLibraryFilter("Mutated", creatureCollection.showFlags.HasFlag(CreatureFlags.Mutated));
            checkBoxUseFiltersInTopStatCalculation.Checked = creatureCollection.useFiltersInTopStatCalculation;

            SetCollectionChanged(creatureWasAdded); // setCollectionChanged only if there really were creatures added from the old library to the just opened one

            ///// creatures loaded.

            // calculate creature values
            RecalculateAllCreaturesValues();

            if (!keepCurrentSelections && creatureCollection.creatures.Count > 0)
            {
                tabControlMain.SelectedTab = tabPageLibrary;
            }

            creatureBoxListView.maxDomLevel = creatureCollection.maxDomLevel;

            UpdateCreatureListings();

            // set global species that was set before loading
            if (selectedSpecies != null &&
                creatureCollection.creatures.Any(c => c.Species != null && c.Species.Equals(selectedSpecies))
                )
            {
                speciesSelector1.SetSpecies(selectedSpecies);
            }
            else if (creatureCollection.creatures.Any())
            {
                speciesSelector1.SetSpecies(creatureCollection.creatures[0].Species);
            }

            // set library species to what it was before loading
            if (selectedlibrarySpecies == null ||
                !creatureCollection.creatures.Any(c => c.Species != null && c.Species.Equals(selectedlibrarySpecies))
                )
            {
                selectedlibrarySpecies = speciesSelector1.SelectedSpecies;
            }
            if (selectedlibrarySpecies != null)
            {
                listBoxSpeciesLib.SelectedIndex = listBoxSpeciesLib.Items.IndexOf(selectedlibrarySpecies);
            }

            filterListAllowed = true;
            FilterLib();

            // apply last sorting
            listViewLibrary.Sort();

            UpdateTempCreatureDropDown();

            Properties.Settings.Default.LastSaveFile = filePath;
            lastAutoSaveBackup = DateTime.Now.AddMinutes(-10);

            return(true);
        }
Beispiel #6
0
        public bool loadAdditionalValues(string filename, bool showResults)
        {
            if (!TryLoadValuesFile(filename, setModFileName: true, out Values modifiedValues))
            {
                return(false);
            }

            _V.modValuesFile = Path.GetFileName(filename);
            int speciesUpdated = 0;
            int speciesAdded   = 0;

            // update data if existing
            // version
            try
            {
                _V.modVersion = new Version(modifiedValues.ver);
            }
            catch
            {
                _V.modVersion = new Version(0, 0);
            }

            // species
            if (modifiedValues.species != null)
            {
                foreach (Species sp in modifiedValues.species)
                {
                    if (string.IsNullOrWhiteSpace(sp.blueprintPath))
                    {
                        continue;
                    }

                    Species originalSpecies = speciesByBlueprint(sp.blueprintPath);
                    if (originalSpecies == null)
                    {
                        _V.species.Add(sp);
                        sp.Initialize();
                        sp.mod = modifiedValues.mod;
                        speciesAdded++;
                    }
                    else
                    {
                        // species already exists, update all values which are not null
                        bool updated = false;
                        if (sp.TamedBaseHealthMultiplier != null)
                        {
                            originalSpecies.TamedBaseHealthMultiplier = sp.TamedBaseHealthMultiplier;
                            updated = true;
                        }
                        if (sp.NoImprintingForSpeed != null)
                        {
                            originalSpecies.NoImprintingForSpeed = sp.NoImprintingForSpeed;
                            updated = true;
                        }
                        if (sp.fullStatsRaw != null && sp.fullStatsRaw.Length > 0)
                        {
                            for (int s = 0; s < statsCount && s < sp.fullStatsRaw.Length; s++)
                            {
                                if (sp.fullStatsRaw[s] == null)
                                {
                                    continue;
                                }
                                for (int si = 0; si < 5 && si < sp.fullStatsRaw[s].Length; si++)
                                {
                                    if (sp.fullStatsRaw[s][si] == null)
                                    {
                                        continue;
                                    }
                                    originalSpecies.fullStatsRaw[s][si] = sp.fullStatsRaw[s][si];
                                    updated = true;
                                }
                            }
                        }
                        if (!string.IsNullOrEmpty(sp.blueprintPath))
                        {
                            originalSpecies.blueprintPath = sp.blueprintPath;
                            updated = true;
                        }
                        if (updated)
                        {
                            speciesUpdated++;
                        }
                    }
                }

                // sort new species
                OrderSpecies();
            }
            // fooddata TODO
            // default-multiplier TODO

            _V.loadAliases();
            _V.updateSpeciesBlueprints();

            if (showResults)
            {
                MessageBox.Show($"Species with changed stats: {speciesUpdated}\nSpecies added: {speciesAdded}",
                                "Additional Values succesfully added", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }

            return(true);
        }
Beispiel #7
0
        /// <summary>
        /// Loads the given creature collection file.
        /// </summary>
        /// <param name="filePath">File that contains the collection</param>
        /// <param name="keepCurrentCreatures">add the creatures of the loaded file to the current ones</param>
        /// <param name="keepCurrentSelections">don't change the species selection or tab, use if a synchronized library is loaded</param>
        /// <returns></returns>
        private bool LoadCollectionFile(string filePath, bool keepCurrentCreatures = false, bool keepCurrentSelections = false)
        {
            Species selectedSpecies        = speciesSelector1.SelectedSpecies;
            Species selectedLibrarySpecies = listBoxSpeciesLib.SelectedItem as Species;

            if (string.IsNullOrEmpty(filePath) || !File.Exists(filePath))
            {
                MessageBox.Show($"Save file with name \"{filePath}\" does not exist!", $"File not found - {Utils.ApplicationNameVersion}", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return(false);
            }

            CreatureCollection previouslyLoadedCreatureCollection = _creatureCollection;

            // Wait until the file is readable
            const int numberOfRetries = 5;
            const int delayOnRetry    = 1000;

            FileStream fileStream = null;

            for (int i = 1; i <= numberOfRetries; ++i)
            {
                // sometimes a synchronized file has only 0 bytes, i.e. it's not yet synchronized fully. In this case wait a bit and try again
                if (Properties.Settings.Default.syncCollection && new FileInfo(filePath).Length == 0)
                {
                    Thread.Sleep(delayOnRetry);
                    continue;
                }
                try
                {
                    if (Path.GetExtension(filePath).ToLower() == ".xml")
                    {
                        // old format for backwards compatibility
                        using (fileStream = File.OpenRead(filePath))
                        {
                            // use xml-serializer for old library-format
                            XmlSerializer reader = new XmlSerializer(typeof(oldLibraryFormat.CreatureCollectionOld));
                            var           creatureCollectionOld = (oldLibraryFormat.CreatureCollectionOld)reader.Deserialize(fileStream);

                            List <Mod> mods = null;
                            // first check if additional values are used, and if the according values-file is already available.
                            // if not, abort conversion and first make sure the file is available, e.g. downloaded
                            if (!string.IsNullOrEmpty(creatureCollectionOld.additionalValues))
                            {
                                // usually the old filename is equal to the mod-tag
                                bool   modFound = false;
                                string modTag   = Path.GetFileNameWithoutExtension(creatureCollectionOld.additionalValues).Replace(" ", "").ToLower().Replace("gaiamod", "gaia");
                                foreach (KeyValuePair <string, ModInfo> tmi in Values.V.modsManifest.modsByTag)
                                {
                                    if (tmi.Key.ToLower() == modTag)
                                    {
                                        modFound = true;

                                        MessageBox.Show("The library contains creatures of modded species. For a correct file-conversion the correct mod-values file is needed.\n\n"
                                                        + "If the mod-value file is not loaded, the conversion may assign wrong species to your creatures.\n"
                                                        + "If the mod-value file is not available locally, it will be tried to download it.",
                                                        $"Mod values needed - {Utils.ApplicationNameVersion}", MessageBoxButtons.OK, MessageBoxIcon.Information);

                                        if (Values.V.loadedModsHash != Values.NoModsHash)
                                        {
                                            LoadStatAndKibbleValues(false); // reset values to default
                                        }
                                        LoadModValueFiles(new List <string> {
                                            tmi.Value.mod.FileName
                                        }, true, true, out mods);
                                        break;
                                    }
                                }
                                if (!modFound &&
                                    MessageBox.Show("The additional-values file in the library you're loading is unknown. You should first get a values-file in the new format for that mod.\n"
                                                    + "If you're loading the library the conversion of some modded species to the new format may fail and the according creatures have to be imported again later.\n\n"
                                                    + $"File:\n{filePath}\n"
                                                    + $"unknown mod-file: {modTag}\n\n"
                                                    + "Do you want to load the library and risk losing creatures?", $"Unknown mod-file - {Utils.ApplicationNameVersion}",
                                                    MessageBoxButtons.YesNo, MessageBoxIcon.Warning) != DialogResult.Yes)
                                {
                                    return(false);
                                }
                            }

                            _creatureCollection         = oldLibraryFormat.FormatConverter.ConvertXml2Asb(creatureCollectionOld, filePath);
                            _creatureCollection.ModList = mods;

                            if (_creatureCollection == null)
                            {
                                throw new Exception("Conversion failed");
                            }

                            string fileNameWOExt = Path.Combine(Path.GetDirectoryName(filePath), Path.GetFileNameWithoutExtension(filePath));
                            // check if new fileName is not yet existing
                            filePath = fileNameWOExt + CollectionFileExtension;
                            if (File.Exists(filePath))
                            {
                                int fi = 2;
                                while (File.Exists(fileNameWOExt + "_" + fi + CollectionFileExtension))
                                {
                                    fi++;
                                }
                                filePath = fileNameWOExt + "_" + fi + CollectionFileExtension;
                            }

                            // save converted library
                            SaveCollectionToFileName(filePath);
                        }
                    }
                    else
                    {
                        // new json-format
                        if (FileService.LoadJsonFile(filePath, out CreatureCollection readCollection, out string errorMessage))
                        {
                            if (!Version.TryParse(readCollection.FormatVersion, out Version ccVersion) ||
                                !Version.TryParse(CreatureCollection.CURRENT_FORMAT_VERSION, out Version currentVersion) ||
                                ccVersion > currentVersion)
                            {
                                throw new FormatException("Unhandled format version");
                            }
                            _creatureCollection = readCollection;
                        }
                        else
                        {
                            MessageBox.Show($"Error while trying to read the library-file\n{filePath}\n\n{errorMessage}",
                                            $"{Loc.S("error")} - {Utils.ApplicationNameVersion}", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            return(false);
                        }
                    }

                    break;
                }
        private Creature convertGameObject(GameObject creatureObject, int?levelStep)
        {
            GameObject statusObject = creatureObject.CharacterStatusComponent();

            string imprinterName = creatureObject.GetPropertyValue <string>("ImprinterName");
            string owner         = string.IsNullOrWhiteSpace(imprinterName) ? creatureObject.GetPropertyValue <string>("TamerString") : imprinterName;

            int[] wildLevels  = Enumerable.Repeat(-1, statsCount).ToArray(); // -1 is unknown
            int[] tamedLevels = new int[statsCount];

            for (int i = 0; i < statsCount; i++)
            {
                wildLevels[i] = statusObject.GetPropertyValue <ArkByteValue>("NumberOfLevelUpPointsApplied", i)?.ByteValue ?? 0;
            }
            wildLevels[(int)StatNames.Torpidity] = statusObject.GetPropertyValue <int>("BaseCharacterLevel", defaultValue: 1) - 1; // torpor

            for (int i = 0; i < statsCount; i++)
            {
                tamedLevels[i] = statusObject.GetPropertyValue <ArkByteValue>("NumberOfLevelUpPointsAppliedTamed", i)?.ByteValue ?? 0;
            }

            Species species = Values.V.speciesByBlueprint(creatureObject.ClassString);

            // for debugging
            if (species == null)
            {
                species = null;
            }

            float  ti = statusObject.GetPropertyValue <float>("TamedIneffectivenessModifier", defaultValue: float.NaN);
            double te = 1f / (1 + (!float.IsNaN(ti) ? ti : creatureObject.GetPropertyValue <float>("TameIneffectivenessModifier")));

            Creature creature = new Creature(species,
                                             creatureObject.GetPropertyValue <string>("TamedName"), owner, creatureObject.GetPropertyValue <string>("TribeName"),
                                             creatureObject.IsFemale() ? Sex.Female : Sex.Male,
                                             wildLevels, tamedLevels, te,
                                             !string.IsNullOrWhiteSpace(creatureObject.GetPropertyValue <string>("ImprinterName")),
                                             statusObject.GetPropertyValue <float>("DinoImprintingQuality"),
                                             levelStep
                                             )
            {
                imprinterName     = creatureObject.GetPropertyValue <string>("ImprinterName"),
                guid              = Utils.ConvertArkIdToGuid(creatureObject.GetDinoId()),
                ArkId             = creatureObject.GetDinoId(),
                ArkIdImported     = true,
                domesticatedAt    = DateTime.Now, // TODO: possible to convert ingame-time to realtime?
                addedToLibrary    = DateTime.Now,
                mutationsMaternal = creatureObject.GetPropertyValue <int>("RandomMutationsFemale"),
                mutationsPaternal = creatureObject.GetPropertyValue <int>("RandomMutationsMale")
            };

            // If it's a baby and still growing, work out growingUntil
            if (creatureObject.GetPropertyValue <bool>("bIsBaby") || !creatureObject.GetPropertyValue <bool>("bIsBaby") && !string.IsNullOrWhiteSpace(imprinterName))
            {
                double maturationTime = species.breeding?.maturationTimeAdjusted ?? 0;
                float  tamedTime      = gameTime - (float)creatureObject.GetPropertyValue <double>("TamedAtTime");
                if (tamedTime < maturationTime - 120) // there seems to be a slight offset of one of these saved values, so don't display a creature as being in cooldown if it is about to leave it in the next 2 minutes
                {
                    creature.growingUntil = DateTime.Now + TimeSpan.FromSeconds(maturationTime - tamedTime);
                }
            }

            // Ancestor linking is done later after entire collection is formed - here we just set the guids
            ArkArrayStruct     femaleAncestors = creatureObject.GetPropertyValue <IArkArray, ArkArrayStruct>("DinoAncestors");
            StructPropertyList femaleAncestor  = (StructPropertyList)femaleAncestors?.LastOrDefault();

            if (femaleAncestor != null)
            {
                creature.motherGuid = Utils.ConvertArkIdToGuid(GameObjectExtensions.CreateDinoId(
                                                                   femaleAncestor.GetPropertyValue <int>("FemaleDinoID1"),
                                                                   femaleAncestor.GetPropertyValue <int>("FemaleDinoID2")));
                creature.motherName = femaleAncestor.GetPropertyValue <string>("FemaleName");
                creature.isBred     = true;
            }
            ArkArrayStruct     maleAncestors = creatureObject.GetPropertyValue <IArkArray, ArkArrayStruct>("DinoAncestorsMale");
            StructPropertyList maleAncestor  = (StructPropertyList)maleAncestors?.LastOrDefault();

            if (maleAncestor != null)
            {
                creature.fatherGuid = Utils.ConvertArkIdToGuid(GameObjectExtensions.CreateDinoId(
                                                                   maleAncestor.GetPropertyValue <int>("MaleDinoID1"),
                                                                   maleAncestor.GetPropertyValue <int>("MaleDinoID2")));
                creature.fatherName = maleAncestor.GetPropertyValue <string>("MaleName");
                creature.isBred     = true;
            }

            creature.colors = new int[6];
            for (int i = 0; i < 6; i++)
            {
                creature.colors[i] = colorModulo(creatureObject.GetPropertyValue <ArkByteValue>("ColorSetIndices", i)?.ByteValue ?? 0);
            }

            bool isDead = creatureObject.GetPropertyValue <bool>("bIsDead");

            if (isDead)
            {
                creature.status = CreatureStatus.Dead; // dead is always dead
            }

            if (!isDead && creature.status == CreatureStatus.Dead)
            {
                creature.status = CreatureStatus.Unavailable; // if found alive when marked dead, mark as unavailable
            }

            creature.recalculateAncestorGenerations();
            creature.recalculateCreatureValues(levelStep);

            return(creature);
        }
Beispiel #9
0
        /// <summary>
        /// Import exported file. Used by a fileWatcher.
        /// </summary>
        /// <param name="filePath"></param>
        private void ImportExportedAddIfPossible(string filePath)
        {
            bool alreadyExists       = ExtractExportedFileInExtractor(filePath);
            bool added               = false;
            bool copyNameToClipboard = Properties.Settings.Default.copyNameToClipboardOnImportWhenAutoNameApplied &&
                                       (Properties.Settings.Default.applyNamePatternOnImportIfEmptyName ||
                                        (!alreadyExists && Properties.Settings.Default.applyNamePatternOnAutoImportForNewCreatures));
            Species species = speciesSelector1.SelectedSpecies;

            if (_extractor.uniqueResults ||
                (alreadyExists && _extractor.validResults))
            {
                AddCreatureToCollection(true, goToLibraryTab: false);
                SetMessageLabelText($"Successful {(alreadyExists ? "updated" : "added")} {creatureInfoInputExtractor.CreatureName} ({species.name}) of the exported file\n" + filePath, MessageBoxIcon.Information);
                added = true;
            }

            bool topLevels    = false;
            bool newTopLevels = false;

            // give feedback in overlay
            string    infoText;
            Color     textColor;
            const int colorSaturation = 200;

            if (added)
            {
                var sb = new StringBuilder();
                sb.AppendLine($"{species.name} \"{creatureInfoInputExtractor.CreatureName}\" {(alreadyExists ? "updated in " : "added to")} the library.");
                if (copyNameToClipboard)
                {
                    sb.AppendLine("Name copied to clipboard.");
                }

                for (int s = 0; s < values.Values.STATS_COUNT; s++)
                {
                    int statIndex = values.Values.statsDisplayOrder[s];
                    if (!species.UsesStat(statIndex))
                    {
                        continue;
                    }

                    sb.Append($"{Utils.StatName(statIndex, true, species.IsGlowSpecies)}: {_statIOs[statIndex].LevelWild} ({_statIOs[statIndex].BreedingValue})");
                    if (_statIOs[statIndex].TopLevel == StatIOStatus.NewTopLevel)
                    {
                        sb.Append($" {Loc.S("newTopLevel")}");
                        newTopLevels = true;
                    }
                    else if (_statIOs[statIndex].TopLevel == StatIOStatus.TopLevel)
                    {
                        sb.Append($" {Loc.S("topLevel")}");
                        topLevels = true;
                    }
                    sb.AppendLine();
                }

                infoText  = sb.ToString();
                textColor = Color.FromArgb(colorSaturation, 255, colorSaturation);
            }
            else
            {
                infoText  = $"Creature \"{creatureInfoInputExtractor.CreatureName}\" couldn't be extracted uniquely, manual level selection is necessary.";
                textColor = Color.FromArgb(255, colorSaturation, colorSaturation);
            }

            _overlay?.SetInfoText(infoText, textColor);

            if (added)
            {
                if (Properties.Settings.Default.MoveAutoImportedFileToSubFolder)
                {
                    string importedPath = Path.Combine(Path.GetDirectoryName(filePath), "imported");
                    if (!FileService.TryCreateDirectory(importedPath, out string errorMessage))
                    {
                        MessageBox.Show($"Subfolder\n{importedPath}\ncould not be created.\n{errorMessage}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return;
                    }
                    FileService.TryMoveFile(filePath, Path.Combine(importedPath, Path.GetFileName(filePath)));
                }
                else if (Properties.Settings.Default.DeleteAutoImportedFile)
                {
                    FileService.TryDeleteFile(filePath);
                }
            }
            else if (copyNameToClipboard)
            {
                // extraction failed, user might expect the name of the new creature in the clipboard
                Clipboard.SetText("Automatic extraction was not possible");
            }

            if (Properties.Settings.Default.PlaySoundOnAutoImport)
            {
                if (added)
                {
                    if (newTopLevels)
                    {
                        Utils.BeepSignal(3);
                    }
                    else if (topLevels)
                    {
                        Utils.BeepSignal(2);
                    }
                    else
                    {
                        Utils.BeepSignal(1);
                    }
                }
                else
                {
                    Utils.BeepSignal(0);
                }
            }
        }
Beispiel #10
0
        /// <summary>
        /// Returns a bitmap image that represents the given colors. If a species color file is available, that is used, else a pic-chart like representation.
        /// </summary>
        /// <param name="colorIds"></param>
        /// <param name="species"></param>
        /// <param name="enabledColorRegions"></param>
        /// <param name="size"></param>
        /// <param name="pieSize"></param>
        /// <param name="onlyColors">Only return a pie-chart like color representation.</param>
        /// <param name="onlyImage">Only return an image of the colored creature. If that's not possible, return null.</param>
        /// <param name="creatureSex">If given, it's tried for find a sex-specific image.</param>
        /// <returns></returns>
        public static Bitmap GetColoredCreature(int[] colorIds, Species species, bool[] enabledColorRegions, int size = 128, int pieSize = 64, bool onlyColors = false, bool onlyImage = false, Sex creatureSex = Sex.Unknown)
        {
            if (colorIds == null)
            {
                colorIds = new int[Species.ColorRegionCount];
            }

            string speciesName = SpeciesImageName(species?.name);

            // check if there are sex specific images
            if (creatureSex != Sex.Unknown)
            {
                string speciesNameWithSex;
                switch (creatureSex)
                {
                case Sex.Female:
                    speciesNameWithSex = speciesName + "F";
                    if (File.Exists(Path.Combine(ImgFolder, speciesNameWithSex + Extension)))
                    {
                        speciesName = speciesNameWithSex;
                    }
                    break;

                case Sex.Male:
                    speciesNameWithSex = speciesName + "M";
                    if (File.Exists(Path.Combine(ImgFolder, speciesNameWithSex + Extension)))
                    {
                        speciesName = speciesNameWithSex;
                    }
                    break;
                }
            }

            string speciesBackgroundFilePath = Path.Combine(ImgFolder, speciesName + Extension);
            string speciesColorMaskFilePath  = Path.Combine(ImgFolder, speciesName + "_m" + Extension);
            string cacheFilePath             = ColoredCreatureCacheFilePath(speciesName, colorIds);
            bool   cacheFileExists           = File.Exists(cacheFilePath);

            if (!onlyColors && !cacheFileExists)
            {
                cacheFileExists = CreateAndSaveCacheSpeciesFile(colorIds, enabledColorRegions, speciesBackgroundFilePath, speciesColorMaskFilePath, cacheFilePath);
            }

            if (onlyImage && !cacheFileExists)
            {
                return(null);                               // creating the species file failed
            }
            if (cacheFileExists && size == TemplateSize)
            {
                try
                {
                    return(new Bitmap(cacheFilePath));
                }
                catch
                {
                    // cached file corrupted, recreate
                    if (CreateAndSaveCacheSpeciesFile(colorIds, enabledColorRegions, speciesBackgroundFilePath,
                                                      speciesColorMaskFilePath, cacheFilePath))
                    {
                        try
                        {
                            return(new Bitmap(cacheFilePath));
                        }
                        catch
                        {
                            // file is still invalid after recreation, ignore file
                        }
                    }
                }
                return(null);
            }

            Bitmap bm = new Bitmap(size, size);

            using (Graphics graph = Graphics.FromImage(bm))
            {
                graph.SmoothingMode = SmoothingMode.AntiAlias;
                if (cacheFileExists)
                {
                    graph.CompositingMode    = CompositingMode.SourceCopy;
                    graph.CompositingQuality = CompositingQuality.HighQuality;
                    graph.InterpolationMode  = InterpolationMode.HighQualityBicubic;
                    graph.SmoothingMode      = SmoothingMode.HighQuality;
                    graph.PixelOffsetMode    = PixelOffsetMode.HighQuality;
                    try
                    {
                        using (var cachedImgBmp = new Bitmap(cacheFilePath))
                            graph.DrawImage(cachedImgBmp, 0, 0, size, size);
                    }
                    catch
                    {
                        // cached file invalid, recreate
                        if (CreateAndSaveCacheSpeciesFile(colorIds, enabledColorRegions, speciesBackgroundFilePath,
                                                          speciesColorMaskFilePath, cacheFilePath))
                        {
                            try
                            {
                                using (var cachedImgBmp = new Bitmap(cacheFilePath))
                                    graph.DrawImage(cachedImgBmp, 0, 0, size, size);
                            }
                            catch
                            {
                                // file is still invalid after recreation, ignore file
                                bm.Dispose();
                                return(null);
                            }
                        }
                    }
                }
                else
                {
                    // draw pieChart
                    int pieAngle = enabledColorRegions?.Count(c => c) ?? Species.ColorRegionCount;
                    pieAngle = 360 / (pieAngle > 0 ? pieAngle : 1);
                    int pieNr = 0;
                    for (int c = 0; c < Species.ColorRegionCount; c++)
                    {
                        if (enabledColorRegions?[c] ?? true)
                        {
                            if (colorIds[c] > 0)
                            {
                                using (var b = new SolidBrush(CreatureColors.CreatureColor(colorIds[c])))
                                {
                                    graph.FillPie(b, (size - pieSize) / 2, (size - pieSize) / 2, pieSize, pieSize,
                                                  pieNr * pieAngle + 270, pieAngle);
                                }
                            }

                            pieNr++;
                        }
                    }

                    using (var pen = new Pen(Color.Gray))
                        graph.DrawEllipse(pen, (size - pieSize) / 2, (size - pieSize) / 2, pieSize, pieSize);
                }
            }

            return(bm);
        }
Beispiel #11
0
        public void displayData(Species species)
        {
            if (species?.breeding == null)
            {
                return;
            }
            string breedingInfo = "";

            string firstTime = "Gestation";

            if (species.breeding.gestationTimeAdjusted <= 0)
            {
                firstTime = "Incubation";
            }

            string[] rowNames = { firstTime, "Baby", "Maturation" };
            for (int k = 0; k < 3; k++)
            {
                int t1, totalTime = 0;
                switch (k)
                {
                default:
                case 0:
                    t1        = (int)(species.breeding.gestationTimeAdjusted == 0 ? species.breeding.incubationTimeAdjusted : species.breeding.gestationTimeAdjusted);
                    totalTime = t1;
                    break;

                case 1:
                    t1        = (int)(.1f * species.breeding.maturationTimeAdjusted);
                    totalTime = t1;
                    break;

                case 2:
                    t1        = (int)species.breeding.maturationTimeAdjusted;
                    totalTime = (int)(species.breeding.gestationTimeAdjusted + species.breeding.incubationTimeAdjusted + species.breeding.maturationTimeAdjusted);
                    break;
                }

                string[] subitems =
                {
                    rowNames[k],
                    new TimeSpan(0, 0, t1).ToString("d':'hh':'mm':'ss"),
                    new TimeSpan(0, 0, totalTime).ToString("d':'hh':'mm':'ss"),
                    DateTime.Now.AddSeconds(totalTime).ToShortTimeString() + ", " + DateTime.Now.AddSeconds(totalTime).ToShortDateString()
                };
                //listView1.Items.Add(new ListViewItem(subitems));
                breedingInfo += string.Join(", ", subitems) + "\n";
            }

            breedingInfo += "\n";

            buttonHatching.Text = firstTime;

            // further info
            if (species.breeding.eggTempMin > 0)
            {
                breedingInfo += raising.Raising.eggTemperature(species);
            }
            if (species.breeding.eggTempMin > 0 && species.breeding.matingCooldownMinAdjusted > 0)
            {
                breedingInfo += "\n\n";
            }
            if (species.breeding.matingCooldownMinAdjusted > 0)
            {
                breedingInfo += "Time until next mating is possible:\n" + new TimeSpan(0, 0, (int)species.breeding.matingCooldownMinAdjusted).ToString("d':'hh':'mm")
                                + " - " + new TimeSpan(0, 0, (int)species.breeding.matingCooldownMaxAdjusted).ToString("d':'hh':'mm");
            }
            labelBreedingInfos.Text = breedingInfo;
        }
Beispiel #12
0
        /// <summary>
        /// Checks if an according species image exists in the cache folder, if not it tries to creates one. Returns false if there's no image.
        /// </summary>
        internal static (bool imageExists, string imagePath, string speciesListName) SpeciesImageExists(Species species, int[] colorIds)
        {
            string speciesImageName   = SpeciesImageName(species?.name);
            string speciesNameForList = SpeciesImageName(species?.name, false);
            string cacheFileName      = ColoredCreatureCacheFilePath(speciesImageName, colorIds, true);

            if (File.Exists(cacheFileName))
            {
                return(true, cacheFileName, speciesNameForList);
            }

            string speciesBackgroundFilePath = Path.Combine(ImgFolder, speciesImageName + Extension);
            string speciesColorMaskFilePath  = Path.Combine(ImgFolder, speciesImageName + "_m" + Extension);

            if (CreateAndSaveCacheSpeciesFile(colorIds,
                                              species?.EnabledColorRegions,
                                              speciesBackgroundFilePath, speciesColorMaskFilePath, cacheFileName, 64))
            {
                return(true, cacheFileName, speciesNameForList);
            }

            return(false, null, null);
        }
        public void SetSpecies(Species species, bool forceRefresh = false)
        {
            if (species == null || (_selectedSpecies == species && !forceRefresh))
            {
                return;
            }

            _selectedSpecies = species;

            if (species.taming == null)
            {
                NoTamingData();
                return;
            }

            this.SuspendDrawing();
            SuspendLayout();

            string speciesName = species.name;

            linkLabelWikiPage.Text = "Wiki: " + speciesName;
            linkLabelWikiPage.Tag  = speciesName;
            _tt.SetToolTip(linkLabelWikiPage, ArkWiki.WikiUrl(speciesName));

            // bone damage adjusters
            _boneDamageAdjustersImmobilization = Taming.BoneDamageAdjustersImmobilization(_selectedSpecies,
                                                                                          out Dictionary <string, double> boneDamageAdjusters);

            int ib = 0;

            foreach (KeyValuePair <string, double> bd in boneDamageAdjusters)
            {
                ib++;
                if (ib >= _rbBoneDamageAdjusters.Count)
                {
                    RadioButton rbBD = new RadioButton();
                    flcBodyDamageMultipliers.Controls.Add(rbBD);
                    flcBodyDamageMultipliers.SetFlowBreak(rbBD, true);
                    rbBD.AutoSize = true;

                    _rbBoneDamageAdjusters.Add(rbBD);
                    _rbBoneDamageAdjusterValues.Add(1);
                    rbBD.CheckedChanged += rbBoneDamage_CheckedChanged;
                }
                _rbBoneDamageAdjusterValues[ib]    = bd.Value;
                _rbBoneDamageAdjusters[ib].Text    = $"{Loc.S(bd.Key)} (× {bd.Value})";
                _rbBoneDamageAdjusters[ib].Visible = true;
            }
            for (int j = ib + 1; j < _rbBoneDamageAdjusters.Count; j++)
            {
                _rbBoneDamageAdjusters[j].Visible = false;
            }
            _rbBoneDamageAdjusters[0].Checked = true;
            // bone damage adjusters adjusted

            _updateCalculation = false;
            TamingData td = species.taming;

            _kibbleRecipe = string.Empty;

            // list all recipes of kibbles that give a reasonable affinity (assuming that is larger or equal than 100)
            foreach (var k in Kibbles.K.kibble)
            {
                var kibbleName = $"{k.Key} Kibble";
                var kibbleFood = Values.V.GetTamingFood(species, kibbleName);

                if (kibbleFood != null &&
                    kibbleFood.affinity >= 100)
                {
                    _kibbleRecipe += $"\n\n{k.Key} Kibble:{k.Value.RecipeAsText()}";
                }
            }

            _foodDepletion = td.foodConsumptionBase * td.foodConsumptionMult * _tamingFoodRateMultiplier;

            SetTamingFoodControls(species);

            _updateCalculation = true;
            UpdateFirstFeedingWaiting();
            UpdateTamingData();
            if (Properties.Settings.Default.TamingFoodOrderByTime)
            {
                SetOrderOfTamingFood(true, true);
            }

            ResumeLayout();
            this.ResumeDrawing();
        }
        /// <summary>
        /// Sets the taming food controls.
        /// </summary>
        private void SetTamingFoodControls(Species species)
        {
            var td = species.taming;
            int i  = 0;

            if (td.eats != null)
            {
                var length = td.eats.Length;
                for (; i < length; i++)
                {
                    string            f = td.eats[i];
                    TamingFoodControl tf;

                    // if Augmented are not wanted, and food control already exist, update it and hide it.
                    if (!checkBoxAugmented.Checked && f.Contains("Augmented"))
                    {
                        if (i < _foodControls.Count)
                        {
                            tf          = _foodControls[i];
                            tf.FoodName = f;
                            tf.Hide();
                        }
                        continue;
                    }

                    if (i >= _foodControls.Count)
                    {
                        tf = new TamingFoodControl(f);
                        tf.valueChanged += UpdateTamingData;
                        tf.Clicked      += OnlyOneFood;
                        _foodControls.Add(tf);
                        flpTamingFood.Controls.Add(tf);
                    }
                    else
                    {
                        tf          = _foodControls[i];
                        tf.FoodName = f;
                        flpTamingFood.Controls.SetChildIndex(tf, i);
                        tf.Show();
                    }

                    // special cases where a creature eats multiple food items of one kind at once
                    var food = Values.V.GetTamingFood(species, f);
                    if (food != null && food.quantity > 1)
                    {
                        tf.foodNameDisplay = food.quantity + "× " + tf.foodNameDisplay;
                    }
                }
            }

            for (int fci = _foodControls.Count - 1; fci >= i; fci--)
            {
                _foodControls[fci].FoodName = null;
                _foodControls[fci].Hide();
            }

            if (i > 0)
            {
                _foodControls[0].amount = Taming.FoodAmountNeeded(species, (int)nudLevel.Value, _tamingSpeedMultiplier, _foodControls[0].FoodName, td.nonViolent);
            }
        }
Beispiel #15
0
        public static void TamingTimes(Species species, int level, double tamingSpeedMultiplier, double tamingFoodRateMultiplier,
                                       List <string> usedFood, List <int> foodAmount, out List <int> foodAmountUsed, out TimeSpan duration,
                                       out int neededNarcoberries, out int neededAscerbicMushrooms, out int neededNarcotics, out int neededBioToxines, out double te, out double hunger, out int bonusLevel, out bool enoughFood)
        {
            double totalTorpor = 0, torporDeplPS = 0, torporNeeded = 0;
            int    totalSeconds = 0;

            bonusLevel              = 0;
            te                      = 1;
            duration                = TimeSpan.Zero;
            neededNarcoberries      = 0;
            neededAscerbicMushrooms = 0;
            neededNarcotics         = 0;
            neededBioToxines        = 0;
            hunger                  = 0;
            enoughFood              = false;

            foodAmountUsed = new List <int>();
            foreach (int i in foodAmount)
            {
                foodAmountUsed.Add(0);
            }

            if (species != null && species.taming != null)
            {
                double affinityNeeded = species.taming.affinityNeeded0 + species.taming.affinityIncreasePL * level;

                // test if creature is tamend non-violently, then use wakeTame multiplicators
                if (!species.taming.nonViolent)
                {
                    //total torpor for level
                    totalTorpor = species.stats[(int)StatNames.Torpidity].BaseValue * (1 + species.stats[(int)StatNames.Torpidity].IncPerWildLevel * (level - 1));
                    // torpor depletion per second for level
                    torporDeplPS = TorporDepletionPS(species.taming.torporDepletionPS0, level);
                }

                double foodByAffinity = 0; // needed for the effectiveness calculation

                // how much food / resources of the different kinds that this creature eats is needed
                for (int f = 0; f < usedFood.Count; f++)
                {
                    if (foodAmount[f] > 0)
                    {
                        string food        = usedFood[f];
                        bool   specialFood = species.taming.specialFoodValues != null && species.taming.specialFoodValues.ContainsKey(food);
                        if (specialFood || Values.V.defaultFoodData.ContainsKey(food))
                        {
                            double foodAffinity;
                            double foodValue;

                            // check if (creature handles this food in a special way (e.g. scorpions not liking raw meat as much)
                            if (specialFood)
                            {
                                foodAffinity = species.taming.specialFoodValues[food].affinity;
                                foodValue    = species.taming.specialFoodValues[food].foodValue;
                            }
                            else
                            {
                                foodAffinity = Values.V.defaultFoodData[food].affinity;
                                foodValue    = Values.V.defaultFoodData[food].foodValue;
                            }

                            foodAffinity *= specialFood ? species.taming.specialFoodValues[food].quantity : 1;

                            if (species.taming.nonViolent)
                            {
                                // consider wake taming multiplicators (non - violent taming)
                                foodAffinity *= species.taming.wakeAffinityMult;
                                foodValue     = foodValue * species.taming.wakeFoodDeplMult;
                            }

                            // *2 in accordance with the hardcoded 2x taming-bonus that was introduced in the game in patch 253.0 on 2016-12-23
                            // https://ark.gamepedia.com/253.0
                            foodAffinity *= tamingSpeedMultiplier * 2;

                            if (foodAffinity > 0 && foodValue > 0)
                            {
                                // amount of food needed for the left affinity.
                                int foodPiecesNeeded = (int)Math.Ceiling(affinityNeeded / foodAffinity);

                                if (foodPiecesNeeded > foodAmount[f])
                                {
                                    foodPiecesNeeded = foodAmount[f];
                                }

                                foodAmountUsed[f] = foodPiecesNeeded;

                                // time to eat needed food
                                // mantis eats every 3 minutes, regardless of level
                                int seconds;
                                if (species.name == "Mantis")
                                {
                                    seconds = foodPiecesNeeded * 180;
                                }
                                else
                                {
                                    seconds = (int)Math.Ceiling(foodPiecesNeeded * foodValue / (species.taming.foodConsumptionBase * species.taming.foodConsumptionMult * tamingFoodRateMultiplier));
                                }
                                affinityNeeded -= foodPiecesNeeded * foodAffinity;

                                // new approach with 1/(1 + IM*IA*N/AO + ID*D) from https://forums.unrealengine.com/development-discussion/modding/ark-survival-evolved/56959-tutorial-dinosaur-taming-parameters?85457-Tutorial-Dinosaur-Taming-Parameters=
                                foodByAffinity += foodPiecesNeeded / foodAffinity;

                                if (!species.taming.nonViolent)
                                {
                                    //extra needed torpor to eat needed food
                                    torporNeeded += torporDeplPS * seconds;
                                }
                                totalSeconds += seconds;
                            }
                            if (affinityNeeded <= 0)
                            {
                                break;
                            }
                        }
                    }
                }
                // add tamingIneffectivenessMultiplier? Needs settings?
                te = 1 / (1 + species.taming.tamingIneffectiveness * foodByAffinity); // ignores damage, which has no input
                if (te < 0)
                {
                    te = 0;
                }

                torporNeeded -= totalTorpor;

                if (torporNeeded < 0)
                {
                    torporNeeded = 0;
                }
                // amount of Narcoberries(give 7.5 torpor each over 3s)
                neededNarcoberries = (int)Math.Ceiling(torporNeeded / (7.5 + 3 * torporDeplPS));
                // amount of Ascerbic Mushrooms (give 25 torpor each over 3s)
                neededAscerbicMushrooms = (int)Math.Ceiling(torporNeeded / (25 + 3 * torporDeplPS));
                // amount of Narcotics(give 40 each over 8s)
                neededNarcotics = (int)Math.Ceiling(torporNeeded / (40 + 8 * torporDeplPS));
                // amount of BioToxines (give 80 each over 16s)
                neededBioToxines = (int)Math.Ceiling(torporNeeded / (80 + 16 * torporDeplPS));

                enoughFood = affinityNeeded <= 0;

                // needed Time to eat
                duration = new TimeSpan(0, 0, totalSeconds);

                bonusLevel = (int)Math.Floor(level * te / 2);

                for (int i = 0; i < usedFood.Count; i++)
                {
                    if (species.taming.specialFoodValues != null && species.taming.specialFoodValues.ContainsKey(usedFood[i]))
                    {
                        hunger += foodAmountUsed[i] * species.taming.specialFoodValues[usedFood[i]].foodValue;
                    }
                    else if (Values.V.defaultFoodData.ContainsKey(usedFood[i]))
                    {
                        hunger += foodAmountUsed[i] * Values.V.defaultFoodData[usedFood[i]].foodValue;
                    }
                }
            }
        }
Beispiel #16
0
        public void determineBestBreeding(Creature chosenCreature = null, bool forceUpdate = false, Species setSpecies = null)
        {
            if (creatureCollection == null)
            {
                return;
            }

            Species selectedSpecies = (chosenCreature != null ? chosenCreature.Species : null);
            bool    newSpecies      = false;

            if (selectedSpecies == null)
            {
                selectedSpecies = setSpecies != null ? setSpecies : currentSpecies;
            }
            if (selectedSpecies != null && currentSpecies != selectedSpecies)
            {
                CurrentSpecies = selectedSpecies;
                newSpecies     = true;

                EnabledColorRegions = currentSpecies?.colors.Select(n => n.name != "").ToArray() ?? new bool[6] {
                    true, true, true, true, true, true
                };

                breedingPlanNeedsUpdate = true;
            }
            if (forceUpdate || breedingPlanNeedsUpdate)
            {
                Creatures = creatureCollection.creatures
                            .Where(c => c.speciesBlueprint == currentSpecies.blueprintPath &&
                                   c.status == CreatureStatus.Available &&
                                   !c.neutered &&
                                   (cnBPIncludeCooldowneds.Checked || c.cooldownUntil < DateTime.Now && c.growingUntil < DateTime.Now))
                            .ToList();
            }

            statWeights = statWeighting1.Weightings;

            this.chosenCreature = chosenCreature;
            calculateBreedingScoresAndDisplayPairs(breedingMode, newSpecies);
            breedingPlanNeedsUpdate = false;
        }
Beispiel #17
0
        public void DetermineBestBreeding(Creature chosenCreature = null, bool forceUpdate = false, Species setSpecies = null)
        {
            if (creatureCollection == null)
            {
                return;
            }

            Species selectedSpecies = chosenCreature?.Species;
            bool    newSpecies      = false;

            if (selectedSpecies == null)
            {
                selectedSpecies = setSpecies ?? currentSpecies;
            }
            if (selectedSpecies != null && currentSpecies != selectedSpecies)
            {
                CurrentSpecies = selectedSpecies;
                newSpecies     = true;

                EnabledColorRegions = currentSpecies?.colors.Select(n => !string.IsNullOrEmpty(n?.name)).ToArray() ?? new bool[6] {
                    true, true, true, true, true, true
                };

                breedingPlanNeedsUpdate = true;
            }
            if (forceUpdate || breedingPlanNeedsUpdate)
            {
                Creatures = creatureCollection.creatures
                            .Where(c => c.speciesBlueprint == currentSpecies.blueprintPath &&
                                   c.status == CreatureStatus.Available &&
                                   !c.flags.HasFlag(CreatureFlags.Neutered) &&
                                   (cbBPIncludeCooldowneds.Checked ||
                                    !(c.cooldownUntil > DateTime.Now ||
                                      c.growingUntil > DateTime.Now
                                      )
                                   )
                                   )
                            .ToList();
            }

            statWeights = statWeighting1.Weightings;

            this.chosenCreature = chosenCreature;
            CalculateBreedingScoresAndDisplayPairs(breedingMode, newSpecies);
            breedingPlanNeedsUpdate = false;
        }
Beispiel #18
0
        public bool loadAdditionalValues(string filename, bool showResults)
        {
            // load extra values-file that can add values or modify existing ones
            bool loadedSuccessful = true;

            // check if file exists
            if (!File.Exists(filename))
            {
                MessageBox.Show("Additional Values-File '" + filename + "' not found.\nThis collection seems to have modified or added values that are saved in a separate file, which couldn't be found at the saved location. You can load it manually via the menu File - Load additional values…", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return(false);
            }

            DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(Values));

            System.IO.FileStream file = System.IO.File.OpenRead(filename);

            Values modifiedValues = new Values();

            try
            {
                modifiedValues = (Values)ser.ReadObject(file);
            }
            catch (Exception e)
            {
                MessageBox.Show("File Couldn't be opened or read.\nErrormessage:\n\n" + e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                loadedSuccessful = false;
            }
            file.Close();
            if (!loadedSuccessful)
            {
                return(false);
            }

            _V.modValuesFile = Path.GetFileName(file.Name);
            int speciesUpdated = 0;
            int speciesAdded   = 0;

            // update data if existing
            // version
            try
            {
                _V.modVersion = new Version(modifiedValues.ver);
            }
            catch
            {
                _V.modVersion = new Version(0, 0);
            }

            // species
            if (modifiedValues.species != null)
            {
                foreach (Species sp in modifiedValues.species)
                {
                    if (!_V.speciesNames.Contains(sp.name))
                    {
                        _V.species.Add(sp);
                        sp.initialize();
                        _V.speciesNames.Add(sp.name);
                        speciesAdded++;
                    }
                    else
                    {
                        // species already exists, update all values which are not null
                        Species originalSpecies = _V.species[_V.speciesNames.IndexOf(sp.name)];
                        bool    updated         = false;
                        if (sp.TamedBaseHealthMultiplier != null)
                        {
                            originalSpecies.TamedBaseHealthMultiplier = sp.TamedBaseHealthMultiplier;
                            updated = true;
                        }
                        if (sp.NoImprintingForSpeed != null)
                        {
                            originalSpecies.NoImprintingForSpeed = sp.NoImprintingForSpeed;
                            updated = true;
                        }
                        if (sp.statsRaw != null && sp.statsRaw.Length > 0)
                        {
                            for (int s = 0; s < 8 && s < sp.statsRaw.Length; s++)
                            {
                                if (sp.statsRaw[s] != null)
                                {
                                    for (int si = 0; si < 5 && si < sp.statsRaw[s].Length; si++)
                                    {
                                        if (sp.statsRaw[s][si] != null)
                                        {
                                            originalSpecies.statsRaw[s][si] = sp.statsRaw[s][si];
                                            updated = true;
                                        }
                                    }
                                }
                            }
                        }
                        if (string.IsNullOrEmpty(sp.blueprintPath))
                        {
                            originalSpecies.blueprintPath = sp.blueprintPath;
                            updated = true;
                        }
                        if (updated)
                        {
                            speciesUpdated++;
                        }
                    }
                }
            }
            // fooddata TODO
            // default-multiplier TODO

            _V.loadAliases();
            _V.updateSpeciesBlueprints();

            if (showResults)
            {
                MessageBox.Show("Species with changed stats: " + speciesUpdated + "\nSpecies added: " + speciesAdded, "Additional Values succesfully added", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }

            return(true);
        }
Beispiel #19
0
        public bool LoadModValues(List <string> modValueFiles, bool showResults, out List <Mod> mods)
        {
            loadedModsHash = 0;
            List <Values> modifiedValues = new List <Values>();

            mods = new List <Mod>();
            if (modValueFiles == null)
            {
                return(false);
            }

            foreach (string mf in modValueFiles)
            {
                string filename = FileService.GetJsonPath(Path.Combine("mods", mf));

                if (TryLoadValuesFile(filename, setModFileName: true, out Values modValues))
                {
                    modifiedValues.Add(modValues);
                }
            }

            int speciesUpdated = 0;
            int speciesAdded   = 0;

            // update data if existing
            foreach (Values modValues in modifiedValues)
            {
                // if mods are loaded multiple times, only keep the last
                mods.Remove(modValues.mod);
                mods.Add(modValues.mod);

                // species
                if (modValues.species != null)
                {
                    foreach (Species sp in modValues.species)
                    {
                        if (string.IsNullOrWhiteSpace(sp.blueprintPath))
                        {
                            continue;
                        }

                        Species originalSpecies = speciesByBlueprint(sp.blueprintPath);
                        if (originalSpecies == null)
                        {
                            _V.species.Add(sp);
                            sp.Initialize();
                            sp.mod = modValues.mod;
                            speciesAdded++;

                            if (!blueprintToSpecies.ContainsKey(sp.blueprintPath))
                            {
                                blueprintToSpecies.Add(sp.blueprintPath, sp);
                            }
                        }
                        else
                        {
                            // species already exists, update all values which are not null
                            bool updated = false;
                            if (sp.TamedBaseHealthMultiplier != null)
                            {
                                originalSpecies.TamedBaseHealthMultiplier = sp.TamedBaseHealthMultiplier;
                                updated = true;
                            }
                            if (sp.NoImprintingForSpeed != null)
                            {
                                originalSpecies.NoImprintingForSpeed = sp.NoImprintingForSpeed;
                                updated = true;
                            }
                            if (sp.fullStatsRaw != null && sp.fullStatsRaw.Length > 0)
                            {
                                for (int s = 0; s < statsCount && s < sp.fullStatsRaw.Length; s++)
                                {
                                    if (sp.fullStatsRaw[s] == null)
                                    {
                                        continue;
                                    }
                                    for (int si = 0; si < 5 && si < sp.fullStatsRaw[s].Length; si++)
                                    {
                                        if (sp.fullStatsRaw[s][si] == null)
                                        {
                                            continue;
                                        }
                                        originalSpecies.fullStatsRaw[s][si] = sp.fullStatsRaw[s][si];
                                        updated = true;
                                    }
                                }
                            }
                            if (!string.IsNullOrEmpty(sp.blueprintPath))
                            {
                                originalSpecies.blueprintPath = sp.blueprintPath;
                                updated = true;
                            }
                            if (updated)
                            {
                                speciesUpdated++;
                            }
                        }
                    }
                }
            }

            loadedModsHash = CreatureCollection.CalculateModListId(mods);

            // sort new species
            OrderSpecies();

            // fooddata TODO
            // default-multiplier TODO

            _V.loadAliases();
            _V.updateSpeciesBlueprints();

            if (showResults)
            {
                MessageBox.Show($"Species with changed stats: {speciesUpdated}\nSpecies added: {speciesAdded}",
                                "Additional Values succesfully added", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }

            return(true);
        }
        public static Bitmap getColoredCreature(int[] colorIds, Species species, bool[] enabledColorRegions, int size = 128, int pieSize = 64, bool onlyColors = false, bool dontCache = false)
        {
            //float[][] hsl = new float[6][];
            int[][] rgb = new int[6][];
            for (int c = 0; c < 6; c++)
            {
                Color cl = CreatureColors.creatureColor(colorIds[c]);
                rgb[c] = new int[] { cl.R, cl.G, cl.B };
            }
            Bitmap bm = new Bitmap(size, size);

            using (Graphics graph = Graphics.FromImage(bm))
            {
                graph.SmoothingMode = SmoothingMode.AntiAlias;
                string imgFolder   = Path.Combine(FileService.GetPath(), imageFolderName);
                string cacheFolder = Path.Combine(FileService.GetPath(), imageFolderName, cacheFolderName);
                string speciesName = species?.name ?? string.Empty;

                string cacheFileName = Path.Combine(cacheFolder, speciesName.Substring(0, Math.Min(speciesName.Length, 5)) + "_" + (speciesName + string.Join("", colorIds.Select(i => i.ToString()).ToArray())).GetHashCode().ToString("X8") + extension);
                if (!onlyColors && File.Exists(Path.Combine(imgFolder, speciesName + extension)) && File.Exists(Path.Combine(imgFolder, speciesName + "_m" + extension)))
                {
                    if (!File.Exists(cacheFileName))
                    {
                        const int defaultSizeOfTemplates = 256;
                        Bitmap    bmC = new Bitmap(Path.Combine(imgFolder, speciesName + extension));
                        graph.DrawImage(new Bitmap(Path.Combine(imgFolder, speciesName + extension)), 0, 0, defaultSizeOfTemplates, defaultSizeOfTemplates);
                        Bitmap mask = new Bitmap(defaultSizeOfTemplates, defaultSizeOfTemplates);
                        Graphics.FromImage(mask).DrawImage(new Bitmap(Path.Combine(imgFolder, speciesName + "_m" + extension)), 0, 0, defaultSizeOfTemplates, defaultSizeOfTemplates);
                        float o         = 0;
                        bool  imageFine = false;
                        try
                        {
                            for (int i = 0; i < bmC.Width; i++)
                            {
                                for (int j = 0; j < bmC.Height; j++)
                                {
                                    Color bc = bmC.GetPixel(i, j);
                                    if (bc.A > 0)
                                    {
                                        int r = mask.GetPixel(i, j).R;
                                        int g = mask.GetPixel(i, j).G;
                                        int b = mask.GetPixel(i, j).B;
                                        for (int m = 0; m < 6; m++)
                                        {
                                            if (!enabledColorRegions[m] || colorIds[m] == 0)
                                            {
                                                continue;
                                            }
                                            switch (m)
                                            {
                                            case 0:
                                                o = Math.Max(0, r - g - b) / 255f;
                                                break;

                                            case 1:
                                                o = Math.Max(0, g - r - b) / 255f;
                                                break;

                                            case 2:
                                                o = Math.Max(0, b - r - g) / 255f;
                                                break;

                                            case 3:
                                                o = Math.Min(g, b) / 255f;
                                                break;

                                            case 4:
                                                o = Math.Min(r, g) / 255f;
                                                break;

                                            case 5:
                                                o = Math.Min(r, b) / 255f;
                                                break;
                                            }
                                            if (o == 0)
                                            {
                                                continue;
                                            }
                                            // using "grain merge", e.g. see https://docs.gimp.org/en/gimp-concepts-layer-modes.html
                                            int rMix = bc.R + rgb[m][0] - 128;
                                            if (rMix < 0)
                                            {
                                                rMix = 0;
                                            }
                                            else if (rMix > 255)
                                            {
                                                rMix = 255;
                                            }
                                            int gMix = bc.G + rgb[m][1] - 128;
                                            if (gMix < 0)
                                            {
                                                gMix = 0;
                                            }
                                            else if (gMix > 255)
                                            {
                                                gMix = 255;
                                            }
                                            int bMix = bc.B + rgb[m][2] - 128;
                                            if (bMix < 0)
                                            {
                                                bMix = 0;
                                            }
                                            else if (bMix > 255)
                                            {
                                                bMix = 255;
                                            }
                                            Color c = Color.FromArgb(rMix, gMix, bMix);
                                            bc = Color.FromArgb(bc.A, (int)(o * c.R + (1 - o) * bc.R), (int)(o * c.G + (1 - o) * bc.G), (int)(o * c.B + (1 - o) * bc.B));
                                        }
                                        bmC.SetPixel(i, j, bc);
                                    }
                                }
                            }
                            imageFine = true;
                        }
                        catch
                        {
                            // error during drawing, maybe mask is smaller than image
                        }
                        if (imageFine)
                        {
                            if (!Directory.Exists(cacheFolder))
                            {
                                Directory.CreateDirectory(cacheFolder);
                            }
                            bmC.Save(cacheFileName); // safe in cache}
                        }
                    }
                }
                if (File.Exists(cacheFileName))
                {
                    graph.CompositingMode    = CompositingMode.SourceCopy;
                    graph.CompositingQuality = CompositingQuality.HighQuality;
                    graph.InterpolationMode  = InterpolationMode.HighQualityBicubic;
                    graph.SmoothingMode      = SmoothingMode.HighQuality;
                    graph.PixelOffsetMode    = PixelOffsetMode.HighQuality;
                    graph.DrawImage(new Bitmap(cacheFileName), 0, 0, size, size);
                }
                else
                {
                    // draw piechart
                    int pieAngle = enabledColorRegions.Count(c => c);
                    pieAngle = 360 / (pieAngle > 0 ? pieAngle : 1);
                    int pieNr = 0;
                    for (int c = 0; c < 6; c++)
                    {
                        if (enabledColorRegions[c])
                        {
                            if (colorIds[c] > 0)
                            {
                                using (var b = new SolidBrush(CreatureColors.creatureColor(colorIds[c])))
                                {
                                    graph.FillPie(b, (size - pieSize) / 2, (size - pieSize) / 2, pieSize, pieSize, pieNr * pieAngle + 270, pieAngle);
                                }
                            }
                            pieNr++;
                        }
                    }
                    graph.DrawEllipse(new Pen(Color.Gray), (size - pieSize) / 2, (size - pieSize) / 2, pieSize, pieSize);
                }
            }
            return(bm);
        }
        public void SetSpecies(Species species)
        {
            if (species == null || selectedSpecies == species)
            {
                return;
            }

            selectedSpecies = species;

            if (species.taming == null)
            {
                NoTamingData();
                return;
            }

            SuspendLayout();

            string speciesName = species.name;

            linkLabelWikiPage.Text = "Wiki: " + speciesName;
            linkLabelWikiPage.Tag  = speciesName;

            // bone damage adjusters
            boneDamageAdjustersImmobilization = Taming.BoneDamageAdjustersImmobilization(selectedSpecies,
                                                                                         out Dictionary <string, double> boneDamageAdjusters);

            int ib = 0;

            foreach (KeyValuePair <string, double> bd in boneDamageAdjusters)
            {
                ib++;
                if (ib >= rbBoneDamageAdjusters.Count)
                {
                    RadioButton rbBD = new RadioButton();
                    flcBodyDamageMultipliers.Controls.Add(rbBD);
                    flcBodyDamageMultipliers.SetFlowBreak(rbBD, true);
                    rbBD.AutoSize = true;

                    rbBoneDamageAdjusters.Add(rbBD);
                    rbBoneDamageAdjusterValues.Add(1);
                    rbBD.CheckedChanged += rbBoneDamage_CheckedChanged;
                }
                rbBoneDamageAdjusterValues[ib]    = bd.Value;
                rbBoneDamageAdjusters[ib].Text    = $"{Loc.s(bd.Key)} (× {bd.Value})";
                rbBoneDamageAdjusters[ib].Visible = true;
            }
            for (int j = ib + 1; j < rbBoneDamageAdjusters.Count; j++)
            {
                rbBoneDamageAdjusters[j].Visible = false;
            }
            rbBoneDamageAdjusters[0].Checked = true;
            // bone damage adjusters adjusted

            updateCalculation = false;
            TamingData td = species.taming;

            kibbleRecipe = "";


            // TODO replace with new kibble recipes
            //if (td.favoriteKibble != null && Kibbles.K.kibble.ContainsKey(td.favoriteKibble))
            //{
            //    kibbleRecipe = "\n\nKibble:" + Kibbles.K.kibble[td.favoriteKibble].RecipeAsText();
            //}

            foodDepletion = td.foodConsumptionBase * td.foodConsumptionMult * tamingFoodRateMultiplier;

            int i = 0;

            if (td.eats != null)
            {
                for (i = 0; i < td.eats.Count; i++)
                {
                    string            f = td.eats[i];
                    TamingFoodControl tf;
                    if (i >= foodControls.Count)
                    {
                        tf = new TamingFoodControl(f);
                        tf.valueChanged += UpdateTamingData;
                        tf.Clicked      += OnlyOneFood;
                        foodControls.Add(tf);
                        flpTamingFood.Controls.Add(tf);
                    }
                    else
                    {
                        tf          = foodControls[i];
                        tf.FoodName = f;
                        tf.Show();
                    }
                    if (f == "Kibble")
                    {
                        tf.foodNameDisplay = $"Kibble ({td.favoriteKibble} {Loc.s("Egg")})";
                    }
                    if (td.specialFoodValues != null && td.specialFoodValues.ContainsKey(f) && td.specialFoodValues[f].quantity > 1)
                    {
                        tf.foodNameDisplay = td.specialFoodValues[f].quantity + "× " + tf.foodNameDisplay;
                    }
                }
            }

            for (int fci = foodControls.Count - 1; fci >= i; fci--)
            {
                foodControls[fci].Hide();
            }

            if (i > 0)
            {
                foodControls[0].amount = Taming.FoodAmountNeeded(species, (int)nudLevel.Value, tamingSpeedMultiplier, foodControls[0].FoodName, td.nonViolent);
            }

            updateCalculation = true;
            UpdateFirstFeedingWaiting();
            UpdateTamingData();

            ResumeLayout();
        }
Beispiel #22
0
        /// <summary>
        /// Returns a bitmap image that represents the given colors. If a species color file is available, that is used, else a pic-chart like representation.
        /// </summary>
        /// <param name="colorIds"></param>
        /// <param name="species"></param>
        /// <param name="enabledColorRegions"></param>
        /// <param name="size"></param>
        /// <param name="pieSize"></param>
        /// <param name="onlyColors">Only return a pie-chart like color representation.</param>
        /// <param name="onlyImage">Only return an image of the colored creature. If that's not possible, return null.</param>
        /// <returns></returns>
        public static Bitmap GetColoredCreature(int[] colorIds, Species species, bool[] enabledColorRegions, int size = 128, int pieSize = 64, bool onlyColors = false, bool onlyImage = false, Library.Sex creatureSex = Sex.Unknown)
        {
            if (colorIds == null)
            {
                return(null);
            }
            //float[][] hsl = new float[Species.ColorRegionCount][];
            int[][] rgb = new int[Species.ColorRegionCount][];
            for (int c = 0; c < Species.ColorRegionCount; c++)
            {
                Color cl = CreatureColors.CreatureColor(colorIds[c]);
                rgb[c] = new int[] { cl.R, cl.G, cl.B };
            }

            string imgFolder   = Path.Combine(FileService.GetPath(), imageFolderName);
            string cacheFolder = Path.Combine(FileService.GetPath(), imageFolderName, cacheFolderName);
            string speciesName = species?.name ?? string.Empty;

            // check if there are sex specific images
            if (creatureSex != Sex.Unknown)
            {
                string speciesNameWithSex = null;
                switch (creatureSex)
                {
                case Sex.Female:
                    speciesNameWithSex = speciesName + "F";
                    if (File.Exists(Path.Combine(imgFolder, speciesNameWithSex + extension)))
                    {
                        speciesName = speciesNameWithSex;
                    }
                    break;

                case Sex.Male:
                    speciesNameWithSex = speciesName + "M";
                    if (File.Exists(Path.Combine(imgFolder, speciesNameWithSex + extension)))
                    {
                        speciesName = speciesNameWithSex;
                    }
                    break;
                }
            }

            string speciesBackgroundFilePath = Path.Combine(imgFolder, speciesName + extension);
            string cacheFileName             = Path.Combine(cacheFolder, speciesName.Substring(0, Math.Min(speciesName.Length, 5)) + "_" + (speciesName + string.Join(".", colorIds.Select(i => i.ToString()))).GetHashCode().ToString("X8") + extension);
            string speciesColorMaskFilePath  = Path.Combine(imgFolder, speciesName + "_m" + extension);

            if (!onlyColors && File.Exists(speciesBackgroundFilePath) && File.Exists(speciesColorMaskFilePath) && !File.Exists(cacheFileName))
            {
                using (Bitmap bmpBackground = new Bitmap(speciesBackgroundFilePath))
                    using (Bitmap bmpCreature = new Bitmap(bmpBackground.Width, bmpBackground.Height, PixelFormat.Format32bppArgb))
                        using (Graphics graph = Graphics.FromImage(bmpCreature))
                        {
                            bool imageFine = false;
                            graph.SmoothingMode = SmoothingMode.AntiAlias;
                            const int defaultSizeOfTemplates = 256;

                            using (Bitmap bmpMask = new Bitmap(defaultSizeOfTemplates, defaultSizeOfTemplates))
                            {
                                using (var g = Graphics.FromImage(bmpMask))
                                    using (var bmpMaskOriginal = new Bitmap(speciesColorMaskFilePath))
                                        g.DrawImage(bmpMaskOriginal, 0, 0,
                                                    defaultSizeOfTemplates, defaultSizeOfTemplates);
                                float o = 0;
                                try
                                {
                                    // shadow
                                    using (var b = new SolidBrush(Color.FromArgb(12, 0, 0, 0)))
                                    {
                                        int    scx          = defaultSizeOfTemplates / 2;
                                        int    scy          = (int)(scx * 1.6);
                                        int    factor       = 25;
                                        int    sr           = scx - 2 * factor;
                                        double heightFactor = 0.3;

                                        for (int i = 2; i >= 0; i--)
                                        {
                                            int radius = sr + i * factor;
                                            graph.FillEllipse(b, scx - radius, scy - (int)(heightFactor * .7 * radius), 2 * radius,
                                                              (int)(2 * heightFactor * radius));
                                        }
                                    }

                                    graph.DrawImage(bmpBackground, 0, 0, defaultSizeOfTemplates, defaultSizeOfTemplates);

                                    for (int i = 0; i < bmpBackground.Width; i++)
                                    {
                                        for (int j = 0; j < bmpBackground.Height; j++)
                                        {
                                            Color bc = bmpBackground.GetPixel(i, j);
                                            if (bc.A > 0)
                                            {
                                                var cl = bmpMask.GetPixel(i, j);
                                                int r  = cl.R;
                                                int g  = cl.G;
                                                int b  = cl.B;
                                                for (int m = 0; m < Species.ColorRegionCount; m++)
                                                {
                                                    if (!enabledColorRegions[m] || colorIds[m] == 0)
                                                    {
                                                        continue;
                                                    }
                                                    switch (m)
                                                    {
                                                    case 0:
                                                        o = Math.Max(0, r - g - b) / 255f;
                                                        break;

                                                    case 1:
                                                        o = Math.Max(0, g - r - b) / 255f;
                                                        break;

                                                    case 2:
                                                        o = Math.Max(0, b - r - g) / 255f;
                                                        break;

                                                    case 3:
                                                        o = Math.Min(g, b) / 255f;
                                                        break;

                                                    case 4:
                                                        o = Math.Min(r, g) / 255f;
                                                        break;

                                                    case 5:
                                                        o = Math.Min(r, b) / 255f;
                                                        break;
                                                    }

                                                    if (o == 0)
                                                    {
                                                        continue;
                                                    }
                                                    // using "grain merge", e.g. see https://docs.gimp.org/en/gimp-concepts-layer-modes.html
                                                    int rMix = bc.R + rgb[m][0] - 128;
                                                    if (rMix < 0)
                                                    {
                                                        rMix = 0;
                                                    }
                                                    else if (rMix > 255)
                                                    {
                                                        rMix = 255;
                                                    }
                                                    int gMix = bc.G + rgb[m][1] - 128;
                                                    if (gMix < 0)
                                                    {
                                                        gMix = 0;
                                                    }
                                                    else if (gMix > 255)
                                                    {
                                                        gMix = 255;
                                                    }
                                                    int bMix = bc.B + rgb[m][2] - 128;
                                                    if (bMix < 0)
                                                    {
                                                        bMix = 0;
                                                    }
                                                    else if (bMix > 255)
                                                    {
                                                        bMix = 255;
                                                    }
                                                    Color c = Color.FromArgb(rMix, gMix, bMix);
                                                    bc = Color.FromArgb(bc.A, (int)(o * c.R + (1 - o) * bc.R),
                                                                        (int)(o * c.G + (1 - o) * bc.G), (int)(o * c.B + (1 - o) * bc.B));
                                                }

                                                bmpCreature.SetPixel(i, j, bc);
                                            }
                                        }
                                    }

                                    imageFine = true;
                                }
                                catch
                                {
                                    // error during drawing, maybe mask is smaller than image
                                }
                            }
                            if (imageFine)
                            {
                                if (!Directory.Exists(cacheFolder))
                                {
                                    Directory.CreateDirectory(cacheFolder);
                                }
                                bmpCreature.Save(cacheFileName); // safe in cache}
                            }
                        }
            }

            bool cacheFileExists = File.Exists(cacheFileName);

            if (onlyImage && !cacheFileExists)
            {
                return(null);
            }

            Bitmap bm = new Bitmap(size, size);

            using (Graphics graph = Graphics.FromImage(bm))
            {
                graph.SmoothingMode = SmoothingMode.AntiAlias;
                if (cacheFileExists)
                {
                    graph.CompositingMode    = CompositingMode.SourceCopy;
                    graph.CompositingQuality = CompositingQuality.HighQuality;
                    graph.InterpolationMode  = InterpolationMode.HighQualityBicubic;
                    graph.SmoothingMode      = SmoothingMode.HighQuality;
                    graph.PixelOffsetMode    = PixelOffsetMode.HighQuality;
                    graph.DrawImage(new Bitmap(cacheFileName), 0, 0, size, size);
                }
                else
                {
                    // draw piechart
                    int pieAngle = enabledColorRegions.Count(c => c);
                    pieAngle = 360 / (pieAngle > 0 ? pieAngle : 1);
                    int pieNr = 0;
                    for (int c = 0; c < Species.ColorRegionCount; c++)
                    {
                        if (enabledColorRegions[c])
                        {
                            if (colorIds[c] > 0)
                            {
                                using (var b = new SolidBrush(CreatureColors.CreatureColor(colorIds[c])))
                                {
                                    graph.FillPie(b, (size - pieSize) / 2, (size - pieSize) / 2, pieSize, pieSize,
                                                  pieNr * pieAngle + 270, pieAngle);
                                }
                            }

                            pieNr++;
                        }
                    }

                    using (var pen = new Pen(Color.Gray))
                        graph.DrawEllipse(pen, (size - pieSize) / 2, (size - pieSize) / 2, pieSize, pieSize);
                }
            }

            return(bm);
        }