/// <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 } } }
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()); }
/// <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); }
/// <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 }
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}"); }
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 } }
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); }
/// <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()); }
/// <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);
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); }