/// <summary>
        ///     Calculates the trickled influence.
        /// </summary>
        /// now iterate over the classification tree in preorder, bringing down accumulated influence from parent to highest influence child
        /// also fill the _pickedInfluencesCache with nodes with non zero influence and no child nodes with non zero influence
        /// <param name="initialDict">The initial dictionary.</param>
        private static void CalculateTrickledInfluence([NotNull] Dictionary <AnimalClassBase, float> initialDict)
        {
            _pickedInfluencesCache.Clear();
            _trickleCache.Clear();
            foreach (AnimalClassBase animalClass in PreorderTreeInternal)
            {
                AnimalClassBase hChild            = null;
                float           maxInfluence      = 0;
                float           trickleDownAmount = initialDict.TryGetValue(animalClass);
                if (animalClass.ParentClass != null)
                {
                    trickleDownAmount +=
                        _trickleCache.TryGetValue(animalClass); //add in any amount the parent chose to give this node
                }
                foreach (AnimalClassBase child in animalClass.Children)
                {
                    float cInf = _accumInfluenceCache[child];
                    if (cInf > maxInfluence)
                    {
                        hChild       = child;
                        maxInfluence = cInf;
                    }
                }

                if (hChild != null)
                {
                    _trickleCache[hChild] = trickleDownAmount;
                }
                else if (trickleDownAmount > 0)
                {
                    _pickedInfluencesCache
                    .Add(animalClass);    //if there are no children or none have non zero influences pick this node
                }
            }
        }
예제 #2
0
        private static MorphDef GetChimeraRace([CanBeNull] AnimalClassBase hInfluence)
        {
            if (hInfluence == null)
            {
                return(MorphCategoryDefOf.Chimera.AllMorphsInCategories.RandomElement());
            }

            var morph = hInfluence as MorphDef;

            //if the highest influence isn't a morph pick a random morph from the animal class
            morph = morph ?? ((AnimalClassDef)hInfluence).GetAllMorphsInClass().RandomElementWithFallback();
            if (morph.categories.Contains(MorphCategoryDefOf.Canid)) //TODO use the classes of these not the categories
            {
                return(MorphDefOfs.ChaofoxMorph);
            }
            if (morph.categories.Contains(MorphCategoryDefOf.Reptile))
            {
                return(MorphDefOfs.ChaodinoMorph);
            }
            if (morph == MorphDefOfs.BoomalopeMorph)
            {
                return(MorphDefOfs.ChaoboomMorph);
            }
            if (morph == MorphDefOfs.CowMorph)
            {
                return(MorphDefOfs.ChaocowMorph);
            }

            return(MorphCategoryDefOf.Chimera.AllMorphsInCategories.RandomElement());
        }
예제 #3
0
        /// <summary> Add mutations to the given part. </summary>
        private void AddMutationToPart(BodyPartRecord record, [NotNull] Pawn pawn, AnimalClassBase aClass = null, bool recursive = false, MutagenDef mutagen = null)
        {
            MutationDef mutation;

            if (aClass != null)
            {
                mutation = aClass?.GetAllMorphsInClass()
                           .SelectMany(m => m.GetMutationForPart(record.def))
                           .RandomElementWithFallback();
            }
            else
            {
                mutation = MutationUtilities.GetMutationsByPart(record.def).RandomElementWithFallback();
            }

            if (mutation != null)
            {
                MutationUtilities.AddMutation(pawn, mutation, record);
            }

            mutagen?.TryApplyAspects(pawn);

            if (recursive) // Recursively add mutations to child parts.
            {
                foreach (BodyPartRecord cPart in record.GetDirectChildParts())
                {
                    AddMutationToPart(cPart, pawn, aClass, true, mutagen);
                }
            }
        }
        public static IEnumerable <MorphDef> GetAllMorphsInClass([NotNull] this AnimalClassBase classDef)
        {
            if (classDef == null)
            {
                throw new ArgumentNullException(nameof(classDef));
            }

            if (_morphsUnderCache.TryGetValue(classDef, out List <MorphDef> morphs))
            {
                return(morphs);
            }
            morphs = new List <MorphDef>();

            if (classDef is MorphDef morph)
            {
                morphs.Add(morph);
                _morphsUnderCache[classDef] = morphs;
                return(morphs);
            }

            IEnumerable <AnimalClassBase> preorder = TreeUtilities.Preorder(classDef, c => c.Children);

            foreach (MorphDef morphDef in preorder.OfType <MorphDef>())
            {
                morphs.Add(morphDef);
            }
            _morphsUnderCache[classDef] = morphs;
            return(morphs);
        }
