public ApparelEntry GetAllOffsets([NotNull] Apparel ap) { if (Outfitter.Cache.ApparelEntries.ContainsKey(ap)) { return(Outfitter.Cache.ApparelEntries[ap]); } var entry = new ApparelEntry(); GetStatsOfApparel(ap, ref entry.EquippedOffsets, ref entry.StatBases); GetStatsOfApparelInfused(ap, ref entry.InfusedOffsets); Outfitter.Cache.ApparelEntries.Add(ap, entry); return(entry); }
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); }