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(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); }
private void ApplyThought(Pawn thoughtReceiver, Pawn thoughtTarget, string defName) { var thought = ThoughtDef.Named(defName); if (ThoughtUtility.CanGetThought(thoughtReceiver, thought)) { thoughtReceiver.needs.mood.thoughts.memories.TryGainMemory((Thought_Memory)ThoughtMaker.MakeThought(thought), thoughtTarget); } }
public static float ApparelScoreRaw(Pawn pawn, Apparel apparel, NeededWarmth neededWarmth = NeededWarmth.Any) { var outfit = pawn.outfits.CurrentOutfit as ExtendedOutfit; if (outfit == null) { Log.ErrorOnce("Outfitted :: Not an ExtendedOutfit, something went wrong.", 399441); return(0f); } float score = 0.1f + ApparelScoreRawPriorities(pawn, apparel, outfit); if (outfit.AutoWorkPriorities) { score += ApparelScoreAutoWorkPriorities(pawn, apparel); } if (apparel.def.useHitPoints) { float x = (float)apparel.HitPoints / apparel.MaxHitPoints; score *= HitPointsPercentScoreFactorCurve.Evaluate(x); } score += apparel.GetSpecialApparelScoreOffset(); score += ApparelScoreRawInsulation(pawn, apparel, outfit, neededWarmth); if (outfit.PenaltyWornByCorpse && apparel.WornByCorpse && ThoughtUtility.CanGetThought(pawn, ThoughtDefOf.DeadMansApparel)) { score -= 0.5f; if (score > 0f) { score *= 0.1f; } } if (apparel.Stuff == ThingDefOf.Human.race.leatherDef) { if (ThoughtUtility.CanGetThought(pawn, ThoughtDefOf.HumanLeatherApparelSad)) { score -= 0.5f; if (score > 0f) { score *= 0.1f; } } if (ThoughtUtility.CanGetThought(pawn, ThoughtDefOf.HumanLeatherApparelHappy)) { score += 0.12f; } } return(score); }
public static bool HasSocialSituationalThought(Pawn pawn, Pawn other, ThoughtDef thought) { if (!ThoughtUtility.CanGetThought(pawn, thought)) { return(false); } ThoughtState thoughtState = thought.Worker.CurrentSocialState(pawn, other); if (thoughtState.Active) { return(true); } 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(pawn, thought.def)) { return; } pawn.needs?.mood?.thoughts?.memories?.TryGainMemory(thought, otherPawn); }
public static bool TryGainMemory(MemoryThoughtHandler __instance, Thought_Memory newThought, Pawn otherPawn = null) { if (!ThoughtUtility.CanGetThought(__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) //ADDED { __instance.memories.Add(newThought); } } 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); }
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(pawn, thoughtDef)) //take the first one that matches { return(thoughtDef); } } //no matches found return(def); }
public override void GameConditionTick() { base.GameConditionTick(); if (firstTick) { foreach (Pawn pawn in Map.mapPawns.FreeColonistsAndPrisoners) { if (ThoughtUtility.CanGetThought(pawn, HPLDefOf.HPLovecraft_SawBloodMoonSad)) { pawn.needs.mood.thoughts.memories.TryGainMemory(HPLDefOf.HPLovecraft_SawBloodMoonSad); } else if (ThoughtUtility.CanGetThought(pawn, HPLDefOf.HPLovecraft_SawBloodMoonHappy)) { pawn.needs.mood.thoughts.memories.TryGainMemory(HPLDefOf.HPLovecraft_SawBloodMoonHappy); } } firstTick = false; } }
public override void GameConditionTick() { base.GameConditionTick(); if (!firstTick) { return; } firstTick = false; var affectedPawns = new List <Pawn>(); foreach (var map in AffectedMaps) { affectedPawns.AddRange(map.mapPawns.FreeColonistsAndPrisoners); //Add a wolf pack var wolfType = map.mapTemperature.OutdoorTemp > 0f ? PawnKindDef.Named("Wolf_Timber") : PawnKindDef.Named("Wolf_Arctic"); RCellFinder.TryFindRandomPawnEntryCell(out var loc, map, CellFinder.EdgeRoadChance_Animal); var numberOfWolves = Rand.Range(3, 6); for (var i = 0; i < numberOfWolves; i++) { var newWolf = PawnGenerator.GeneratePawn(wolfType); GenSpawn.Spawn(newWolf, loc, map); } } foreach (var pawn in affectedPawns) { if (ThoughtUtility.CanGetThought(pawn, HPLDefOf.HPLovecraft_SawBloodMoonSad)) { pawn.needs.mood.thoughts.memories.TryGainMemory(HPLDefOf.HPLovecraft_SawBloodMoonSad); continue; } if (ThoughtUtility.CanGetThought(pawn, HPLDefOf.HPLovecraft_SawBloodMoonHappy)) { pawn.needs.mood.thoughts.memories.TryGainMemory(HPLDefOf.HPLovecraft_SawBloodMoonHappy); } } }
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(pawn, tGroupThought)) { __result = true; return; } } } if (__result) { __result = def.IsValidFor(pawn); } }
public static void GainSocialThought(Pawn initiator, Pawn target, ThoughtDef thoughtDef) { if (!ThoughtUtility.CanGetThought(target, thoughtDef)) { return; } float impact = initiator.GetStatValue(StatDefOf.SocialImpact); var thoughtMemory = (Thought_Memory)ThoughtMaker.MakeThought(thoughtDef); thoughtMemory.moodPowerFactor = impact; var thoughtSocialMemory = thoughtMemory as Thought_MemorySocial; if (thoughtSocialMemory != null) { thoughtSocialMemory.opinionOffset *= impact; } target.needs.mood.thoughts.memories.TryGainMemory(thoughtMemory, initiator); }
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(pReactor, thought)) { pReactor.TryGainMemory(thought); } } } //TODO handle bond animal reverted? }
private void TryAddMemory(Pawn pawn, ThoughtDef memory) { ThoughtHandler thoughts = pawn.needs?.mood?.thoughts; if (thoughts == null) { return; } if (!ThoughtUtility.CanGetThought(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 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(pawn, ThoughtDefOf.DeadMansApparel, true)) { score -= 0.5f; if (score > 0f) { score *= 0.1f; } } if (apparel.Stuff == ThingDefOf.Human.race.leatherDef) { if (ThoughtUtility.CanGetThought(pawn, ThoughtDefOf.HumanLeatherApparelSad, true)) { score -= 0.5f; if (score > 0f) { score *= 0.1f; } } if (ThoughtUtility.CanGetThought(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); }
public override void DoWindowContents(Rect inRect) { ApparelStatCache conf = this._pawn.GetApparelStatCache(); Rect conRect = new Rect(inRect); conRect.height -= 50f; BeginArea(conRect); // begin main group BeginVertical(); Label(this.GetTitle(), this._headline); Text.Font = GameFont.Small; // GUI.BeginGroup(contentRect); float labelWidth = conRect.width - BaseValue - BaseValue - BaseValue - 48f; this.DrawLine("Status", labelWidth, "BaseMod", "Strength", "Score", this._fontBold); Space(6f); Label(string.Empty, this._whiteLine, Height(1)); Space(6f); ApparelEntry apparelEntry = conf.GetAllOffsets(this._apparel); HashSet <StatDef> equippedOffsets = apparelEntry.EquippedOffsets; HashSet <StatDef> statBases = apparelEntry.StatBases; HashSet <StatDef> infusedOffsets = apparelEntry.InfusedOffsets; this._scrollPosition = BeginScrollView(this._scrollPosition, Width(conRect.width)); // relevant apparel stats // start score at 1 float score = 1; // add values for each statdef modified by the apparel foreach (StatPriority statPriority in this._pawn.GetApparelStatCache().StatCache .OrderBy(i => i.Stat.LabelCap)) { StatDef stat = statPriority.Stat; string statLabel = stat.LabelCap; // statbases, e.g. armor // StatCache.DoApparelScoreRaw_PawnStatsHandlers(_pawn, _apparel, statPriority.Stat, ref currentStat); if (statBases.Contains(stat)) { float statValue = this._apparel.GetStatValue(stat); float statScore = 0f; if (ApparelStatCache.SpecialStats.Contains(stat)) { ApparelStatCache.CalculateScoreForSpecialStats(this._apparel, statPriority, this._pawn, statValue, ref statScore); } else { // statValue += StatCache.StatInfused(infusionSet, statPriority, ref baseInfused); statScore = statValue * statPriority.Weight; } score += statScore; this.DrawLine( statLabel, labelWidth, statValue.ToStringPercent("N1"), statPriority.Weight.ToString("N2"), statScore.ToString("N2")); } if (equippedOffsets.Contains(stat)) { float statValue = this._apparel.GetEquippedStatValue(this._pawn, stat); // statValue += StatCache.StatInfused(infusionSet, statPriority, ref equippedInfused); float statScore = 0f; if (ApparelStatCache.SpecialStats.Contains(stat)) { ApparelStatCache.CalculateScoreForSpecialStats(this._apparel, statPriority, this._pawn, statValue, ref statScore); } else { statScore = statValue * statPriority.Weight; } score += statScore; this.DrawLine( statLabel, labelWidth, statValue.ToStringPercent("N1"), statPriority.Weight.ToString("N2"), statScore.ToString("N2")); } if (infusedOffsets.Contains(stat)) { GUI.color = Color.green; // new Color(0.5f, 1f, 1f, 1f); // float statInfused = StatCache.StatInfused(infusionSet, statPriority, ref dontcare); ApparelStatCache.DoApparelScoreRaw_PawnStatsHandlers(this._apparel, stat, out float statValue); bool flag = true; float statScore = 0f; if (ApparelStatCache.SpecialStats.Contains(stat)) { ApparelStatCache.CalculateScoreForSpecialStats(this._apparel, statPriority, this._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; } this.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, this._whiteLine, Height(1)); Space(6f); this.DrawLine(string.Empty, labelWidth, "Modifier", string.Empty, "Subtotal"); this.DrawLine("BasicStatusOfApparel".Translate(), labelWidth, "1.00", "+", score.ToString("N2")); float special = this._apparel.GetSpecialApparelScoreOffset(); if (Math.Abs(special) > 0f) { score += special; this.DrawLine( "OutfitterSpecialScore".Translate(), labelWidth, special.ToString("N2"), "+", score.ToString("N2")); } float armor = ApparelStatCache.ApparelScoreRaw_ProtectionBaseStat(this._apparel); if (Math.Abs(armor) > 0.01f) { score += armor; this.DrawLine("OutfitterArmor".Translate(), labelWidth, armor.ToString("N2"), "+", score.ToString("N2")); } if (this._apparel.def.useHitPoints) { // durability on 0-1 scale float x = this._apparel.HitPoints / (float)this._apparel.MaxHitPoints; score *= ApparelStatsHelper.HitPointsPercentScoreFactorCurve.Evaluate(x); this.DrawLine( "OutfitterHitPoints".Translate(), labelWidth, x.ToString("N2"), "weighted", score.ToString("N2")); GUI.color = Color.white; } if (this._apparel.WornByCorpse && ThoughtUtility.CanGetThought(this._pawn, ThoughtDefOf.DeadMansApparel)) { score -= 0.5f; if (score > 0f) { score *= 0.1f; } this.DrawLine( "OutfitterWornByCorpse".Translate(), labelWidth, "modified", "weighted", score.ToString("N2")); } if (this._apparel.Stuff == ThingDefOf.Human.race.leatherDef) { if (ThoughtUtility.CanGetThought(this._pawn, ThoughtDefOf.HumanLeatherApparelSad)) { score -= 0.5f; if (score > 0f) { score *= 0.1f; } } if (ThoughtUtility.CanGetThought(this._pawn, ThoughtDefOf.HumanLeatherApparelHappy)) { score *= 2f; } this.DrawLine( "OutfitterHumanLeather".Translate(), labelWidth, "modified", "weighted", score.ToString("N2")); } float temperature = conf.ApparelScoreRaw_Temperature(this._apparel); if (Math.Abs(temperature - 1f) > 0) { score *= temperature; this.DrawLine( "OutfitterTemperature".Translate(), labelWidth, temperature.ToString("N2"), "*", score.ToString("N2")); } this.DrawLine( "OutfitterTotal".Translate(), labelWidth, string.Empty, "=", conf.ApparelScoreRaw(this._apparel).ToString("N2")); GUI.color = Color.white; Text.Anchor = TextAnchor.UpperLeft; // end main group EndVertical(); EndArea(); }
public float ApparelScoreRaw([NotNull] Apparel ap) { if (this.RawScoreDict.ContainsKey(ap)) { return(this.RawScoreDict[ap]); } // only allow shields to be considered if a primary weapon is equipped and is melee Pawn thisPawn = this._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 ApparelEntry entry = this.GetAllOffsets(ap); HashSet <StatDef> statBases = entry.StatBases; HashSet <StatDef> equippedOffsets = entry.EquippedOffsets; HashSet <StatDef> infusedOffsets = entry.InfusedOffsets; // start score at 1 float score = 1; // add values for each statdef modified by the apparel List <StatPriority> stats = thisPawn.GetApparelStatCache().StatCache; foreach (StatPriority statPriority in stats.Where(statPriority => statPriority != null)) { StatDef stat = statPriority.Stat; if (statBases.Contains(stat)) { float 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)) { float apStat = ap.GetEquippedStatValue(this._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)) { // float statInfused = StatInfused(infusionSet, statPriority, ref dontcare); DoApparelScoreRaw_PawnStatsHandlers(ap, stat, out float 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) { float x = ap.HitPoints / (float)ap.MaxHitPoints; score *= ApparelStatsHelper.HitPointsPercentScoreFactorCurve.Evaluate(x); } if (ap.WornByCorpse && ThoughtUtility.CanGetThought(thisPawn, ThoughtDefOf.DeadMansApparel)) { score -= 0.5f; if (score > 0f) { score *= 0.1f; } } if (ap.Stuff == ThingDefOf.Human.race.leatherDef) { if (ThoughtUtility.CanGetThought(thisPawn, ThoughtDefOf.HumanLeatherApparelSad)) { score -= 0.5f; if (score > 0f) { score *= 0.1f; } } if (ThoughtUtility.CanGetThought(thisPawn, ThoughtDefOf.HumanLeatherApparelHappy)) { score *= 2f; } } score *= this.ApparelScoreRaw_Temperature(ap); this.RawScoreDict.Add(ap, score); return(score); }
/// <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(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(rPawn, thought)) { rPawn.TryGainMemory(thought); } } }
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(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(pawn, ThoughtDefOf.HumanLeatherApparelSad, checkIfNullified: true)) { num -= 0.5f; if (num > 0f) { num *= 0.1f; } } if (pawn != null && ThoughtUtility.CanGetThought(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(reactor, def)) { var memory = ThoughtMaker.MakeThought(def, defaultStage); reactor.TryGainMemory(memory); } } }