diff --git a/Assemblies/Outfitter.dll b/Assemblies/Outfitter.dll index f521518..374108c 100644 Binary files a/Assemblies/Outfitter.dll and b/Assemblies/Outfitter.dll differ diff --git a/Source/Outfitter/ApparelEntry.cs b/Source/Outfitter/ApparelEntry.cs index 87413b1..e90c77b 100644 --- a/Source/Outfitter/ApparelEntry.cs +++ b/Source/Outfitter/ApparelEntry.cs @@ -8,7 +8,11 @@ namespace Outfitter public class ApparelEntry { - #region Public Fields + public HashSet equippedOffsets; + + public HashSet infusedOffsets; + + public HashSet statBases; public ApparelEntry() { @@ -16,13 +20,5 @@ public ApparelEntry() this.infusedOffsets = new HashSet(); this.statBases = new HashSet(); } - - public HashSet equippedOffsets; - - public HashSet infusedOffsets; - - public HashSet statBases; - - #endregion Public Fields } } \ No newline at end of file diff --git a/Source/Outfitter/ApparelStatCache.cs b/Source/Outfitter/ApparelStatCache.cs index 0bc1c04..5d4a0b5 100644 --- a/Source/Outfitter/ApparelStatCache.cs +++ b/Source/Outfitter/ApparelStatCache.cs @@ -20,13 +20,14 @@ namespace Outfitter using Verse; - public partial class ApparelStatCache + public class ApparelStatCache { - // public List recentApparel = new List(); + public const float MaxValue = 2.5f; + // public List recentApparel = new List(); public readonly List Cache; - public const float MaxValue = 2.5f; + public Dictionary ToDropList = new Dictionary(); private readonly Pawn pawn; @@ -75,8 +76,8 @@ public List StatCache get { // update auto stat priorities roughly between every vanilla gear check cycle - if (Find.TickManager.TicksGame - this.lastStatUpdate > JobGiver_OutfitterOptimizeApparel.ApparelStatCheck - || this.pawnSave.forceStatUpdate) + if (Find.TickManager.TicksGame - this.lastStatUpdate + > JobGiver_OutfitterOptimizeApparel.ApparelStatCheck || this.pawnSave.forceStatUpdate) { // list of auto stats if (this.Cache.Count < 1 && this.pawnSave.Stats.Count > 0) @@ -94,6 +95,7 @@ public List StatCache this.Cache.RemoveAll(stat => stat.Assignment == StatAssignment.Individual); // loop over each (new) stat + // Armor only used by the Battle beacon, no relevance to jobs etc. if (this.pawnSave.armorOnly) { Dictionary updateArmorStats = this.pawn.GetWeightedApparelArmorStats(); @@ -121,6 +123,12 @@ public List StatCache Dictionary updateIndividualPriorities = this.pawn.GetWeightedApparelIndividualStats(); + // updateAutoPriorities = updateAutoPriorities.OrderBy(x => x.Key.label).ToDictionary(x => x.Key, x => x.Value); + updateAutoPriorities = updateAutoPriorities.OrderByDescending(x => Mathf.Abs(x.Value)) + .ToDictionary(x => x.Key, x => x.Value); + updateIndividualPriorities = updateIndividualPriorities.OrderBy(x => x.Key.label) + .ToDictionary(x => x.Key, x => x.Value); + foreach (KeyValuePair pair in updateIndividualPriorities) { // find index of existing priority for this stat @@ -182,11 +190,11 @@ public List StatCache Saveable_Pawn_StatDef stats = new Saveable_Pawn_StatDef - { - Stat = statPriority.Stat, - Assignment = statPriority.Assignment, - Weight = statPriority.Weight - }; + { + Stat = statPriority.Stat, + Assignment = statPriority.Assignment, + Weight = statPriority.Weight + }; this.pawnSave.Stats.Add(stats); } } @@ -219,8 +227,6 @@ private FloatRange TemperatureWeight } } - public Dictionary ToDropList = new Dictionary(); - public static float ApparelScoreRaw_ProtectionBaseStat(Apparel ap) { float num = 1f; @@ -229,7 +235,10 @@ public static float ApparelScoreRaw_ProtectionBaseStat(Apparel ap) return num + num2 * 1.25f; } - public static void DoApparelScoreRaw_PawnStatsHandlers([NotNull] Apparel apparel, [NotNull] StatDef statDef, out float num) + public static void DoApparelScoreRaw_PawnStatsHandlers( + [NotNull] Apparel apparel, + [NotNull] StatDef statDef, + out float num) { num = 0f; ApparelScoreRaw_PawnStatsHandlers?.Invoke(apparel, statDef, out num); @@ -411,7 +420,6 @@ public float ApparelScoreRaw([NotNull] Apparel ap, [NotNull] Pawn pawn) if (infusedOffsets.Contains(statPriority.Stat)) { // float statInfused = StatInfused(infusionSet, statPriority, ref dontcare); - DoApparelScoreRaw_PawnStatsHandlers(ap, statPriority.Stat, out float statInfused); score += statInfused * statPriority.Weight; @@ -470,7 +478,6 @@ public float ApparelScoreRaw_Temperature([NotNull] Apparel apparel) // temperature FloatRange targetTemperatures = this.TargetTemperatures; - // offsets on apparel float insulationCold = apparel.GetStatValue(StatDefOf.Insulation_Cold); float insulationHeat = apparel.GetStatValue(StatDefOf.Insulation_Heat); @@ -479,15 +486,21 @@ public float ApparelScoreRaw_Temperature([NotNull] Apparel apparel) insulationHeat += apparel.def.equippedStatOffsets.GetStatOffsetFromList(StatDefOf.Insulation_Heat); { // offsets on apparel infusions - DoApparelScoreRaw_PawnStatsHandlers(apparel, StatDefOf.ComfyTemperatureMin, out float infInsulationCold); - DoApparelScoreRaw_PawnStatsHandlers(apparel, StatDefOf.ComfyTemperatureMax, out float infInsulationHeat); + DoApparelScoreRaw_PawnStatsHandlers( + apparel, + StatDefOf.ComfyTemperatureMin, + out float infInsulationCold); + DoApparelScoreRaw_PawnStatsHandlers( + apparel, + StatDefOf.ComfyTemperatureMax, + out float infInsulationHeat); insulationCold += infInsulationCold; insulationHeat += infInsulationHeat; } - // string log = apparel.LabelCap + " - InsCold: " + insulationCold + " - InsHeat: " + insulationHeat + " - TargTemp: " - // + targetTemperatures + "\nMinComfy: " + minComfyTemperature + " - MaxComfy: " - // + maxComfyTemperature; + // string log = apparel.LabelCap + " - InsCold: " + insulationCold + " - InsHeat: " + insulationHeat + " - TargTemp: " + // + targetTemperatures + "\nMinComfy: " + minComfyTemperature + " - MaxComfy: " + // + maxComfyTemperature; // if this gear is currently worn, we need to make sure the contribution to the pawn's comfy temps is removed so the gear is properly scored List wornApparel = this.pawn.apparel.WornApparel; @@ -495,7 +508,7 @@ public float ApparelScoreRaw_Temperature([NotNull] Apparel apparel) { if (wornApparel.Contains(apparel)) { - // log += "\nPawn is wearer of this apparel."; + // log += "\nPawn is wearer of this apparel."; minComfyTemperature -= insulationCold; maxComfyTemperature -= insulationHeat; } @@ -536,7 +549,7 @@ public float ApparelScoreRaw_Temperature([NotNull] Apparel apparel) } } - // log += "\nBasic stat - MinComfy: " + minComfyTemperature + " - MaxComfy: " + maxComfyTemperature; + // log += "\nBasic stat - MinComfy: " + minComfyTemperature + " - MaxComfy: " + maxComfyTemperature; // now for the interesting bit. FloatRange temperatureScoreOffset = new FloatRange(0f, 0f); @@ -548,14 +561,15 @@ public float ApparelScoreRaw_Temperature([NotNull] Apparel apparel) // isolation_warm is given as positive numbers. float neededInsulation_Warmth = targetTemperatures.max - maxComfyTemperature; - // log += "\nWeight: " + tempWeight + " - NeedInsCold: " + neededInsulation_Cold + " - NeedInsWarmth: " - // + neededInsulation_Warmth; + // log += "\nWeight: " + tempWeight + " - NeedInsCold: " + neededInsulation_Cold + " - NeedInsWarmth: " + // + neededInsulation_Warmth; // currently too cold if (neededInsulation_Cold < 0) { temperatureScoreOffset.min += -insulationCold * Math.Abs(tempWeight.min); } + // currently warm enough else { @@ -571,6 +585,7 @@ public float ApparelScoreRaw_Temperature([NotNull] Apparel apparel) { temperatureScoreOffset.max += insulationHeat * Math.Abs(tempWeight.max); } + // currently cool enough else { @@ -581,21 +596,36 @@ public float ApparelScoreRaw_Temperature([NotNull] Apparel apparel) * Math.Abs(tempWeight.max); } } + // Punish bad apparel temperatureScoreOffset.min *= temperatureScoreOffset.min < 0 ? 2f : 1f; temperatureScoreOffset.max *= temperatureScoreOffset.max < 0 ? 2f : 1f; - // log += "\nScoreOffsetMin: " + temperatureScoreOffset.min + " - ScoreOffsetMax: " - // + temperatureScoreOffset.max + " => " + 1 + (temperatureScoreOffset.min + temperatureScoreOffset.max) / 25; - // - // Log.Message(log); + // log += "\nScoreOffsetMin: " + temperatureScoreOffset.min + " - ScoreOffsetMax: " + // + temperatureScoreOffset.max + " => " + 1 + (temperatureScoreOffset.min + temperatureScoreOffset.max) / 25; + // Log.Message(log); + return 1 + (temperatureScoreOffset.min + temperatureScoreOffset.max) / 15; + } + + public ApparelEntry GetAllOffsets([NotNull] Apparel ap) + { + if (Outfitter.Cache.ApparelEntries.ContainsKey(ap)) + { + return Outfitter.Cache.ApparelEntries[ap]; + } + + ApparelEntry entry = new ApparelEntry(); + this.GetStatsOfApparel(ap, ref entry.equippedOffsets, ref entry.statBases); + this.GetStatsOfApparelInfused(ap, ref entry.infusedOffsets); - return 1 + (temperatureScoreOffset.min + temperatureScoreOffset.max) / 25; + Outfitter.Cache.ApparelEntries.Add(ap, entry); + return entry; } public void UpdateTemperatureIfNecessary(bool force = false, bool forceweight = false) { - if (Find.TickManager.TicksGame - this.lastTempUpdate > JobGiver_OutfitterOptimizeApparel.ApparelStatCheck || force) + if (Find.TickManager.TicksGame - this.lastTempUpdate > JobGiver_OutfitterOptimizeApparel.ApparelStatCheck + || force) { // get desired temperatures if (!this.pawnSave.TargetTemperaturesOverride) @@ -622,15 +652,13 @@ public void UpdateTemperatureIfNecessary(bool force = false, bool forceweight = { this.pawnSave.TargetTemperatures.min = Mathf.Min(this.pawnSave.TargetTemperatures.min, -3); } - } this.lastTempUpdate = Find.TickManager.TicksGame; } } - var RealComfyTemperatures = this.pawn.ComfortableTemperatureRange(); - + FloatRange RealComfyTemperatures = this.pawn.ComfortableTemperatureRange(); if (Find.TickManager.TicksGame - this.lastWeightUpdate > JobGiver_OutfitterOptimizeApparel.ApparelStatCheck || forceweight) @@ -639,14 +667,12 @@ public void UpdateTemperatureIfNecessary(bool force = false, bool forceweight = if (this.pawnSave.TargetTemperatures.min < RealComfyTemperatures.min) { - weight.min += Math.Abs( - (this.pawnSave.TargetTemperatures.min - RealComfyTemperatures.min) / 100); + weight.min += Math.Abs((this.pawnSave.TargetTemperatures.min - RealComfyTemperatures.min) / 100); } if (this.pawnSave.TargetTemperatures.max > RealComfyTemperatures.max) { - weight.max += Math.Abs( - (this.pawnSave.TargetTemperatures.max - RealComfyTemperatures.max) / 100); + weight.max += Math.Abs((this.pawnSave.TargetTemperatures.max - RealComfyTemperatures.max) / 100); } this.pawnSave.Temperatureweight = weight; @@ -662,22 +688,10 @@ private static void FillInfusionHashset_PawnStatsHandlers( ApparelScoreRaw_FillInfusedStat?.Invoke(apparel, parentStat, ref infusedOffsets); } - public ApparelEntry GetAllOffsets([NotNull] Apparel ap) - { - if (Outfitter.Cache.ApparelEntries.ContainsKey(ap)) - { - return Outfitter.Cache.ApparelEntries[ap]; - } - - ApparelEntry entry = new ApparelEntry(); - this.GetStatsOfApparel(ap, ref entry.equippedOffsets, ref entry.statBases); - this.GetStatsOfApparelInfused(ap, ref entry.infusedOffsets); - - Outfitter.Cache.ApparelEntries.Add(ap, entry); - return entry; - } - - private void GetStatsOfApparel([NotNull] Apparel ap, ref HashSet equippedOffsets, ref HashSet statBases) + private void GetStatsOfApparel( + [NotNull] Apparel ap, + ref HashSet equippedOffsets, + ref HashSet statBases) { if (ap.def.equippedStatOffsets != null) { diff --git a/Source/Outfitter/ApparelStatsHelper.cs b/Source/Outfitter/ApparelStatsHelper.cs index 6f6fd54..163a7fb 100644 --- a/Source/Outfitter/ApparelStatsHelper.cs +++ b/Source/Outfitter/ApparelStatsHelper.cs @@ -22,6 +22,36 @@ public static class ApparelStatsHelper { private const float ScoreFactorIfNotReplacing = 10f; + private static float NegMax(bool mainJob = false) + { + return mainJob ? -9f : -3f; + } + + private static float PosMax(bool mainJob = false) + { + return mainJob ? 9f : 3f; + } + + private static float NegMed(bool mainJob = false) + { + return mainJob ? -6f : -2f; + } + + private static float PosMed(bool mainJob = false) + { + return mainJob ? 6f : 2f; + } + + private static float PosMin(bool mainJob = false) + { + return mainJob ? 3f : 1f; + } + + private static float NegMin(bool mainJob = false) + { + return mainJob ? -3f : -1f; + } + // New curve public static readonly SimpleCurve HitPointsPercentScoreFactorCurve = new SimpleCurve { @@ -58,7 +88,6 @@ public static class ApparelStatsHelper private static List allApparelStats; - public static FloatRange MinMaxTemperatureRange => new FloatRange(-100, 100); private static List AllStatDefsModifiedByAnyApparel @@ -189,57 +218,50 @@ public static Dictionary GetWeightedApparelIndividualStats(this // dict.Add(StatDefOf.ArmorRating_Sharp, 0.25f); if (pawnSave.AddIndividualStats) { - bool activeDrone = false; - - PsychicDroneLevel psychicDroneLevel = PsychicDroneLevel.None; // ReSharper disable once InconsistentNaming - activeDrone = ExtantShipPart(pawn.Map); - - GameCondition_PsychicEmanation activeCondition = - pawn.Map.gameConditionManager.GetActiveCondition(); - if (activeCondition != null && activeCondition.gender == pawn.gender - && activeCondition.def.droneLevel > psychicDroneLevel) - { - activeDrone = true; - } - - if (activeDrone) + if (pawn.Map.gameConditionManager.ConditionIsActive(GameConditionDefOf.PsychicDrone)) { - switch (pawn.story.traits.DegreeOfTrait(TraitDef.Named("PsychicSensitivity"))) + GameCondition_PsychicEmanation activeCondition = + pawn.Map.gameConditionManager.GetActiveCondition(); + if (activeCondition.gender == pawn.gender && activeCondition.def.droneLevel > PsychicDroneLevel.None) { - case -1: - { - AddStatToDict(StatDefOf.PsychicSensitivity, -0.25f, ref dict); - break; - } + switch (pawn.story.traits.DegreeOfTrait(TraitDefOf.PsychicSensitivity)) + { + case -1: + { + AddStatToDict(StatDefOf.PsychicSensitivity, -0.25f, ref dict); + break; + } - case 0: - { - AddStatToDict(StatDefOf.PsychicSensitivity, -0.5f, ref dict); - break; - } + case 0: + { + AddStatToDict(StatDefOf.PsychicSensitivity, 0.5f, ref dict); + break; + } - case 1: - { - AddStatToDict(StatDefOf.PsychicSensitivity, -0.75f, ref dict); - break; - } + case 1: + { + AddStatToDict(StatDefOf.PsychicSensitivity, -0.75f, ref dict); + break; + } - case 2: - { - AddStatToDict(StatDefOf.PsychicSensitivity, -1f, ref dict); - break; - } + case 2: + { + AddStatToDict(StatDefOf.PsychicSensitivity, -1f, ref dict); + break; + } + } } } + if (pawn.Map.gameConditionManager.ConditionIsActive(GameConditionDefOf.PsychicSoothe)) { if (pawn.Map.gameConditionManager.GetActiveCondition().gender == pawn.gender) { - switch (pawn.story.traits.DegreeOfTrait(TraitDef.Named("PsychicSensitivity"))) + switch (pawn.story.traits.DegreeOfTrait(TraitDefOf.PsychicSensitivity)) { case -1: { @@ -304,10 +326,9 @@ public static Dictionary GetWeightedApparelIndividualStats(this // float v1 = pawn.GetStatValue(StatDefOf.MentalBreakThreshold); // float v2 = pawn.def.GetStatValueAbstract(StatDefOf.MentalBreakThreshold); - // // if (v1 > v2) // { - // AddStatToDict(StatDefOf.MentalBreakThreshold, (-v1 - v2) * 5, ref dict); + // AddStatToDict(StatDefOf.MentalBreakThreshold, (-v1 - v2) * 5, ref dict); // } } @@ -349,44 +370,56 @@ public static Dictionary GetWeightedApparelStats(this Pawn pawn) 1, (current, workType) => Mathf.Min(current, pawn.GetWorkPriority(workType))); - var log = "Outfitter Priorities, Pawn: " + pawn + " - Max: " + minPriority + "/" + maxPriority; + string log = "Outfitter Priorities, Pawn: " + pawn + " - Max: " + minPriority + "/" + maxPriority; foreach (WorkTypeDef workType in workTypes) { - foreach (KeyValuePair stat in GetStatsOfWorkType(pawn, workType)) + List> statsOfWorkType = GetStatsOfWorkType(pawn, workType).ToList(); + + foreach (KeyValuePair stat in statsOfWorkType) { int priority = Find.PlaySettings.useWorkPriorities ? pawn.GetWorkPriority(workType) : 3; float priorityAdjust = 1f / priority / maxPriority; - float weight = stat.Value * priorityAdjust; - for (int i = 0; i < workType.relevantSkills.Count; i++) + if (pawnSave.AddPersonalStats) { - var relSkill = workType.relevantSkills[i]; - SkillRecord record = pawn.skills.GetSkill(relSkill); - float skillMod = 1 + (record.Level / 20); - switch (record.passion) + for (int i = 0; i < workType.relevantSkills.Count; i++) { - case Passion.None: break; - case Passion.Minor: - skillMod *= 2; - break; - case Passion.Major: - skillMod *= 4; - break; + SkillDef relSkill = workType.relevantSkills[i]; + SkillRecord record = pawn.skills.GetSkill(relSkill); + float skillMod = 1 + (2f * record.Level / 20); + switch (record.passion) + { + case Passion.None: break; + case Passion.Minor: + skillMod *= 2f; + break; + + case Passion.Major: + skillMod *= 3f; + break; + } + priorityAdjust *= skillMod; } - priorityAdjust *= skillMod; } + float weight = stat.Value * priorityAdjust; + AddStatToDict(stat.Key, weight, ref dict); - log += "\n" + workType.defName + " - priority " + "-" + priority + " - adjusted " + priorityAdjust; + + log += "\n" + workType.defName + " - priority " + "-" + priority + " - adjusted " + + priorityAdjust; } } - Log.Message(log); + + // Log.Message(log); + // adjustments for traits AdjustStatsForTraits(pawn, ref dict); } - var num = ApparelStatCache.MaxValue / 8 * 5; + + float num = ApparelStatCache.MaxValue / 8 * 5; if (dict.Count > 0) { // normalize weights @@ -397,13 +430,10 @@ public static Dictionary GetWeightedApparelStats(this Pawn pawn) dict[key] /= max / num; } } - dict.OrderByDescending(x => x.Value); return dict; } - - [NotNull] public static List NotYetAssignedStatDefs([NotNull] this Pawn pawn) { @@ -473,12 +503,6 @@ private static void AdjustStatsForTraits(Pawn pawn, [NotNull] ref Dictionary list = map.listerThings.ThingsOfDef(ThingDefOf.CrashedPsychicEmanatorShipPart); - - return list.Any(); - } private static IEnumerable> GetStatsOfArmorMelee() { @@ -486,7 +510,7 @@ private static IEnumerable> GetStatsOfArmorMelee() yield return new KeyValuePair(StatDefOf.MeleeDodgeChance, 3f); yield return new KeyValuePair(StatDefOf.AccuracyTouch, 1.8f); yield return new KeyValuePair(StatDefOf.MeleeHitChance, 3f); - yield return new KeyValuePair(StatDefOf2.MeleeDPS, 2.4f); + yield return new KeyValuePair(StatDefOf.MeleeDPS, 2.4f); yield return new KeyValuePair(StatDefOf.MeleeWeapon_CooldownMultiplier, -2.4f); yield return new KeyValuePair(StatDefOf.MeleeWeapon_DamageMultiplier, 1.2f); yield return new KeyValuePair(StatDefOf.ArmorRating_Blunt, 2.5f); @@ -513,7 +537,7 @@ private static IEnumerable> GetStatsOfArmorRanged() yield return new KeyValuePair(StatDefOf.AccuracyMedium, 1.8f); yield return new KeyValuePair(StatDefOf.AccuracyLong, 1.8f); yield return new KeyValuePair(StatDefOf.MeleeHitChance, 1.8f); - yield return new KeyValuePair(StatDefOf2.MeleeDPS, 1f); + yield return new KeyValuePair(StatDefOf.MeleeDPS, 1f); yield return new KeyValuePair(StatDefOf.MeleeWeapon_CooldownMultiplier, -1f); yield return new KeyValuePair(StatDefOf.MeleeWeapon_DamageMultiplier, 1f); yield return new KeyValuePair(StatDefOf.ArmorRating_Blunt, 2.5f); @@ -522,39 +546,43 @@ private static IEnumerable> GetStatsOfArmorRanged() yield return new KeyValuePair(StatDefOf.ArmorRating_Electric, 1.5f); } - private static IEnumerable> GetStatsOfWorkType(Pawn pawn, WorkTypeDef worktype) + private static IEnumerable> GetStatsOfWorkType([NotNull] this Pawn pawn, + [NotNull] WorkTypeDef worktype) { SaveablePawn pawnSave = pawn.GetSaveablePawn(); - + bool mainJob = false; if (pawnSave.mainJob == MainJob.Soldier00Close_Combat) { - yield return new KeyValuePair(StatDefOf.MoveSpeed, 3f); - yield return new KeyValuePair(StatDefOf.AimingDelayFactor, -3f); - yield return new KeyValuePair(StatDefOf2.MeleeDPS, 2.4f); - yield return new KeyValuePair(StatDefOf.MeleeHitChance, 3f); - yield return new KeyValuePair(StatDefOf.MeleeDodgeChance, 3f); - yield return new KeyValuePair(StatDefOf.ArmorRating_Blunt, 1.8f); - yield return new KeyValuePair(StatDefOf.ArmorRating_Sharp, 1.8f); - yield return new KeyValuePair(StatDefOf.AccuracyTouch, 1.8f); - yield return new KeyValuePair(StatDefOf.MeleeWeapon_DamageMultiplier, 1.2f); - yield return new KeyValuePair(StatDefOf.MeleeWeapon_CooldownMultiplier, -2.4f); - yield return new KeyValuePair(StatDefOf.PainShockThreshold, 3f); + mainJob = true; + + yield return new KeyValuePair(StatDefOf.MoveSpeed, PosMax(mainJob)); + yield return new KeyValuePair(StatDefOf.AimingDelayFactor, NegMax(mainJob)); + yield return new KeyValuePair(StatDefOf.MeleeDPS, PosMax(mainJob)); + yield return new KeyValuePair(StatDefOf.MeleeHitChance, PosMax(mainJob)); + yield return new KeyValuePair(StatDefOf.MeleeDodgeChance, PosMax(mainJob)); + yield return new KeyValuePair(StatDefOf.ArmorRating_Blunt, PosMed(mainJob)); + yield return new KeyValuePair(StatDefOf.ArmorRating_Sharp, PosMed()); + yield return new KeyValuePair(StatDefOf.AccuracyTouch, PosMax(mainJob)); + yield return new KeyValuePair(StatDefOf.MeleeWeapon_DamageMultiplier, PosMed(mainJob)); + yield return new KeyValuePair(StatDefOf.MeleeWeapon_CooldownMultiplier, NegMax(mainJob)); + yield return new KeyValuePair(StatDefOf.PainShockThreshold, PosMax(mainJob)); yield break; } if (pawnSave.mainJob == MainJob.Soldier00Ranged_Combat) { - yield return new KeyValuePair(StatDefOf.ShootingAccuracy, 3f); - yield return new KeyValuePair(StatDefOf.AccuracyShort, 1.8f); - yield return new KeyValuePair(StatDefOf.AccuracyMedium, 1.8f); - yield return new KeyValuePair(StatDefOf.AccuracyLong, 1.8f); - yield return new KeyValuePair(StatDefOf.MoveSpeed, 1.5f); - yield return new KeyValuePair(StatDefOf.ArmorRating_Blunt, 1.5f); - yield return new KeyValuePair(StatDefOf.ArmorRating_Sharp, 1.5f); - yield return new KeyValuePair(StatDefOf.MeleeDodgeChance, 0.5f); - yield return new KeyValuePair(StatDefOf.AimingDelayFactor, -3f); - yield return new KeyValuePair(StatDefOf.RangedWeapon_Cooldown, -3f); - yield return new KeyValuePair(StatDefOf.PainShockThreshold, 3f); + mainJob = true; + yield return new KeyValuePair(StatDefOf.ShootingAccuracy, PosMax(mainJob)); + yield return new KeyValuePair(StatDefOf.AccuracyShort, PosMed(mainJob)); + yield return new KeyValuePair(StatDefOf.AccuracyMedium, PosMed(mainJob)); + yield return new KeyValuePair(StatDefOf.AccuracyLong, PosMed(mainJob)); + yield return new KeyValuePair(StatDefOf.MoveSpeed, PosMed(mainJob)); + yield return new KeyValuePair(StatDefOf.ArmorRating_Blunt, PosMed(mainJob)); + yield return new KeyValuePair(StatDefOf.ArmorRating_Sharp, PosMed(mainJob)); + yield return new KeyValuePair(StatDefOf.MeleeDodgeChance, PosMin()); + yield return new KeyValuePair(StatDefOf.AimingDelayFactor, NegMax(mainJob)); + yield return new KeyValuePair(StatDefOf.RangedWeapon_Cooldown, NegMax(mainJob)); + yield return new KeyValuePair(StatDefOf.PainShockThreshold, PosMax(mainJob)); yield break; } @@ -567,17 +595,13 @@ private static IEnumerable> GetStatsOfWorkType(Pawn case "Doctor": if (pawnSave.mainJob == MainJob.Doctor) { - yield return new KeyValuePair(StatDefOf2.MedicalOperationSpeed, 3f); - yield return new KeyValuePair(StatDefOf.MedicalSurgerySuccessChance, 3f); - yield return new KeyValuePair(StatDefOf.MedicalTendQuality, 3f); - yield return new KeyValuePair(StatDefOf.MedicalTendSpeed, 1.5f); - yield break; + mainJob = true; } - yield return new KeyValuePair(StatDefOf2.MedicalOperationSpeed, 1f); - yield return new KeyValuePair(StatDefOf.MedicalSurgerySuccessChance, 1f); - yield return new KeyValuePair(StatDefOf.MedicalTendQuality, 1f); - yield return new KeyValuePair(StatDefOf.MedicalTendSpeed, 0.5f); + yield return new KeyValuePair(StatDefOf2.MedicalOperationSpeed, PosMax(mainJob)); + yield return new KeyValuePair(StatDefOf.MedicalSurgerySuccessChance, PosMax(mainJob)); + yield return new KeyValuePair(StatDefOf.MedicalTendQuality, PosMax(mainJob)); + yield return new KeyValuePair(StatDefOf.MedicalTendSpeed, PosMed(mainJob)); yield break; case "PatientBedRest": yield break; @@ -587,266 +611,202 @@ private static IEnumerable> GetStatsOfWorkType(Pawn case "Warden": if (pawnSave.mainJob == MainJob.Warden) { - yield return new KeyValuePair(StatDefOf.RecruitPrisonerChance, 3f); - yield return new KeyValuePair(StatDefOf.SocialImpact, 1.5f); - yield break; + mainJob = true; } - yield return new KeyValuePair(StatDefOf.RecruitPrisonerChance, 1f); - yield return new KeyValuePair(StatDefOf.SocialImpact, 0.5f); + yield return new KeyValuePair(StatDefOf.RecruitPrisonerChance, PosMax(mainJob)); + yield return new KeyValuePair(StatDefOf.SocialImpact, PosMed(mainJob)); yield break; case "Handling": if (pawnSave.mainJob == MainJob.Handler) { - yield return new KeyValuePair(StatDefOf.TameAnimalChance, 3f); - yield return new KeyValuePair(StatDefOf.TrainAnimalChance, 3f); - yield return new KeyValuePair(StatDefOf.ArmorRating_Blunt, 1.25f); - yield return new KeyValuePair(StatDefOf.ArmorRating_Sharp, 1.25f); - yield return new KeyValuePair(StatDefOf.MeleeDodgeChance, 1f); - yield return new KeyValuePair(StatDefOf.MeleeHitChance, 0.6f); - yield return new KeyValuePair(StatDefOf.MoveSpeed, 0.9f); - yield return new KeyValuePair(StatDefOf.AnimalGatherYield, 1.2f); - yield return new KeyValuePair(StatDefOf.AnimalGatherSpeed, 0.6f); - yield return new KeyValuePair(StatDefOf.CarryingCapacity, 0.3f); - yield return new KeyValuePair(StatDefOf2.MeleeDPS, 0.6f); - yield return new KeyValuePair(StatDefOf.AccuracyTouch, 0.6f); - yield return new KeyValuePair(StatDefOf.MeleeWeapon_CooldownMultiplier, -0.6f); - yield return new KeyValuePair(StatDefOf.MeleeWeapon_DamageMultiplier, 0.6f); - yield break; + mainJob = true; } - yield return new KeyValuePair(StatDefOf.TameAnimalChance, 1f); - yield return new KeyValuePair(StatDefOf.TrainAnimalChance, 1f); - yield return new KeyValuePair(StatDefOf.ArmorRating_Blunt, 0.25f); - yield return new KeyValuePair(StatDefOf.ArmorRating_Sharp, 0.25f); - yield return new KeyValuePair(StatDefOf.MeleeDodgeChance, 0.5f); - yield return new KeyValuePair(StatDefOf.MeleeHitChance, 0.2f); - yield return new KeyValuePair(StatDefOf.MoveSpeed, 0.3f); - yield return new KeyValuePair(StatDefOf.AnimalGatherYield, 0.4f); - yield return new KeyValuePair(StatDefOf.AnimalGatherSpeed, 0.2f); - yield return new KeyValuePair(StatDefOf.CarryingCapacity, 0.1f); - yield return new KeyValuePair(StatDefOf2.MeleeDPS, 0.2f); - yield return new KeyValuePair(StatDefOf.AccuracyTouch, 0.2f); - yield return new KeyValuePair(StatDefOf.MeleeWeapon_CooldownMultiplier, -0.2f); - yield return new KeyValuePair(StatDefOf.MeleeWeapon_DamageMultiplier, 0.2f); + yield return new KeyValuePair(StatDefOf.TameAnimalChance, PosMax(mainJob)); + yield return new KeyValuePair(StatDefOf.TrainAnimalChance, PosMax(mainJob)); + yield return new KeyValuePair(StatDefOf.ArmorRating_Blunt, PosMin(mainJob)); + yield return new KeyValuePair(StatDefOf.ArmorRating_Sharp, PosMin(mainJob)); + yield return new KeyValuePair(StatDefOf.MeleeDodgeChance, PosMed(mainJob)); + yield return new KeyValuePair(StatDefOf.MeleeHitChance, PosMin(mainJob)); + yield return new KeyValuePair(StatDefOf.MoveSpeed, PosMin(mainJob)); + yield return new KeyValuePair(StatDefOf.AnimalGatherYield, PosMax(mainJob)); + yield return new KeyValuePair(StatDefOf.AnimalGatherSpeed, PosMax(mainJob)); + // yield return new KeyValuePair(StatDefOf.CarryingCapacity, PosMin(mainJob)); + yield return new KeyValuePair(StatDefOf.MeleeDPS, PosMin(mainJob)); + yield return new KeyValuePair(StatDefOf.AccuracyTouch, PosMin(mainJob)); + yield return new KeyValuePair(StatDefOf.MeleeWeapon_CooldownMultiplier, NegMin(mainJob)); + yield return new KeyValuePair(StatDefOf.MeleeWeapon_DamageMultiplier, PosMin(mainJob)); yield break; case "Cooking": if (pawnSave.mainJob == MainJob.Cook) { - yield return new KeyValuePair(StatDefOf2.CookSpeed, 3f); - yield return new KeyValuePair(StatDefOf2.BrewingSpeed, 3f); - yield return new KeyValuePair(StatDefOf2.ButcheryFleshSpeed, 3f); - yield return new KeyValuePair(StatDefOf2.ButcheryFleshEfficiency, 3f); - yield return new KeyValuePair(StatDefOf.WorkSpeedGlobal, 0.6f); - yield return new KeyValuePair(StatDefOf.MoveSpeed, 0.3f); - yield return new KeyValuePair(StatDefOf.FoodPoisonChance, -1.5f); - yield break; + mainJob = true; } // yield return new KeyValuePair(StatDefOf.MoveSpeed, 0.05f); // yield return new KeyValuePair(StatDefOf.WorkSpeedGlobal, 0.2f); - yield return new KeyValuePair(StatDefOf2.CookSpeed, 1f); - yield return new KeyValuePair(StatDefOf2.BrewingSpeed, 1f); - yield return new KeyValuePair(StatDefOf2.ButcheryFleshSpeed, 1f); - yield return new KeyValuePair(StatDefOf2.ButcheryFleshEfficiency, 1f); - yield return new KeyValuePair(StatDefOf.WorkSpeedGlobal, 0.2f); - yield return new KeyValuePair(StatDefOf.MoveSpeed, 0.1f); - yield return new KeyValuePair(StatDefOf.FoodPoisonChance, -0.5f); + yield return new KeyValuePair(StatDefOf2.CookSpeed, PosMax(mainJob)); + yield return new KeyValuePair(StatDefOf2.BrewingSpeed, PosMax(mainJob)); + yield return new KeyValuePair(StatDefOf2.ButcheryFleshSpeed, PosMax(mainJob)); + yield return new KeyValuePair(StatDefOf2.ButcheryFleshEfficiency, PosMax(mainJob)); + yield return new KeyValuePair(StatDefOf.WorkSpeedGlobal, PosMin(mainJob)); + yield return new KeyValuePair(StatDefOf.MoveSpeed, PosMin(mainJob)); + yield return new KeyValuePair(StatDefOf.FoodPoisonChance, NegMax(mainJob)); yield break; case "Hunting": if (pawnSave.mainJob == MainJob.Hunter) { - yield return new KeyValuePair(StatDefOf.ShootingAccuracy, 3f); - yield return new KeyValuePair(StatDefOf.MoveSpeed, 1.5f); - yield return new KeyValuePair(StatDefOf.AccuracyShort, 1.2f); - yield return new KeyValuePair(StatDefOf.AccuracyMedium, 1.2f); - yield return new KeyValuePair(StatDefOf.AccuracyLong, 1.2f); - yield return new KeyValuePair(StatDefOf2.MeleeDPS, 0.75f); - yield return new KeyValuePair(StatDefOf.MeleeHitChance, 0.75f); - yield return new KeyValuePair(StatDefOf.ArmorRating_Blunt, 0.75f); - yield return new KeyValuePair(StatDefOf.ArmorRating_Sharp, 0.75f); - yield return new KeyValuePair(StatDefOf.RangedWeapon_Cooldown, -2.4f); - yield return new KeyValuePair(StatDefOf.AimingDelayFactor, -3f); - yield return new KeyValuePair(StatDefOf.PainShockThreshold, 3f); - yield break; + mainJob = true; } - yield return new KeyValuePair(StatDefOf.ShootingAccuracy, 1f); - yield return new KeyValuePair(StatDefOf.MoveSpeed, 0.5f); - yield return new KeyValuePair(StatDefOf.AccuracyShort, 0.4f); - yield return new KeyValuePair(StatDefOf.AccuracyMedium, 0.4f); - yield return new KeyValuePair(StatDefOf.AccuracyLong, 0.4f); - yield return new KeyValuePair(StatDefOf2.MeleeDPS, 0.25f); - yield return new KeyValuePair(StatDefOf.MeleeHitChance, 0.25f); - yield return new KeyValuePair(StatDefOf.ArmorRating_Blunt, 0.25f); - yield return new KeyValuePair(StatDefOf.ArmorRating_Sharp, 0.25f); - yield return new KeyValuePair(StatDefOf.RangedWeapon_Cooldown, -0.8f); - yield return new KeyValuePair(StatDefOf.AimingDelayFactor, -1f); - yield return new KeyValuePair(StatDefOf.PainShockThreshold, 1f); + yield return new KeyValuePair(StatDefOf.ShootingAccuracy, PosMax(mainJob)); + yield return new KeyValuePair(StatDefOf.MoveSpeed, PosMed(mainJob)); + yield return new KeyValuePair(StatDefOf.AccuracyShort, PosMed(mainJob)); + yield return new KeyValuePair(StatDefOf.AccuracyMedium, PosMed(mainJob)); + yield return new KeyValuePair(StatDefOf.AccuracyLong, PosMed(mainJob)); + yield return new KeyValuePair(StatDefOf.MeleeDPS, PosMin(mainJob)); + yield return new KeyValuePair(StatDefOf.MeleeHitChance, PosMin(mainJob)); + yield return new KeyValuePair(StatDefOf.ArmorRating_Blunt, PosMin(mainJob)); + yield return new KeyValuePair(StatDefOf.ArmorRating_Sharp, PosMin(mainJob)); + yield return new KeyValuePair(StatDefOf.RangedWeapon_Cooldown, NegMax(mainJob)); + yield return new KeyValuePair(StatDefOf.AimingDelayFactor, NegMax(mainJob)); + yield return new KeyValuePair(StatDefOf.PainShockThreshold, PosMax(mainJob)); yield break; case "Construction": if (pawnSave.mainJob == MainJob.Constructor) { - yield return new KeyValuePair(StatDefOf.ConstructionSpeed, 3f); - yield return new KeyValuePair(StatDefOf.ConstructSuccessChance, 3f); - yield return new KeyValuePair(StatDefOf.FixBrokenDownBuildingSuccessChance, 3f); - yield return new KeyValuePair(StatDefOf.SmoothingSpeed, 3f); - yield return new KeyValuePair(StatDefOf.CarryingCapacity, 0.75f); - yield return new KeyValuePair(StatDefOf.MoveSpeed, 0.6f); - yield return new KeyValuePair(StatDefOf.WorkSpeedGlobal, 0.6f); - yield break; + mainJob = true; } - yield return new KeyValuePair(StatDefOf.ConstructionSpeed, 1f); - yield return new KeyValuePair(StatDefOf.ConstructSuccessChance, 1f); - yield return new KeyValuePair(StatDefOf.FixBrokenDownBuildingSuccessChance, 1f); - yield return new KeyValuePair(StatDefOf.SmoothingSpeed, 1f); - yield return new KeyValuePair(StatDefOf.CarryingCapacity, 0.25f); - yield return new KeyValuePair(StatDefOf.MoveSpeed, 0.2f); - yield return new KeyValuePair(StatDefOf.WorkSpeedGlobal, 0.2f); + yield return new KeyValuePair(StatDefOf.ConstructionSpeed, PosMax(mainJob)); + yield return new KeyValuePair(StatDefOf.ConstructSuccessChance, PosMax(mainJob)); + yield return new KeyValuePair(StatDefOf.FixBrokenDownBuildingSuccessChance, PosMax(mainJob)); + yield return new KeyValuePair(StatDefOf.SmoothingSpeed, PosMax(mainJob)); + // yield return new KeyValuePair(StatDefOf.CarryingCapacity, PosMin(mainJob)); + yield return new KeyValuePair(StatDefOf.MoveSpeed, PosMin(mainJob)); + yield return new KeyValuePair(StatDefOf.WorkSpeedGlobal, PosMin(mainJob)); yield break; case "Repair": - yield return new KeyValuePair(StatDefOf.FixBrokenDownBuildingSuccessChance, 1f); - yield return new KeyValuePair(StatDefOf.MoveSpeed, 0.2f); - yield return new KeyValuePair(StatDefOf.WorkSpeedGlobal, 0.2f); + yield return new KeyValuePair(StatDefOf.FixBrokenDownBuildingSuccessChance, PosMax(mainJob)); + yield return new KeyValuePair(StatDefOf.MoveSpeed, PosMin(mainJob)); + yield return new KeyValuePair(StatDefOf.WorkSpeedGlobal, PosMin(mainJob)); yield break; case "Growing": if (pawnSave.mainJob == MainJob.Grower) { - yield return new KeyValuePair(StatDefOf.PlantHarvestYield, 3f); - yield return new KeyValuePair(StatDefOf.PlantWorkSpeed, 3f); - yield return new KeyValuePair(StatDefOf.MoveSpeed, 0.3f); - yield return new KeyValuePair(StatDefOf.WorkSpeedGlobal, 0.6f); - yield break; + mainJob = true; } - yield return new KeyValuePair(StatDefOf.PlantHarvestYield, 1f); - yield return new KeyValuePair(StatDefOf.PlantWorkSpeed, 1f); - yield return new KeyValuePair(StatDefOf.MoveSpeed, 0.1f); - yield return new KeyValuePair(StatDefOf.WorkSpeedGlobal, 0.2f); + yield return new KeyValuePair(StatDefOf.PlantHarvestYield, PosMax(mainJob)); + yield return new KeyValuePair(StatDefOf.PlantWorkSpeed, PosMax(mainJob)); + yield return new KeyValuePair(StatDefOf.MoveSpeed, PosMin(mainJob)); + yield return new KeyValuePair(StatDefOf.WorkSpeedGlobal, PosMin(mainJob)); yield break; case "Mining": if (pawnSave.mainJob == MainJob.Miner) { - yield return new KeyValuePair(StatDefOf.MiningYield, 3f); - yield return new KeyValuePair(StatDefOf.MiningSpeed, 3f); - yield return new KeyValuePair(StatDefOf.CarryingCapacity, 0.75f); - yield return new KeyValuePair(StatDefOf.WorkSpeedGlobal, 0.6f); - yield return new KeyValuePair(StatDefOf.MoveSpeed, 0.3f); - yield break; + mainJob = true; } - yield return new KeyValuePair(StatDefOf.MiningYield, 1f); - yield return new KeyValuePair(StatDefOf.MiningSpeed, 1f); - yield return new KeyValuePair(StatDefOf.CarryingCapacity, 0.25f); - yield return new KeyValuePair(StatDefOf.WorkSpeedGlobal, 0.2f); - yield return new KeyValuePair(StatDefOf.MoveSpeed, 0.1f); + yield return new KeyValuePair(StatDefOf.MiningYield, PosMax(mainJob)); + yield return new KeyValuePair(StatDefOf.MiningSpeed, PosMax(mainJob)); + // yield return new KeyValuePair(StatDefOf.CarryingCapacity, PosMin(mainJob)); + yield return new KeyValuePair(StatDefOf.WorkSpeedGlobal, PosMin(mainJob)); + yield return new KeyValuePair(StatDefOf.MoveSpeed, PosMin(mainJob)); yield break; case "PlantCutting": - yield return new KeyValuePair(StatDefOf.PlantWorkSpeed, 0.5f); - yield return new KeyValuePair(StatDefOf.WorkSpeedGlobal, 0.2f); + yield return new KeyValuePair(StatDefOf.PlantWorkSpeed, PosMax(mainJob)); + yield return new KeyValuePair(StatDefOf.PlantHarvestYield, PosMed(mainJob)); + yield return new KeyValuePair(StatDefOf.WorkSpeedGlobal, PosMin(mainJob)); yield break; case "Smithing": if (pawnSave.mainJob == MainJob.Smith) { - yield return new KeyValuePair(StatDefOf2.SmithingSpeed, 3f); - yield return new KeyValuePair(StatDefOf.WorkSpeedGlobal, 0.6f); - yield break; + mainJob = true; } - yield return new KeyValuePair(StatDefOf2.SmithingSpeed, 1f); - yield return new KeyValuePair(StatDefOf.WorkSpeedGlobal, 0.2f); + yield return new KeyValuePair(StatDefOf2.SmithingSpeed, PosMax(mainJob)); + yield return new KeyValuePair(StatDefOf.WorkSpeedGlobal, PosMin(mainJob)); yield break; case "Tailoring": if (pawnSave.mainJob == MainJob.Tailor) { - yield return new KeyValuePair(StatDefOf2.TailoringSpeed, 3f); - yield return new KeyValuePair(StatDefOf.WorkSpeedGlobal, 0.6f); - yield break; + mainJob = true; } - yield return new KeyValuePair(StatDefOf2.TailoringSpeed, 1f); - yield return new KeyValuePair(StatDefOf.WorkSpeedGlobal, 0.2f); + yield return new KeyValuePair(StatDefOf2.TailoringSpeed, PosMax(mainJob)); + yield return new KeyValuePair(StatDefOf.WorkSpeedGlobal, PosMin(mainJob)); yield break; case "Art": if (pawnSave.mainJob == MainJob.Artist) { - yield return new KeyValuePair(StatDefOf2.SculptingSpeed, 3f); - yield return new KeyValuePair(StatDefOf.WorkSpeedGlobal, 0.6f); - yield break; + mainJob = true; } - yield return new KeyValuePair(StatDefOf2.SculptingSpeed, 1f); - yield return new KeyValuePair(StatDefOf.WorkSpeedGlobal, 0.2f); + yield return new KeyValuePair(StatDefOf2.SculptingSpeed, PosMax(mainJob)); + yield return new KeyValuePair(StatDefOf.WorkSpeedGlobal, PosMin(mainJob)); yield break; case "Crafting": if (pawnSave.mainJob == MainJob.Crafter) { - yield return new KeyValuePair(StatDefOf.WorkSpeedGlobal, 2.5f); - yield return new KeyValuePair(StatDefOf2.SmeltingSpeed, 3f); - yield return new KeyValuePair(StatDefOf2.ButcheryMechanoidSpeed, 1.5f); - yield return new KeyValuePair(StatDefOf2.ButcheryMechanoidEfficiency, 1.5f); - yield break; + mainJob = true; } - yield return new KeyValuePair(StatDefOf.WorkSpeedGlobal, 0.75f); - yield return new KeyValuePair(StatDefOf2.SmeltingSpeed, 1f); - yield return new KeyValuePair(StatDefOf2.ButcheryMechanoidSpeed, 0.5f); - yield return new KeyValuePair(StatDefOf2.ButcheryMechanoidEfficiency, 0.5f); + yield return new KeyValuePair(StatDefOf.WorkSpeedGlobal, PosMed(mainJob)); + yield return new KeyValuePair(StatDefOf2.SmeltingSpeed, PosMax(mainJob)); + yield return new KeyValuePair(StatDefOf2.ButcheryMechanoidSpeed, PosMed(mainJob)); + yield return new KeyValuePair(StatDefOf2.ButcheryMechanoidEfficiency, PosMed(mainJob)); yield break; case "Hauling": if (pawnSave.mainJob == MainJob.Hauler) { - yield return new KeyValuePair(StatDefOf.MoveSpeed, 3f); - yield return new KeyValuePair(StatDefOf.CarryingCapacity, 0.75f); - yield break; + mainJob = true; } - yield return new KeyValuePair(StatDefOf.MoveSpeed, 1f); - yield return new KeyValuePair(StatDefOf.CarryingCapacity, 0.25f); + yield return new KeyValuePair(StatDefOf.MoveSpeed, PosMax(mainJob)); + yield return new KeyValuePair(StatDefOf.CarryingCapacity, PosMin(mainJob)); yield break; case "Cleaning": - yield return new KeyValuePair(StatDefOf.MoveSpeed, 0.5f); - yield return new KeyValuePair(StatDefOf.WorkSpeedGlobal, 0.25f); + yield return new KeyValuePair(StatDefOf.MoveSpeed, PosMax(mainJob)); + yield return new KeyValuePair(StatDefOf.WorkSpeedGlobal, PosMax(mainJob)); yield break; case "Research": if (pawnSave.mainJob == MainJob.Researcher) { - yield return new KeyValuePair(StatDefOf.ResearchSpeed, 3f); - yield return new KeyValuePair(StatDefOf.WorkSpeedGlobal, 0.6f); - yield break; + mainJob = true; } - yield return new KeyValuePair(StatDefOf.ResearchSpeed, 1f); - yield return new KeyValuePair(StatDefOf.WorkSpeedGlobal, 0.2f); + yield return new KeyValuePair(StatDefOf.ResearchSpeed, PosMax(mainJob)); + yield return new KeyValuePair(StatDefOf.WorkSpeedGlobal, PosMin(mainJob)); yield break; // Colony Manager case "Managing": - yield return new KeyValuePair(StatDefOf.SocialImpact, 0.25f); - yield return new KeyValuePair(DefDatabase.GetNamed("ManagingSpeed"), 0.5f); + yield return new KeyValuePair(StatDefOf.SocialImpact, PosMin(mainJob)); + yield return new KeyValuePair(DefDatabase.GetNamed("ManagingSpeed"), PosMed(mainJob)); yield break; // Hospitality case "Diplomat": - yield return new KeyValuePair(StatDefOf.SocialImpact, 0.5f); - yield return new KeyValuePair(StatDefOf.DiplomacyPower, 1f); - yield return new KeyValuePair(StatDefOf.TradePriceImprovement, 1f); + yield return new KeyValuePair(StatDefOf.SocialImpact, PosMed(mainJob)); + yield return new KeyValuePair(StatDefOf.DiplomacyPower, PosMax(mainJob)); + yield return new KeyValuePair(StatDefOf.TradePriceImprovement, PosMax(mainJob)); yield break; // Else @@ -859,7 +819,7 @@ private static IEnumerable> GetStatsOfWorkType(Pawn default: if (!IgnoredWorktypeDefs.Contains(worktype.defName)) { - Log.Warning("WorkTypeDef " + worktype.defName + " not handled."); + Log.Warning("Outfitter: WorkTypeDef " + worktype.defName + " not handled. \nThis is not a bug, just a notice for the mod author."); IgnoredWorktypeDefs.Add(worktype.defName); } diff --git a/Source/Outfitter/Cache.cs b/Source/Outfitter/Cache.cs index 1f45aa7..e76cf7c 100644 --- a/Source/Outfitter/Cache.cs +++ b/Source/Outfitter/Cache.cs @@ -6,8 +6,6 @@ using RimWorld; - using Verse; - public static class Cache { // ReSharper disable once FieldCanBeMadeReadOnly.Global @@ -18,25 +16,22 @@ public static float GetEquippedStatValue([NotNull] this Apparel apparel, StatDef float currentStat = apparel.def.equippedStatOffsets.GetStatOffsetFromList(stat); // { - // float baseStat = apparel.GetStatValue(stat, true); - // float currentStat = baseStat; - // currentStat += apparel.def.equippedStatOffsets.GetStatOffsetFromList(stat.); - // - // DoApparelScoreRaw_PawnStatsHandlers(apparel, StatDefOf.Insulation_Cold, out float infInsulationCold); - // DoApparelScoreRaw_PawnStatsHandlers(apparel, StatDefOf.Insulation_Heat, out float infInsulationHeat); - // - // if (baseStat == 0) - // return currentStat; - // else - // return currentStat / baseStat; + // float baseStat = apparel.GetStatValue(stat, true); + // float currentStat = baseStat; + // currentStat += apparel.def.equippedStatOffsets.GetStatOffsetFromList(stat.); + // DoApparelScoreRaw_PawnStatsHandlers(apparel, StatDefOf.Insulation_Cold, out float infInsulationCold); + // DoApparelScoreRaw_PawnStatsHandlers(apparel, StatDefOf.Insulation_Heat, out float infInsulationHeat); + // if (baseStat == 0) + // return currentStat; + // else + // return currentStat / baseStat; // } // float pawnStat = p.GetStatValue(stat); - // // var x = pawnStat; // if (!p.apparel.WornApparel.Contains(apparel)) // { - // x += currentStat; + // x += currentStat; // } // currentStat += apparel.def.equippedStatOffsets.GetStatOffsetFromList(stat.StatDef); @@ -44,7 +39,6 @@ public static float GetEquippedStatValue([NotNull] this Apparel apparel, StatDef // { // return apparel.def.equippedStatOffsets.GetStatOffsetFromList(stat.StatDef) - baseStat; // } - return currentStat; } } diff --git a/Source/Outfitter/Extensions.cs b/Source/Outfitter/Extensions.cs index 826a72f..b3cd024 100644 --- a/Source/Outfitter/Extensions.cs +++ b/Source/Outfitter/Extensions.cs @@ -1,10 +1,7 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace Outfitter +namespace Outfitter { + using System.Linq; + using Verse; public static class Extensions @@ -33,4 +30,4 @@ public static int GetWorkPriority(this Pawn pawn, WorkTypeDef workType) return pawn.workSettings.GetPriority(workType); } } -} +} \ No newline at end of file diff --git a/Source/Outfitter/GameComponent_Outfitter.cs b/Source/Outfitter/GameComponent_Outfitter.cs index c69fb8e..824a6d1 100644 --- a/Source/Outfitter/GameComponent_Outfitter.cs +++ b/Source/Outfitter/GameComponent_Outfitter.cs @@ -10,11 +10,11 @@ public class GameComponent_Outfitter : GameComponent { + public static bool updated; + [NotNull] public List _pawnCache = new List(); - public static bool updated; - public GameComponent_Outfitter() { } @@ -41,12 +41,11 @@ public GameComponent_Outfitter(Game game) } } - public override void ExposeData() { base.ExposeData(); - Scribe_Collections.Look(ref _pawnCache, "Pawns", LookMode.Deep); + Scribe_Collections.Look(ref this._pawnCache, "Pawns", LookMode.Deep); } } } \ No newline at end of file diff --git a/Source/Outfitter/HarmonyPatches.cs b/Source/Outfitter/HarmonyPatches.cs index 5343837..7ce8186 100644 --- a/Source/Outfitter/HarmonyPatches.cs +++ b/Source/Outfitter/HarmonyPatches.cs @@ -5,11 +5,13 @@ // public override string ModIdentifier { get { return "Outfitter"; } } // } -using Harmony; -using Outfitter; using System.Linq; using System.Reflection; +using Harmony; + +using Outfitter; + using RimWorld; using Verse; @@ -27,8 +29,10 @@ static HarmonyPatches() // new HarmonyMethod(typeof(TabsPatch), nameof(TabsPatch.DoTabs_Prefix)), // null); harmony.Patch( - AccessTools.Method(typeof(RimWorld.JobGiver_OptimizeApparel), "TryGiveJob"), - new HarmonyMethod(typeof(JobGiver_OutfitterOptimizeApparel), nameof(JobGiver_OutfitterOptimizeApparel.TryGiveJob_Prefix)), + AccessTools.Method(typeof(JobGiver_OptimizeApparel), "TryGiveJob"), + new HarmonyMethod( + typeof(JobGiver_OutfitterOptimizeApparel), + nameof(JobGiver_OutfitterOptimizeApparel.TryGiveJob_Prefix)), null); harmony.Patch( @@ -41,10 +45,20 @@ static HarmonyPatches() null, new HarmonyMethod(typeof(HarmonyPatches), nameof(UpdatePriorities))); - // harmony.Patch( - // AccessTools.Method(typeof(ThinkNode_JobGiver), nameof(ThinkNode_JobGiver.TryIssueJobPackage)), - // null, - // new HarmonyMethod(typeof(HarmonyPatches), nameof(LogJobActivities))); + harmony.Patch( + AccessTools.Method(typeof(ITab_Bills), "FillTab"), + new HarmonyMethod(typeof(ITab_Bills_Patch), nameof(ITab_Bills_Patch.FillTab_Prefix)), + null); + + harmony.Patch( + AccessTools.Method(typeof(ITab_Bills), "TabUpdate"), + new HarmonyMethod(typeof(ITab_Bills_Patch), nameof(ITab_Bills_Patch.TabUpdate_Prefix)), + null); + + // harmony.Patch( + // AccessTools.Method(typeof(ThinkNode_JobGiver), nameof(ThinkNode_JobGiver.TryIssueJobPackage)), + // null, + // new HarmonyMethod(typeof(HarmonyPatches), nameof(LogJobActivities))); // harmony.Patch( // AccessTools.Method(typeof(ITab_Bills), "FillTab"), @@ -56,18 +70,23 @@ static HarmonyPatches() "Outfitter successfully completed " + harmony.GetPatchedMethods().Count() + " patches with harmony."); } - private static void UpdatePriorities(Pawn_WorkSettings __instance) + private static void LogJobActivities( + ThinkNode_JobGiver __instance, + ThinkResult __result, + Pawn pawn, + JobIssueParams jobParams) { - FieldInfo fieldInfo = typeof(Pawn_WorkSettings).GetField("pawn", BindingFlags.NonPublic | BindingFlags.Instance); - Pawn pawn = (Pawn)fieldInfo?.GetValue(__instance); - pawn.GetSaveablePawn().forceStatUpdate = true; + // if (__result.Job.def.driverClass.) + // { + // __result.Job. + // } } - private static void LogJobActivities(ThinkNode_JobGiver __instance, ThinkResult __result, Pawn pawn, JobIssueParams jobParams) + private static void UpdatePriorities(Pawn_WorkSettings __instance) { - // if (__result.Job.def.driverClass.) - // { - // __result.Job. - // } + FieldInfo fieldInfo = + typeof(Pawn_WorkSettings).GetField("pawn", BindingFlags.NonPublic | BindingFlags.Instance); + Pawn pawn = (Pawn)fieldInfo?.GetValue(__instance); + pawn.GetSaveablePawn().forceStatUpdate = true; } } \ No newline at end of file diff --git a/Source/Outfitter/Helper/HelperThingFilterUI.cs b/Source/Outfitter/Helper/HelperThingFilterUI.cs deleted file mode 100644 index e45aa9c..0000000 --- a/Source/Outfitter/Helper/HelperThingFilterUI.cs +++ /dev/null @@ -1,117 +0,0 @@ -using System.Linq; -using RimWorld; -using UnityEngine; -using Verse; - -namespace Outfitter.Helper -{ - public static class HelperThingFilterUI - { - private const float ExtraViewHeight = 90f; - - private const float RangeLabelTab = 10f; - - private const float RangeLabelHeight = 19f; - - private const float SliderHeight = 26f; - - private const float SliderTab = 20f; - - private static float viewHeight; - - // Verse.ThingFilterUI - public static void DoThingFilterConfigWindow(Rect rect, ref Vector2 scrollPosition, ThingFilter filter, ThingFilter parentFilter = null, int openMask = 1, string filterText = null) - { - Widgets.DrawMenuSection(rect, true); - Text.Font = GameFont.Tiny; - float num = rect.width - 2f; - Rect rect2 = new Rect(rect.x + 1f, rect.y + 1f, num / 2f, 24f); - if (Widgets.ButtonText(rect2, "ClearAll".Translate(), true, false, true)) - { - filter.SetDisallowAll(); - } - - Rect rect3 = new Rect(rect2.xMax + 1f, rect2.y, num / 2f, 24f); - if (Widgets.ButtonText(rect3, "AllowAll".Translate(), true, false, true)) - { - filter.SetAllowAll(parentFilter); - } - - Text.Font = GameFont.Small; - rect.yMin = rect2.yMax; - Rect viewRect = new Rect(0f, 0f, rect.width - 16f, HelperThingFilterUI.viewHeight); - Widgets.BeginScrollView(rect, ref scrollPosition, viewRect); - float num2 = 2f; - HelperThingFilterUI.DrawHitPointsFilterConfig(ref num2, viewRect.width, filter); - HelperThingFilterUI.DrawQualityFilterConfig(ref num2, viewRect.width, filter); - float num3 = num2; - Rect rect4 = new Rect(0f, num2, viewRect.width, 9999f); - Listing_TreeThingFilter listing_TreeThingFilter = new Listing_TreeThingFilter(rect4, filter, parentFilter); - TreeNode_ThingCategory node = ThingCategoryNodeDatabase.RootNode; - if (parentFilter != null) - { - if (parentFilter.DisplayRootCategory == null) - { - parentFilter.RecalculateDisplayRootCategory(); - } - - node = parentFilter.DisplayRootCategory; - } - - if (filterText != null && filterText.Length > 2) - { - TreeNode_ThingCategory rootNode = new TreeNode_ThingCategory(new ThingCategoryDef()); - - node.catDef.DescendantThingDefs.Where(td => td.label.ToLower().Contains(filterText.ToLower())); - - foreach (ThingDef currentThing in node.catDef.DescendantThingDefs.Where(td => td.label.ToLower().Contains(filterText.ToLower()))) - { - rootNode.catDef.childThingDefs.Add(currentThing); - } - - node = rootNode; - } - - listing_TreeThingFilter.DoCategoryChildren(node, 0, openMask, true); - listing_TreeThingFilter.End(); - if (Event.current.type == EventType.Layout) - { - HelperThingFilterUI.viewHeight = num3 + listing_TreeThingFilter.CurHeight + 90f; - } - - Widgets.EndScrollView(); - } - - private static void DrawHitPointsFilterConfig(ref float y, float width, ThingFilter filter) - { - if (!filter.allowedHitPointsConfigurable) - { - return; - } - - Rect rect = new Rect(20f, y, width - 20f, 26f); - FloatRange allowedHitPointsPercents = filter.AllowedHitPointsPercents; - Widgets.FloatRange(rect, 1, ref allowedHitPointsPercents, 0f, 1f, "HitPoints", ToStringStyle.PercentZero); - filter.AllowedHitPointsPercents = allowedHitPointsPercents; - y += 26f; - y += 5f; - Text.Font = GameFont.Small; - } - - private static void DrawQualityFilterConfig(ref float y, float width, ThingFilter filter) - { - if (!filter.allowedQualitiesConfigurable) - { - return; - } - - Rect rect = new Rect(20f, y, width - 20f, 26f); - QualityRange allowedQualityLevels = filter.AllowedQualityLevels; - Widgets.QualityRange(rect, 2, ref allowedQualityLevels); - filter.AllowedQualityLevels = allowedQualityLevels; - y += 26f; - y += 5f; - Text.Font = GameFont.Small; - } - } -} \ No newline at end of file diff --git a/Source/Outfitter/ITab_Bills_Patch.cs b/Source/Outfitter/ITab_Bills_Patch.cs index 12ecfa8..1e10932 100644 --- a/Source/Outfitter/ITab_Bills_Patch.cs +++ b/Source/Outfitter/ITab_Bills_Patch.cs @@ -1,77 +1,105 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace Outfitter +namespace Outfitter { + using System; + using System.Collections.Generic; + using System.Linq; using System.Reflection; - using Harmony; - using RimWorld; using UnityEngine; using Verse; - using FloatMenuOption = Verse.FloatMenuOption; - public static class ITab_Bills_Patch { private static float viewHeight = 1000f; private static Vector2 scrollPosition = default(Vector2); - // RimWorld.ITab_Bills private static readonly Vector2 WinSize = new Vector2(420f, 480f); + private static Bill mouseoverBill; + + // RimWorld.ITab_Bills + public static bool FillTab_Prefix() { + Building_WorkTable selTable = (Building_WorkTable)Find.Selector.SingleSelectedThing; + PlayerKnowledgeDatabase.KnowledgeDemonstrated(ConceptDefOf.BillsTab, KnowledgeAmount.FrameDisplayed); - Rect rect = new Rect(0f, 0f, WinSize.x, WinSize.y).ContractedBy(10f); + float x = WinSize.x; + Vector2 winSize2 = WinSize; + Rect rect2 = new Rect(0f, 0f, x, winSize2.y).ContractedBy(10f); Func> recipeOptionsMaker = delegate { List list = new List(); - for (int i = 0; i < SelTable.def.AllRecipes.Count; i++) + for (int i = 0; i < selTable.def.AllRecipes.Count; i++) { - list.Add(new FloatMenuOption("LOL", null)); - - if (SelTable.def.AllRecipes[i].AvailableNow) + if (selTable.def.AllRecipes[i].AvailableNow) { - RecipeDef recipe = SelTable.def.AllRecipes[i]; - list.Add(new FloatMenuOption(recipe.LabelCap, delegate - { - if (!SelTable.Map.mapPawns.FreeColonists.Any((Pawn col) => recipe.PawnSatisfiesSkillRequirements(col))) - { - Bill.CreateNoPawnsWithSkillDialog(recipe); - } - Bill bill = recipe.MakeNewBill(); - SelTable.billStack.AddBill(bill); - if (recipe.conceptLearned != null) - { - PlayerKnowledgeDatabase.KnowledgeDemonstrated(recipe.conceptLearned, KnowledgeAmount.Total); - } - if (TutorSystem.TutorialMode) - { - TutorSystem.Notify_Event("AddBill-" + recipe.LabelCap); - } - })); + RecipeDef recipe = selTable.def.AllRecipes[i]; + list.Add( + new FloatMenuOption( + recipe.LabelCap, + delegate + { + if (!selTable.Map.mapPawns.FreeColonists.Any( + col => recipe.PawnSatisfiesSkillRequirements(col))) + { + Bill.CreateNoPawnsWithSkillDialog(recipe); + } + + Bill bill = recipe.MakeNewBill(); + selTable.billStack.AddBill(bill); + if (recipe.conceptLearned != null) + { + PlayerKnowledgeDatabase.KnowledgeDemonstrated( + recipe.conceptLearned, + KnowledgeAmount.Total); + } + + if (TutorSystem.TutorialMode) + { + TutorSystem.Notify_Event("AddBill-" + recipe.LabelCap); + } + }, + MenuOptionPriority.Default, + null, + null, + 29f, + rect => Widgets.InfoCardButton( + (float)(rect.x + 5.0), + (float)(rect.y + (rect.height - 24.0) / 2.0), + recipe))); } } - if (!Enumerable.Any(list)) + + if (!list.Any()) { - list.Add(new FloatMenuOption("NoneBrackets".Translate(), null)); + list.Add( + new FloatMenuOption( + "NoneBrackets".Translate(), + null)); } return list; }; - Bill mouseoverBill = SelTable.billStack.DoListing(rect, recipeOptionsMaker, ref scrollPosition, ref viewHeight); + mouseoverBill = selTable.billStack.DoListing(rect2, recipeOptionsMaker, ref scrollPosition, ref viewHeight); - typeof(Bill).GetField( - "mouseoverBill", - BindingFlags.Instance | BindingFlags.NonPublic).SetValue(typeof(Bill), mouseoverBill); + + return false; + + } + + public static bool TabUpdate_Prefix() + { + if (mouseoverBill != null) + { + mouseoverBill.TryDrawIngredientSearchRadiusOnMap(Find.Selector.SingleSelectedThing.Position); + mouseoverBill = null; + } return false; } } diff --git a/Source/Outfitter/InfusedStats/HarmonyPatchInfused.cs b/Source/Outfitter/InfusedStats/HarmonyPatchInfused.cs deleted file mode 100644 index 54120f5..0000000 --- a/Source/Outfitter/InfusedStats/HarmonyPatchInfused.cs +++ /dev/null @@ -1,75 +0,0 @@ -//namespace Outfitter -//{ -// public class Outfitter_ModBase : HugsLib.ModBase -// { -// public override string ModIdentifier { get { return "Outfitter"; } } -// } - -using System; - -using Harmony; - -using Outfitter; -using Outfitter.InfusedStats; - -using Verse; - -[StaticConstructorOnStartup] -internal class HarmonyPatchInfused -{ - #region Public Constructors - - static HarmonyPatchInfused() - { - HarmonyInstance harmony = HarmonyInstance.Create("com.outfitterinfused.rimworld.mod"); - - try - { - ((Action)(() => - { - if (AccessTools.Method(typeof(Infused.GenInfusion), nameof(Infused.GenInfusion.TryGetInfusions)) - == null) - { - return; - } - - harmony.Patch( - AccessTools.Method( - typeof(ApparelStatCache), - nameof(ApparelStatCache.ApparelScoreRaw_PawnStatsHandlers)), - null, - new HarmonyMethod( - typeof(InfusedStats), - nameof(InfusedStats.ApparelScoreRaw_PawnStatsHandlers))); - - harmony.Patch( - AccessTools.Method( - typeof(ApparelStatCache), - nameof(ApparelStatCache.ApparelScoreRaw_FillInfusedStat)), - null, - new HarmonyMethod( - typeof(InfusedStats), - nameof(InfusedStats.ApparelScoreRaw_FillInfusedStat))); - - harmony.Patch( - AccessTools.Method( - typeof(ApparelStatCache), - nameof(ApparelStatCache.Ignored_WTHandlers)), - null, - new HarmonyMethod( - typeof(InfusedStats), - nameof(InfusedStats.Ignored_WTHandlers))); - // ApparelStatCache.ApparelScoreRaw_PawnStatsHandlers += InfusedStats.ApparelScoreRaw_PawnStatsHandlers; - // ApparelStatCache.ApparelScoreRaw_FillInfusedStat += InfusedStats.ApparelScoreRaw_FillInfusedStat; - // ApparelStatCache.Ignored_WTHandlers += InfusedStats.Ignored_WTHandlers; - }))(); - } - catch (TypeLoadException) - { - } - - Log.Message("Outfitter successfully initialized Infused stats."); - } - - #endregion Public Constructors -} \ No newline at end of file diff --git a/Source/Outfitter/InfusedStats/InfusedStats.cs b/Source/Outfitter/InfusedStats/InfusedStats.cs deleted file mode 100644 index 9254595..0000000 --- a/Source/Outfitter/InfusedStats/InfusedStats.cs +++ /dev/null @@ -1,83 +0,0 @@ -namespace Outfitter.Infused -{ - using System.Collections.Generic; - using System.Linq; - - using RimWorld; - - using Verse; - - public static class InfusedStats - { - public static void ApparelScoreRaw_FillInfusedStat(Apparel apparel, StatDef parentStat, ref HashSet infusedOffsets) - { - if (apparel.TryGetInfusions(out InfusionSet inf)) - { - StatMod mod; - - Def prefix = inf.prefix; - Def suffix = inf.suffix; - - if (prefix != null && prefix.TryGetStatValue(parentStat, out mod)) - { - infusedOffsets.Add(parentStat); - } - - if (suffix != null && suffix.TryGetStatValue(parentStat, out mod)) - { - infusedOffsets.Add(parentStat); - } - - // if (!infusionSet.PassPre && prefix.GetStatValue(parentStat, out statMod)) - // { - // val += statMod.offset; - // val *= statMod.multiplier; - // } - // if (infusionSet.PassSuf || !suffix.GetStatValue(parentStat, out statMod)) - // return; - // val += statMod.offset; - // val *= statMod.multiplier; - } - } - - public static void ApparelScoreRaw_PawnStatsHandlers(Apparel apparel, StatDef statPriority, ref float val) - { - InfusionSet inf; - if (apparel.TryGetInfusions(out inf)) - { - Def prefix = inf.prefix; - Def suffix = inf.suffix; - - float statInfusedPrefix = 0f; - float statInfusedSuffix = 0f; - - if (prefix != null && prefix.TryGetStatValue(statPriority, out StatMod mod)) - { - statInfusedPrefix += mod.offset; - statInfusedPrefix += mod.multiplier - 1; - } - - if (suffix != null && suffix.TryGetStatValue(statPriority, out mod)) - { - statInfusedSuffix += mod.offset; - statInfusedSuffix += mod.multiplier - 1; - } - - val += statInfusedPrefix + statInfusedSuffix; - } - } - - public static void Ignored_WTHandlers(ref List allApparelStats) - { - // add all stat modifiers from all infusions - foreach (KeyValuePair mod in DefDatabase.AllDefsListForReading.SelectMany( - infusion => infusion.stats)) - { - if (!allApparelStats.Contains(mod.Key)) - { - allApparelStats.Add(mod.Key); - } - } - } - } -} \ No newline at end of file diff --git a/Source/Outfitter/JobGiver_OutfitterOptimizeApparel.cs b/Source/Outfitter/JobGiver_OutfitterOptimizeApparel.cs index fb14e82..dae7364 100644 --- a/Source/Outfitter/JobGiver_OutfitterOptimizeApparel.cs +++ b/Source/Outfitter/JobGiver_OutfitterOptimizeApparel.cs @@ -1,11 +1,15 @@ namespace Outfitter { - using JetBrains.Annotations; - using RimWorld; using System.Collections.Generic; using System.Linq; using System.Text; + + using JetBrains.Annotations; + + using RimWorld; + using UnityEngine; + using Verse; using Verse.AI; @@ -23,6 +27,15 @@ public static class JobGiver_OutfitterOptimizeApparel private static Apparel lastItem; + public static void SetNextOptimizeTick([NotNull] Pawn pawn) + { + pawn.mindState.nextApparelOptimizeTick = Find.TickManager.TicksGame + + Random.Range( + ApparelOptimizeCheckIntervalMin, + ApparelOptimizeCheckIntervalMax); + + // pawn.GetApparelStatCache().recentApparel.Clear(); + } // private static NeededWarmth neededWarmth; public static bool TryGiveJob_Prefix(ref Job __result, Pawn pawn) @@ -30,7 +43,9 @@ public static bool TryGiveJob_Prefix(ref Job __result, Pawn pawn) __result = null; if (pawn.outfits == null) { - Log.ErrorOnce(pawn + " tried to run JobGiver_OutfitterOptimizeApparel without an OutfitTracker", 5643897); + Log.ErrorOnce( + pawn + " tried to run JobGiver_OutfitterOptimizeApparel without an OutfitTracker", + 5643897); return false; } @@ -77,6 +92,7 @@ public static bool TryGiveJob_Prefix(ref Job __result, Pawn pawn) pawn.GetApparelStatCache().ToDropList[ap].mindState.Notify_OutfitChanged(); pawn.GetApparelStatCache().ToDropList.Remove(ap); } + return false; } } @@ -115,9 +131,8 @@ public static bool TryGiveJob_Prefix(ref Job __result, Pawn pawn) // not very elegant but working // if (pawn.GetApparelStatCache().recentApparel.Contains(apparel)) // { - // gain *= 0.01f; + // gain *= 0.01f; // } - if (DebugViewSettings.debugApparelOptimize) { debugSb.AppendLine(apparel.LabelCap + ": " + gain.ToString("F2")); @@ -144,15 +159,15 @@ public static bool TryGiveJob_Prefix(ref Job __result, Pawn pawn) } // New stuff - if (false) { - var list2 = pawn.Map.mapPawns.FreeColonistsSpawned.Where(x => x.IsColonistPlayerControlled); + IEnumerable list2 = pawn.Map.mapPawns.FreeColonistsSpawned.Where(x => x.IsColonistPlayerControlled); foreach (Apparel ap in wornApparel) { foreach (Pawn otherPawn in list2) { - foreach (Apparel otherAp in otherPawn.apparel.WornApparel.Where(x => !ApparelUtility.CanWearTogether(ap.def, x.def, pawn.RaceProps.body))) + foreach (Apparel otherAp in otherPawn.apparel.WornApparel.Where( + x => !ApparelUtility.CanWearTogether(ap.def, x.def, pawn.RaceProps.body))) { float gain = pawn.ApparelScoreGain(otherAp); float otherGain = otherPawn.ApparelScoreGain(ap); @@ -183,21 +198,10 @@ public static bool TryGiveJob_Prefix(ref Job __result, Pawn pawn) // foreach (Apparel apparel in wornApparel) // { - // pawn.GetApparelStatCache().recentApparel.Add(apparel); + // pawn.GetApparelStatCache().recentApparel.Add(apparel); // } - __result = new Job(JobDefOf.Wear, thing); return false; } - - public static void SetNextOptimizeTick([NotNull] Pawn pawn) - { - pawn.mindState.nextApparelOptimizeTick = Find.TickManager.TicksGame - + Random.Range( - ApparelOptimizeCheckIntervalMin, - ApparelOptimizeCheckIntervalMax); - // pawn.GetApparelStatCache().recentApparel.Clear(); - - } } } \ No newline at end of file diff --git a/Source/Outfitter/Optional/Harmony_DDWorkTab.cs b/Source/Outfitter/Optional/Harmony_DDWorkTab.cs index 499e19e..15a4a59 100644 --- a/Source/Outfitter/Optional/Harmony_DDWorkTab.cs +++ b/Source/Outfitter/Optional/Harmony_DDWorkTab.cs @@ -9,12 +9,8 @@ using Harmony; - using RimWorld; - using Verse; - using Extensions = Outfitter.Extensions; - // Blatantly stolen from "Psychology" [StaticConstructorOnStartup] internal static class Harmony_DDWorkTab @@ -26,14 +22,12 @@ static Harmony_DDWorkTab() { ((Action)(() => { - if (AccessTools.Method( - typeof(PawnSurface), - nameof(PawnSurface.EnableWorkType)) != null) + if (AccessTools.Method(typeof(PawnSurface), nameof(PawnSurface.EnableWorkType)) != null) { - harmony.Patch( - AccessTools.Method(typeof(PawnSurface), "UpdatePawnPriorities"), - null, - new HarmonyMethod(typeof(Harmony_DDWorkTab), nameof(UpdatePriorities))); + harmony.Patch( + AccessTools.Method(typeof(PawnSurface), "UpdatePawnPriorities"), + null, + new HarmonyMethod(typeof(Harmony_DDWorkTab), nameof(UpdatePriorities))); harmony.Patch( AccessTools.Method(typeof(ApparelStatsHelper), nameof(Extensions.GetWorkPriority)), @@ -66,27 +60,33 @@ static Harmony_DDWorkTab() } } - private static void UpdatePriorities(PawnSurface __instance) - { - __instance.pawn.GetSaveablePawn().forceStatUpdate = true; - } - private static bool GetWorkPriorityDD(Pawn pawn, WorkTypeDef workType, ref int __result) { __result = 20; - var GetManager = Current.Game.GetComponent(); + SurfaceManager GetManager = Current.Game.GetComponent(); PawnSurface surface = GetManager.GetPawnSurface(pawn); - var childrenFieldInfo = typeof(PawnSurface).GetField("children", BindingFlags.NonPublic | BindingFlags.Instance); + FieldInfo childrenFieldInfo = + typeof(PawnSurface).GetField("children", BindingFlags.NonPublic | BindingFlags.Instance); List children = (List)childrenFieldInfo?.GetValue(surface); if (children.NullOrEmpty()) { return true; } - List ignoreList = new List() { "Firefighter", "Patient", "PatientBedRest", "Flicker", "HaulingUrgent", "FinishingOff" }; - List filtered = children.Where(x => !x.Disabled && !ignoreList.Contains(x.Def.defName)).ToList(); + + List ignoreList = new List + { + "Firefighter", + "Patient", + "PatientBedRest", + "Flicker", + "HaulingUrgent", + "FinishingOff" + }; + List filtered = children.Where(x => !x.Disabled && !ignoreList.Contains(x.Def.defName)) + .ToList(); for (int i = 0; i < filtered.Count; i++) { @@ -96,11 +96,18 @@ private static bool GetWorkPriorityDD(Pawn pawn, WorkTypeDef workType, ref int _ { continue; } + int priority = i + 1; __result = priority; break; } + return false; } + + private static void UpdatePriorities(PawnSurface __instance) + { + __instance.pawn.GetSaveablePawn().forceStatUpdate = true; + } } } \ No newline at end of file diff --git a/Source/Outfitter/Outfitter.csproj b/Source/Outfitter/Outfitter.csproj index 6d50eb6..04c57ce 100644 --- a/Source/Outfitter/Outfitter.csproj +++ b/Source/Outfitter/Outfitter.csproj @@ -70,9 +70,7 @@ - - - + @@ -87,7 +85,6 @@ - diff --git a/Source/Outfitter/Saveables/Saveable_Pawn.cs b/Source/Outfitter/Saveables/Saveable_Pawn.cs index cc0036f..87769c3 100644 --- a/Source/Outfitter/Saveables/Saveable_Pawn.cs +++ b/Source/Outfitter/Saveables/Saveable_Pawn.cs @@ -4,12 +4,8 @@ using Verse; - public partial class SaveablePawn : IExposable + public class SaveablePawn : IExposable { - private bool addIndividualStats = true; - - private bool addWorkStats = true; - public List ApparelStats = new List(); public bool armorOnly = false; @@ -17,8 +13,7 @@ public partial class SaveablePawn : IExposable public bool AutoEquipWeapon; // public FloatRange RealComfyTemperatures; - public bool forceStatUpdate = false; - + public bool forceStatUpdate; public MainJob mainJob; // Exposed members @@ -32,28 +27,39 @@ public partial class SaveablePawn : IExposable public FloatRange Temperatureweight; - public bool AddWorkStats + private bool addIndividualStats = true; + private bool addPersonalStats = true; + + private bool addWorkStats = true; + + public bool AddIndividualStats { - get + get => this.addIndividualStats; + set { - return addWorkStats; + this.addIndividualStats = value; + this.forceStatUpdate = true; } + } + public bool AddPersonalStats + { + get => this.addPersonalStats; set { - addWorkStats = value; + this.addPersonalStats = value; this.forceStatUpdate = true; } } - public bool AddIndividualStats + public bool AddWorkStats { - get => this.addIndividualStats; + get => this.addWorkStats; + set { - this.addIndividualStats = value; + this.addWorkStats = value; this.forceStatUpdate = true; } - } // public SaveablePawn(Pawn pawn) @@ -76,6 +82,7 @@ public void ExposeData() Scribe_Collections.Look(ref this.ApparelStats, "WeaponStats", LookMode.Deep); Scribe_Values.Look(ref this.addWorkStats, "AddWorkStats", true); Scribe_Values.Look(ref this.addIndividualStats, "AddIndividualStats", true); + Scribe_Values.Look(ref this.addPersonalStats, "addPersonalStats", true); Scribe_Values.Look(ref this.mainJob, "mainJob"); } } diff --git a/Source/Outfitter/StatDefOf2.cs b/Source/Outfitter/StatDefOf2.cs index 5ad01de..015f199 100644 --- a/Source/Outfitter/StatDefOf2.cs +++ b/Source/Outfitter/StatDefOf2.cs @@ -20,7 +20,6 @@ public static class StatDefOf2 public static StatDef MedicalOperationSpeed; - public static StatDef MeleeDPS; public static StatDef SculptingSpeed; diff --git a/Source/Outfitter/StatPriority.cs b/Source/Outfitter/StatPriority.cs index 71f619a..451cf31 100644 --- a/Source/Outfitter/StatPriority.cs +++ b/Source/Outfitter/StatPriority.cs @@ -14,7 +14,6 @@ namespace Outfitter using Verse; - public class StatPriority { public StatPriority(StatDef stat, float priority, StatAssignment assignment = StatAssignment.Automatic) @@ -69,5 +68,4 @@ public void Reset(Pawn pawn) } // ReSharper disable once CollectionNeverUpdated.Global - } \ No newline at end of file diff --git a/Source/Outfitter/Window/Dialog_PawnApparelComparer.cs b/Source/Outfitter/Window/Dialog_PawnApparelComparer.cs index 442dc56..073b67d 100644 --- a/Source/Outfitter/Window/Dialog_PawnApparelComparer.cs +++ b/Source/Outfitter/Window/Dialog_PawnApparelComparer.cs @@ -1,10 +1,14 @@ namespace Outfitter.Window { - using JetBrains.Annotations; - using RimWorld; using System.Collections.Generic; using System.Linq; + + using JetBrains.Annotations; + + using RimWorld; + using UnityEngine; + using Verse; public class Dialog_PawnApparelComparer : Window @@ -15,6 +19,10 @@ public class Dialog_PawnApparelComparer : Window [NotNull] private readonly Pawn pawn; + private List _calculatedApparelItems; + + private List _calculatedApparelScore; + private Vector2 scrollPosition; public Dialog_PawnApparelComparer(Pawn p, Apparel apparel) @@ -29,9 +37,19 @@ public Dialog_PawnApparelComparer(Pawn p, Apparel apparel) public override Vector2 InitialSize => new Vector2(500f, 700f); + public void DIALOG_CalculateApparelScoreGain(Pawn pawn, Apparel apparel, out float gain) + { + if (this._calculatedApparelItems == null) + { + this.DIALOG_InitializeCalculatedApparelScoresFromWornApparel(); + } + + gain = pawn.ApparelScoreGain(apparel); + } + public override void DoWindowContents(Rect windowRect) { - ApparelStatCache apparelStatCache = new ApparelStatCache(pawn.GetSaveablePawn()); + ApparelStatCache apparelStatCache = new ApparelStatCache(this.pawn.GetSaveablePawn()); List allApparels = new List( this.pawn.Map.listerThings.ThingsInGroup(ThingRequestGroup.Apparel).OfType()); foreach (Pawn pawn in PawnsFinder.AllMaps_FreeColonists.Where(x => x.Map == this.pawn.Map)) @@ -99,7 +117,7 @@ public override void DoWindowContents(Rect windowRect) allApparels = allApparels.OrderByDescending( i => { - DIALOG_CalculateApparelScoreGain(this.pawn, i, out float g); + this.DIALOG_CalculateApparelScoreGain(this.pawn, i, out float g); return g; }).ToList(); @@ -138,7 +156,7 @@ public override void DoWindowContents(Rect windowRect) } } - DIALOG_CalculateApparelScoreGain(this.pawn, currentAppel, out float gain); + this.DIALOG_CalculateApparelScoreGain(this.pawn, currentAppel, out float gain); string gainString = this.pawn.outfits.forcedHandler.AllowedToAutomaticallyDrop(currentAppel) ? gain.ToString("N5") : "No Allow"; @@ -170,23 +188,10 @@ public override void DoWindowContents(Rect windowRect) Text.Anchor = TextAnchor.UpperLeft; GUI.EndGroup(); } - private List _calculatedApparelItems; - - private List _calculatedApparelScore; - - public void DIALOG_CalculateApparelScoreGain(Pawn pawn, Apparel apparel, out float gain) - { - if (this._calculatedApparelItems == null) - { - this.DIALOG_InitializeCalculatedApparelScoresFromWornApparel(); - } - - gain = pawn.ApparelScoreGain(apparel); - } private void DIALOG_InitializeCalculatedApparelScoresFromWornApparel() { - var conf = this.pawn.GetApparelStatCache(); + ApparelStatCache conf = this.pawn.GetApparelStatCache(); this._calculatedApparelItems = new List(); this._calculatedApparelScore = new List(); foreach (Apparel apparel in this.pawn.apparel.WornApparel) diff --git a/Source/Outfitter/Window/ITab_Pawn_Outfitter.cs b/Source/Outfitter/Window/ITab_Pawn_Outfitter.cs index 743bcab..d2c3fff 100644 --- a/Source/Outfitter/Window/ITab_Pawn_Outfitter.cs +++ b/Source/Outfitter/Window/ITab_Pawn_Outfitter.cs @@ -173,22 +173,25 @@ protected override void FillTab() } // Status checkboxes - Rect rectCheckboxes = new Rect(rectStatus.x, rectStatus.yMax + Margin, rectStatus.width, 48f); + Rect rectCheckboxes = new Rect(rectStatus.x, rectStatus.yMax + Margin, rectStatus.width, 72f); Rect check1 = new Rect(rectCheckboxes.x, rectCheckboxes.y, rectCheckboxes.width, 24f); Rect check2 = new Rect(rectCheckboxes.x, check1.yMax, rectCheckboxes.width, 24f); + Rect check3 = new Rect(rectCheckboxes.x, check2.yMax, rectCheckboxes.width, 24f); bool pawnSaveAddWorkStats = pawnSave.AddWorkStats; bool pawnSaveAddIndividualStats = pawnSave.AddIndividualStats; - DrawCheckBoxArea(check1, "AddWorkStats".Translate(), ref pawnSaveAddWorkStats); - DrawCheckBoxArea(check2, "AddIndividualStats".Translate(), ref pawnSaveAddIndividualStats); + bool pawnSaveAddPersonalStats = pawnSave.AddPersonalStats; + Widgets.CheckboxLabeled(check1, "AddWorkStats".Translate(), ref pawnSaveAddWorkStats); + Widgets.CheckboxLabeled(check2, "AddIndividualStats".Translate(), ref pawnSaveAddIndividualStats); + Widgets.CheckboxLabeled(check3, "AddPersonalStats".Translate(), ref pawnSaveAddPersonalStats); - if (pawnSaveAddWorkStats != pawnSave.AddWorkStats) + if (GUI.changed) { pawnSave.AddWorkStats = pawnSaveAddWorkStats; - } - if (pawnSaveAddIndividualStats != pawnSave.AddIndividualStats) - { + pawnSave.AddIndividualStats = pawnSaveAddIndividualStats; + + pawnSave.AddPersonalStats = pawnSaveAddPersonalStats; } // main canvas @@ -208,11 +211,6 @@ protected override void FillTab() Text.Anchor = TextAnchor.UpperLeft; } - private static void DrawCheckBoxArea(Rect rect, string name, ref bool stat) - { - Widgets.CheckboxLabeled(rect, name, ref stat); - } - private void DrawApparelList() { // main canvas @@ -345,7 +343,7 @@ private void DrawApparelStats(Vector2 cur, Rect canvas) Text.Font = GameFont.Tiny; GUI.color = Color.grey; Text.Anchor = TextAnchor.LowerLeft; - Widgets.Label(legendRect,"-"+ ApparelStatCache.MaxValue.ToString("N1")); + Widgets.Label(legendRect, "-" + ApparelStatCache.MaxValue.ToString("N1")); Text.Anchor = TextAnchor.LowerRight; Widgets.Label(legendRect, ApparelStatCache.MaxValue.ToString("N1")); Text.Anchor = TextAnchor.UpperLeft; diff --git a/Source/Outfitter/Window/Window_Pawn_ApparelDetail.cs b/Source/Outfitter/Window/Window_Pawn_ApparelDetail.cs index f374df2..f92fe09 100644 --- a/Source/Outfitter/Window/Window_Pawn_ApparelDetail.cs +++ b/Source/Outfitter/Window/Window_Pawn_ApparelDetail.cs @@ -18,24 +18,30 @@ namespace Outfitter public class Window_Pawn_ApparelDetail : Verse.Window { + private const float baseValue = 85f; + private readonly Apparel apparel; private readonly GUIStyle fontBold = new GUIStyle - { - fontStyle = FontStyle.Bold, - normal = { textColor = Color.white }, - padding = new RectOffset(0, 0, 12, 6) - }; + { + fontStyle = FontStyle.Bold, + normal = { + textColor = Color.white + }, + padding = new RectOffset(0, 0, 12, 6) + }; private readonly GUIStyle headline = new GUIStyle - { - fontStyle = FontStyle.Bold, - fontSize = 16, - normal = { textColor = Color.white }, - padding = new RectOffset(0, 0, 12, 6) - }; + { + fontStyle = FontStyle.Bold, + fontSize = 16, + normal = { + textColor = Color.white + }, + padding = new RectOffset(0, 0, 12, 6) + }; private readonly GUIStyle hoverBox = new GUIStyle { hover = { background = OutfitterTextures.BgColor } }; @@ -195,7 +201,6 @@ public override void DoWindowContents(Rect windowRect) if (infusedOffsets.Contains(statPriority.Stat)) { // float statInfused = StatCache.StatInfused(infusionSet, statPriority, ref dontcare); - ApparelStatCache.DoApparelScoreRaw_PawnStatsHandlers( this.apparel, statPriority.Stat, @@ -352,9 +357,14 @@ protected override void SetInitialSizeAndPosition() this.InitialSize.x, this.InitialSize.y).Rounded(); } - private const float baseValue = 85f; - private void DrawLine(string statDefLabelText, float statDefLabelWidth, string statDefValueText, string multiplierText, string finalValueText, GUIStyle style = null) + private void DrawLine( + string statDefLabelText, + float statDefLabelWidth, + string statDefValueText, + string multiplierText, + string finalValueText, + GUIStyle style = null) { if (style != null) { diff --git a/Source/Outfitter_Infused/OutfitterInfused.cs b/Source/Outfitter_Infused/OutfitterInfused.cs index fab9957..a348364 100644 --- a/Source/Outfitter_Infused/OutfitterInfused.cs +++ b/Source/Outfitter_Infused/OutfitterInfused.cs @@ -1,14 +1,16 @@ namespace OutfitterInfused { - using Infused; - using Outfitter; - using RimWorld; using System.Collections.Generic; using System.Linq; - using Harmony; + using Infused; + + using Outfitter; + + using RimWorld; using Verse; + using Def = Infused.Def; public class GameComponent_OutfitterInfused : GameComponent @@ -19,7 +21,6 @@ public GameComponent_OutfitterInfused(Game game) ApparelStatCache.ApparelScoreRaw_PawnStatsHandlers += ApparelScoreRaw_PawnStatsHandlers; ApparelStatCache.ApparelScoreRaw_FillInfusedStat += ApparelScoreRaw_FillInfusedStat; ApparelStatCache.Ignored_WTHandlers += Ignored_WTHandlers; - } private static void ApparelScoreRaw_FillInfusedStat(