private List <int> GetStagesForAspect([NotNull] AspectDef aspectDef)
        {
            if (_lookupDict == null)
            {
                _lookupDict = new Dictionary <AspectDef, List <int> >();
                foreach (Entry aspectEntry in aspectEntries)
                {
                    if (aspectEntry.aspectDef == null)
                    {
                        continue;
                    }

                    List <int> lst;
                    if (!_lookupDict.TryGetValue(aspectEntry.aspectDef, out lst))
                    {
                        lst = new List <int>();
                        _lookupDict[aspectEntry.aspectDef] = lst;
                    }

                    lst.Add(aspectEntry.stageIndex);
                }
            }

            return(_lookupDict.TryGetValue(aspectDef));
        }
Example #2
0
        private static void ApplyAspects(Pawn pawn, MorphPawnKindExtension extension)
        {
            if (pawn.GetAspectTracker() == null)
            {
                return;
            }
            if (extension.aspects.Count == 0)
            {
                return;
            }

            int addAspect = extension.aspectRange.RandomInRange;

            if (addAspect == 0)
            {
                return;
            }

            AspectTracker aspectTracker = pawn.GetAspectTracker();

            if (aspectTracker == null)
            {
                return;
            }

            List <AspectDef> availableAspects = extension.GetAllAspectDefs().ToList();

            addAspect = Mathf.Min(availableAspects.Count - 1, addAspect);

            if (addAspect == availableAspects.Count - 1)
            {
                foreach (AspectDef aspectDef in availableAspects)
                {
                    int stage = extension.GetAvailableStagesFor(aspectDef).RandomElementWithFallback();
                    aspectTracker.Add(aspectDef, stage);
                }

                return;
            }


            for (var i = 0; i < addAspect; i++)
            {
                int       r     = Rand.Range(0, availableAspects.Count); //pick a random entry
                AspectDef def   = availableAspects[r];
                int       stage = extension.GetAvailableStagesFor(def).RandomElementWithFallback();
                aspectTracker.Add(def, stage);
                availableAspects.RemoveAt(r); //remove it so we don't pick it twice
            }
        }
Example #3
0
        private List <DebugMenuOption> GetAddAspectOptions(AspectDef def, Pawn p)
        {
            var outLst = new List <DebugMenuOption>();

            for (var i = 0; i < def.stages.Count; i++)
            {
                AspectStage stage = def.stages[i];
                int         i1    = i; //need to make a copy
                var         label = string.IsNullOrEmpty(stage.label) ? def.label : stage.label;
                outLst.Add(new DebugMenuOption($"{i}) {label}", DebugMenuOptionMode.Action,
                                               () => AddAspectAtStage(def, p, i1)));
            }

            return(outLst);
        }
Example #4
0
        private List <DebugMenuOption> GetAddAspectOptions(Pawn pawn)
        {
            AspectTracker tracker = pawn.GetAspectTracker();
            var           outLst  = new List <DebugMenuOption>();

            foreach (AspectDef aspectDef in DefDatabase <AspectDef> .AllDefs.Where(d => !tracker.Contains(d))
                     ) //don't allow aspects to be added more then once
            {
                AspectDef tmpDef = aspectDef;

                outLst.Add(new DebugMenuOption($"{aspectDef.defName}", DebugMenuOptionMode.Action,
                                               () =>
                                               Find.WindowStack
                                               .Add(new Dialog_DebugOptionListLister(GetAddAspectOptions(tmpDef,
                                                                                                         pawn)))));
            }

            return(outLst);
        }
Example #5
0
        /// <summary>
        /// safely change the pawns race
        /// </summary>
        /// <param name="pawn"></param>
        /// <param name="race"></param>
        /// <param name="reRollTraits">if race related traits should be reRolled</param>
        public static void ChangePawnRace([NotNull] Pawn pawn, ThingDef race, bool reRollTraits = false)
        {
            if (pawn == null)
            {
                throw new ArgumentNullException(nameof(pawn));
            }
            MorphDef oldMorph = pawn.def.GetMorphOfRace();
            ThingDef oldRace  = pawn.def;

            AspectTracker aTracker = pawn.GetAspectTracker();

            AspectDef oldMorphAspectDef = oldMorph?.group?.aspectDef;

            if (oldMorphAspectDef != null && aTracker != null)
            {
                Aspect aspect = aTracker.GetAspect(oldMorphAspectDef);
                if (aspect != null)
                {
                    aTracker.Remove(aspect);
                }
            }

            //var pos = pawn.Position;
            Faction faction = pawn.Faction;
            Map     map     = pawn.Map;

            if (map != null)
            {
                RegionListersUpdater.DeregisterInRegions(pawn, map);
            }
            var removed = false;

            if (map != null)
            {
                if (map.listerThings.Contains(pawn))
                {
                    map.listerThings.Remove(pawn); //make sure to update the lister things or else dying will break
                    removed = true;
                }
            }

            pawn.def = race;

            if (removed && !map.listerThings.Contains(pawn))
            {
                map.listerThings.Add(pawn);
            }

            if (map != null)
            {
                RegionListersUpdater.RegisterInRegions(pawn, map);
            }

            map?.mapPawns.UpdateRegistryForPawn(pawn);

            //add the group hediff if applicable
            AspectDef aspectDef = race.GetMorphOfRace()?.group?.aspectDef;

            if (aspectDef != null)
            {
                aTracker?.Add(aspectDef);
            }

            if (map != null)
            {
                var comp = map.GetComponent <MorphTracker>();
                comp.NotifyPawnRaceChanged(pawn, oldMorph);
            }

            //no idea what HarmonyPatches.Patch.ChangeBodyType is for, not listed in pasterbin
            pawn.RefreshGraphics();

            if (reRollTraits && race is ThingDef_AlienRace alienDef)
            {
                ReRollRaceTraits(pawn, alienDef);
            }

            //save location
            if (Current.ProgramState == ProgramState.Playing)
            {
                pawn.ExposeData();
            }
            if (pawn.Faction != faction)
            {
                pawn.SetFaction(faction);
            }
            foreach (IRaceChangeEventReceiver raceChangeEventReceiver in pawn.AllComps.OfType <IRaceChangeEventReceiver>())
            {
                raceChangeEventReceiver.OnRaceChange(oldRace);
            }
        }