예제 #5
0
 /// <summary>
 /// Determines whether this instance contains the object.
 /// </summary>
 /// <param name="aClass">a class.</param>
 /// <returns>
 ///   <c>true</c> if contains the specified a class; otherwise, <c>false</c>.
 /// </returns>
 public override bool Contains(AnimalClassBase aClass)
 {
     if (aClass == this)
     {
         return(true);
     }
     return
         (_subClasses.Any(c => c == aClass || c.Contains(aClass))); //check if any of the children are a type or contain it
 }
예제 #6
0
        IEnumerable <MutationDef> GetAllAssociatedMutations()
        {
            var restrictionSet = new HashSet <MutationDef>();

            var                set        = new HashSet <(BodyPartDef bodyPart, MutationLayer layer)>();
            AnimalClassBase    curNode    = this;
            List <MutationDef> tmpList    = new List <MutationDef>();
            var                tmpSiteLst = new List <(BodyPartDef bodyPart, MutationLayer layer)>();

            while (curNode != null)
            {
                restrictionSet.AddRange(curNode.MutationExclusionList);

                tmpList.Clear();
                foreach (MutationDef mutation in MutationDef.AllMutations) //grab all mutations that give the current influence directly
                {
                    if (restrictionSet.Contains(mutation))
                    {
                        continue;
                    }
                    if (curNode != this && mutation.IsRestricted && !allowAllRestrictedParts)
                    {
                        continue; //do not allow restricted parts for higher up in the hierarchy to show up unless allowAllRestrictedParts is set to true
                    }

                    if (mutation.classInfluence == curNode)
                    {
                        tmpList.Add(mutation);
                    }
                }

                foreach (MutationDef mutationDef in tmpList)
                {
                    tmpSiteLst.Clear();
                    tmpSiteLst.AddRange(mutationDef.GetAllDefMutationSites());
                    bool shouldReject = true;
                    foreach (var entry in tmpSiteLst)
                    {
                        if (!set.Contains(entry))
                        {
                            shouldReject = false;
                            break;
                        }
                    }

                    if (!shouldReject) //if there are any free slots yield the mutation
                    {
                        set.AddRange(tmpSiteLst);
                        yield return(mutationDef);
                    }
                }


                curNode = curNode.ParentClass; //move up one in the hierarchy
            }
        }
        public static IEnumerable <MutationDef> GetAllMutationIn([NotNull] this AnimalClassBase animalClass)
        {
            if (animalClass == null)
            {
                throw new ArgumentNullException(nameof(animalClass));
            }
            if (animalClass is AnimalClassDef aClass)
            {
                return(GetAllMutationIn(aClass));
            }

            if (animalClass is MorphDef morph)
            {
                return(morph.AllAssociatedMutations);
            }

            throw new NotImplementedException($"{animalClass.GetType().Name}");
        }
예제 #8
0
        IEnumerable <MutationDef> GetAllAssociatedMutations()
        {
            var                set     = new HashSet <VTuple <BodyPartDef, MutationLayer> >();
            AnimalClassBase    curNode = this;
            List <MutationDef> tmpList = new List <MutationDef>();
            List <VTuple <BodyPartDef, MutationLayer> > tmpSiteLst = new List <VTuple <BodyPartDef, MutationLayer> >();

            while (curNode != null)
            {
                tmpList.Clear();
                foreach (MutationDef mutation in MutationDef.AllMutations) //grab all mutations that give the current influence directly
                {
                    if (mutation.classInfluence == curNode)
                    {
                        tmpList.Add(mutation);
                    }
                }

                foreach (MutationDef mutationDef in tmpList)
                {
                    tmpSiteLst.Clear();
                    tmpSiteLst.AddRange(mutationDef.GetAllDefMutationSites());
                    bool shouldReject = true;
                    foreach (VTuple <BodyPartDef, MutationLayer> vTuple in tmpSiteLst)
                    {
                        if (!set.Contains(vTuple))
                        {
                            shouldReject = false;
                            break;
                        }
                    }

                    if (!shouldReject) //if there are any free slots yield the mutation
                    {
                        set.AddRange(tmpSiteLst);
                        yield return(mutationDef);
                    }
                }


                curNode = curNode.ParentClass; //move up one in the hierarchy
            }
        }
