Exemplo n.º 1
0
        public override void DoWindowContents(Rect inRect)
        {
            var conf = _pawn.GetApparelStatCache();

            var conRect = new Rect(inRect);

            conRect.height -= 50f;

            BeginArea(conRect);

            // begin main group
            BeginVertical();

            Label(GetTitle(), _headline);
            Text.Font = GameFont.Small;

            // GUI.BeginGroup(contentRect);
            var labelWidth = conRect.width - BaseValue - BaseValue - BaseValue - 48f;

            DrawLine("Status", labelWidth, "BaseMod", "Strength", "Score", _fontBold);

            Space(6f);
            Label(string.Empty, _whiteLine, Height(1));
            Space(6f);

            var apparelEntry = conf.GetAllOffsets(_apparel);

            var equippedOffsets = apparelEntry.EquippedOffsets;
            var statBases       = apparelEntry.StatBases;
            var infusedOffsets  = apparelEntry.InfusedOffsets;

            _scrollPosition = BeginScrollView(_scrollPosition, Width(conRect.width));

            // relevant apparel stats

            // start score at 1
            float score = 1;

            // add values for each statdef modified by the apparel
            foreach (var statPriority in _pawn.GetApparelStatCache().StatCache
                     .OrderBy(i => i.Stat.LabelCap))
            {
                var    stat      = statPriority.Stat;
                string statLabel = stat.LabelCap;

                // statbases, e.g. armor

                // StatCache.DoApparelScoreRaw_PawnStatsHandlers(_pawn, _apparel, statPriority.Stat, ref currentStat);
                if (statBases.Contains(stat))
                {
                    var statValue = _apparel.GetStatValue(stat);
                    var statScore = 0f;
                    if (ApparelStatCache.SpecialStats.Contains(stat))
                    {
                        ApparelStatCache.CalculateScoreForSpecialStats(_apparel, statPriority, _pawn, statValue,
                                                                       ref statScore);
                    }
                    else
                    {
                        // statValue += StatCache.StatInfused(infusionSet, statPriority, ref baseInfused);
                        statScore = statValue * statPriority.Weight;
                    }

                    score += statScore;

                    DrawLine(
                        statLabel,
                        labelWidth,
                        statValue.ToStringPercent("N1"),
                        statPriority.Weight.ToString("N2"),
                        statScore.ToString("N2"));
                }

                if (equippedOffsets.Contains(stat))
                {
                    var statValue = _apparel.GetEquippedStatValue(_pawn, stat);

                    // statValue += StatCache.StatInfused(infusionSet, statPriority, ref equippedInfused);
                    var statScore = 0f;
                    if (ApparelStatCache.SpecialStats.Contains(stat))
                    {
                        ApparelStatCache.CalculateScoreForSpecialStats(_apparel, statPriority, _pawn, statValue,
                                                                       ref statScore);
                    }
                    else
                    {
                        statScore = statValue * statPriority.Weight;
                    }

                    score += statScore;

                    DrawLine(
                        statLabel,
                        labelWidth,
                        statValue.ToStringPercent("N1"),
                        statPriority.Weight.ToString("N2"),
                        statScore.ToString("N2"));
                }

                if (!infusedOffsets.Contains(stat))
                {
                    continue;
                }

                {
                    GUI.color = Color.green; // new Color(0.5f, 1f, 1f, 1f);

                    // float statInfused = StatCache.StatInfused(infusionSet, statPriority, ref dontcare);
                    ApparelStatCache.DoApparelScoreRaw_PawnStatsHandlers(_apparel, stat, out var statValue);

                    var flag = true;

                    var statScore = 0f;
                    if (ApparelStatCache.SpecialStats.Contains(stat))
                    {
                        ApparelStatCache.CalculateScoreForSpecialStats(_apparel,
                                                                       statPriority, _pawn,
                                                                       statValue,
                                                                       ref statScore);
                    }
                    else
                    {
                        // Bug with Infused and "Ancient", it completely kills the pawn's armor
                        if (statValue < 0 &&
                            (stat == StatDefOf.ArmorRating_Blunt || stat == StatDefOf.ArmorRating_Sharp))
                        {
                            score = -2f;
                            flag  = false;
                        }

                        statScore = statValue * statPriority.Weight;
                    }

                    DrawLine(
                        statLabel,
                        labelWidth,
                        statValue.ToStringPercent("N1"),
                        statPriority.Weight.ToString("N2"),
                        statScore.ToString("N2"));

                    GUI.color = Color.white;

                    if (flag)
                    {
                        score += statScore;
                    }
                    else
                    {
                        break;
                    }
                }
            }

            GUI.color = Color.white;

            // end upper group
            EndScrollView();

            // begin lower group
            FlexibleSpace();
            Space(6f);
            Label(string.Empty, _whiteLine, Height(1));
            Space(6f);
            DrawLine(string.Empty, labelWidth, "Modifier", string.Empty, "Subtotal");

            DrawLine("BasicStatusOfApparel".Translate(), labelWidth, "1.00", "+", score.ToString("N2"));

            var special = _apparel.GetSpecialApparelScoreOffset();

            if (Math.Abs(special) > 0f)
            {
                score += special;

                DrawLine(
                    "OutfitterSpecialScore".Translate(),
                    labelWidth,
                    special.ToString("N2"),
                    "+",
                    score.ToString("N2"));
            }

            var armor = ApparelStatCache.ApparelScoreRaw_ProtectionBaseStat(_apparel);

            if (Math.Abs(armor) > 0.01f)
            {
                score += armor;

                DrawLine("OutfitterArmor".Translate(), labelWidth, armor.ToString("N2"), "+", score.ToString("N2"));
            }

            if (_apparel.def.useHitPoints)
            {
                // durability on 0-1 scale
                var x = _apparel.HitPoints / (float)_apparel.MaxHitPoints;
                score *= ApparelStatsHelper.HitPointsPercentScoreFactorCurve.Evaluate(x);

                DrawLine(
                    "OutfitterHitPoints".Translate(),
                    labelWidth,
                    x.ToString("N2"),
                    "weighted",
                    score.ToString("N2"));

                GUI.color = Color.white;
            }

            if (_apparel.WornByCorpse && ThoughtUtility.CanGetThought_NewTemp(_pawn, ThoughtDefOf.DeadMansApparel))
            {
                score -= 0.5f;
                if (score > 0f)
                {
                    score *= 0.1f;
                }

                DrawLine(
                    "OutfitterWornByCorpse".Translate(),
                    labelWidth,
                    "modified",
                    "weighted",
                    score.ToString("N2"));
            }

            if (_apparel.Stuff == ThingDefOf.Human.race.leatherDef)
            {
                if (ThoughtUtility.CanGetThought_NewTemp(_pawn, ThoughtDefOf.HumanLeatherApparelSad))
                {
                    score -= 0.5f;
                    if (score > 0f)
                    {
                        score *= 0.1f;
                    }
                }

                if (ThoughtUtility.CanGetThought_NewTemp(_pawn, ThoughtDefOf.HumanLeatherApparelHappy))
                {
                    score *= 2f;
                }

                DrawLine(
                    "OutfitterHumanLeather".Translate(),
                    labelWidth,
                    "modified",
                    "weighted",
                    score.ToString("N2"));
            }

            var temperature = conf.ApparelScoreRaw_Temperature(_apparel);

            if (Math.Abs(temperature - 1f) > 0)
            {
                score *= temperature;

                DrawLine(
                    "OutfitterTemperature".Translate(),
                    labelWidth,
                    temperature.ToString("N2"),
                    "*",
                    score.ToString("N2"));
            }

            DrawLine(
                "OutfitterTotal".Translate(),
                labelWidth,
                string.Empty,
                "=",
                conf.ApparelScoreRaw(_apparel).ToString("N2"));

            GUI.color   = Color.white;
            Text.Anchor = TextAnchor.UpperLeft;

            // end main group
            EndVertical();
            EndArea();
        }
        // private static NeededWarmth neededWarmth;
        // ReSharper disable once InconsistentNaming
        public static bool TryGiveJob_Prefix([CanBeNull] ref Job __result, Pawn pawn)
        {
            __result = null;
            if (pawn.outfits == null)
            {
                Log.ErrorOnce(
                    pawn + " tried to run JobGiver_OutfitterOptimizeApparel without an OutfitTracker",
                    5643897);
                return(false);
            }

            if (pawn.Faction != Faction.OfPlayer)
            {
                Log.ErrorOnce("Non-colonist " + pawn + " tried to optimize apparel.", 764323);
                return(false);
            }

            if (!DebugViewSettings.debugApparelOptimize)
            {
                if (Find.TickManager.TicksGame < pawn.mindState.nextApparelOptimizeTick)
                {
                    return(false);
                }
            }
            else
            {
                _debugSb = new StringBuilder();
                _debugSb.AppendLine(string.Concat("Outfiter scanning for ", pawn, " at ", pawn.Position));
            }

            Outfit         currentOutfit = pawn.outfits.CurrentOutfit;
            List <Apparel> wornApparel   = pawn.apparel.WornApparel;

            for (int i = 0; i < wornApparel.Count; i++)
            {
                Apparel          ap   = wornApparel[i];
                ApparelStatCache conf = pawn.GetApparelStatCache();

                bool notAllowed = !currentOutfit.filter.Allows(ap) &&
                                  pawn.outfits.forcedHandler.AllowedToAutomaticallyDrop(ap);

                bool shouldDrop = conf.ApparelScoreRaw(ap) < 0f &&
                                  pawn.outfits.forcedHandler.AllowedToAutomaticallyDrop(ap);

                bool someoneWantsIt = pawn.GetApparelStatCache().ToDropList.ContainsKey(ap);

                if (notAllowed || shouldDrop || someoneWantsIt)
                {
                    __result = new Job(JobDefOf.RemoveApparel, ap)
                    {
                        haulDroppedApparel = true
                    };
                    if (someoneWantsIt)
                    {
                        pawn.GetApparelStatCache().ToDropList[ap].mindState.nextApparelOptimizeTick = -5000;
                        pawn.GetApparelStatCache().ToDropList[ap].mindState.Notify_OutfitChanged();
                        pawn.GetApparelStatCache().ToDropList.Remove(ap);
                    }

                    return(false);
                }
            }

            Thing        thing = null;
            float        score = 0f;
            List <Thing> list  = pawn.Map.listerThings.ThingsInGroup(ThingRequestGroup.Apparel);

            if (list.Count == 0)
            {
                SetNextOptimizeTick(pawn);
                return(false);
            }

            for (int i = 0; i < list.Count; i++)
            {
                Thing   t       = list[i];
                Apparel apparel = (Apparel)t;

                // Not allowed
                if (!currentOutfit.filter.Allows(apparel))
                {
                    continue;
                }

                // Not in store
                if (apparel.Map.haulDestinationManager.SlotGroupAt(apparel.Position) == null)
                {
                    continue;
                }

                // Forbidden
                if (apparel.IsForbidden(pawn))
                {
                    continue;
                }

                float gain = pawn.ApparelScoreGain(apparel);

                // this blocks pawns constantly switching between the recent apparel, due to shifting calculations
                // not very elegant but working
                // if (pawn.GetApparelStatCache().recentApparel.Contains(apparel))
                // {
                // gain *= 0.01f;
                // }
                if (DebugViewSettings.debugApparelOptimize)
                {
                    _debugSb.AppendLine(apparel.LabelCap + ": " + gain.ToString("F2"));
                }

                //  float otherGain = 0f;
                //  Pawn otherPawn = null;
                //  foreach (Pawn otherP in pawn.Map.mapPawns.FreeColonistsSpawned.ToList())
                //  {
                //      if (otherP == pawn)
                //      {
                //          continue;
                //      }
                //      if (otherP.ApparelScoreGain(apparel) >= MinScoreGainToCare)
                //      {
                //          if (ApparelUtility.HasPartsToWear(pawn, apparel.def))
                //          {
                //              if (pawn.CanReserveAndReach(apparel, PathEndMode.OnCell, pawn.NormalMaxDanger(), 1))
                //              {
                //                  thing = apparel;
                //                  score = gain;
                //              }
                //          }
                //          otherPawn = otherP;
                //          otherGain = Mathf.Max(otherGain, otherP.ApparelScoreGain(apparel));
                //      }
                //  }

                if (gain >= MinScoreGainToCare && gain >= score)
                {
                    if (ApparelUtility.HasPartsToWear(pawn, apparel.def))
                    {
                        if (pawn.CanReserveAndReach(apparel, PathEndMode.OnCell, pawn.NormalMaxDanger()))
                        {
                            thing = apparel;
                            score = gain;
                        }
                    }
                }
            }

            if (DebugViewSettings.debugApparelOptimize)
            {
                _debugSb.AppendLine("BEST: " + thing);
                //Log.Message(_debugSb.ToString());
                _debugSb = null;
            }

            // New stuff
            if (false)
            {
                IEnumerable <Pawn> 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)))
                        {
                            float gain      = pawn.ApparelScoreGain(otherAp);
                            float otherGain = otherPawn.ApparelScoreGain(ap);
                            if (gain > MinScoreGainToCare && gain >= score && otherGain > MinScoreGainToCare)
                            {
                                score = gain;
                                Log.Message(
                                    "OUTFITTER: " + pawn + " wants " + otherAp + " currently worn by " + otherPawn
                                    + ", scores: " + gain + " - " + otherGain + " - " + score);

                                if (!otherPawn.GetApparelStatCache().ToDropList.ContainsKey(ap))
                                {
                                    otherPawn.GetApparelStatCache().ToDropList.Add(otherAp, otherPawn);
                                    otherPawn.mindState.nextApparelOptimizeTick = -5000;
                                    otherPawn.mindState.Notify_OutfitChanged();
                                }
                            }
                        }
                    }
                }
            }

            if (thing == null)
            {
                SetNextOptimizeTick(pawn);
                return(false);
            }

            // foreach (Apparel apparel in wornApparel)
            // {
            // pawn.GetApparelStatCache().recentApparel.Add(apparel);
            // }
            __result = new Job(JobDefOf.Wear, thing);
            pawn.Reserve(thing, __result, 1, 1);
            return(false);
        }
        private void DrawTemperatureStats([NotNull] SaveablePawn pawnSave, ref Vector2 cur, Rect canvas)
        {
            // header
            Rect tempHeaderRect = new Rect(cur.x, cur.y, canvas.width, 30f);

            cur.y      += 30f;
            Text.Anchor = TextAnchor.LowerLeft;
            Widgets.Label(tempHeaderRect, "PreferedTemperature".Translate());
            Text.Anchor = TextAnchor.UpperLeft;

            // line
            GUI.color = Color.grey;
            Widgets.DrawLineHorizontal(cur.x, cur.y, canvas.width);
            GUI.color = Color.white;

            // some padding
            cur.y += Margin;

            // temperature slider
            // SaveablePawn pawnStatCache = MapComponent_Outfitter.Get.GetSaveablePawn(SelPawn);
            ApparelStatCache pawnStatCache = this.SelPawnForGear.GetApparelStatCache();
            FloatRange       targetTemps   = pawnStatCache.TargetTemperatures;
            FloatRange       minMaxTemps   = ApparelStatsHelper.MinMaxTemperatureRange;
            Rect             sliderRect    = new Rect(cur.x, cur.y, canvas.width - 20f, 40f);
            Rect             tempResetRect = new Rect(sliderRect.xMax + 4f, cur.y + Margin, 16f, 16f);

            cur.y += 40f;                          // includes padding

            // current temperature settings
            GUI.color = pawnSave.TargetTemperaturesOverride ? Color.white : Color.grey;
            Widgets_FloatRange.FloatRange(
                sliderRect,
                123123123,
                ref targetTemps,
                minMaxTemps,
                ToStringStyle.Temperature);
            GUI.color = Color.white;

            if (Math.Abs(targetTemps.min - pawnStatCache.TargetTemperatures.min) > 1e-4 ||
                Math.Abs(targetTemps.max - pawnStatCache.TargetTemperatures.max) > 1e-4)
            {
                pawnStatCache.TargetTemperatures = targetTemps;
            }

            if (pawnSave.TargetTemperaturesOverride)
            {
                if (Widgets.ButtonImage(tempResetRect, OutfitterTextures.ResetButton))
                {
                    pawnSave.TargetTemperaturesOverride = false;

                    // var saveablePawn = MapComponent_Outfitter.Get.GetSaveablePawn(SelPawn);
                    // saveablePawn.targetTemperaturesOverride = false;
                    pawnStatCache.UpdateTemperatureIfNecessary(true);
                }

                TooltipHandler.TipRegion(tempResetRect, "TemperatureRangeReset".Translate());
            }

            Text.Font = GameFont.Small;
            this.TryDrawComfyTemperatureRange(ref cur.y, canvas.width);
        }
        private void DrawThingRowModded(ref float y, float width, Apparel apparel)
        {
            if (apparel == null)
            {
                this.DrawThingRowVanilla(ref y, width, apparel);
                return;
            }

            Rect rect = new Rect(0f, y, width, ThingRowHeight);

            if (Mouse.IsOver(rect))
            {
                GUI.color = HighlightColor;
                GUI.DrawTexture(rect, TexUI.HighlightTex);
            }

            GUI.color = ThingLabelColor;

            // LMB doubleclick
            if (Widgets.ButtonInvisible(rect))
            {
                // Left Mouse Button Menu
                if (Event.current.button == 0)
                {
                    Find.WindowStack.Add(new Window_Pawn_ApparelDetail(this.SelPawn, apparel));
                }

                // RMB menu
                if (Event.current.button == 1)
                {
                    List <FloatMenuOption> floatOptionList =
                        new List <FloatMenuOption>
                    {
                        new FloatMenuOption(
                            "ThingInfo".Translate(),
                            delegate { Find.WindowStack.Add(new Dialog_InfoCard(apparel)); })
                    };

                    if (this.CanControl)
                    {
                        floatOptionList.Add(
                            new FloatMenuOption(
                                "OutfitterComparer".Translate(),
                                delegate
                        {
                            Find.WindowStack.Add(
                                new
                                Dialog_PawnApparelComparer(this.SelPawnForGear,
                                                           apparel));
                        }));

                        Action dropApparel = delegate
                        {
                            SoundDefOf.Tick_High.PlayOneShotOnCamera();
                            this.InterfaceDrop(apparel);
                        };
                        Action dropApparelHaul = delegate
                        {
                            SoundDefOf.Tick_High.PlayOneShotOnCamera();
                            this.InterfaceDropHaul(apparel);
                        };
                        floatOptionList.Add(new FloatMenuOption("DropThing".Translate(), dropApparel));
                        floatOptionList.Add(new FloatMenuOption("DropThingHaul".Translate(), dropApparelHaul));
                    }

                    FloatMenu window = new FloatMenu(floatOptionList, string.Empty);
                    Find.WindowStack.Add(window);
                }
            }

            if (apparel.def.DrawMatSingle != null && apparel.def.DrawMatSingle.mainTexture != null)
            {
                Widgets.ThingIcon(new Rect(4f, y + 5f, ThingIconSize, ThingIconSize), apparel);
            }

            Text.Anchor = TextAnchor.MiddleLeft;
            GUI.color   = ThingLabelColor;
            Rect textRect  = new Rect(ThingLeftX, y, width - ThingLeftX, ThingRowHeight - Text.LineHeight);
            Rect scoreRect = new Rect(ThingLeftX, textRect.yMax, width - ThingLeftX, Text.LineHeight);

            ApparelStatCache conf      = this.SelPawn.GetApparelStatCache();
            string           text      = apparel.LabelCap;
            string           textScore = Math.Round(conf.ApparelScoreRaw(apparel), 2).ToString("N2");

            if (apparel is Apparel && this.SelPawn.outfits != null &&
                this.SelPawn.outfits.forcedHandler.IsForced(apparel))
            {
                text = text + ", " + "ApparelForcedLower".Translate();
                Widgets.Label(textRect, text);
            }
            else
            {
                GUI.color = new Color(0.75f, 0.75f, 0.75f);
                if (apparel.def.useHitPoints)
                {
                    float x = apparel.HitPoints / (float)apparel.MaxHitPoints;
                    if (x < 0.5f)
                    {
                        GUI.color = Color.yellow;
                    }

                    if (x < 0.2f)
                    {
                        GUI.color = Color.red;
                    }
                }

                Widgets.Label(textRect, text);
                GUI.color = Color.white;
                Widgets.Label(scoreRect, textScore);
            }

            y += ThingRowHeight;
        }
