+
+
+
\ No newline at end of file
diff --git a/About/About.xml b/About/About.xml
index e6413a1..c47c4e4 100644
--- a/About/About.xml
+++ b/About/About.xml
@@ -19,6 +19,7 @@
1.3
1.4
1.5
+
1.6
Adds a customizable general overview tab, allowing you to see any stats on all your colonists or prisoners in a single window. Original by koisama. Updated, expanded and maintained by Mehni.
\ No newline at end of file
diff --git a/Defs/PawnColumnDef/PawnColumns_Numbers.xml b/Defs/PawnColumnDef/PawnColumns_Numbers.xml
index d79cd4d..06123cf 100644
--- a/Defs/PawnColumnDef/PawnColumns_Numbers.xml
+++ b/Defs/PawnColumnDef/PawnColumns_Numbers.xml
@@ -203,4 +203,12 @@
+
+ IdeoligionCertainty
+
+ 80
+ UI/Icons/Ideo/Certainty
+ Numbers.PawnColumnWorker_IdeoCertainty
+ true
+
\ No newline at end of file
diff --git a/Languages/English/Keyed/Keys.xml b/Languages/English/Keyed/Keys.xml
index 31f9b40..e1ecfbb 100644
--- a/Languages/English/Keyed/Keys.xml
+++ b/Languages/English/Keyed/Keys.xml
@@ -30,6 +30,7 @@
Note: Applies to *all* PawnTables, not just Numbers.Use tiny font for headers (experimental)Reset tables to default columns.
+ Enable Wild Men TableLoad saved viewNothing saved
diff --git a/Numbers/MainTabWindow_Numbers.cs b/Numbers/MainTabWindow_Numbers.cs
index d8f3a83..611c77a 100644
--- a/Numbers/MainTabWindow_Numbers.cs
+++ b/Numbers/MainTabWindow_Numbers.cs
@@ -1,14 +1,14 @@
-namespace Numbers
+using RimWorld;
+using RimWorld.Planet;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using UnityEngine;
+using Verse;
+
+namespace Numbers
{
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Reflection;
- using RimWorld;
- using RimWorld.Planet;
- using UnityEngine;
- using Verse;
-
public class MainTabWindow_Numbers : MainTabWindow_PawnTable
{
public const float buttonWidth = 110f;
@@ -128,7 +128,15 @@ public override void DoWindowContents(Rect rect)
//worktypes
if (PawnTableDef == NumbersDefOf.Numbers_MainTable)
{
- DoButton(workTabName, optionsMaker.FloatMenuOptionsFor(DefDatabase.AllDefsListForReading.Where(pcd => pcd.workType != null).Reverse()), ref x);
+ var workColumns = DefDatabase.AllDefsListForReading
+ .Where(pcd => pcd.workType != null)
+ .OrderBy(pcd => pcd.workType.labelShort.CapitalizeFirst());
+
+ DoButton(workTabName,
+ optionsMaker.FloatMenuOptionsFor(
+ workColumns,
+ labelOverride: pcd => pcd.workType.labelShort.CapitalizeFirst()),
+ ref x);
}
//skills
@@ -167,11 +175,12 @@ public override void DoWindowContents(Rect rect)
//abilities btn
var abilities = optionsMaker.OptionsMakerForGenericDef(DefDatabase.AllDefsListForReading.OrderBy(y => y.label));
- if (abilities.Count > 0)
+ if (abilities.Count > 0 &&
+ PawnTableDef != NumbersDefOf.Numbers_Animals && PawnTableDef != NumbersDefOf.Numbers_WildAnimals &&
+ PawnTableDef != NumbersDefOf.Numbers_AnimalCorpses && PawnTableDef != NumbersDefOf.Numbers_Corpses)
{
DoButton("Abilities".Translate(), abilities, ref x);
}
-
//records btn
DoButton("TabRecords".Translate(), optionsMaker.OptionsMakerForGenericDef(DefDatabase.AllDefsListForReading), ref x);
@@ -186,6 +195,22 @@ public override void DoWindowContents(Rect rect)
Find.WindowStack.Add(new FloatMenu(optionsMaker.PresetOptionsMaker()));
}
+ // Auto Slaughter Button (only for Animals)
+
+ if (PawnTableDef == NumbersDefOf.Numbers_Animals && Find.CurrentMap != null)
+ {
+ // Magic Numbers Incoming
+ float buttonWidth = 200f;
+ float xOffset = 1f; // smaller = move further left
+ float yOffset = 68f; // smaller = move higher up
+
+ Rect autoSlaughterBtn = new Rect(rect.x + xOffset, rect.y + yOffset, buttonWidth, buttonHeight);
+ if (Widgets.ButtonText(autoSlaughterBtn, "ManageAutoSlaughter".Translate()))
+ {
+ Find.WindowStack.Add(new Dialog_AutoSlaughter(Find.CurrentMap));
+ }
+ }
+
base.DoWindowContents(rect);
}
@@ -264,9 +289,34 @@ private List GetHumanLikeStatDefs()
.Where(s => s.stat != null && s.ShouldDisplay() && s.stat.Worker != null)
.Select(s => s.stat);
+ // Some stats are flaky and disappear between game/save loads, before gear is initialized
+ // or if pawn is not wearing required gear. Force add those stats. Missing DLC is also handled
+ string[] flakyStatNames =
+ [
+ "EatingSpeed",
+ "ForagedNutritionPerDay",
+ "VacuumResistance",
+ "ToxicEnvironmentResistance"
+ ];
+
+ var flakyStats = flakyStatNames
+ .Select(name =>
+ {
+ var stat = DefDatabase.GetNamedSilentFail(name);
+ if (stat == null)
+ Log.Message($"[Numbers] Stat not found: {name}. DLC might be inactive. If this is an error, report to the author");
+ return stat;
+ })
+ .Where(stat => stat != null);
+
+ var combinedStats = pawnHumanlikeStatDef
+ .Concat(flakyStats)
+ .GroupBy(stat => stat.defName)
+ .Select(g => g.First());
+
tmpPawn.Destroy(DestroyMode.KillFinalize);
- return [.. pawnHumanlikeStatDef.OrderBy(stat => stat.LabelCap.Resolve())];
+ return [.. combinedStats.OrderBy(stat => stat.LabelCap.Resolve())];
}
}
}
diff --git a/Numbers/Numbers.cs b/Numbers/Numbers.cs
index 8ebd90c..f2cfc39 100644
--- a/Numbers/Numbers.cs
+++ b/Numbers/Numbers.cs
@@ -455,10 +455,11 @@ public override void DoSettingsWindowContents(Rect inRect)
listingStandard.CheckboxLabeled("Numbers_pawnTableClickSelect".Translate(), ref Numbers_Settings.pawnTableClickSelect, "Numbers_pawnTableClickSelect_Desc".Translate());
listingStandard.CheckboxLabeled("Numbers_pawnTableHighSelected".Translate(), ref Numbers_Settings.pawnTableHighlightSelected, "Numbers_pawnTableHighSelected_Desc".Translate());
listingStandard.CheckboxLabeled("Numbers_useSmolFont".Translate(), ref Numbers_Settings.useTinyFont);
+ listingStandard.CheckboxLabeled("Numbers_showWildMenTable".Translate(), ref Numbers_Settings.showWildMenTable);
listingStandard.SliderLabeled("Numbers_maxTableHeight".Translate(), ref Numbers_Settings.maxHeight, Numbers_Settings.maxHeight.ToStringPercent(), 0.3f);
listingStandard.End();
- DrawResetButton(inRect);
+ if (Current.ProgramState == ProgramState.Playing) DrawResetButton(inRect);
DrawStoredTables(inRect);
diff --git a/Numbers/Numbers.csproj b/Numbers/Numbers.csproj
index e8c57e5..a6a9a96 100644
--- a/Numbers/Numbers.csproj
+++ b/Numbers/Numbers.csproj
@@ -7,12 +7,12 @@
1.1.0.0nonelatest
- ..\1.5\Assemblies\
+ ..\1.6\Assemblies\false
-
-
+
+ all
diff --git a/Numbers/Numbers_Settings.cs b/Numbers/Numbers_Settings.cs
index d1c8588..af61378 100644
--- a/Numbers/Numbers_Settings.cs
+++ b/Numbers/Numbers_Settings.cs
@@ -16,6 +16,7 @@ public class Numbers_Settings : ModSettings
public static bool pawnTableClickSelect = true;
public static bool useTinyFont = false;
+ public static bool showWildMenTable = false;
public List storedPawnTableDefs = [];
private readonly List workingList = [];
@@ -50,6 +51,7 @@ public override void ExposeData()
Scribe_Values.Look(ref pawnTableClickSelect, "pawnTableClickSelect", true);
Scribe_Values.Look(ref maxHeight, "maxHeight", 1f);
Scribe_Values.Look(ref useTinyFont, "useTinyFont");
+ Scribe_Values.Look(ref showWildMenTable, "showWildMenTable");
Scribe_Collections.Look(ref storedPawnTableDefs, "numbersPawnTableDefs");
}
}
diff --git a/Numbers/Numbers_Utility.cs b/Numbers/Numbers_Utility.cs
index 0560b83..230bdca 100644
--- a/Numbers/Numbers_Utility.cs
+++ b/Numbers/Numbers_Utility.cs
@@ -102,5 +102,6 @@ public class NumbersDefOf
public static PawnTableDef Numbers_WildAnimals;
public static PawnTableDef Numbers_Corpses;
public static PawnTableDef Numbers_AnimalCorpses;
+ public static PawnTableDef Numbers_WildMen;
}
}
diff --git a/Numbers/OptionsMaker.cs b/Numbers/OptionsMaker.cs
index 496a249..612c43a 100644
--- a/Numbers/OptionsMaker.cs
+++ b/Numbers/OptionsMaker.cs
@@ -73,8 +73,19 @@ private IEnumerable General()
yield return new FloatMenuOption("Gender", () => AddPawnColumnAtBestPositionAndRefresh(DefDatabase.GetNamedSilentFail("Gender")));
}
+ public List FloatMenuOptionsFor(IEnumerable pcdList, Func labelOverride)
+ => pcdList.Select(pcd => new FloatMenuOption(labelOverride(pcd), () => AddPawnColumnAtBestPositionAndRefresh(pcd))).ToList();
+
public List FloatMenuOptionsFor(IEnumerable pcdList)
- => pcdList.Select(pcd => new FloatMenuOption(GetBestLabelForPawnColumn(pcd), () => AddPawnColumnAtBestPositionAndRefresh(pcd))).ToList();
+ => pcdList
+ .Where(pcd => pcd != null)
+ .Select(pcd =>
+ {
+ string label = GetBestLabelForPawnColumn(pcd);
+ return new FloatMenuOption(label, () => AddPawnColumnAtBestPositionAndRefresh(pcd));
+ })
+ .OrderBy(option => option.Label)
+ .ToList();
public List OtherOptionsMaker()
{
@@ -85,7 +96,8 @@ public List OtherOptionsMaker()
NumbersDefOf.Numbers_Prisoners,
NumbersDefOf.Numbers_Enemies,
NumbersDefOf.Numbers_Corpses,
- NumbersDefOf.Numbers_Guests
+ NumbersDefOf.Numbers_Guests,
+ NumbersDefOf.Numbers_WildMen
}.Contains(PawnTable))
{
list.AddRange(FloatMenuOptionsFor(PawnColumnOptionDefOf.EquipmentBearers.options));
@@ -127,6 +139,18 @@ public List OtherOptionsMaker()
.Where(x => pcdValidator(x))));
}
+ if (PawnTable == NumbersDefOf.Numbers_WildMen)
+ {
+ // Add Wild Animals Options to Wildmen Table
+ list.RemoveAll(x => x.Label == "Gender"); //duplicate
+ list.AddRange(FloatMenuOptionsFor(PawnColumnOptionDefOf.WildAnimals.options
+ .Concat(DefDatabase.GetNamed("Wildlife").columns)
+ .Where(x => pcdValidator(x))));
+ //list.AddRange(FloatMenuOptionsFor(PawnColumnOptionDefOf.WildMen.options
+ // .Concat(DefDatabase.GetNamed("WildMen").columns)
+ // .Where(x => pcdValidator(x))));
+ }
+
//all dead things
if (new[] { NumbersDefOf.Numbers_AnimalCorpses, NumbersDefOf.Numbers_Corpses }.Contains(PawnTable))
{
@@ -140,7 +164,7 @@ public List OptionsMakerForGenericDef(IEnumerable listOfD
{
List list = [];
- foreach (var defCurrent in listOfDefs)
+ foreach (var defCurrent in listOfDefs.OrderBy(d => d.LabelCap.Resolve()))
{
void Action()
{
@@ -159,6 +183,9 @@ public List PawnSelector()
List list = [];
foreach (KeyValuePair> filter in WorldComponent_Numbers.PrimaryFilter)
{
+ // Skip WildMen table if the user has disabled it
+ if (filter.Key == NumbersDefOf.Numbers_WildMen && !Numbers_Settings.showWildMenTable)
+ continue;
void Action()
{
if (filter.Value != MainTabWindow_Numbers.filterValidator.First())
diff --git a/Numbers/PawnColumnOptionDef.cs b/Numbers/PawnColumnOptionDef.cs
index 63c2cb7..8dfa572 100644
--- a/Numbers/PawnColumnOptionDef.cs
+++ b/Numbers/PawnColumnOptionDef.cs
@@ -19,6 +19,7 @@ public class PawnColumnOptionDefOf
public static PawnColumnOptionDef MainTable;
public static PawnColumnOptionDef WildAnimals;
public static PawnColumnOptionDef DeadThings;
+ public static PawnColumnOptionDef WildMen;
public PawnColumnOptionDefOf()
{
diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_AnimalWildness.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_AnimalWildness.cs
deleted file mode 100644
index e14db1b..0000000
--- a/Numbers/PawnColumnWorkers/PawnColumnWorker_AnimalWildness.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-namespace Numbers
-{
- using RimWorld;
- using Verse;
-
- public class PawnColumnWorker_AnimalWildness : PawnColumnWorker_Text
- {
- public override int Compare(Pawn a, Pawn b)
- => (a.AnimalOrWildMan() || b.AnimalOrWildMan())
- ? GetValue(a).CompareTo(GetValue(b))
- : 0;
-
- protected override string GetTextFor(Pawn pawn)
- => pawn.AnimalOrWildMan()
- ? GetValue(pawn).ToStringPercent()
- : string.Empty;
-
- private float GetValue(Pawn pawn)
- => pawn.RaceProps.wildness;
- }
-}
diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_CaravanCarryingCapacity.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_CaravanCarryingCapacity.cs
new file mode 100644
index 0000000..58654b3
--- /dev/null
+++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_CaravanCarryingCapacity.cs
@@ -0,0 +1,32 @@
+using RimWorld;
+using UnityEngine;
+using Verse;
+
+namespace Numbers
+{
+ public class PawnColumnWorker_CaravanCarryingCapacity : PawnColumnWorker_Text
+ {
+ public override int Compare(Pawn a, Pawn b)
+ {
+ float capA = MassUtility.Capacity(a);
+ float capB = MassUtility.Capacity(b);
+ return capA.CompareTo(capB);
+ }
+
+ protected override string GetTextFor(Pawn pawn)
+ {
+ if (pawn == null)
+ return "";
+
+ float capacity = MassUtility.Capacity(pawn);
+ return $"{capacity:0.#} kg";
+ }
+
+ protected override string GetTip(Pawn pawn)
+ {
+ if (pawn == null)
+ return null;
+ return "Amount of mass that can be carried in caravan. It is not same as carrying capacity.";
+ }
+ }
+}
\ No newline at end of file
diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_Entropy.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_Entropy.cs
index 0cfceb6..49b6f66 100644
--- a/Numbers/PawnColumnWorkers/PawnColumnWorker_Entropy.cs
+++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_Entropy.cs
@@ -4,11 +4,8 @@
using UnityEngine;
using Verse;
- [StaticConstructorOnStartup]
public class PawnColumnWorker_Entropy : PawnColumnWorker
{
- private static readonly Texture2D EntropyBarTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.46f, 0.34f, 0.35f));
-
//mostly from PawnColumnWorker_Need
public override void DoCell(Rect rect, Pawn pawn, PawnTable table)
@@ -30,7 +27,7 @@ public override void DoCell(Rect rect, Pawn pawn, PawnTable table)
Rect rect3 = new(rect.x, rect.y + rect.height / 2f, rect.width, rect.height / 2f);
rect3 = new Rect(rect3.x + barWidth, rect3.y, rect3.width - barWidth * 2f, rect3.height - barHeight);
- Widgets.FillableBar(rect3, curEntropyLevel, EntropyBarTex);
+ Widgets.FillableBar(rect3, curEntropyLevel, StaticConstructorOnGameStart.EntropyBarTex);
Text.Font = GameFont.Small;
}
diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_ExtractSkull.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_ExtractSkull.cs
new file mode 100644
index 0000000..07aec07
--- /dev/null
+++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_ExtractSkull.cs
@@ -0,0 +1,48 @@
+using RimWorld;
+using System.Linq;
+using Verse;
+
+namespace Numbers
+{
+ // Credits to Marek15 for the original code
+ public class PawnColumnWorker_ExtractSkull : PawnColumnWorker_Checkbox
+ {
+ private readonly Designator_ExtractSkull desSkull = new();
+
+ protected override bool HasCheckbox(Pawn pawn)
+ {
+ if (!pawn.RaceProps.Humanlike || !pawn.Dead)
+ return false;
+
+ var corpse = pawn.Corpse;
+ if (corpse == null || corpse.InnerPawn == null)
+ return false;
+
+ return corpse.InnerPawn.health.hediffSet.GetNotMissingParts()
+ .Any(part => part.def == BodyPartDefOf.Head);
+ }
+
+ protected override bool GetValue(Pawn pawn)
+ {
+ if (pawn?.ParentHolder is not Thing thing)
+ return false;
+
+ var designations = thing.Map?.designationManager?.AllDesignations;
+ if (designations == null)
+ return false;
+
+ return designations.Any(d => d.target == thing && d.def == DesignationDefOf.ExtractSkull);
+ }
+
+ protected override void SetValue(Pawn pawn, bool value, PawnTable table)
+ {
+ if (pawn?.ParentHolder is not Thing thing || thing.Map == null)
+ return;
+
+ if (value)
+ desSkull.DesignateThing(thing);
+ else
+ thing.Map.designationManager.TryRemoveDesignationOn(thing, DesignationDefOf.ExtractSkull);
+ }
+ }
+}
diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_IdeologyCertainty.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_IdeologyCertainty.cs
new file mode 100644
index 0000000..9210fae
--- /dev/null
+++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_IdeologyCertainty.cs
@@ -0,0 +1,33 @@
+using RimWorld;
+using Verse;
+
+namespace Numbers
+{
+ public class PawnColumnWorker_IdeologyCertainty : PawnColumnWorker_Text
+ {
+ protected override string GetTextFor(Pawn pawn)
+ {
+ float? certainty = pawn.ideo?.Certainty;
+ return certainty is float value && value >= 0f ? $"{value * 100f:F0}%" : "-";
+ }
+
+ protected override string GetTip(Pawn pawn)
+ {
+ Ideo ideo = pawn.ideo?.Ideo;
+ string certainty = GetTextFor(pawn);
+
+ NamedArgument ideoArg = ideo != null ? ideo.Named("IDEO") : "None".Named("IDEO");
+
+ return "CertaintyInIdeo".Translate(pawn.Named("PAWN"), ideoArg) + $": {certainty}";
+ }
+
+ protected override string GetHeaderTip(PawnTable table) => "Certainty".Translate();
+
+ public override int Compare(Pawn a, Pawn b)
+ {
+ float certaintyA = a.ideo?.Certainty ?? -1f;
+ float certaintyB = b.ideo?.Certainty ?? -1f;
+ return certaintyA.CompareTo(certaintyB);
+ }
+ }
+}
diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_JobCurrent.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_JobCurrent.cs
index 4ef8fd6..35bd26c 100644
--- a/Numbers/PawnColumnWorkers/PawnColumnWorker_JobCurrent.cs
+++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_JobCurrent.cs
@@ -7,6 +7,14 @@
public class PawnColumnWorker_JobCurrent : PawnColumnWorker_Text
{
protected override string GetTextFor(Pawn pawn)
+ {
+ string job = GetJob(pawn);
+ if (job == null) return null;
+ GenText.SetTextSizeToFit(job, new Rect(0f, 0f, Mathf.CeilToInt(Text.CalcSize(def.LabelCap).x), GetMinCellHeight(pawn)));
+ return job;
+ }
+
+ private string GetJob(Pawn pawn)
{
if (!Numbers_Settings.showMoreInfoThanVanilla && !(pawn.Faction == Faction.OfPlayer || pawn.HostFaction == Faction.OfPlayer) && !pawn.InMentalState)
return null;
@@ -14,14 +22,12 @@ protected override string GetTextFor(Pawn pawn)
if (pawn.jobs.curDriver != null)
{
string text = pawn.jobs.curDriver.GetReport().CapitalizeFirst();
- GenText.SetTextSizeToFit(text, new Rect(0f, 0f, Mathf.CeilToInt(Text.CalcSize(def.LabelCap).x), GetMinCellHeight(pawn)));
-
return text;
}
return null;
}
- protected override string GetTip(Pawn pawn) => GetTextFor(pawn);
+ protected override string GetTip(Pawn pawn) => GetJob(pawn);
public override int Compare(Pawn a, Pawn b)
=> (a.jobs?.curDriver.GetReport()).CompareTo(b.jobs?.curDriver.GetReport());
diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_JobQueued.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_JobQueued.cs
index e78a995..5ef17bf 100644
--- a/Numbers/PawnColumnWorkers/PawnColumnWorker_JobQueued.cs
+++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_JobQueued.cs
@@ -1,30 +1,51 @@
-namespace Numbers
+using RimWorld;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using UnityEngine;
+using Verse;
+
+namespace Numbers
{
- using System.Linq;
- using RimWorld;
- using UnityEngine;
- using Verse;
public class PawnColumnWorker_JobQueued : PawnColumnWorker_Text
{
protected override string GetTextFor(Pawn pawn)
{
- if (pawn.jobs?.jobQueue.Any() ?? false)
- {
- string text = pawn.jobs.jobQueue[0].job.GetReport(pawn).CapitalizeFirst();
+ var jobs = GetJobs(pawn);
+ if (jobs.Count == 0) return null;
- GenText.SetTextSizeToFit(text, new Rect(0f, 0f, Mathf.CeilToInt(Text.CalcSize(def.LabelCap).x), GetMinCellHeight(pawn)));
+ string text = jobs[0];
+ GenText.SetTextSizeToFit(text, new Rect(0f, 0f, Mathf.CeilToInt(Text.CalcSize(def.LabelCap).x), GetMinCellHeight(pawn)));
- return text;
- }
- return null;
+ return text;
}
public override int Compare(Pawn a, Pawn b)
=> (a.jobs?.jobQueue?.Count ?? 0).CompareTo(b.jobs?.jobQueue?.Count ?? 0);
protected override string GetTip(Pawn pawn)
- => pawn.jobs?.jobQueue?.Count.ToString();
+ {
+ var jobs = GetJobs(pawn);
+ if (jobs.Count == 0) return null;
+
+ var sb = new StringBuilder();
+ int width = jobs.Count.ToString().Length;
+ for (int i = 0; i < jobs.Count; i++) sb.AppendLine($"{(i + 1).ToString().PadLeft(width)}. {jobs[i]}");
+
+ return sb.ToString().TrimEnd();
+ }
+
+ private List GetJobs(Pawn pawn)
+ {
+ var result = new List();
+ if (pawn.jobs?.jobQueue.Any() ?? false)
+ {
+ // queued jobs
+ foreach (var queued in pawn.jobs.jobQueue) result.Add(queued.job.GetReport(pawn).CapitalizeFirst());
+ }
+ return result;
+ }
public override int GetMinWidth(PawnTable table)
=> Mathf.Max(base.GetMinWidth(table), 200);
diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_Loyalty.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_Loyalty.cs
new file mode 100644
index 0000000..c633b4e
--- /dev/null
+++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_Loyalty.cs
@@ -0,0 +1,28 @@
+using RimWorld;
+using Verse;
+
+namespace Numbers
+{
+ public class PawnColumnWorker_Loyalty : PawnColumnWorker_Text
+ {
+ protected override string GetTextFor(Pawn pawn)
+ {
+ if (pawn.guest == null) return string.Empty;
+
+ return pawn.guest.Recruitable ? "UnwaveringlyLoyal".Translate() : "Recruitable".Translate();
+ }
+
+ public override int Compare(Pawn a, Pawn b)
+ {
+ bool aUnwavering = a.guest?.Recruitable == true;
+ bool bUnwavering = b.guest?.Recruitable == true;
+
+ return aUnwavering.CompareTo(bUnwavering);
+ }
+
+ protected override string GetTip(Pawn pawn)
+ {
+ return "UnwaveringlyLoyalDesc".Translate();
+ }
+ }
+}
diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_SelfTend.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_SelfTend.cs
index 0762b5b..98d1722 100644
--- a/Numbers/PawnColumnWorkers/PawnColumnWorker_SelfTend.cs
+++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_SelfTend.cs
@@ -1,9 +1,10 @@
-namespace Numbers
-{
- using RimWorld;
- using UnityEngine;
- using Verse;
+using RimWorld;
+using System;
+using UnityEngine;
+using Verse;
+namespace Numbers
+{
public class PawnColumnWorker_SelfTend : PawnColumnWorker_Checkbox
{
public static float IconPositionVertical = 35f;
@@ -15,15 +16,41 @@ public class PawnColumnWorker_SelfTend : PawnColumnWorker_Checkbox
protected override void SetValue(Pawn pawn, bool value, PawnTable table)
{
- if (value && pawn.workSettings.GetPriority(WorkTypeDefOf.Doctor) == 0)
- Messages.Message("MessageSelfTendUnsatisfied".Translate(pawn.LabelShort, pawn), MessageTypeDefOf.CautionInput, false);
+ if (pawn.workSettings != null)
+ {
+ int priority;
+ try
+ {
+ priority = pawn.workSettings.GetPriority(WorkTypeDefOf.Doctor);
+ }
+ catch (ArgumentOutOfRangeException)
+ {
+ // Work priorities may be uninitialized (e.g., newly joined pawn) or corrupt
+ Messages.Message(
+ "Cannot enable self tend because work priorities are uninitialized or corrupt for the pawn.",
+ pawn,
+ MessageTypeDefOf.CautionInput,
+ false
+ );
+ return;
+ }
+
+ if (value && priority == 0)
+ {
+ Messages.Message(
+ "MessageSelfTendUnsatisfied".Translate(pawn.LabelShort, pawn),
+ MessageTypeDefOf.CautionInput,
+ false
+ );
+ }
+ }
pawn.playerSettings.selfTend = value;
}
protected override string GetHeaderTip(PawnTable table) => "SelfTend".Translate() + "\n\n" + "Numbers_ColumnHeader_Tooltip".Translate();
- protected override string GetTip(Pawn pawn) => "SelfTendTip".Translate(Faction.OfPlayer.def.pawnsPlural, TendUtility.SelfTendQualityFactor.ToStringPercent()).CapitalizeFirst();
+ protected override string GetTip(Pawn pawn) => "AllowSelfTendTip".Translate(Faction.OfPlayer.def.pawnsPlural, TendUtility.SelfTendQualityFactor.ToStringPercent()).CapitalizeFirst();
public override void DoHeader(Rect rect, PawnTable table)
{
diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_Skill.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_Skill.cs
index da9abc6..a1b0819 100644
--- a/Numbers/PawnColumnWorkers/PawnColumnWorker_Skill.cs
+++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_Skill.cs
@@ -5,15 +5,10 @@
using UnityEngine;
using Verse;
- [StaticConstructorOnStartup]
//mostly from Koisama
public class PawnColumnWorker_Skill : PawnColumnWorker
{
- private static readonly Texture2D passionMinorIcon = ContentFinder.Get("UI/Icons/PassionMinor");
- private static readonly Texture2D passionMajorIcon = ContentFinder.Get("UI/Icons/PassionMajor");
- private static readonly Texture2D SkillBarFillTex = SolidColorMaterials.NewSolidColorTexture(new Color(1f, 1f, 1f, 0.25f));
- private static readonly Texture2D SkillBarBgTex = SolidColorMaterials.NewSolidColorTexture(new Color(1f, 1f, 1f, 0.07f));
private static readonly Color DisabledSkillColor = new(1f, 1f, 1f, 0.5f);
private static readonly MethodInfo mGetSkillDescription = typeof(SkillUI).GetMethod("GetSkillDescription", BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.InvokeMethod, null, [typeof(SkillRecord)], null);
@@ -34,13 +29,13 @@ public override void DoCell(Rect rect, Pawn pawn, PawnTable table)
Rect position = new(3f, 3f, 24f, 24f);
if (skill.passion > Passion.None)
{
- Texture2D image = (skill.passion != Passion.Major) ? passionMinorIcon : passionMajorIcon;
+ Texture2D image = (skill.passion != Passion.Major) ? StaticConstructorOnGameStart.PassionMinorIcon : StaticConstructorOnGameStart.PassionMajorIcon;
GUI.DrawTexture(position, image);
}
if (!skill.TotallyDisabled)
{
Rect rect3 = new(position.xMax, 0f, rect.width - position.xMax, rect.height);
- Widgets.FillableBar(rect3, skill.Level / 20f, SkillBarFillTex, SkillBarBgTex, false);
+ Widgets.FillableBar(rect3, skill.Level / 20f, StaticConstructorOnGameStart.SkillBarFillTex, StaticConstructorOnGameStart.SkillBarBgTex, false);
}
Rect rect4 = new(position.xMax + 4f, 0f, 999f, rect.height);
rect4.yMin += 3f;
diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_TameChance.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_TameChance.cs
index ef681bc..624d02e 100644
--- a/Numbers/PawnColumnWorkers/PawnColumnWorker_TameChance.cs
+++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_TameChance.cs
@@ -10,7 +10,7 @@ public class PawnColumnWorker_TameChance : PawnColumnWorker_Text
protected override string GetTextFor(Pawn pawn) => pawn.AnimalOrWildMan() ? GetValue(pawn).ToStringPercent() : string.Empty;
- private float GetValue(Pawn pawn) => pawn.AnimalOrWildMan() ? TameChanceFactorCurve_Wildness.Evaluate(pawn.RaceProps.wildness) : 0;
+ private float GetValue(Pawn pawn) => pawn.AnimalOrWildMan() ? TameChanceFactorCurve_Wildness.Evaluate(pawn.GetStatValue(StatDefOf.Wildness)) : 0;
#if DEBUG
diff --git a/Numbers/PawnColumnWorkers/PawnColumnWorker_ToxicBuildUp.cs b/Numbers/PawnColumnWorkers/PawnColumnWorker_ToxicBuildUp.cs
new file mode 100644
index 0000000..8e59000
--- /dev/null
+++ b/Numbers/PawnColumnWorkers/PawnColumnWorker_ToxicBuildUp.cs
@@ -0,0 +1,54 @@
+using RimWorld;
+using UnityEngine;
+using Verse;
+
+namespace Numbers
+{
+ public class PawnColumnWorker_ToxicBuildup : PawnColumnWorker_Text
+ {
+ private static readonly Color LowToxicColor = Color.gray;
+ private static readonly Color MediumToxicColor = Color.yellow; // yellowish
+ private static readonly Color HighToxicColor = new Color(0.9f, 0.5f, 0f); // orange
+ private static readonly Color CriticalToxicColor = Color.red;
+
+ public override int Compare(Pawn a, Pawn b)
+ {
+ float aSeverity = GetToxicSeverity(a);
+ float bSeverity = GetToxicSeverity(b);
+ return aSeverity.CompareTo(bSeverity);
+ }
+
+ public override void DoCell(Rect rect, Pawn pawn, PawnTable table)
+ {
+ GUI.color = GetColorForToxicSeverity(GetToxicSeverity(pawn));
+ base.DoCell(rect, pawn, table);
+ GUI.color = Color.white;
+ }
+
+ protected override string GetTextFor(Pawn pawn)
+ {
+ float severity = GetToxicSeverity(pawn);
+ return $"{(severity * 100f):0.#}%";
+ }
+
+ protected override string GetTip(Pawn pawn)
+ {
+ return HediffDefOf.ToxicBuildup.description;
+ }
+
+ private float GetToxicSeverity(Pawn pawn)
+ {
+ if (pawn?.health == null) return 0f;
+ Hediff toxicHediff = pawn.health.hediffSet.GetFirstHediffOfDef(HediffDefOf.ToxicBuildup);
+ return toxicHediff?.Severity ?? 0f;
+ }
+
+ private Color GetColorForToxicSeverity(float severity)
+ {
+ if (severity <= 0f) return LowToxicColor;
+ if (severity < 0.25f) return MediumToxicColor;
+ if (severity < 0.5f) return HighToxicColor;
+ return CriticalToxicColor;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Numbers/StaticConstructorOnGameStart.cs b/Numbers/StaticConstructorOnGameStart.cs
index d2be6f7..42a3e37 100644
--- a/Numbers/StaticConstructorOnGameStart.cs
+++ b/Numbers/StaticConstructorOnGameStart.cs
@@ -24,7 +24,12 @@ static class StaticConstructorOnGameStart
SortingDescendingIcon = ContentFinder.Get("UI/Icons/SortingDescending"),
BarInstantMarkerTex = ContentFinder.Get("UI/Misc/BarInstantMarker"),
Drop = ContentFinder.Get("UI/Buttons/Drop"),
- UnwaveringlyLoyal = ContentFinder.Get("UI/Icons/UnwaveringlyLoyal");
+ UnwaveringlyLoyal = ContentFinder.Get("UI/Icons/UnwaveringlyLoyal"),
+ PassionMinorIcon = ContentFinder.Get("UI/Icons/PassionMinor"),
+ PassionMajorIcon = ContentFinder.Get("UI/Icons/PassionMajor"),
+ SkillBarFillTex = SolidColorMaterials.NewSolidColorTexture(new Color(1f, 1f, 1f, 0.25f)),
+ SkillBarBgTex = SolidColorMaterials.NewSolidColorTexture(new Color(1f, 1f, 1f, 0.07f)),
+ EntropyBarTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.46f, 0.34f, 0.35f));
public static List combatPreset = [],
workTabPlusPreset = [],
@@ -114,7 +119,10 @@ private static void PopulatePsycastingPreset()
psycastingPreset.Add(DefDatabase.GetNamed("Numbers_Psyfocus"));
psycastingPreset.Add(DefDatabase.GetNamed("Numbers_Entropy"));
psycastingPreset.AddRange(
- DefDatabase.AllDefsListForReading.Where(pcd => pcd.Ext(logError: false)?.ability != null).ToList()
+ DefDatabase.AllDefsListForReading.Where(pcd =>
+ pcd.Ext(logError: false)?.ability != null &&
+ typeof(Psycast).IsAssignableFrom(pcd.Ext(logError: false).ability.abilityClass))
+ .ToList()
.OrderBy(x => x.Ext().ability.level)
.ThenBy(x => x.Ext().ability.PsyfocusCost)
.ThenBy(x => x.Ext().ability.EntropyGain)
diff --git a/Numbers/WorldComponent_Numbers.cs b/Numbers/WorldComponent_Numbers.cs
index 56a5dfe..78c230e 100644
--- a/Numbers/WorldComponent_Numbers.cs
+++ b/Numbers/WorldComponent_Numbers.cs
@@ -13,9 +13,9 @@ public WorldComponent_Numbers(World world) : base(world)
{
}
- public override void FinalizeInit()
+ public override void FinalizeInit(bool fromLoad)
{
- base.FinalizeInit();
+ base.FinalizeInit(fromLoad);
primaryFilter = PrimaryFilter.First();
if (!sessionTable.Any())
@@ -77,7 +77,8 @@ public override void ExposeData()
{ NumbersDefOf.Numbers_Animals, pawn => !pawn.Dead && pawn.IsVisible() && pawn.IsAnimal() && pawn.Faction == Faction.OfPlayer },
{ NumbersDefOf.Numbers_WildAnimals, pawn => !pawn.Dead && pawn.IsVisible() && pawn.IsWildAnimal() },
{ NumbersDefOf.Numbers_Corpses, pawn => pawn.Dead && pawn.IsVisible() && !pawn.IsAnimal() },
- { NumbersDefOf.Numbers_AnimalCorpses, pawn => pawn.Dead && pawn.IsVisible() && pawn.IsAnimal() }
+ { NumbersDefOf.Numbers_AnimalCorpses, pawn => pawn.Dead && pawn.IsVisible() && pawn.IsAnimal() },
+ { NumbersDefOf.Numbers_WildMen, pawn => !pawn.Dead && pawn.IsVisible() && pawn.IsWildMan() }
};
internal void NotifySettingsChanged()