private static void ApplyHumanLeatherScoring(Pawn pawn, Thing apparel, ref float score) { if (apparel.Stuff != ThingDefOf.Human.race.leatherDef) { return; } if (ThoughtUtility.CanGetThought_NewTemp(pawn, ThoughtDefOf.HumanLeatherApparelSad)) { #if DEBUG Log.Message("OutfitManager: Penalizing human leather apparel", true); #endif score -= HumanLeatherScorePenalty; if (score > 0f) { score *= HumanLeatherScoreFactor; } } if (ThoughtUtility.CanGetThought_NewTemp(pawn, ThoughtDefOf.HumanLeatherApparelHappy)) { #if DEBUG Log.Message("OutfitManager: Promoting human leather apparel", true); #endif score += HumanLeatherScoreBonus; } }
public static Thought_Memory GetSubstitute([NotNull] this Thought_Memory memory, [NotNull] Pawn pawn) { IEnumerable <ThoughtGroupDefExtension> tGroups = memory.def.modExtensions.MakeSafe().OfType <ThoughtGroupDefExtension>(); foreach (ThoughtDef thoughtDef in tGroups.SelectMany(g => g.thoughts)) { if (ThoughtUtility.CanGetThought_NewTemp(pawn, thoughtDef)) { int forcedStage = Mathf.Min(memory.CurStageIndex, thoughtDef.stages.Count - 1); if (forcedStage != memory.CurStageIndex) { Log.Warning($"in memory {memory.def.defName}, substituted thought {thoughtDef.defName} does not the same number of stages\noriginal:{memory.def.stages.Count} sub:{thoughtDef.stages.Count}"); } Thought_Memory newMemory = ThoughtMaker.MakeThought(thoughtDef, forcedStage); if (newMemory == null) { Log.Error($"in thought {memory.def.defName} group, thought {thoughtDef.defName} is not a memory"); continue; } return(newMemory); } } return(memory); }
public static bool TryGainMemory(MemoryThoughtHandler __instance, Thought_Memory newThought, Pawn otherPawn = null) { if (!ThoughtUtility.CanGetThought_NewTemp(__instance.pawn, newThought.def)) { return(false); } if (newThought is Thought_MemorySocial && newThought.otherPawn == null && otherPawn == null) { Log.Error(string.Concat("Can't gain social thought ", newThought.def, " because its otherPawn is null and otherPawn passed to this method is also null. Social thoughts must have otherPawn.")); return(false); } newThought.pawn = __instance.pawn; newThought.otherPawn = otherPawn; if (!newThought.TryMergeWithExistingMemory(out bool showBubble)) { lock (__instance) { List <Thought_Memory> newMemories = new List <Thought_Memory>(__instance.Memories) { newThought }; memoriesFieldRef(__instance) = newMemories; } } if (newThought.def.stackLimitForSameOtherPawn >= 0) { while (__instance.NumMemoriesInGroup(newThought) > newThought.def.stackLimitForSameOtherPawn) { __instance.RemoveMemory(__instance.OldestMemoryInGroup(newThought)); } } if (newThought.def.stackLimit >= 0) { while (__instance.NumMemoriesOfDef(newThought.def) > newThought.def.stackLimit) { __instance.RemoveMemory(__instance.OldestMemoryOfDef(newThought.def)); } } if (newThought.def.thoughtToMake != null) { __instance.TryGainMemory(newThought.def.thoughtToMake, newThought.otherPawn); } if (showBubble && newThought.def.showBubble && __instance.pawn.Spawned && PawnUtility.ShouldSendNotificationAbout(__instance.pawn)) { MoteMaker.MakeMoodThoughtBubble(__instance.pawn, newThought); } return(false); }
/// <summary> /// Try to give this pawn a new memory. <br /> /// If pawn does not have needs/mood/thoughts ect this call does nothing. /// </summary> /// <param name="pawn">The pawn.</param> /// <param name="thought">The thought.</param> /// <param name="otherPawn">The other pawn.</param> /// <param name="respectTraits">if ThoughtUtility.CanGetThought should be checked before giving the thought</param> /// <exception cref="ArgumentNullException">pawn</exception> public static void TryGainMemory([NotNull] this Pawn pawn, Thought_Memory thought, Pawn otherPawn = null, bool respectTraits = true) //move extension methods elsewhere? { if (pawn == null) { throw new ArgumentNullException(nameof(pawn)); } if (respectTraits && !ThoughtUtility.CanGetThought_NewTemp(pawn, thought.def)) { return; } pawn.needs?.mood?.thoughts?.memories?.TryGainMemory(thought, otherPawn); }
public static ThoughtDef GetSubstitute([NotNull] this ThoughtDef def, [NotNull] Pawn pawn) { IEnumerable <ThoughtGroupDefExtension> tGroups = def.modExtensions.MakeSafe().OfType <ThoughtGroupDefExtension>(); foreach (ThoughtDef thoughtDef in tGroups.SelectMany(g => g.thoughts)) { if (ThoughtUtility.CanGetThought_NewTemp(pawn, thoughtDef)) //take the first one that matches { return(thoughtDef); } } //no matches found return(def); }
private static void ApplyTaintedScoring(Pawn pawn, Apparel apparel, ExtendedOutfit outfit, ref float score) { if (!outfit.PenalizeTaintedApparel || !apparel.WornByCorpse || !ThoughtUtility.CanGetThought_NewTemp(pawn, ThoughtDefOf.DeadMansApparel)) { return; } #if DEBUG Log.Message("OutfitManager: Penalizing tainted apparel", true); #endif score -= TaintedApparelScorePenalty; if (score > 0f) { score *= TaintedApparelScoreFactor; } }
private static void CanGetThoughtPostfix([NotNull] Pawn pawn, [NotNull] ThoughtDef def, ref bool __result) { var tracker = pawn.GetAspectTracker(); if (tracker != null) { foreach (Aspect aspect in tracker) { if (aspect.NullifiedThoughts.Contains(def)) { __result = false; break; } } } var tGroup = def.GetModExtension <ThoughtGroupDefExtension>(); if (tGroup != null && !__result) { //if the default thought is invalid and it has a thought group extension check if any of the specific thoughts are valid foreach (ThoughtDef tGroupThought in tGroup.thoughts) { if (tGroupThought.HasModExtension <ThoughtGroupDefExtension>()) { Log.Warning($"thought in {def.defName} has thought {tGroupThought.defName} with thought group extension! this is not currently supported as it may cause infinite recursion"); continue; } if (ThoughtUtility.CanGetThought_NewTemp(pawn, tGroupThought)) { __result = true; return; } } } if (__result) { __result = def.IsValidFor(pawn); } }
HandleRelatedPawnsReaction(Pawn original, Pawn animalPawn, EventType type) //use PotentiallyRelatedPawns to get all relationships not DirectRelations for some reason { foreach (Pawn pReactor in original.relations.PotentiallyRelatedPawns) { if (pReactor == animalPawn) { continue; //make sure pawns don't react to themselves as if it were a different pawn } if (pReactor == original) { continue; } if (pReactor.needs?.mood == null) { continue; } PawnRelationDef importantRelation = pReactor.GetMostImportantRelation(original); var modExt = importantRelation?.GetModExtension <RelationshipDefExtension>(); if (modExt != null) { ThoughtDef thought = modExt.GetThoughtDef(type, original.gender); if (thought == null) { Log.Warning($"relation {importantRelation.defName} has (Pawnmorpher) extension but no thought for {type}, is this intentional?"); continue; } if (ThoughtUtility.CanGetThought_NewTemp(pReactor, thought)) { pReactor.TryGainMemory(thought); } } } //TODO handle bond animal reverted? }
private static Thought_SituationalSocial TryCreateSocialThought(SituationalThoughtHandler __instance, ThoughtDef def, Pawn otherPawn) { Thought_SituationalSocial situationalSocial = null; try { if (!ThoughtUtility.CanGetThought_NewTemp(__instance.pawn, def, false) || !def.Worker.CurrentSocialState(__instance.pawn, otherPawn).ActiveFor(def)) { return(null); } situationalSocial = (Thought_SituationalSocial)ThoughtMaker.MakeThought(def); situationalSocial.pawn = __instance.pawn; situationalSocial.otherPawn = otherPawn; situationalSocial.RecalculateState(); } catch (Exception ex) { Log.Error("Exception while recalculating " + def + " thought state for pawn " + __instance.pawn + ": " + ex, false); } return(situationalSocial); }
private void TryAddMemory(Pawn pawn, ThoughtDef memory) { ThoughtHandler thoughts = pawn.needs?.mood?.thoughts; if (thoughts == null) { return; } if (!ThoughtUtility.CanGetThought_NewTemp(pawn, memory)) { return; } var counter = 0; int max = PMUtilities.GetSettings().maxMutationThoughts; if (!ignoreThoughtLimit) { foreach (Thought_Memory thought in thoughts.memories.Memories) { if (MutationUtilities.AllMutationMemories.Contains(thought.def)) { counter++; } counter++; if (counter >= max) { return; //make sure to only add so many thoughts at once } } } pawn.TryGainMemory(memory); }
public float ApparelScoreRaw([NotNull] Apparel ap) { if (RawScoreDict.ContainsKey(ap)) { return(RawScoreDict[ap]); } // only allow shields to be considered if a primary weapon is equipped and is melee var thisPawn = _pawn; if (ap.def.thingClass == typeof(ShieldBelt) && thisPawn.equipment.Primary?.def.IsRangedWeapon == true) { return(-1f); } // Fail safe to prevent pawns get out of the regular temperature. // Might help making pawn drop equipped apparel if it's too cold/warm. // this.GetInsulationStats(ap, out float insulationCold, out float insulationHeat); // FloatRange temperatureRange = this.pawn.ComfortableTemperatureRange(); // if (ap.Wearer != thisPawn) // { // temperatureRange.min += insulationCold; // temperatureRange.max += insulationHeat; // } // if (temperatureRange.min > 12 && insulationCold > 0 || temperatureRange.max < 32 && insulationHeat < 0) // { // return -3f; // } // relevant apparel stats var entry = GetAllOffsets(ap); var statBases = entry.StatBases; var equippedOffsets = entry.EquippedOffsets; var infusedOffsets = entry.InfusedOffsets; // start score at 1 float score = 1; // add values for each statdef modified by the apparel var stats = thisPawn.GetApparelStatCache().StatCache; foreach (var statPriority in stats.Where(statPriority => statPriority != null)) { var stat = statPriority.Stat; if (statBases.Contains(stat)) { var apStat = ap.GetStatValue(stat); if (SpecialStats.Contains(stat)) { CalculateScoreForSpecialStats(ap, statPriority, thisPawn, apStat, ref score); } else { // add stat to base score before offsets are handled // (the pawn's apparel stat cache always has armors first as it is initialized with it). score += apStat * statPriority.Weight; } } // equipped offsets, e.g. movement speeds if (equippedOffsets.Contains(stat)) { var apStat = ap.GetEquippedStatValue(_pawn, stat); if (SpecialStats.Contains(stat)) { CalculateScoreForSpecialStats(ap, statPriority, thisPawn, apStat, ref score); } else { score += apStat * statPriority.Weight; } // multiply score to favour items with multiple offsets // score *= adjusted; // debug.AppendLine( statWeightPair.Key.LabelCap + ": " + score ); } // infusions if (!infusedOffsets.Contains(stat)) { continue; } // float statInfused = StatInfused(infusionSet, statPriority, ref dontcare); DoApparelScoreRaw_PawnStatsHandlers(ap, stat, out var statInfused); if (SpecialStats.Contains(stat)) { CalculateScoreForSpecialStats(ap, statPriority, thisPawn, statInfused, ref score); } else { // Bug with Infused and "Ancient", it completely kills the pawn's armor if (statInfused < 0 && (stat == StatDefOf.ArmorRating_Blunt || stat == StatDefOf.ArmorRating_Sharp)) { score = -2f; return(score); } score += statInfused * statPriority.Weight; } } score += ap.GetSpecialApparelScoreOffset(); score += ApparelScoreRaw_ProtectionBaseStat(ap); // offset for apparel hitpoints if (ap.def.useHitPoints) { var x = ap.HitPoints / (float)ap.MaxHitPoints; score *= ApparelStatsHelper.HitPointsPercentScoreFactorCurve.Evaluate(x); } if (ap.WornByCorpse && ThoughtUtility.CanGetThought_NewTemp(thisPawn, ThoughtDefOf.DeadMansApparel)) { score -= 0.5f; if (score > 0f) { score *= 0.1f; } } if (ap.Stuff == ThingDefOf.Human.race.leatherDef) { if (ThoughtUtility.CanGetThought_NewTemp(thisPawn, ThoughtDefOf.HumanLeatherApparelSad)) { score -= 0.5f; if (score > 0f) { score *= 0.1f; } } if (ThoughtUtility.CanGetThought_NewTemp(thisPawn, ThoughtDefOf.HumanLeatherApparelHappy)) { score *= 2f; } } score *= ApparelScoreRaw_Temperature(ap); RawScoreDict.Add(ap, score); return(score); }
public override void DoWindowContents(Rect inRect) { var conf = _pawn.GetApparelStatCache(); var conRect = new Rect(inRect); conRect.height -= 50f; BeginArea(conRect); // begin main group BeginVertical(); Label(GetTitle(), _headline); Text.Font = GameFont.Small; // GUI.BeginGroup(contentRect); var labelWidth = conRect.width - BaseValue - BaseValue - BaseValue - 48f; DrawLine("Status", labelWidth, "BaseMod", "Strength", "Score", _fontBold); Space(6f); Label(string.Empty, _whiteLine, Height(1)); Space(6f); var apparelEntry = conf.GetAllOffsets(_apparel); var equippedOffsets = apparelEntry.EquippedOffsets; var statBases = apparelEntry.StatBases; var infusedOffsets = apparelEntry.InfusedOffsets; _scrollPosition = BeginScrollView(_scrollPosition, Width(conRect.width)); // relevant apparel stats // start score at 1 float score = 1; // add values for each statdef modified by the apparel foreach (var statPriority in _pawn.GetApparelStatCache().StatCache .OrderBy(i => i.Stat.LabelCap)) { var stat = statPriority.Stat; string statLabel = stat.LabelCap; // statbases, e.g. armor // StatCache.DoApparelScoreRaw_PawnStatsHandlers(_pawn, _apparel, statPriority.Stat, ref currentStat); if (statBases.Contains(stat)) { var statValue = _apparel.GetStatValue(stat); var statScore = 0f; if (ApparelStatCache.SpecialStats.Contains(stat)) { ApparelStatCache.CalculateScoreForSpecialStats(_apparel, statPriority, _pawn, statValue, ref statScore); } else { // statValue += StatCache.StatInfused(infusionSet, statPriority, ref baseInfused); statScore = statValue * statPriority.Weight; } score += statScore; DrawLine( statLabel, labelWidth, statValue.ToStringPercent("N1"), statPriority.Weight.ToString("N2"), statScore.ToString("N2")); } if (equippedOffsets.Contains(stat)) { var statValue = _apparel.GetEquippedStatValue(_pawn, stat); // statValue += StatCache.StatInfused(infusionSet, statPriority, ref equippedInfused); var statScore = 0f; if (ApparelStatCache.SpecialStats.Contains(stat)) { ApparelStatCache.CalculateScoreForSpecialStats(_apparel, statPriority, _pawn, statValue, ref statScore); } else { statScore = statValue * statPriority.Weight; } score += statScore; DrawLine( statLabel, labelWidth, statValue.ToStringPercent("N1"), statPriority.Weight.ToString("N2"), statScore.ToString("N2")); } if (!infusedOffsets.Contains(stat)) { continue; } { GUI.color = Color.green; // new Color(0.5f, 1f, 1f, 1f); // float statInfused = StatCache.StatInfused(infusionSet, statPriority, ref dontcare); ApparelStatCache.DoApparelScoreRaw_PawnStatsHandlers(_apparel, stat, out var statValue); var flag = true; var statScore = 0f; if (ApparelStatCache.SpecialStats.Contains(stat)) { ApparelStatCache.CalculateScoreForSpecialStats(_apparel, statPriority, _pawn, statValue, ref statScore); } else { // Bug with Infused and "Ancient", it completely kills the pawn's armor if (statValue < 0 && (stat == StatDefOf.ArmorRating_Blunt || stat == StatDefOf.ArmorRating_Sharp)) { score = -2f; flag = false; } statScore = statValue * statPriority.Weight; } DrawLine( statLabel, labelWidth, statValue.ToStringPercent("N1"), statPriority.Weight.ToString("N2"), statScore.ToString("N2")); GUI.color = Color.white; if (flag) { score += statScore; } else { break; } } } GUI.color = Color.white; // end upper group EndScrollView(); // begin lower group FlexibleSpace(); Space(6f); Label(string.Empty, _whiteLine, Height(1)); Space(6f); DrawLine(string.Empty, labelWidth, "Modifier", string.Empty, "Subtotal"); DrawLine("BasicStatusOfApparel".Translate(), labelWidth, "1.00", "+", score.ToString("N2")); var special = _apparel.GetSpecialApparelScoreOffset(); if (Math.Abs(special) > 0f) { score += special; DrawLine( "OutfitterSpecialScore".Translate(), labelWidth, special.ToString("N2"), "+", score.ToString("N2")); } var armor = ApparelStatCache.ApparelScoreRaw_ProtectionBaseStat(_apparel); if (Math.Abs(armor) > 0.01f) { score += armor; DrawLine("OutfitterArmor".Translate(), labelWidth, armor.ToString("N2"), "+", score.ToString("N2")); } if (_apparel.def.useHitPoints) { // durability on 0-1 scale var x = _apparel.HitPoints / (float)_apparel.MaxHitPoints; score *= ApparelStatsHelper.HitPointsPercentScoreFactorCurve.Evaluate(x); DrawLine( "OutfitterHitPoints".Translate(), labelWidth, x.ToString("N2"), "weighted", score.ToString("N2")); GUI.color = Color.white; } if (_apparel.WornByCorpse && ThoughtUtility.CanGetThought_NewTemp(_pawn, ThoughtDefOf.DeadMansApparel)) { score -= 0.5f; if (score > 0f) { score *= 0.1f; } DrawLine( "OutfitterWornByCorpse".Translate(), labelWidth, "modified", "weighted", score.ToString("N2")); } if (_apparel.Stuff == ThingDefOf.Human.race.leatherDef) { if (ThoughtUtility.CanGetThought_NewTemp(_pawn, ThoughtDefOf.HumanLeatherApparelSad)) { score -= 0.5f; if (score > 0f) { score *= 0.1f; } } if (ThoughtUtility.CanGetThought_NewTemp(_pawn, ThoughtDefOf.HumanLeatherApparelHappy)) { score *= 2f; } DrawLine( "OutfitterHumanLeather".Translate(), labelWidth, "modified", "weighted", score.ToString("N2")); } var temperature = conf.ApparelScoreRaw_Temperature(_apparel); if (Math.Abs(temperature - 1f) > 0) { score *= temperature; DrawLine( "OutfitterTemperature".Translate(), labelWidth, temperature.ToString("N2"), "*", score.ToString("N2")); } DrawLine( "OutfitterTotal".Translate(), labelWidth, string.Empty, "=", conf.ApparelScoreRaw(_apparel).ToString("N2")); GUI.color = Color.white; Text.Anchor = TextAnchor.UpperLeft; // end main group EndVertical(); EndArea(); }
public static float ApparelScoreRaw(Pawn pawn, Apparel ap) { float num = 0.1f + ap.def.apparel.scoreOffset; float num2 = ap.GetStatValue(StatDefOf.ArmorRating_Sharp) + ap.GetStatValue(StatDefOf.ArmorRating_Blunt) + ap.GetStatValue(StatDefOf.ArmorRating_Heat); num += num2; if (ap.def.useHitPoints) { float x = (float)ap.HitPoints / (float)ap.MaxHitPoints; num *= HitPointsPercentScoreFactorCurve.Evaluate(x); } num += ap.GetSpecialApparelScoreOffset(); float num3 = 1f; //if (neededWarmth == NeededWarmth.Warm) //{ // float statValue = ap.GetStatValue(StatDefOf.Insulation_Cold); // num3 *= InsulationColdScoreFactorCurve_NeedWarm.Evaluate(statValue); //} num *= num3; if (ap.WornByCorpse && (pawn == null || ThoughtUtility.CanGetThought_NewTemp(pawn, ThoughtDefOf.DeadMansApparel, checkIfNullified: true))) { num -= 0.5f; if (num > 0f) { num *= 0.1f; } } if (ap.Stuff == ThingDefOf.Human.race.leatherDef) { if (pawn == null || ThoughtUtility.CanGetThought_NewTemp(pawn, ThoughtDefOf.HumanLeatherApparelSad, checkIfNullified: true)) { num -= 0.5f; if (num > 0f) { num *= 0.1f; } } if (pawn != null && ThoughtUtility.CanGetThought_NewTemp(pawn, ThoughtDefOf.HumanLeatherApparelHappy, checkIfNullified: true)) { num += 0.12f; } } if (pawn != null && !ap.def.apparel.CorrectGenderForWearing(pawn.gender)) { num *= 0.01f; } if (pawn != null && pawn.royalty != null && pawn.royalty.AllTitlesInEffectForReading.Count > 0) { tmpAllowedApparels.Clear(); tmpRequiredApparels.Clear(); tmpBodyPartGroupsWithRequirement.Clear(); QualityCategory qualityCategory = QualityCategory.Awful; foreach (RoyalTitle item in pawn.royalty.AllTitlesInEffectForReading) { if (item.def.requiredApparel != null) { for (int i = 0; i < item.def.requiredApparel.Count; i++) { tmpAllowedApparels.AddRange(item.def.requiredApparel[i].AllAllowedApparelForPawn(pawn, ignoreGender: false, includeWorn: true)); tmpRequiredApparels.AddRange(item.def.requiredApparel[i].AllRequiredApparelForPawn(pawn, ignoreGender: false, includeWorn: true)); tmpBodyPartGroupsWithRequirement.AddRange(item.def.requiredApparel[i].bodyPartGroupsMatchAny); } } if ((int)item.def.requiredMinimumApparelQuality > (int)qualityCategory) { qualityCategory = item.def.requiredMinimumApparelQuality; } } bool num4 = ap.def.apparel.bodyPartGroups.Any((BodyPartGroupDef bp) => tmpBodyPartGroupsWithRequirement.Contains(bp)); if (ap.TryGetQuality(out QualityCategory qc) && (int)qc < (int)qualityCategory) { num *= 0.25f; } if (num4) { foreach (ThingDef tmpRequiredApparel in tmpRequiredApparels) { tmpAllowedApparels.Remove(tmpRequiredApparel); } if (tmpAllowedApparels.Contains(ap.def)) { num *= 10f; } if (tmpRequiredApparels.Contains(ap.def)) { num *= 25f; } } } return(num); }
private static void HandleColonistReactions(Pawn original, Pawn transformedPawn, FormerHumanReactionStatus reactionStatus, EventType type, IEnumerable <Pawn> pawns = null) { pawns = pawns ?? PawnsFinder.AllMapsCaravansAndTravelingTransportPods_Alive_FreeColonists .Where(p => p != original); //use all colonists except the original pawn as the default ThoughtDef defaultThought; switch (type) { case EventType.Transformation: defaultThought = ThoughtDefOfs.DefaultTransformationReaction; break; case EventType.Reverted: defaultThought = ThoughtDefOfs.DefaultRevertedPawnReaction; break; case EventType.PermanentlyFeral: defaultThought = ThoughtDefOfs.DefaultPermanentlyFeralReaction; break; case EventType.Merged: defaultThought = ThoughtDefOfs.DefaultMergedThought; break; default: throw new ArgumentOutOfRangeException(nameof(type), type, null); } int defaultStage = (int)reactionStatus; defaultStage = Mathf.Min(defaultStage, (defaultThought?.stages?.Count - 1) ?? 0); foreach (Pawn reactor in pawns) { if (reactor == transformedPawn) { continue; //make sure pawns don't react to themselves as if they were a different pawn } ThoughtDef opinionThought = GetOpinionThought(original, reactor, type); ThoughtDef def; if (opinionThought != null) { def = opinionThought; defaultStage = 0; } else { def = defaultThought; } if (def == null) { continue; } if (ThoughtUtility.CanGetThought_NewTemp(reactor, def)) { var memory = ThoughtMaker.MakeThought(def, defaultStage); reactor.TryGainMemory(memory); } } }
/// <summary> /// call when 2 pawns are merged into one meld/merge to handle giving the correct thoughts to colonists /// </summary> /// <param name="merge0">the first pawn of the merge</param> /// <param name="wasPrisoner0">if the first pawn was a prisoner</param> /// <param name="merge1">the second pawn of the merge</param> /// <param name="wasPrisoner1">if the second pawn was a prisoner</param> /// <param name="animalPawn">the resulting animal pawn</param> public static void OnPawnsMerged(Pawn merge0, bool wasPrisoner0, Pawn merge1, bool wasPrisoner1, Pawn animalPawn) //TODO take reaction status into account { _scratchList.Clear(); _scratchList.AddRange(PawnsFinder.AllMapsCaravansAndTravelingTransportPods_Alive_FreeColonists .Where(p => p != merge0 && p != merge1)); //don't give the merged pawns thoughts about themselves HandleColonistReactions(merge0, animalPawn, wasPrisoner0 ? FormerHumanReactionStatus.Prisoner : FormerHumanReactionStatus.Colonist, EventType.Merged, _scratchList); HandleColonistReactions(merge1, animalPawn, wasPrisoner1 ? FormerHumanReactionStatus.Prisoner : FormerHumanReactionStatus.Colonist, EventType.Merged, _scratchList); //need to handle relationships manually _scratchList.Clear(); bool IsValidRelation(Pawn p) { return(p != merge0 && p != merge1 && p.needs?.mood != null && p.relations != null); } IEnumerable <Pawn> linq = merge0.relations.PotentiallyRelatedPawns.Where(IsValidRelation); foreach (Pawn rPawn in linq) { PawnRelationDef relation = rPawn.GetMostImportantRelation(merge0); var modExt = relation?.GetModExtension <RelationshipDefExtension>(); if (modExt == null) { continue; } ThoughtDef thought = modExt.GetThoughtDef(EventType.Merged, merge0.gender); if (thought == null) { Log.Warning($"relationship {relation.defName} has (pawnmorpher) extension but no thought for morphing, is this intentional?"); continue; } if (ThoughtUtility.CanGetThought_NewTemp(rPawn, thought)) { rPawn.TryGainMemory(thought); } } foreach (Pawn rPawn in merge1.relations.PotentiallyRelatedPawns.Where(IsValidRelation)) { PawnRelationDef relation = rPawn.GetMostImportantRelation(merge1); var modExt = relation?.GetModExtension <RelationshipDefExtension>(); if (modExt == null) { continue; } ThoughtDef thought = modExt.GetThoughtDef(EventType.Merged, merge0.gender); if (thought == null) { Log.Warning($"relationship {relation.defName} has (pawnmorpher) extension but no thought for morphing, is this intentional?"); continue; } if (ThoughtUtility.CanGetThought_NewTemp(rPawn, thought)) { rPawn.TryGainMemory(thought); } } }
public static float ApparelScoreRaw(Pawn pawn, Apparel apparel, NeededWarmth neededWarmth = NeededWarmth.Any) { var outfit = pawn?.outfits?.CurrentOutfit as ExtendedOutfit; if (pawn != null && outfit == null) { Log.ErrorOnce("Outfitted :: Not an ExtendedOutfit, something went wrong.", 399441); return(0f); } float score = 0.1f + ApparelScoreRawPriorities(apparel, outfit); if (pawn != null && outfit?.AutoWorkPriorities == true) { score += ApparelScoreAutoWorkPriorities(pawn, apparel); } if (apparel.def.useHitPoints) { float x = (float)apparel.HitPoints / apparel.MaxHitPoints; score *= HitPointsPercentScoreFactorCurve.Evaluate(x); } score += apparel.GetSpecialApparelScoreOffset(); if (pawn != null && outfit != null) { score += ApparelScoreRawInsulation(pawn, apparel, outfit, neededWarmth); } if (pawn?.def?.race?.Animal == false) { if (outfit?.PenaltyWornByCorpse == true && apparel.WornByCorpse && ThoughtUtility.CanGetThought_NewTemp(pawn, ThoughtDefOf.DeadMansApparel, true)) { score -= 0.5f; if (score > 0f) { score *= 0.1f; } } if (apparel.Stuff == ThingDefOf.Human.race.leatherDef) { if (ThoughtUtility.CanGetThought_NewTemp(pawn, ThoughtDefOf.HumanLeatherApparelSad, true)) { score -= 0.5f; if (score > 0f) { score *= 0.1f; } } if (ThoughtUtility.CanGetThought_NewTemp(pawn, ThoughtDefOf.HumanLeatherApparelHappy, true)) { score += 0.12f; } } } //royalty titles if (pawn?.royalty?.AllTitlesInEffectForReading?.Count > 0) { HashSet <ThingDef> tmpAllowedApparels = new HashSet <ThingDef>(); HashSet <ThingDef> tmpRequiredApparels = new HashSet <ThingDef>(); HashSet <BodyPartGroupDef> tmpBodyPartGroupsWithRequirement = new HashSet <BodyPartGroupDef>(); QualityCategory qualityCategory = QualityCategory.Awful; foreach (RoyalTitle item in pawn.royalty.AllTitlesInEffectForReading) { if (item.def.requiredApparel != null) { for (int i = 0; i < item.def.requiredApparel.Count; i++) { tmpAllowedApparels.AddRange(item.def.requiredApparel[i].AllAllowedApparelForPawn(pawn, ignoreGender: false, includeWorn: true)); tmpRequiredApparels.AddRange(item.def.requiredApparel[i].AllRequiredApparelForPawn(pawn, ignoreGender: false, includeWorn: true)); tmpBodyPartGroupsWithRequirement.AddRange(item.def.requiredApparel[i].bodyPartGroupsMatchAny); } } if (item.def.requiredMinimumApparelQuality > qualityCategory) { qualityCategory = item.def.requiredMinimumApparelQuality; } } if (apparel.TryGetQuality(out QualityCategory qc) && qc < qualityCategory) { score *= 0.25f; } bool isRequired = apparel.def.apparel.bodyPartGroups.Any(bp => tmpBodyPartGroupsWithRequirement.Contains(bp)); if (isRequired) { foreach (ThingDef tmpRequiredApparel in tmpRequiredApparels) { tmpAllowedApparels.Remove(tmpRequiredApparel); } if (tmpAllowedApparels.Contains(apparel.def)) { score *= 10f; } if (tmpRequiredApparels.Contains(apparel.def)) { score *= 25f; } } } return(score); }