예제 #9
0
        private static MorphDef GetMorphForPawn(Pawn pawn, bool isBelowChimeraThreshold, AnimalClassBase hInfluence, out MorphDef curMorph)
        {
            MorphDef setMorph;

            curMorph = pawn.def.GetMorphOfRace();
            try
            {
                Rand.PushState(pawn.thingIDNumber); // make sure this is deterministic for each pawn

                if (isBelowChimeraThreshold)        //if they'er below turn them into a chimera
                {
                    setMorph = GetChimeraRace(hInfluence);
                }
                else
                {
                    setMorph = hInfluence as MorphDef;
                }
            }
            finally
            {
                Rand.PopState();
            }

            return(setMorph);
        }
예제 #10
0
 /// <summary>
 ///     Determines whether this instance contains the object.
 /// </summary>
 /// <param name="other">The other.</param>
 /// <returns>
 ///     <c>true</c> if [contains] [the specified other]; otherwise, <c>false</c>.
 /// </returns>
 public override bool Contains(AnimalClassBase other)
 {
     return(other == this);
 }
        /// <summary>
        /// Generates  debug information on how part influences are calculated.
        /// </summary>
        /// <param name="mutations">The mutations.</param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException">mutations</exception>
        public static string GenerateDebugInfo([NotNull] IEnumerable <Hediff_AddedMutation> mutations)
        {
            if (mutations == null)
            {
                throw new ArgumentNullException(nameof(mutations));
            }
            var mutationList = mutations.ToList();
            Dictionary <AnimalClassBase, float> endDict = new Dictionary <AnimalClassBase, float>();
            StringBuilder builder = new StringBuilder();


            //header

            builder.AppendLine("Mutations:");

            foreach (Hediff_AddedMutation mutation in mutationList)
            {
                AnimalClassBase inf = mutation.Influence;
                builder.AppendLine($"|\t{mutation.def.defName}:{inf.defName }");
                var i = endDict.TryGetValue(inf);
                i           += 1;
                endDict[inf] = i;
            }

            builder.AppendLine("Initial Influences:");

            //raw dict
            foreach (KeyValuePair <AnimalClassBase, float> kvp in endDict)
            {
                builder.AppendLine($"|\t{kvp.Key.defName}:{kvp.Value}");
            }

            CalculateAccumulatedInfluence(endDict);

            builder.AppendLine("Accumulation Cache");
            foreach (KeyValuePair <AnimalClassBase, float> kvp in _accumInfluenceCache)
            {
                builder.AppendLine($"|\t{kvp.Key.defName}:{kvp.Value}");
            }

            //trickle down
            CalculateTrickledInfluence(endDict);
            builder.AppendLine("Trickle down cache");
            foreach (KeyValuePair <AnimalClassBase, float> kvp in _trickleCache)
            {
                builder.AppendLine($"|\t{kvp.Key.defName}:{kvp.Value}");
            }

            foreach (AnimalClassBase animalClass in _pickedInfluencesCache) //now calculate the final values
            {
                endDict[animalClass] = _trickleCache.TryGetValue(animalClass) + endDict.TryGetValue(animalClass);
            }

            builder.AppendLine($"End Amounts");


            foreach (KeyValuePair <AnimalClassBase, float> kvp in endDict)
            {
                builder.AppendLine($"|\t{kvp.Key.defName}:{kvp.Value}");
            }

            return(builder.ToString());
        }
예제 #12
0
 /// <summary>
 /// Determines whether this instance contains the given class.
 /// </summary>
 /// <param name="aClass">a class.</param>
 /// <returns>
 ///   <c>true</c> if contains the specified a class; otherwise, <c>false</c>.
 /// </returns>
 public abstract bool Contains([NotNull] AnimalClassBase aClass);
예제 #13
0
        private static MorphDef GetMorphForPawn(Pawn pawn, bool isBelowChimeraThreshold, AnimalClassBase hInfluence, out MorphDef curMorph)
        {
            MorphDef setMorph;

            curMorph = pawn.def.GetMorphOfRace();
            try
            {
                Rand.PushState(pawn.thingIDNumber); // make sure this is deterministic for each pawn

                if (isBelowChimeraThreshold)        //if they'er below turn them into a chimera
                {
                    setMorph = GetChimeraRace(hInfluence);
                }
                else
                {
                    setMorph = hInfluence as MorphDef;
                    //if the highest influence isn't a morph just set it to a random morph in that class
                    setMorph = setMorph ?? ((AnimalClassDef)hInfluence).GetAllMorphsInClass().RandomElementWithFallback();
                }
            }
            finally
            {
                Rand.PopState();
            }

            return(setMorph);
        }