Example #6
0
 private void AddAspectAtStage(AspectDef def, Pawn p, int i)
 {
     p.GetAspectTracker()?.Add(def, i);
 }
        /// <summary>
        /// safely change the pawns race
        /// </summary>
        /// <param name="pawn">The pawn.</param>
        /// <param name="race">The race.</param>
        /// <param name="reRollTraits">if race related traits should be reRolled</param>
        /// <exception cref="ArgumentNullException">pawn</exception>
        public static void ChangePawnRace([NotNull] Pawn pawn, [NotNull] ThingDef race, bool reRollTraits = false)
        {
            if (pawn == null)
            {
                throw new ArgumentNullException(nameof(pawn));
            }
            if (race == null)
            {
                throw new ArgumentNullException(nameof(race));
            }
            MorphDef oldMorph = pawn.def.GetMorphOfRace();
            ThingDef oldRace  = pawn.def;

            AspectTracker aTracker = pawn.GetAspectTracker();

            AspectDef oldMorphAspectDef = oldMorph?.group?.aspectDef;

            if (oldMorphAspectDef != null && aTracker != null)
            {
                Aspect aspect = aTracker.GetAspect(oldMorphAspectDef);
                if (aspect != null)
                {
                    aTracker.Remove(aspect);
                }
            }

            TransformerUtility.ScaleInjuriesToNewRace(pawn, race);

            //var pos = pawn.Position;
            Faction faction = pawn.Faction;
            Map     map     = pawn.Map;

            if (map != null)
            {
                RegionListersUpdater.DeregisterInRegions(pawn, map);
            }
            var removed = false;

            if (map?.listerThings != null)
            {
                if (map.listerThings.Contains(pawn))
                {
                    map.listerThings.Remove(pawn); //make sure to update the lister things or else dying will break
                    removed = true;
                }
            }

            pawn.def = race;

            if (removed && !map.listerThings.Contains(pawn))
            {
                map.listerThings.Add(pawn);
            }

            if (map != null)
            {
                RegionListersUpdater.RegisterInRegions(pawn, map);
            }

            map?.mapPawns.UpdateRegistryForPawn(pawn);

            //add the group hediff if applicable
            AspectDef aspectDef = race.GetMorphOfRace()?.group?.aspectDef;

            if (aspectDef != null)
            {
                aTracker?.Add(aspectDef);
            }

            if (map != null)
            {
                var comp = map.GetComponent <MorphTracker>();
                comp.NotifyPawnRaceChanged(pawn, oldMorph);
            }


            //always revert to human settings first so the race change is consistent
            ValidateReversion(pawn);

            //check if the body def changed and handle any apparel changes
            if (oldRace.race.body != race.race.body)
            {
                ValidateApparelForChangedPawn(pawn, oldRace);
            }


            if (race != ThingDefOf.Human)
            {
                ValidateExplicitRaceChange(pawn, race, oldRace);
            }

            var mTracker = pawn.GetComp <MorphTrackingComp>();

            if (mTracker == null)
            {
                Warning($"changing the race of {pawn.Name} but they have no {nameof(MorphTrackingComp)}!");
            }
            else
            {
                mTracker.needsRaceCompCheck = true;
            }

            //no idea what HarmonyPatches.Patch.ChangeBodyType is for, not listed in pasterbin
            pawn.RefreshGraphics();

            if (reRollTraits && race is ThingDef_AlienRace alienDef)
            {
                ReRollRaceTraits(pawn, alienDef);
            }

            //save location
            if (Current.ProgramState == ProgramState.Playing)
            {
                pawn.ExposeData();
            }
            if (pawn.Faction != faction)
            {
                pawn.SetFaction(faction);
            }
            foreach (IRaceChangeEventReceiver raceChangeEventReceiver in pawn.AllComps.OfType <IRaceChangeEventReceiver>())
            {
                raceChangeEventReceiver.OnRaceChange(oldRace);
            }
        }