Exemplo n.º 5
0
        protected override void FillTab()
        {
            // main canvas
            Rect canvas = new Rect(0f, 0f, size.x, size.y).ContractedBy(20f);

            GUI.BeginGroup(canvas);
            Vector2 cur = Vector2.zero;

            // header
            Rect tempHeaderRect = new Rect(cur.x, cur.y, canvas.width, 30f);

            cur.y      += 30f;
            Text.Anchor = TextAnchor.LowerLeft;
            Widgets.Label(tempHeaderRect, "PreferedTemperature".Translate());
            Text.Anchor = TextAnchor.UpperLeft;

            // line
            GUI.color = Color.grey;
            Widgets.DrawLineHorizontal(cur.x, cur.y, canvas.width);
            GUI.color = Color.white;

            // some padding
            cur.y += 10f;

            // temperature slider
            ApparelStatCache pawnStatCache = SelPawn.GetApparelStatCache();
            FloatRange       targetTemps   = pawnStatCache.TargetTemperatures;
            FloatRange       minMaxTemps   = ApparelStatsHelper.MinMaxTemperatureRange;

            Rect sliderRect    = new Rect(cur.x, cur.y, canvas.width - 20f, 40f);
            Rect tempResetRect = new Rect(sliderRect.xMax + 4f, cur.y + 10f, 16f, 16f);

            cur.y += 60f; // includes padding

            // current temperature settings
            GUI.color = pawnStatCache.targetTemperaturesOverride ? Color.white : Color.grey;
            Widgets_FloatRange.FloatRange(sliderRect, 123123123, ref targetTemps, minMaxTemps, ToStringStyle.Temperature);
            GUI.color = Color.white;

            if (Math.Abs(targetTemps.min - SelPawn.GetApparelStatCache().TargetTemperatures.min) > 1e-4 ||
                Math.Abs(targetTemps.max - SelPawn.GetApparelStatCache().TargetTemperatures.max) > 1e-4)
            {
                SelPawn.GetApparelStatCache().TargetTemperatures = targetTemps;
            }

            if (pawnStatCache.targetTemperaturesOverride)
            {
                if (Widgets.ImageButton(tempResetRect, resetButton))
                {
                    pawnStatCache.targetTemperaturesOverride = false;
                    pawnStatCache.UpdateTemperatureIfNecessary(true);
                }
                TooltipHandler.TipRegion(tempResetRect, "TemperatureRangeReset".Translate());
            }


            // header
            Rect statsHeaderRect = new Rect(cur.x, cur.y, canvas.width, 30f);

            cur.y      += 30f;
            Text.Anchor = TextAnchor.LowerLeft;
            Text.Font   = GameFont.Small;
            Widgets.Label(statsHeaderRect, "PreferredStats".Translate());
            Text.Anchor = TextAnchor.UpperLeft;

            // add button
            Rect addStatRect = new Rect(statsHeaderRect.xMax - 16f, statsHeaderRect.yMin + 10f, 16f, 16f);

            if (Widgets.ImageButton(addStatRect, addButton))
            {
                List <FloatMenuOption> options = new List <FloatMenuOption>();
                foreach (StatDef def in SelPawn.NotYetAssignedStatDefs())
                {
                    options.Add(new FloatMenuOption(def.LabelCap, delegate
                    {
                        SelPawn.GetApparelStatCache()
                        .StatCache.Insert(0, new ApparelStatCache.StatPriority(def, 0f, StatAssignment.Manual));
                    }));
                }
                Find.WindowStack.Add(new FloatMenu(options));
            }
            TooltipHandler.TipRegion(addStatRect, "StatPriorityAdd".Translate());

            // line
            GUI.color = Color.grey;
            Widgets.DrawLineHorizontal(cur.x, cur.y, canvas.width);
            GUI.color = Color.white;

            // some padding
            cur.y += 10f;

            // main content in scrolling view
            Rect contentRect = new Rect(cur.x, cur.y, canvas.width, canvas.height - cur.y);
            Rect viewRect    = contentRect;

            viewRect.height = SelPawn.GetApparelStatCache().StatCache.Count * 30f + 10f;
            if (viewRect.height > contentRect.height)
            {
                viewRect.width -= 20f;
            }

            Widgets.BeginScrollView(contentRect, ref _scrollPosition, viewRect);
            GUI.BeginGroup(viewRect);
            cur = Vector2.zero;

            // none label
            if (!SelPawn.GetApparelStatCache().StatCache.Any())
            {
                Rect noneLabel = new Rect(cur.x, cur.y, viewRect.width, 30f);
                GUI.color   = Color.grey;
                Text.Anchor = TextAnchor.MiddleCenter;
                Widgets.Label(noneLabel, "None".Translate());
                Text.Anchor = TextAnchor.UpperLeft;
                GUI.color   = Color.white;
                cur.y      += 30f;
            }
            else
            {
                // legend kind of thingy.
                Rect legendRect = new Rect(cur.x + (viewRect.width - 24) / 2, cur.y, (viewRect.width - 24) / 2, 20f);
                Text.Font   = GameFont.Tiny;
                GUI.color   = Color.grey;
                Text.Anchor = TextAnchor.LowerLeft;
                Widgets.Label(legendRect, "-10");
                Text.Anchor = TextAnchor.LowerRight;
                Widgets.Label(legendRect, "10");
                Text.Anchor = TextAnchor.UpperLeft;
                Text.Font   = GameFont.Small;
                GUI.color   = Color.white;
                cur.y      += 15f;

                // stat weight sliders
                foreach (ApparelStatCache.StatPriority stat in SelPawn.GetApparelStatCache().StatCache)
                {
                    bool stop_UI;
                    ApparelStatCache.DrawStatRow(ref cur, viewRect.width, stat, SelPawn, out stop_UI);
                    if (stop_UI)
                    {
                        // DrawStatRow can change the StatCache, invalidating the loop. So if it does that, stop looping - we'll redraw on the next tick.
                        break;
                    }
                }
            }

            GUI.EndGroup();
            Widgets.EndScrollView();

            GUI.EndGroup();
        }