diff --git a/EdBPrepareCarefully.csproj b/EdBPrepareCarefully.csproj
index 6a3ed5c..ab9ccd0 100644
--- a/EdBPrepareCarefully.csproj
+++ b/EdBPrepareCarefully.csproj
@@ -62,6 +62,7 @@
+
diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs
index 701876a..2ca84cb 100644
--- a/Properties/AssemblyInfo.cs
+++ b/Properties/AssemblyInfo.cs
@@ -14,4 +14,4 @@
[assembly: AssemblyVersion("1.1.1")]
// Increment for each new release
-[assembly: AssemblyFileVersion("1.5.7")]
+[assembly: AssemblyFileVersion("1.5.8")]
diff --git a/Resources/About/About.xml b/Resources/About/About.xml
index 76d8d92..9c8a160 100644
--- a/Resources/About/About.xml
+++ b/Resources/About/About.xml
@@ -25,7 +25,7 @@
If you get a set of starting colonists that you like, save them as a preset so that you can start your game the same way next time.
-[Version 1.5.7]
+[Version 1.5.8]
net.pardeike.rimworld.mod.harmony
diff --git a/Resources/About/Manifest.xml b/Resources/About/Manifest.xml
index 56ec00c..849484c 100644
--- a/Resources/About/Manifest.xml
+++ b/Resources/About/Manifest.xml
@@ -1,7 +1,7 @@
EdB.PrepareCarefully
- 1.5.7
+ 1.5.8
false
https://github.com/edbmods/EdBPrepareCarefully/raw/master/Resources/About/Manifest.xml
https://github.com/edbmods/EdBPrepareCarefully/releases/latest
diff --git a/Resources/CHANGELOG.txt b/Resources/CHANGELOG.txt
index 6b8ae45..f0c01d9 100644
--- a/Resources/CHANGELOG.txt
+++ b/Resources/CHANGELOG.txt
@@ -1,3 +1,17 @@
+ _____________________________________________________________________________
+
+ Version 1.5.8
+ _____________________________________________________________________________
+
+ - Added support for Mechanitor implants in the Health panel's Implants and
+ Bionics dialog
+ - Added Mechanoid options to the Equipment Tab
+ - Bug fixes:
+ - Fixed issue where sibling relationships were sometimes lost when loading
+ from a preset
+ - Fixed issue where non-parent/child relationships between starting pawns
+ and hidden/world pawns were removed when initializing the game
+
_____________________________________________________________________________
Version 1.5.7
diff --git a/Resources/Common/Languages/English/Keyed/EdBPrepareCarefully.xml b/Resources/Common/Languages/English/Keyed/EdBPrepareCarefully.xml
index 46101ef..cab1bce 100644
--- a/Resources/Common/Languages/English/Keyed/EdBPrepareCarefully.xml
+++ b/Resources/Common/Languages/English/Keyed/EdBPrepareCarefully.xml
@@ -1,6 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
@@ -208,6 +219,9 @@
Apply
This implant cannot be installed because it conflicts with the following:\n\n- {0}, {1}
Select Implants and Bionics
+ Implant {0}
+ This implant must be added because it is required by one of the other implants that you selected
+ {0}:
Select a condition
You must select a condition
@@ -262,6 +276,7 @@
Apparel
Furniture
Food
+ Mechanoids
Medical
Resources
Weapons
@@ -269,10 +284,12 @@
Processing materials...
Processing items...
Finished
+ {0}: {1}%
Start With
Start Near
Possessions - {0}
Animals
+ Mechanoids
All Categories
All Mods
Cost: {0}
@@ -281,8 +298,11 @@
Gender:
Hit Points:
Material:
+ Mechanoids
Quality:
+ {0}:
Random Pet
+ Random Mechanoid
Spawn Type:
Style:
diff --git a/Resources/Common/Textures/EdB/PrepareCarefully/Checkmark.png b/Resources/Common/Textures/EdB/PrepareCarefully/Checkmark.png
new file mode 100644
index 0000000..46afc83
Binary files /dev/null and b/Resources/Common/Textures/EdB/PrepareCarefully/Checkmark.png differ
diff --git a/Resources/Common/Textures/EdB/PrepareCarefully/CheckmarkForcedSelection.png b/Resources/Common/Textures/EdB/PrepareCarefully/CheckmarkForcedSelection.png
new file mode 100644
index 0000000..aa03f7a
Binary files /dev/null and b/Resources/Common/Textures/EdB/PrepareCarefully/CheckmarkForcedSelection.png differ
diff --git a/Source/ControllerPage.cs b/Source/ControllerPage.cs
index 4ca9094..2a862f2 100644
--- a/Source/ControllerPage.cs
+++ b/Source/ControllerPage.cs
@@ -146,13 +146,14 @@ public void PreparePawns() {
Find.GameInitData.startingPossessions.Remove(key);
}
// Destroy any starting pawn that are not in our customized pawn list
+ Logger.Debug("Destroy any pawn that is not in our carefully prepared pawn list:");
foreach (var pawn in Find.GameInitData.startingAndOptionalPawns) {
if (!State.Customizations.AllPawns.Select(p => p.Pawn).Contains(pawn)) {
- Logger.Debug("Destroyed starting pawn: " + pawn.LabelCap);
+ Logger.Debug(" Destroyed starting pawn: " + pawn.LabelShort);
ManagerPawns.DestroyPawn(pawn);
}
else {
- Logger.Debug("Kept starting pawn: " + pawn.LabelCap);
+ Logger.Debug(" Kept starting pawn: " + pawn.LabelShort);
}
}
Find.GameInitData.startingPawnCount = State.Customizations.ColonyPawns.Count;
@@ -189,10 +190,7 @@ public void PrepareEquipment() {
// Add scenario parts for all of our customized equipment selections
foreach (var equipment in State.Customizations.Equipment) {
- ScenPart part = CreateScenarioPartForCustomizedEquipment(equipment);
- if (part != null) {
- scenarioPartsToUse.Add(part);
- }
+ scenarioPartsToUse.AddRange(CreateScenarioPartForCustomizedEquipment(equipment).Where(p => p != null));
}
ReflectionUtil.SetFieldValue(Find.Scenario, "parts", scenarioPartsToUse);
@@ -207,23 +205,26 @@ public bool ShouldReplaceScenarioPart(ScenPart part) {
return false;
}
- public ScenPart CreateScenarioPartForCustomizedEquipment(CustomizedEquipment equipment) {
- Logger.Debug(string.Format("AddScenarioPartForCustomizedEquipment({0}), Animal = {1}", equipment.EquipmentOption?.ThingDef?.defName, equipment.Animal));
+ public IEnumerable CreateScenarioPartForCustomizedEquipment(CustomizedEquipment equipment) {
+ Logger.Debug(string.Format("AddScenarioPartForCustomizedEquipment({0}), Animal = {1}, Mech = {2}", equipment.EquipmentOption?.ThingDef?.defName, equipment.Animal, equipment.Mech));
if (equipment.Animal) {
- return CreateStartingAnimalScenarioPart(equipment);
+ return new List() { CreateStartingAnimalScenarioPart(equipment) };
+ }
+ else if (equipment.Mech) {
+ return CreateStartingMechScenarioParts(equipment);
}
var spawnType = equipment.SpawnType;
if (equipment.EquipmentOption.RestrictedSpawnType && equipment.EquipmentOption.DefaultSpawnType != spawnType) {
spawnType = equipment.EquipmentOption.DefaultSpawnType;
}
if (spawnType == EquipmentSpawnType.SpawnsWith) {
- return CreateStartsWithScenarioPart(equipment);
+ return new List() { CreateStartsWithScenarioPart(equipment) };
}
else if (spawnType == EquipmentSpawnType.SpawnsNear) {
- return CreateScatterThingsNearScenarioPart(equipment);
+ return new List() { CreateScatterThingsNearScenarioPart(equipment) };
}
else {
- return null;
+ return Enumerable.Empty();
}
}
@@ -260,6 +261,49 @@ public ScenPart CreateStartingAnimalScenarioPart(CustomizedEquipment equipment)
return CreateStartingAnimalWithRandomGenderScenarioPart(equipment);
}
}
+ public IEnumerable CreateStartingMechScenarioParts(CustomizedEquipment equipment) {
+ if (equipment.EquipmentOption.RandomMech) {
+ return CreateRandomStartingMechScenarioParts(equipment);
+ }
+ else {
+ return CreateDefinedStartingMechScenarioParts(equipment);
+ }
+ }
+ public IEnumerable CreateDefinedStartingMechScenarioParts(CustomizedEquipment equipment) {
+ ScenPartDef scenPartDef = DefDatabase.GetNamedSilentFail("StartingMech");
+ if (scenPartDef == null) {
+ Logger.Warning("Could not find definition for starting mech scenario part. Cannot add scenario part");
+ yield break;
+ }
+ PawnKindDef pawnKindDef = FindPawnKindDefForRace(equipment);
+ if (pawnKindDef == null) {
+ Logger.Warning(string.Format("Could not spawn selected mech ({0}). Could not find matching pawn kind", equipment.EquipmentOption?.ThingDef?.defName));
+ yield break;
+ }
+ for (int i = 0; i < equipment.Count; i++) {
+ var part = new ScenPart_StartingMech() {
+ def = scenPartDef
+ };
+ part.SetPrivateField("mechKind", pawnKindDef);
+ part.SetPrivateField("overseenByPlayerPawnChance", equipment.OverseenChance);
+ yield return part;
+ }
+ }
+ public IEnumerable CreateRandomStartingMechScenarioParts(CustomizedEquipment equipment) {
+ ScenPartDef scenPartDef = DefDatabase.GetNamedSilentFail("StartingMech");
+ if (scenPartDef == null) {
+ Logger.Warning("Could not find definition for starting mech scenario part. Cannot add scenario part");
+ yield break;
+ }
+ for (int i = 0; i < equipment.Count; i++) {
+ var part = new ScenPart_StartingMech() {
+ def = scenPartDef
+ };
+ part.SetPrivateField("overseenByPlayerPawnChance", equipment.OverseenChance);
+ yield return part;
+ }
+ }
+
public ScenPart CreateRandomStartingAnimalScenarioPart(CustomizedEquipment equipment) {
ScenPartDef scenPartDef = DefDatabase.GetNamedSilentFail("StartingAnimal");
if (scenPartDef == null) {
@@ -278,7 +322,7 @@ public ScenPart CreateStartingAnimalWithRandomGenderScenarioPart(CustomizedEquip
Logger.Warning("Could not find definition for starting animal scenario part. Cannot add scenario part");
return null;
}
- PawnKindDef pawnKindDef = FindPawnKindDefForAnimal(equipment);
+ PawnKindDef pawnKindDef = FindPawnKindDefForRace(equipment);
if (pawnKindDef == null) {
Logger.Warning(string.Format("Could not spawn selected animal ({0}). Could not find matching pawn kind", equipment.EquipmentOption?.ThingDef?.defName));
return null;
@@ -291,7 +335,7 @@ public ScenPart CreateStartingAnimalWithRandomGenderScenarioPart(CustomizedEquip
return part;
}
public ScenPart CreateStartingAnimalWithSpecificGenderScenarioPart(CustomizedEquipment equipment) {
- PawnKindDef pawnKindDef = FindPawnKindDefForAnimal(equipment);
+ PawnKindDef pawnKindDef = FindPawnKindDefForRace(equipment);
if (pawnKindDef == null) {
Logger.Warning(string.Format("Could not spawn selected animal ({0}). Could not find matching pawn kind", equipment.EquipmentOption?.ThingDef?.defName));
return null;
@@ -303,8 +347,8 @@ public ScenPart CreateStartingAnimalWithSpecificGenderScenarioPart(CustomizedEqu
};
return part;
}
- public PawnKindDef FindPawnKindDefForAnimal(CustomizedEquipment equipment) {
- return (from td in DefDatabase.AllDefs where td.race == equipment.EquipmentOption.ThingDef select td).FirstOrDefault();
+ public PawnKindDef FindPawnKindDefForRace(CustomizedEquipment equipment) {
+ return DefDatabase.AllDefs.Where(k => k.race == equipment.EquipmentOption.ThingDef).FirstOrDefault();
}
public void MarkCostsForRecalculation() {
diff --git a/Source/ControllerTabViewPawns.cs b/Source/ControllerTabViewPawns.cs
index 2af8eb5..ee4a0ee 100644
--- a/Source/ControllerTabViewPawns.cs
+++ b/Source/ControllerTabViewPawns.cs
@@ -313,11 +313,8 @@ public void AddInjury(Injury injury) {
public void AddImplant(Implant implant) {
PawnManager.AddPawnImplant(ViewState?.CurrentPawn, implant);
}
- public void RemoveHediff(Hediff hediff) {
- PawnManager.RemovePawnHediff(ViewState?.CurrentPawn, hediff);
- }
public void RemoveHediffs(IEnumerable hediffs) {
- PawnManager.RemovePawnHediffs(ViewState?.CurrentPawn, hediffs);
+ PawnManager.RemoveHediffs(ViewState?.CurrentPawn, hediffs);
}
public void RandomizeAppearance() {
diff --git a/Source/CostCalculator.cs b/Source/CostCalculator.cs
index fb554bb..01dac4c 100644
--- a/Source/CostCalculator.cs
+++ b/Source/CostCalculator.cs
@@ -95,6 +95,7 @@ public class CostCalculator {
protected HashSet cheapApparel = new HashSet();
public StatWorker MarketValueStatWorker { get; set; }
public float CostForRandomAnimal { get; set; } = 250f;
+ public float CostForRandomMech { get; set; } = 1200f;
public CostCalculator() {
@@ -174,6 +175,21 @@ public PawnCostDetailsRefactored CalculatePawnCost(CustomizedPawn pawn) {
//Logger.Debug(string.Format("Market value for pawn apparel; pawn = {0}, apparel = {1}, cost = {2}", pawn.Pawn.LabelShortCap, apparel.def.defName, c));
}
+ // Implants that have a ThingDef associated with them (like a Mechlink) need to include the
+ // cost of that ThingDef
+ foreach (Implant implant in pawn.Customizations.Implants) {
+ if (implant.HediffDef == null) {
+ continue;
+ }
+ if (implant.Option?.ThingDef != null) {
+ int count = 1;
+ if (implant.Option.MaxSeverity > 0) {
+ count = (int)implant.Severity;
+ }
+ cost.bionics += MarketValueStatWorker.GetValue(StatRequest.For(implant.Option.ThingDef, null)) * count;
+ }
+ }
+
// Calculate cost for any materials needed for implants.
OptionsHealth healthOptions = ProviderHealthOptions.GetOptions(pawn);
foreach (Implant option in pawn.Customizations.Implants) {
@@ -228,6 +244,9 @@ public double CalculateEquipmentCost(CustomizedEquipment equipment) {
else if (equipment.EquipmentOption.RandomAnimal) {
return CostForRandomAnimal * equipment.Count;
}
+ else if (equipment.EquipmentOption.RandomMech) {
+ return CostForRandomMech * equipment.Count;
+ }
else {
return 0;
}
diff --git a/Source/CustomizationsPawn.cs b/Source/CustomizationsPawn.cs
index 884b0d6..419bc8e 100644
--- a/Source/CustomizationsPawn.cs
+++ b/Source/CustomizationsPawn.cs
@@ -120,8 +120,6 @@ public class CustomizationsPawn {
public List Injuries { get; set; } = new List();
public List Implants { get; set; } = new List();
- public List BodyParts = new List();
-
// Titles
public List Titles { get; set; } = new List();
diff --git a/Source/CustomizedEquipment.cs b/Source/CustomizedEquipment.cs
index c2d2907..e536186 100644
--- a/Source/CustomizedEquipment.cs
+++ b/Source/CustomizedEquipment.cs
@@ -12,13 +12,18 @@ public class CustomizedEquipment {
public EquipmentSpawnType? SpawnType { get; set; }
public int Count { get; set; }
public Gender? Gender { get; set; }
+ public float? OverseenChance { get; set; }
public bool Animal {
get {
return EquipmentOption.RandomAnimal || (EquipmentOption.ThingDef?.race?.Animal ?? false);
}
}
-
+ public bool Mech {
+ get {
+ return EquipmentOption.RandomMech || (EquipmentOption.ThingDef?.race?.IsMechanoid ?? false);
+ }
+ }
public CustomizedEquipment CreateCopy() {
return new CustomizedEquipment() {
EquipmentOption = this.EquipmentOption,
@@ -27,6 +32,7 @@ public CustomizedEquipment CreateCopy() {
Count = this.Count,
SpawnType = this.SpawnType,
Gender = this.Gender,
+ OverseenChance = this.OverseenChance,
};
}
@@ -36,7 +42,8 @@ public override bool Equals(object obj) {
EqualityComparer.Default.Equals(StuffDef, equipment.StuffDef) &&
Quality == equipment.Quality &&
SpawnType == equipment.SpawnType &&
- Gender == equipment.Gender;
+ Gender == equipment.Gender &&
+ OverseenChance == equipment.OverseenChance;
}
public override int GetHashCode() {
@@ -46,6 +53,7 @@ public override int GetHashCode() {
hashCode = hashCode * -1521134295 + Quality.GetHashCode();
hashCode = hashCode * -1521134295 + SpawnType.GetHashCode();
hashCode = hashCode * -1521134295 + Gender.GetHashCode();
+ hashCode = hashCode * -1521134295 + OverseenChance.GetHashCode();
return hashCode;
}
}
diff --git a/Source/CustomizedHediff.cs b/Source/CustomizedHediff.cs
index 6720f07..255a481 100644
--- a/Source/CustomizedHediff.cs
+++ b/Source/CustomizedHediff.cs
@@ -6,31 +6,7 @@
namespace EdB.PrepareCarefully {
public abstract class CustomizedHediff {
- public abstract BodyPartRecord BodyPartRecord { get; set; }
-
- public virtual string PartName {
- get {
- return BodyPartRecord != null ? (BodyPartRecord.LabelCap) : "EdB.PC.BodyParts.WholeBody".Translate().Resolve();
- }
- }
-
- abstract public string ChangeName {
- get;
- }
-
- abstract public Color LabelColor {
- get;
- }
-
- public virtual bool HasTooltip {
- get {
- return false;
- }
- }
-
- public abstract string Tooltip {
- get;
- }
+ public BodyPartRecord BodyPartRecord { get; set; }
}
}
diff --git a/Source/DialogManageImplants.cs b/Source/DialogManageImplants.cs
index 4d22fe4..52e5434 100644
--- a/Source/DialogManageImplants.cs
+++ b/Source/DialogManageImplants.cs
@@ -11,57 +11,49 @@
namespace EdB.PrepareCarefully {
public class DialogManageImplants : Window {
public class ImplantBodyPart {
- public UniqueBodyPart UniquePart {
- get; set;
- }
+ public UniqueBodyPart UniquePart { get; set; }
public BodyPartRecord Part {
get {
- return UniquePart.Record;
+ return UniquePart?.Record;
}
}
- public bool Selected {
- get; set;
- }
- public bool Disabled {
- get; set;
- }
- public Implant Implant {
- get; set;
- }
- public Implant BlockingImplant {
- get; set;
- }
+ public bool Selected { get; set; }
+ public bool Disabled { get; set; }
+ public Implant Implant { get; set; }
+ public Implant BlockingImplant { get; set; }
}
- public class ImplantRecipe {
- protected List parts = new List();
+ public class DialogOption {
+ public ImplantOption ImplantOption { get; set; }
public RecipeDef Recipe {
- get; set;
- }
- public bool Selected {
- get; set;
- }
- public bool PartiallySelected {
- get; set;
- }
- public bool Disabled {
- get; set;
+ get {
+ return ImplantOption?.RecipeDef;
+ }
}
+ public bool Selected { get; set; }
+ public bool PartiallySelected { get; set; }
+ public bool SelectedDependency { get; set; }
+ public bool Disabled { get; set; }
public bool RequiresPartSelection {
get {
- return parts != null && parts.Count > 1;
+ return Parts.CountAllowNull() > 1;
}
}
- public Implant BlockingImplant {
- get; set;
- }
- public List Parts {
+ public string Label {
get {
- return parts;
- }
- set {
- parts = value;
+ if (Recipe != null) {
+ return Recipe?.LabelCap;
+ }
+ else if (ImplantOption?.HediffDef != null) {
+ return "EdB.PC.Dialog.Implant.InstallImplantLabel".Translate(ImplantOption.HediffDef.label);
+ }
+ else {
+ return "";
+ }
}
}
+ public Implant BlockingImplant { get; set; }
+ public List Parts { get; set; } = new List();
+ public float Severity { get; set; } = 1;
}
public string ConfirmButtonLabel = "EdB.PC.Dialog.Implant.Button.Confirm";
public string CancelButtonLabel = "EdB.PC.Common.Cancel";
@@ -80,14 +72,17 @@ public List Parts {
public Rect HeaderRect { get; protected set; }
public Rect CancelButtonRect { get; protected set; }
public Rect ConfirmButtonRect { get; protected set; }
+ public Vector2 LevelLabelSize { get; protected set; }
+ public Vector2 LevelValueSize { get; protected set; }
+ public float LevelSliderWidth { get; protected set; }
public Rect SingleButtonRect { get; protected set; }
public Color DottedLineColor = new Color(60f / 255f, 64f / 255f, 67f / 255f);
public Vector2 DottedLineSize = new Vector2(342, 2);
protected string headerLabel;
protected bool resizeDirtyFlag = true;
protected bool confirmed = false;
- protected WidgetTable table;
- protected List recipes = new List();
+ protected WidgetTable table;
+ protected List options = new List();
protected List implantList = new List();
protected Dictionary replacedParts = new Dictionary();
protected CustomizedPawn customizedPawn = null;
@@ -109,7 +104,7 @@ public DialogManageImplants(CustomizedPawn customizedPawn, ProviderHealthOptions
protected void InitializeWithCustomizedPawn(CustomizedPawn customizedPawn) {
this.customizedPawn = customizedPawn;
InitializeImplantList();
- InitializeRecipes();
+ InitializeOptions();
ResetDisabledState();
}
@@ -117,6 +112,7 @@ protected void InitializeImplantList() {
implantList.Clear();
replacedParts.Clear();
foreach (var implant in customizedPawn.Customizations.Implants) {
+ Logger.Debug("initialize implant " + implant.Option?.HediffDef?.defName + ", severity = " + implant.Severity);
implantList.Add(implant);
if (implant.ReplacesPart) {
replacedParts.Add(implant.BodyPartRecord, implant);
@@ -124,20 +120,28 @@ protected void InitializeImplantList() {
}
}
- protected void InitializeRecipes() {
+ protected void InitializeOptions() {
OptionsHealth health = providerHealth.GetOptions(customizedPawn);
- this.recipes.Clear();
- var result = new List();
- foreach (var recipe in health.ImplantRecipes) {
- var implant = new ImplantRecipe();
- implant.Recipe = recipe;
- implant.Selected = implantList.FirstOrDefault((Implant i) => { return i.Recipe == recipe; }) != null;
- implant.Disabled = false;
- implant.Parts = new List();
- foreach (var part in health.FindBodyPartsForImplantRecipe(recipe)) {
+ this.options.Clear();
+ var result = new List();
+ foreach (var implantOption in health.ImplantOptions) {
+ var option = new DialogOption();
+ option.ImplantOption = implantOption;
+ Implant matchingImplant = implantList.FirstOrDefault((Implant i) => {
+ return (i.Recipe == implantOption.RecipeDef && implantOption.RecipeDef != null)
+ || (i.HediffDef == implantOption.HediffDef && implantOption.HediffDef != null);
+ });
+ if (matchingImplant != null) {
+ option.Selected = true;
+ option.Severity = matchingImplant.Severity;
+ Logger.Debug("Initialize implant option " + implantOption.HediffDef.defName + " with severity " + matchingImplant.Severity);
+ }
+ option.Disabled = false;
+ option.Parts = new List();
+ foreach (var part in health.FindBodyPartsForImplantRecipe(implantOption.RecipeDef)) {
var implantPart = new ImplantBodyPart();
implantPart.UniquePart = part;
- Implant foundImplant = implantList.FirstOrDefault((Implant i) => { return i.Recipe == recipe && i.BodyPartRecord == part.Record; });
+ Implant foundImplant = implantList.FirstOrDefault((Implant i) => { return i.Recipe == implantOption.RecipeDef && i.BodyPartRecord == part.Record; });
if (foundImplant != null) {
implantPart.Selected = true;
implantPart.Implant = foundImplant;
@@ -147,11 +151,50 @@ protected void InitializeRecipes() {
implantPart.Implant = null;
}
implantPart.Disabled = false;
- implant.Parts.Add(implantPart);
+ option.Parts.Add(implantPart);
+ }
+ if (implantOption.BodyPartRecord != null) {
+ UniqueBodyPart uniqueBodyPart = health.FindBodyPartsForRecord(implantOption.BodyPartRecord);
+ if (uniqueBodyPart != null) {
+ var implantPart = new ImplantBodyPart();
+ implantPart.UniquePart = uniqueBodyPart;
+ Implant foundImplant = implantList.FirstOrDefault((Implant i) => { return i.HediffDef == implantOption.HediffDef && i.BodyPartRecord == implantOption.BodyPartRecord; });
+ if (foundImplant != null) {
+ implantPart.Selected = true;
+ implantPart.Implant = foundImplant;
+ }
+ else {
+ implantPart.Selected = false;
+ implantPart.Implant = null;
+ }
+ implantPart.Disabled = false;
+ option.Parts.Add(implantPart);
+ }
}
- result.Add(implant);
+ if (implantOption.HediffDef != null && implantOption.BodyPartDefs != null) {
+ List allBodyParts = new List();
+ foreach (var partDef in implantOption.BodyPartDefs) {
+ allBodyParts.AddRange(health.FindBodyPartsForDef(partDef));
+ }
+ foreach (var part in allBodyParts) {
+ var implantPart = new ImplantBodyPart();
+ implantPart.UniquePart = part;
+ Implant foundImplant = implantList.FirstOrDefault((Implant i) => { return i.HediffDef == implantOption.HediffDef && i.BodyPartRecord == part.Record; });
+ if (foundImplant != null) {
+ implantPart.Selected = true;
+ implantPart.Implant = foundImplant;
+ }
+ else {
+ implantPart.Selected = false;
+ implantPart.Implant = null;
+ }
+ implantPart.Disabled = false;
+ option.Parts.Add(implantPart);
+ }
+ }
+ result.Add(option);
}
- this.recipes = result;
+ this.options = result.OrderBy(o => o.Label).ToList();
}
protected void ResetDisabledState() {
@@ -160,7 +203,7 @@ protected void ResetDisabledState() {
// Iterate each selected implant in order to determine if it's valid--if it's not
// trying to replace or install on top of an already-missing part.
- // The first pass looks for duplicate implants that both try replace the same part.
+ // The first pass looks for duplicate implants that both try to replace the same part.
Dictionary firstPassReplacedParts = new Dictionary();
List firstPassValidImplants = new List();
foreach (var implant in implantList) {
@@ -222,19 +265,18 @@ protected void ResetDisabledState() {
// Logger.Debug(" " + i.recipe.LabelCap + ", " + i.PartName + (i.ReplacesPart ? ", replaces part" : ""));
//}
- // Iterate each each body part option for each recipe to determine if that body part is missing,
+ // Iterate each body part option for each recipe to determine if that body part is missing,
// based on the whether or not it or one of its ancestors has been replaced. Only evaluate each
// body part once. The result will be used to determine if recipes and part options should be
// disabled.
HashSet evaluatedParts = new HashSet();
Dictionary blockedParts = new Dictionary();
- foreach (var recipe in recipes) {
+ foreach (var recipe in options) {
foreach (var part in recipe.Parts) {
if (evaluatedParts.Contains(part.Part)) {
continue;
}
- Implant blockingImplant = null;
- if (!replacedParts.TryGetValue(part.Part, out blockingImplant)) {
+ if (!replacedParts.TryGetValue(part.Part, out Implant blockingImplant)) {
foreach (var ancestor in part.UniquePart.Ancestors) {
if (replacedParts.TryGetValue(ancestor.Record, out blockingImplant)) {
break;
@@ -251,12 +293,12 @@ protected void ResetDisabledState() {
// Go through each recipe and recipe part, marking the parts as disabled if
// they are missing and marking the recipes as disabled if all of its parts
// are disabled.
- foreach (var recipe in recipes) {
- recipe.Disabled = false;
- recipe.BlockingImplant = null;
+ foreach (var option in options) {
+ option.Disabled = false;
+ option.BlockingImplant = null;
int disabledCount = 0;
- int partCount = recipe.Parts.Count;
- foreach (var part in recipe.Parts) {
+ int partCount = option.Parts.Count;
+ foreach (var part in option.Parts) {
part.Disabled = false;
part.BlockingImplant = null;
Implant blockingImplant = null;
@@ -266,18 +308,18 @@ protected void ResetDisabledState() {
part.BlockingImplant = blockingImplant;
disabledCount++;
if (partCount == 1) {
- recipe.BlockingImplant = blockingImplant;
+ option.BlockingImplant = blockingImplant;
}
}
}
}
- if (disabledCount == recipe.Parts.Count) {
- recipe.Disabled = true;
+ if (disabledCount == option.Parts.Count) {
+ option.Disabled = true;
}
}
// Evaluate each recipe's selected state.
- foreach (var recipe in recipes) {
+ foreach (var recipe in options) {
recipe.PartiallySelected = false;
if (recipe.Selected) {
int selectedCount = 0;
@@ -298,7 +340,7 @@ protected void ResetDisabledState() {
protected void ResetCachedBlockedSelectionAlert() {
bool showAlert = false;
- foreach (var recipe in recipes) {
+ foreach (var recipe in options) {
foreach (var part in recipe.Parts) {
if (part.Disabled && part.Implant != null) {
showAlert = true;
@@ -314,7 +356,7 @@ protected void ResetCachedBlockedSelectionAlert() {
return;
}
List blockedSelections = new List();
- foreach (var recipe in recipes) {
+ foreach (var recipe in options) {
int partCount = recipe.Parts.Count;
foreach (var part in recipe.Parts) {
if (part.Disabled && part.Implant != null) {
@@ -374,46 +416,174 @@ protected void MarkResizeFlagDirty() {
resizeDirtyFlag = true;
}
- public void ClickRecipeAction (ImplantRecipe recipe) {
- if (recipe.Disabled && !recipe.Selected) {
+ public void ClickOptionAction(DialogOption option) {
+ if (option.Disabled && !option.Selected) {
return;
}
SoundDefOf.Tick_Tiny.PlayOneShotOnCamera();
- if (recipe.Selected) {
- recipe.Selected = false;
- foreach (var part in recipe.Parts) {
- if (part.Selected) {
- part.Selected = false;
- RemoveImplant(recipe, part);
+ if (option.Selected) {
+ DeselectOption(option);
+ RemoveUnneededDependencies();
+ AddMissingDependencies();
+ }
+ else {
+ SelectOption(option);
+ AddMissingDependencies();
+ }
+ MarkDisabledOptionsAsDirty();
+ }
+
+ public void SelectOption(DialogOption option) {
+ option.SelectedDependency = false;
+ if (option.Selected) {
+ return;
+ }
+ option.Selected = true;
+ if (option.Parts.Count == 1) {
+ if (!option.Parts[0].Selected) {
+ option.Parts[0].Selected = true;
+ AddImplant(option, option.Parts[0]);
+ }
+ }
+ }
+
+ public void SelectDependencyOption(DialogOption option) {
+ if (option.Selected) {
+ return;
+ }
+ option.SelectedDependency = true;
+ if (option.Parts.Count == 1) {
+ option.Parts[0].Selected = true;
+ AddImplant(option, option.Parts[0]);
+ }
+ }
+
+ public void AddMissingDependencies() {
+ HashSet missingDependencies = new HashSet();
+ int maxAttempts = 100;
+ int attempt = 0;
+ while (NeedsDependencies(ref missingDependencies)) {
+ if (attempt++ > maxAttempts) {
+ return;
+ }
+ foreach (var d in missingDependencies) {
+ SelectDependencyOption(d);
+ }
+ missingDependencies.Clear();
+ }
+ }
+
+ public bool NeedsDependencies(ref HashSet missingDependencies) {
+ Logger.Debug("NeedsDependencies()");
+ if (missingDependencies == null) {
+ missingDependencies = new HashSet();
+ }
+ HashSet selected = new HashSet(implantList.Select(i => i.Option.HediffDef));
+ Logger.Debug(" Selected implants: " + string.Join(", ", selected.Select(d => d.defName)));
+ foreach (var implant in implantList) {
+ if (implant.Option.Dependency != null && !selected.Contains(implant.Option.Dependency)) {
+ var optionToAdd = FindDialogOptionForHediff(implant.Option.Dependency);
+ if (optionToAdd != null) {
+ missingDependencies.Add(optionToAdd);
}
}
}
- else {
- recipe.Selected = true;
- if (recipe.Parts.Count == 1) {
- recipe.Parts[0].Selected = true;
- AddImplant(recipe, recipe.Parts[0]);
+ Logger.Debug(" Needs dependencies: " + string.Join(", ", missingDependencies.Select(o => o.ImplantOption.HediffDef.defName)));
+ return missingDependencies.Count > 0;
+ }
+
+ public void RemoveUnneededDependencies() {
+ HashSet unneededDependencies = new HashSet();
+ int maxAttempts = 100;
+ int attempt = 0;
+ while (HasUnneededDependencies(ref unneededDependencies)) {
+ if (attempt++ > maxAttempts) {
+ return;
+ }
+ foreach (var d in unneededDependencies) {
+ DeselectOption(d);
+ }
+ unneededDependencies.Clear();
+ }
+ }
+
+ public bool HasUnneededDependencies(ref HashSet unneededDependencies) {
+ if (unneededDependencies == null) {
+ unneededDependencies = new HashSet();
+ }
+ HashSet neededDependencies = new HashSet(implantList.Select(i => i.Option?.Dependency).Where(d => d != null));
+ foreach (var option in options.Where(o => o.SelectedDependency)) {
+ if (!neededDependencies.Contains(option.ImplantOption.HediffDef)) {
+ unneededDependencies.Add(option);
+ }
+ }
+ Logger.Debug("Unneeded dependencies: " + string.Join(", ", unneededDependencies.Select(o => o.ImplantOption?.HediffDef?.defName ?? "null")));
+
+ return unneededDependencies.Count > 0;
+ }
+
+ protected DialogOption FindDialogOptionForHediff(HediffDef def) {
+ return options.FirstOrDefault(o => o.ImplantOption.HediffDef == def);
+ }
+
+ public void DeselectOption(DialogOption option) {
+ Logger.Debug("DeselectOption(" + option.ImplantOption.HediffDef.defName + ")");
+ option.Selected = false;
+ option.SelectedDependency = false;
+ if (option.Parts != null) {
+ Logger.Debug(" option.Parts = " + string.Join(", ", option.Parts.Select(p => p.UniquePart.Record.def.defName)));
+ }
+ foreach (var part in option.Parts) {
+ if (part.Selected) {
+ part.Selected = false;
+ RemoveImplant(option, part);
}
}
MarkDisabledOptionsAsDirty();
}
- protected void AddImplant(ImplantRecipe recipe, ImplantBodyPart part) {
+ public void UpdateSeverity(DialogOption option, float severity) {
+ if (option.Disabled || !option.Selected) {
+ return;
+ }
+ option.Severity = severity;
+ Implant implant = implantList.FirstOrDefault(i => i.Option == option.ImplantOption);
+ if (implant != null) {
+ implant.Severity = option.Severity;
+ Logger.Debug("Updated implant severity");
+ }
+ else {
+ Logger.Debug("Didn't find implant to update");
+ }
+ }
+ protected void AddImplant(DialogOption option, ImplantBodyPart part) {
Implant implant = new Implant();
- implant.Recipe = recipe.Recipe;
+ implant.Option = option.ImplantOption;
+ implant.Recipe = option.Recipe;
+ implant.HediffDef = option.ImplantOption.HediffDef;
implant.BodyPartRecord = part.Part;
+ implant.Severity = option.Severity;
implantList.Add(implant);
part.Implant = implant;
+ Logger.Debug("Added implant for " + option.ImplantOption.HediffDef.defName);
}
- protected void RemoveImplant(ImplantRecipe recipe, ImplantBodyPart part) {
+ protected void RemoveImplant(DialogOption option, ImplantBodyPart part) {
if (part.Implant != null) {
- implantList.Remove(part.Implant);
+ if (implantList.Remove(part.Implant)) {
+ Logger.Debug("Removed implant for " + option.ImplantOption.HediffDef.defName);
+ }
+ else {
+ Logger.Debug("Couldn't find implant to remvoe for " + option.ImplantOption.HediffDef.defName);
+ }
part.Implant = null;
}
+ else {
+ Logger.Debug("Couldn't remove implant because part had no reference to the implant");
+ }
}
- public void ClickPartAction(ImplantRecipe recipe, ImplantBodyPart part) {
+ public void ClickPartAction(DialogOption recipe, ImplantBodyPart part) {
if (part.Disabled && !part.Selected) {
return;
}
@@ -445,6 +615,11 @@ protected void Resize() {
WindowSize = new Vector2(440f, 584f);
ButtonSize = new Vector2(140f, 40f);
+ Text.Font = GameFont.Small;
+ LevelLabelSize = Text.CalcSize("EdB.PC.Dialog.Implant.LevelLabel".Translate("Level".Translate()));
+ LevelValueSize = Text.CalcSize("00");
+ Text.Font = GameFont.Small;
+
ContentSize = new Vector2(WindowSize.x - WindowPadding * 2 - ContentMargin.x * 2,
WindowSize.y - WindowPadding * 2 - ContentMargin.y * 2 - FooterHeight - headerSize);
@@ -472,17 +647,17 @@ protected void Resize() {
float radioWidth = 36;
Vector2 nameSize = new Vector2(ContentRect.width - portraitSize.x - radioWidth, portraitSize.y * 0.5f);
- table = new WidgetTable();
+ table = new WidgetTable();
table.Rect = new Rect(Vector2.zero, ContentRect.size);
table.RowHeight = LineHeight;
table.RowColor = new Color(0, 0, 0, 0);
table.AlternateRowColor = new Color(0, 0, 0, 0);
- table.SelectedAction = (ImplantRecipe recipe) => {
+ table.SelectedAction = (DialogOption recipe) => {
};
- table.AddColumn(new WidgetTable.Column() {
+ table.AddColumn(new WidgetTable.Column() {
Name = "Recipe",
AdjustForScrollbars = true,
- DrawAction = (ImplantRecipe recipe, Rect rect, WidgetTable.Metadata metadata) => {
+ DrawAction = (DialogOption option, Rect rect, WidgetTable.Metadata metadata) => {
GUI.color = Color.white;
Text.Anchor = TextAnchor.LowerLeft;
Rect labelRect = new Rect(rect.x, rect.y, rect.width, LineHeight);
@@ -491,88 +666,127 @@ protected void Resize() {
Rect clickRect = new Rect(labelRect.x, labelRect.y, labelRect.width - checkboxRect.width, labelRect.height);
GUI.color = DottedLineColor;
GUI.DrawTexture(dottedLineRect, Textures.TextureDottedLine);
- Vector2 labelSize = Text.CalcSize(recipe.Recipe.LabelCap);
+ Vector2 labelSize = Text.CalcSize(option.Label);
GUI.color = Style.ColorWindowBackground;
GUI.DrawTexture(new Rect(labelRect.x, labelRect.y, labelSize.x + 2, labelRect.height), BaseContent.WhiteTex);
+
+ if (option.SelectedDependency) {
+ TooltipHandler.TipRegion(labelRect, "EdB.PC.Dialog.Implant.RequiredImplantMessage".Translate());
+ }
GUI.DrawTexture(checkboxRect.InsetBy(-2, -2, -40, -2), BaseContent.WhiteTex);
- if (!recipe.Disabled) {
- Style.SetGUIColorForButton(labelRect, recipe.Selected, Style.ColorText, Style.ColorButtonHighlight, Style.ColorButtonHighlight);
- Widgets.Label(labelRect, recipe.Recipe.LabelCap);
+ if (!option.Disabled) {
+ Style.SetGUIColorForButton(labelRect, option.Selected || option.SelectedDependency, Style.ColorText, Style.ColorButtonHighlight, Style.ColorButtonHighlight);
+ Widgets.Label(labelRect, option.Label);
if (Widgets.ButtonInvisible(clickRect)) {
- ClickRecipeAction(recipe);
+ ClickOptionAction(option);
}
GUI.color = Color.white;
- Texture2D checkboxTexture = Textures.TextureCheckbox;
- if (recipe.PartiallySelected) {
- checkboxTexture = Textures.TextureCheckboxPartiallySelected;
+ GUI.DrawTexture(checkboxRect, Textures.TextureCheckbox);
+ Texture checkmarkTexture = null;
+ if (option.PartiallySelected) {
+ checkmarkTexture = Textures.TextureCheckboxPartiallySelected;
}
- else if (recipe.Selected) {
- checkboxTexture = Textures.TextureCheckboxSelected;
+ else if (option.Selected) {
+ GUI.color = Style.ColorCheckmark;
+ checkmarkTexture = Textures.TextureCheckmark;
}
- if (Widgets.ButtonImage(checkboxRect, checkboxTexture)) {
- ClickRecipeAction(recipe);
+ else if (option.SelectedDependency) {
+ GUI.color = Style.ColorCheckmark;
+ checkmarkTexture = Textures.TextureCheckmarkForcedSelection;
+ }
+ if (checkmarkTexture != null) {
+ GUI.DrawTexture(checkboxRect, checkmarkTexture);
+ }
+ GUI.color = Color.white;
+ if (Widgets.ButtonInvisible(checkboxRect)) {
+ ClickOptionAction(option);
}
}
else {
GUI.color = Style.ColorControlDisabled;
- Widgets.Label(labelRect, recipe.Recipe.LabelCap);
- GUI.DrawTexture(checkboxRect, recipe.Selected ? Textures.TextureCheckboxPartiallySelected : Textures.TextureCheckbox);
+ Widgets.Label(labelRect, option.Label);
+ GUI.DrawTexture(checkboxRect, option.Selected ? Textures.TextureCheckboxPartiallySelected : Textures.TextureCheckbox);
if (Widgets.ButtonInvisible(checkboxRect)) {
- ClickRecipeAction(recipe);
+ ClickOptionAction(option);
}
- if (recipe.BlockingImplant != null) {
- TooltipHandler.TipRegion(labelRect, "EdB.PC.Dialog.Implant.Conflict".Translate(recipe.BlockingImplant.Recipe.LabelCap, recipe.BlockingImplant.BodyPartRecord.Label));
+ if (option.BlockingImplant != null) {
+ TooltipHandler.TipRegion(labelRect, "EdB.PC.Dialog.Implant.Conflict".Translate(option.BlockingImplant.Recipe.LabelCap, option.BlockingImplant.BodyPartRecord.Label));
}
}
- if (recipe.Selected && recipe.RequiresPartSelection) {
- float partInset = 32;
+ if (option.Selected || option.SelectedDependency) {
+ float inset = 32;
float cursor = labelRect.yMax;
- foreach (var part in recipe.Parts) {
- string labelText = part.Part.LabelCap;
- labelRect = new Rect(rect.x + partInset, cursor, rect.width - partInset * 2, LineHeight);
- dottedLineRect = new Rect(labelRect.x, labelRect.y + 21, DottedLineSize.x, DottedLineSize.y);
- checkboxRect = new Rect(labelRect.x + labelRect.width - 22 - 6, labelRect.MiddleY() - 12, 22, 22);
- clickRect = new Rect(labelRect.x, labelRect.y, labelRect.width - checkboxRect.width, labelRect.height);
- GUI.color = DottedLineColor;
- GUI.DrawTexture(dottedLineRect, Textures.TextureDottedLine);
- labelSize = Text.CalcSize(labelText);
- GUI.color = Style.ColorWindowBackground;
- GUI.DrawTexture(new Rect(labelRect.x, labelRect.y, labelSize.x + 2, labelRect.height), BaseContent.WhiteTex);
- GUI.DrawTexture(checkboxRect.InsetBy(-2, -2, -80, -2), BaseContent.WhiteTex);
- if (!part.Disabled) {
- Style.SetGUIColorForButton(labelRect, part.Selected, Style.ColorText, Style.ColorButtonHighlight, Style.ColorButtonHighlight);
- Widgets.Label(labelRect, labelText);
- if (Widgets.ButtonInvisible(clickRect)) {
- ClickPartAction(recipe, part);
- }
- GUI.color = Color.white;
- if (Widgets.ButtonImage(checkboxRect, part.Selected ? Textures.TextureCheckboxSelected : Textures.TextureCheckbox)) {
- ClickPartAction(recipe, part);
- }
+ if (option.ImplantOption.MaxSeverity > 0) {
+ float rowWidth = rect.width - inset * 2;
+ float sliderWidth = rowWidth - LevelLabelSize.x - LevelValueSize.x - 12;
+ float sliderHeight = 12;
+ float sliderTop = cursor + LineHeight * 0.5f - sliderHeight * 0.5f;
+ Rect levelLabelRect = new Rect(rect.x + inset, cursor, LevelLabelSize.x, LineHeight);
+ Rect sliderRect = new Rect(levelLabelRect.xMax + 8, sliderTop, sliderWidth, sliderHeight);
+ Rect levelValueRect = new Rect(sliderRect.xMax + 4, cursor, LevelValueSize.x, LineHeight);
+ var guiState = UtilityGUIState.Save();
+ Text.Font = GameFont.Small;
+ Text.Anchor = TextAnchor.MiddleLeft;
+ GUI.color = Style.ColorText;
+ Widgets.Label(levelLabelRect, "EdB.PC.Dialog.Implant.LevelLabel".Translate("Level".Translate()));
+ Widgets.Label(levelValueRect, ((int)option.Severity).ToString());
+ guiState.Restore();
+ float value = Widgets.HorizontalSlider(sliderRect, option.Severity, option.ImplantOption.MinSeverity, option.ImplantOption.MaxSeverity, false, null, null, null, 1.0f);
+ if (value != option.Severity) {
+ UpdateSeverity(option, value);
}
- else {
- GUI.color = Style.ColorControlDisabled;
- Widgets.Label(labelRect, labelText);
- GUI.DrawTexture(checkboxRect, part.Selected ? Textures.TextureCheckboxPartiallySelected : Textures.TextureCheckbox);
- if (Widgets.ButtonInvisible(checkboxRect)) {
- ClickPartAction(recipe, part);
+ cursor += sliderRect.height;
+ }
+ if (option.RequiresPartSelection) {
+ foreach (var part in option.Parts) {
+ string labelText = part.Part.LabelCap;
+ labelRect = new Rect(rect.x + inset, cursor, rect.width - inset * 2, LineHeight);
+ dottedLineRect = new Rect(labelRect.x, labelRect.y + 21, DottedLineSize.x, DottedLineSize.y);
+ checkboxRect = new Rect(labelRect.x + labelRect.width - 22 - 6, labelRect.MiddleY() - 12, 22, 22);
+ clickRect = new Rect(labelRect.x, labelRect.y, labelRect.width - checkboxRect.width, labelRect.height);
+ GUI.color = DottedLineColor;
+ GUI.DrawTexture(dottedLineRect, Textures.TextureDottedLine);
+ labelSize = Text.CalcSize(labelText);
+ GUI.color = Style.ColorWindowBackground;
+ GUI.DrawTexture(new Rect(labelRect.x, labelRect.y, labelSize.x + 2, labelRect.height), BaseContent.WhiteTex);
+ GUI.DrawTexture(checkboxRect.InsetBy(-2, -2, -80, -2), BaseContent.WhiteTex);
+ if (!part.Disabled) {
+ Style.SetGUIColorForButton(labelRect, part.Selected, Style.ColorText, Style.ColorButtonHighlight, Style.ColorButtonHighlight);
+ Widgets.Label(labelRect, labelText);
+ if (Widgets.ButtonInvisible(clickRect)) {
+ ClickPartAction(option, part);
+ }
+ GUI.color = Color.white;
+ if (Widgets.ButtonImage(checkboxRect, part.Selected ? Textures.TextureCheckboxSelected : Textures.TextureCheckbox)) {
+ ClickPartAction(option, part);
+ }
}
- if (part.BlockingImplant != null) {
- TooltipHandler.TipRegion(labelRect, "EdB.PC.Dialog.Implant.Conflict".Translate(part.BlockingImplant.Recipe.LabelCap, part.BlockingImplant.BodyPartRecord.Label));
+ else {
+ GUI.color = Style.ColorControlDisabled;
+ Widgets.Label(labelRect, labelText);
+ GUI.DrawTexture(checkboxRect, part.Selected ? Textures.TextureCheckboxPartiallySelected : Textures.TextureCheckbox);
+ if (Widgets.ButtonInvisible(checkboxRect)) {
+ ClickPartAction(option, part);
+ }
+ if (part.BlockingImplant != null) {
+ TooltipHandler.TipRegion(labelRect, "EdB.PC.Dialog.Implant.Conflict".Translate(part.BlockingImplant.Recipe.LabelCap, part.BlockingImplant.BodyPartRecord.Label));
+ }
}
+ cursor += labelRect.height;
}
- cursor += labelRect.height;
}
}
Text.Anchor = TextAnchor.UpperLeft;
},
- MeasureAction = (ImplantRecipe recipe, float width, WidgetTable.Metadata metadata) => {
- if (recipe.Selected && recipe.Parts.Count > 1) {
- return LineHeight + (LineHeight * recipe.Parts.Count);
+ MeasureAction = (DialogOption option, float width, WidgetTable.Metadata metadata) => {
+ float height = LineHeight;
+ if (option.Selected && option.Parts.Count > 1) {
+ height += LineHeight * option.Parts.Count;
}
- else {
- return LineHeight;
+ if (option.Selected && option.ImplantOption.MaxSeverity > 0) {
+ height += LineHeight;
}
+ return height;
},
Width = ContentSize.x
});
@@ -602,7 +816,7 @@ public override void DoWindowContents(Rect inRect) {
GUI.BeginGroup(ContentRect);
try {
- table.Draw(this.recipes);
+ table.Draw(this.options);
}
finally {
GUI.EndGroup();
diff --git a/Source/EquipmentDatabase.cs b/Source/EquipmentDatabase.cs
index 5e25bfb..ca2f670 100644
--- a/Source/EquipmentDatabase.cs
+++ b/Source/EquipmentDatabase.cs
@@ -22,6 +22,7 @@ public class EquipmentDatabase {
protected EquipmentType TypeBuildings = new EquipmentType("Buildings", "EdB.PC.Equipment.Type.Buildings");
protected EquipmentType TypeAnimals = new EquipmentType("Animals", "EdB.PC.Equipment.Type.Animals");
protected EquipmentType TypeDiscard = new EquipmentType("Discard", "");
+ protected EquipmentType TypeMech = new EquipmentType("Mechs", "EdB.PC.Equipment.Type.Mechs");
protected EquipmentType TypeUncategorized = new EquipmentType("Uncategorized", "");
protected ThingCategoryDef thingCategorySweetMeals = null;
@@ -35,6 +36,7 @@ public class EquipmentDatabase {
public Dictionary ThingCategoryItemCounts { get; set; } = new Dictionary();
public Dictionary ModItemCounts { get; set; } = new Dictionary();
public EquipmentOption RandomAnimalEquipmentOption { get; private set; }
+ public EquipmentOption RandomMechEquipmentOption { get; private set; }
public EquipmentDatabase() {
types.Add(TypeResources);
@@ -49,6 +51,7 @@ public EquipmentDatabase() {
thingCategoryMeatRaw = DefDatabase.GetNamedSilentFail("MeatRaw");
AddRandomAnimalToEquipmentOptions();
+ AddRandomMechToEquipmentOptions();
}
public IEnumerable EquipmentOptionsByType(EquipmentType type) {
@@ -62,6 +65,9 @@ public IEnumerable EquipmentOptionsByCategory(ThingCategoryDef
return def.DescendantThingDefs.Select(t => FindOptionForThingDef(t)).Where(t => t != null);
}
}
+ public IEnumerable AllMechEquipmentOptions() {
+ return EquipmentOptions.Where(e => e.Mech);
+ }
public IEnumerable EquipmentOptionsBySearchTerm(string term) {
foreach (var option in EquipmentOptions) {
if (option.Label.IndexOf(term, StringComparison.CurrentCultureIgnoreCase) != -1) {
@@ -173,7 +179,7 @@ protected void UpdateLoadingPhase(LoadingPhase phase) {
&& d.scatterableOnMapGen && !d.destroyOnDrop)
|| (d.category == ThingCategory.Building && d.Minifiable)
//|| (d.category == ThingCategory.Building && d.scatterableOnMapGen) // TODO: Remove to get rid of "Ancient Lamppost"
- || (d.race != null && d.race.Animal)
+ || ((d.race?.IsMechanoid ?? false) && d.GetCompProperties() != null)
)
.GetEnumerator();
}
@@ -347,6 +353,17 @@ protected void AddRandomAnimalToEquipmentOptions() {
};
EquipmentOptions.Add(RandomAnimalEquipmentOption);
}
+ protected void AddRandomMechToEquipmentOptions() {
+ RandomMechEquipmentOption = new EquipmentOption() {
+ ThingDef = null,
+ DefaultSpawnType = EquipmentSpawnType.Mech,
+ Materials = null,
+ SupportsQuality = false,
+ RandomMech = true,
+ EquipmentType = TypeMech
+ };
+ EquipmentOptions.Add(RandomMechEquipmentOption);
+ }
protected bool AddStyleToEquipmentOptions(StyleCategoryDef def) {
if (def.thingDefStyles.NullOrEmpty()) {
@@ -465,6 +482,9 @@ public EquipmentSpawnType DefaultSpawnTypeForThingDef(ThingDef def, out bool res
if (def?.race?.Animal ?? false) {
return EquipmentSpawnType.Animal;
}
+ if (def?.race?.IsMechanoid ?? false) {
+ return EquipmentSpawnType.Mech;
+ }
if (def.apparel != null) {
return EquipmentSpawnType.SpawnsWith;
}
@@ -546,6 +566,14 @@ public EquipmentType ClassifyThingDef(ThingDef def) {
DiscardDebug(def, "Discarding because it is a plant");
return TypeDiscard;
}
+ if (def.race?.IsMechanoid ?? false) {
+ if (def.GetCompProperties() != null) {
+ return TypeMech;
+ }
+ else {
+ return TypeDiscard;
+ }
+ }
if (def.IsApparel) {
return TypeApparel;
}
diff --git a/Source/EquipmentOption.cs b/Source/EquipmentOption.cs
index 4d976a5..acdb672 100644
--- a/Source/EquipmentOption.cs
+++ b/Source/EquipmentOption.cs
@@ -16,12 +16,18 @@ public class EquipmentOption {
public bool RestrictedSpawnType { get; set; }
public EquipmentType EquipmentType { get; set; }
public bool RandomAnimal { get; set; }
-
+ public bool RandomMech { get; set; }
+
public bool Animal {
get {
return RandomAnimal || (ThingDef?.race?.Animal ?? false);
}
}
+ public bool Mech {
+ get {
+ return RandomMech || (ThingDef?.race?.IsMechanoid ?? false);
+ }
+ }
public bool Gendered {
get {
return ThingDef?.race?.hasGenders ?? false;
@@ -29,11 +35,14 @@ public bool Gendered {
}
public string Label {
get {
- if (!RandomAnimal) {
- return ThingDef.LabelCap;
+ if (RandomAnimal) {
+ return "EdB.PC.Equipment.AvailableEquipment.RandomAnimalLabel".Translate();
+ }
+ else if (RandomMech) {
+ return "EdB.PC.Equipment.AvailableEquipment.RandomMechLabel".Translate();
}
else {
- return "EdB.PC.Equipment.AvailableEquipment.RandomAnimalLabel".Translate();
+ return ThingDef.LabelCap;
}
}
}
diff --git a/Source/EquipmentSpawnType.cs b/Source/EquipmentSpawnType.cs
index 6fad8fa..8315b47 100644
--- a/Source/EquipmentSpawnType.cs
+++ b/Source/EquipmentSpawnType.cs
@@ -9,6 +9,7 @@ public enum EquipmentSpawnType {
SpawnsWith,
SpawnsNear,
Possession,
- Animal
+ Animal,
+ Mech
}
}
diff --git a/Source/Implant.cs b/Source/Implant.cs
index d254c7d..2aee0d1 100644
--- a/Source/Implant.cs
+++ b/Source/Implant.cs
@@ -10,74 +10,23 @@ public class Implant : CustomizedHediff {
public string label = "";
- protected string tooltip;
-
public Implant() {
}
- protected BodyPartRecord bodyPartRecord;
- public override BodyPartRecord BodyPartRecord {
- get {
- return bodyPartRecord;
- }
- set {
- bodyPartRecord = value;
- tooltip = null;
- }
- }
-
- protected Hediff hediff = null;
- public Hediff Hediff {
- get => hediff;
- set => hediff = value;
- }
-
- protected HediffDef hediffDef = null;
- public HediffDef HediffDef {
- get => hediffDef;
- set => hediffDef = value;
- }
-
-
- override public string ChangeName {
- get {
- return Label;
- }
- }
-
- override public Color LabelColor {
- get {
- if (recipe.addsHediff != null) {
- return recipe.addsHediff.defaultLabelColor;
- }
- else {
- return Style.ColorText;
- }
- }
- }
-
public Implant(BodyPartRecord bodyPartRecord, RecipeDef recipe) {
this.BodyPartRecord = bodyPartRecord;
- this.recipe = recipe;
+ this.Recipe = recipe;
}
- protected RecipeDef recipe = null;
- public RecipeDef Recipe {
- get {
- return recipe;
- }
- set {
- recipe = value;
- tooltip = null;
- }
- }
+ public ImplantOption Option { get; set; }
+ public RecipeDef Recipe { get; set; }
+ public HediffDef HediffDef { get; set; }
+ public Hediff Hediff { get; set; }
+ public float Severity { get; set; } = 0f;
public string Label {
get {
- if (recipe == null) {
- return "";
- }
- return recipe.addsHediff.LabelCap;
+ return Recipe?.addsHediff?.LabelCap ?? "";
}
}
@@ -92,51 +41,19 @@ public bool ReplacesPart {
}
}
- public override bool HasTooltip {
- get {
- return hediff != null;
- }
- }
-
- public override string Tooltip {
- get {
- if (tooltip == null) {
- InitializeTooltip();
- }
- return tooltip;
- }
- }
-
- protected void InitializeTooltip() {
- StringBuilder stringBuilder = new StringBuilder();
- Hediff_Injury hediff_Injury = hediff as Hediff_Injury;
- string damageLabel = hediff.SeverityLabel;
- if (!hediff.Label.NullOrEmpty() || !damageLabel.NullOrEmpty() || !hediff.CapMods.NullOrEmpty()) {
- stringBuilder.Append(hediff.LabelCap);
- if (!damageLabel.NullOrEmpty()) {
- stringBuilder.Append(": " + damageLabel);
- }
- stringBuilder.AppendLine();
- string tipStringExtra = hediff.TipStringExtra;
- if (!tipStringExtra.NullOrEmpty()) {
- stringBuilder.AppendLine(tipStringExtra.TrimEndNewlines().Indented());
- }
- }
- tooltip = stringBuilder.ToString();
- }
-
public override bool Equals(object obj) {
return obj is Implant implant &&
- EqualityComparer.Default.Equals(bodyPartRecord, implant.bodyPartRecord) &&
- EqualityComparer.Default.Equals(hediffDef, implant.hediffDef) &&
- EqualityComparer.Default.Equals(recipe, implant.recipe);
+ ReferenceEquals(BodyPartRecord, implant.BodyPartRecord) &&
+ ReferenceEquals(HediffDef, implant.HediffDef) &&
+ ReferenceEquals(Recipe, implant.Recipe)
+ ;
}
public override int GetHashCode() {
var hashCode = 223280684;
- hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(bodyPartRecord);
- hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(hediffDef);
- hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(recipe);
+ hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(BodyPartRecord);
+ hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(HediffDef);
+ hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(Recipe);
return hashCode;
}
}
diff --git a/Source/ImplantOption.cs b/Source/ImplantOption.cs
new file mode 100644
index 0000000..86b9449
--- /dev/null
+++ b/Source/ImplantOption.cs
@@ -0,0 +1,25 @@
+using RimWorld;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Verse;
+
+namespace EdB.PrepareCarefully {
+ public class ImplantOption {
+ public RecipeDef RecipeDef { get; set; }
+ public HediffDef HediffDef { get; set; }
+ public HediffDef Dependency { get; set; }
+ public ThingDef ThingDef { get; set; }
+ public BodyPartRecord BodyPartRecord { get; set; }
+ public HashSet BodyPartDefs { get; set; }
+ public float MinSeverity { get; set; } = 0;
+ public float MaxSeverity { get; set; } = 0;
+ public bool SupportsSeverity {
+ get {
+ return MaxSeverity > 0;
+ }
+ }
+ }
+}
diff --git a/Source/Injury.cs b/Source/Injury.cs
index 15eb23b..78c019f 100644
--- a/Source/Injury.cs
+++ b/Source/Injury.cs
@@ -9,124 +9,27 @@
namespace EdB.PrepareCarefully {
public class Injury : CustomizedHediff {
-
+ public InjuryOption Option { get; set; }
public Hediff Hediff { get; set; }
-
- public string tooltip;
-
- public InjuryOption option;
- public InjuryOption Option {
- get {
- return option;
- }
- set {
- option = value;
- tooltip = null;
- stageLabel = ComputeStageLabel();
- }
- }
-
-
-
- protected string stageLabel = null;
-
+ public float Severity { get; set; } = 0;
public float? PainFactor { get; set; }
-
public ChemicalDef Chemical { get; set; }
- protected float severity = 0;
- public float Severity {
- get {
- return severity;
- }
- set {
- tooltip = null;
- severity = value;
- stageLabel = ComputeStageLabel();
- }
- }
-
public Injury() {
}
- public BodyPartRecord bodyPartRecord;
- override public BodyPartRecord BodyPartRecord {
- get {
- return bodyPartRecord;
- }
- set {
- bodyPartRecord = value;
- }
- }
-
- override public string ChangeName {
- get {
- if (stageLabel != null) {
- return stageLabel;
- }
- else if (Option != null) {
- return Option.Label;
- }
- else {
- return "?";
- }
- }
- }
-
- override public Color LabelColor {
- get {
- if (Option != null && Option.HediffDef != null) {
- return Option.IsOldInjury ? Color.gray : Option.HediffDef.defaultLabelColor;
- }
- else {
- return Style.ColorText;
- }
- }
- }
-
- // EVERY RELEASE:
- // Check the PainCategory enum to verify that we still only have 4 values and that their int values match the logic here.
- // This method converts a float value into a PainCategory. It's here because we don't quite remember where that float
- // value comes from and if it contain a value that won't map to one of the PainCategory enum values.
- // Unchanged for 1.14
- protected PainCategory PainCategoryForFloat(float value) {
- int intValue = Mathf.FloorToInt(value);
- if (intValue == 2) {
- intValue = 1;
- }
- else if (intValue > 3 && intValue < 6) {
- intValue = 3;
- }
- else if (intValue > 6) {
- intValue = 6;
- }
- return (PainCategory)intValue;
- }
-
- protected string ComputeStageLabel() {
- if (Option.HasStageLabel) {
- return "EdB.PC.Panel.Health.InjuryLabel.Stage".Translate(this.option.Label, CurStage.label);
- }
- else if (Option.IsOldInjury) {
- return "EdB.PC.Panel.Health.InjuryLabel.Severity".Translate(this.option.Label, (int)severity);
- }
- else {
- return null;
- }
- }
-
protected HediffStage CurStage {
get {
- return (!this.option.HediffDef.stages.NullOrEmpty()) ? this.option.HediffDef.stages[this.CurStageIndex] : null;
+ return (!this.Option.HediffDef.stages.NullOrEmpty()) ? this.Option.HediffDef.stages[this.CurStageIndex] : null;
}
}
protected int CurStageIndex {
get {
- if (this.option.HediffDef.stages == null) {
+ if (this.Option.HediffDef.stages == null) {
return 0;
}
- List stages = this.option.HediffDef.stages;
+ List stages = this.Option.HediffDef.stages;
for (int i = stages.Count - 1; i >= 0; i--) {
if (this.Severity >= stages[i].minSeverity) {
return i;
@@ -136,65 +39,23 @@ protected int CurStageIndex {
}
}
- public override bool HasTooltip {
- get {
- return Hediff != null;
- }
- }
-
- public override string Tooltip {
- get {
- if (tooltip == null) {
- InitializeTooltip();
- }
- return tooltip;
- }
- }
-
- protected void InitializeTooltip() {
- StringBuilder stringBuilder = new StringBuilder();
- if (Hediff.Part != null) {
- stringBuilder.Append(Hediff.Part.def.LabelCap + ": ");
- stringBuilder.Append(" " + Hediff.pawn.health.hediffSet.GetPartHealth(Hediff.Part).ToString() + " / " + Hediff.Part.def.GetMaxHealth(Hediff.pawn).ToString());
- }
- else {
- stringBuilder.Append("WholeBody".Translate());
- }
- stringBuilder.AppendLine();
- stringBuilder.AppendLine("------------------");
- Hediff_Injury hediff_Injury = Hediff as Hediff_Injury;
- string damageLabel = Hediff.SeverityLabel;
- if (!Hediff.Label.NullOrEmpty() || !damageLabel.NullOrEmpty() || !Hediff.CapMods.NullOrEmpty()) {
- stringBuilder.Append(Hediff.LabelCap);
- if (!damageLabel.NullOrEmpty()) {
- stringBuilder.Append(": " + damageLabel);
- }
- stringBuilder.AppendLine();
- string tipStringExtra = Hediff.TipStringExtra;
- if (!tipStringExtra.NullOrEmpty()) {
- stringBuilder.AppendLine(tipStringExtra.TrimEndNewlines().Indented());
- }
- }
- tooltip = stringBuilder.ToString();
- }
-
public override bool Equals(object obj) {
return obj is Injury injury &&
- EqualityComparer.Default.Equals(option, injury.option) &&
+ EqualityComparer.Default.Equals(Option, injury.Option) &&
PainFactor == injury.PainFactor &&
EqualityComparer.Default.Equals(Chemical, injury.Chemical) &&
- severity == injury.severity &&
- EqualityComparer.Default.Equals(bodyPartRecord, injury.bodyPartRecord) &&
+ Severity == injury.Severity &&
+ EqualityComparer.Default.Equals(BodyPartRecord, injury.BodyPartRecord) &&
EqualityComparer.Default.Equals(CurStage, injury.CurStage);
}
public override int GetHashCode() {
var hashCode = 662792533;
- hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(option);
+ hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(Option);
hashCode = hashCode * -1521134295 + PainFactor.GetHashCode();
hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(Chemical);
- hashCode = hashCode * -1521134295 + severity.GetHashCode();
- hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(bodyPartRecord);
+ hashCode = hashCode * -1521134295 + Severity.GetHashCode();
+ hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(BodyPartRecord);
hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(CurStage);
return hashCode;
}
diff --git a/Source/ManagerEquipment.cs b/Source/ManagerEquipment.cs
index e12d68f..aaf0f1f 100644
--- a/Source/ManagerEquipment.cs
+++ b/Source/ManagerEquipment.cs
@@ -121,6 +121,34 @@ public void InitializeStateFromScenarioAndStartingPawns() {
State.ReplacedScenarioParts.Add(part);
}
}
+
+ // Go through all of the scenario steps that spawn a mech and add the mech to the equipment/resource list.
+ if (part is ScenPart_StartingMech mech) {
+ PawnKindDef pawnKindDef = part.GetPrivateField("mechKind");
+ float overseenChance = part.GetPrivateField("overseenByPlayerPawnChance");
+ if (pawnKindDef != null && pawnKindDef.race != null) {
+ EquipmentDatabase.PreloadDefinition(pawnKindDef.race);
+ EquipmentOption option = EquipmentDatabase.FindOptionForThingDef(pawnKindDef.race);
+ if (option != null) {
+ AddEquipment(new CustomizedEquipment() {
+ EquipmentOption = option,
+ Count = 1,
+ SpawnType = EquipmentSpawnType.Mech,
+ OverseenChance = overseenChance
+ });
+ State.ReplacedScenarioParts.Add(part);
+ }
+ }
+ else {
+ AddEquipment(new CustomizedEquipment() {
+ EquipmentOption = EquipmentDatabase.RandomMechEquipmentOption,
+ Count = 1,
+ SpawnType = EquipmentSpawnType.Mech,
+ OverseenChance = overseenChance
+ });
+ State.ReplacedScenarioParts.Add(part);
+ }
+ }
}
// Go through starting possessions
diff --git a/Source/ManagerPawns.cs b/Source/ManagerPawns.cs
index 3ae334b..89d26a7 100644
--- a/Source/ManagerPawns.cs
+++ b/Source/ManagerPawns.cs
@@ -27,6 +27,7 @@ public class ManagerPawns {
public ProviderBodyTypes ProviderBodyTypes { get; set; }
public ProviderFactions ProviderFactions { get; set; }
public ProviderHeadTypes ProviderHeadTypes { get; set; }
+ public ProviderHealthOptions ProviderHealthOptions { get; set; }
public AgeModifier AgeModifier { get; set; }
public EquipmentDatabase EquipmentDatabase { get; set; }
public PawnLoader PawnLoader { get; set; }
@@ -691,7 +692,6 @@ public void AddPawnInjury(CustomizedPawn customizedPawn, Injury injury) {
return;
}
customizations.Injuries.Add(injury);
- customizations.BodyParts.Add(injury);
Customizer.ApplyInjuryAndImplantCustomizationsToPawn(pawn, customizations);
PawnToCustomizationsMapper.MapInjuriesAndImplants(pawn, customizations);
CostAffected?.Invoke();
@@ -703,7 +703,6 @@ public void AddPawnImplant(CustomizedPawn customizedPawn, Implant implant) {
return;
}
customizations.Implants.Add(implant);
- customizations.BodyParts.Add(implant);
Customizer.ApplyInjuryAndImplantCustomizationsToPawn(pawn, customizations);
PawnToCustomizationsMapper.MapInjuriesAndImplants(pawn, customizations);
CostAffected?.Invoke();
@@ -715,66 +714,119 @@ public void UpdateImplants(CustomizedPawn customizedPawn, IEnumerable i
return;
}
List implantsToRemove = new List();
- foreach (var bodyPart in customizations.BodyParts) {
- Implant asImplant = bodyPart as Implant;
- implantsToRemove.Add(asImplant);
- }
- foreach (var implant in implantsToRemove) {
- customizations.BodyParts.Remove(implant);
+ foreach (var existingImplant in customizations.Implants) {
+ var matchingImplant = implants.FirstOrDefault(i => i.Equals(existingImplant));
+ if (matchingImplant == null) {
+ implantsToRemove.Add(existingImplant);
+ }
}
+ RemoveHediffsInternal(customizedPawn, implantsToRemove.SelectMany(i => HediffsMatchingImplant(customizedPawn, i)));
customizations.Implants.Clear();
- foreach (var implant in implants) {
- customizations.BodyParts.Add(implant);
- customizations.Implants.Add(implant);
- }
+ customizations.Implants.AddRange(implants);
Customizer.ApplyInjuryAndImplantCustomizationsToPawn(pawn, customizations);
PawnToCustomizationsMapper.MapInjuriesAndImplants(pawn, customizations);
ClearPawnGraphicsCache(pawn);
CostAffected?.Invoke();
}
- public void RemovePawnHediffs(CustomizedPawn customizedPawn, IEnumerable hediffs) {
+ public IEnumerable HediffsMatchingImplant(CustomizedPawn customizedPawn, Implant implant) {
+ Pawn pawn = customizedPawn.Pawn;
+ if (pawn == null) {
+ return Enumerable.Empty();
+ }
+ if (implant == null) {
+ Logger.Warning("implant is null");
+ return Enumerable.Empty();
+ }
+
+ return pawn.health.hediffSet.hediffs.Where(h => h?.def == implant?.Option?.HediffDef && h?.Part == implant?.BodyPartRecord);
+ }
+
+ private void RemoveHediffsInternal(CustomizedPawn customizedPawn, IEnumerable hediffs) {
Pawn pawn = customizedPawn?.Pawn;
CustomizationsPawn customizations = customizedPawn?.Customizations;
if (pawn == null || customizations == null) {
return;
}
- foreach (Hediff hediff in hediffs) {
- pawn.health.RemoveHediff(hediff);
- Injury injury = customizations.Injuries.FirstOrDefault(i => i.Hediff == hediff);
- Implant implant = customizations.Implants.FirstOrDefault(i => i.Hediff == hediff);
- if (injury != null) {
- RemoveCustomBodyParts(injury, customizations);
- }
- if (implant != null) {
- RemoveCustomBodyParts(implant, customizations);
- }
+ var list = hediffs.ToList();
+ foreach (Hediff hediff in list) {
+ RemoveHediff(customizedPawn, hediff);
}
+ RemoveHediffsWithUnsatisfiedDependencies(customizedPawn);
+ }
+
+ public void RemoveHediffs(CustomizedPawn customizedPawn, IEnumerable hediffs) {
+ Pawn pawn = customizedPawn?.Pawn;
+ CustomizationsPawn customizations = customizedPawn?.Customizations;
+ if (pawn == null || customizations == null) {
+ return;
+ }
+ RemoveHediffsInternal(customizedPawn, hediffs);
+ RemoveHediffsWithUnsatisfiedDependencies(customizedPawn);
Customizer.ApplyInjuryAndImplantCustomizationsToPawn(pawn, customizations);
PawnToCustomizationsMapper.MapInjuriesAndImplants(pawn, customizations);
ClearPawnGraphicsCache(pawn);
CostAffected?.Invoke();
}
- public void RemoveCustomBodyParts(CustomizedHediff part, CustomizationsPawn customizations) {
- Implant implant = part as Implant;
- Injury injury = part as Injury;
- if (implant != null) {
- customizations.Implants.Remove(implant);
+
+ protected void RemoveHediff(CustomizedPawn customizedPawn, Hediff hediff) {
+ Pawn pawn = customizedPawn?.Pawn;
+ CustomizationsPawn customizations = customizedPawn?.Customizations;
+ if (pawn == null || customizations == null) {
+ return;
}
+ Logger.Debug("Removed hediff: " + hediff.def.defName + ", " + hediff.Part?.def?.defName);
+ pawn.health.RemoveHediff(hediff);
+ Injury injury = customizations.Injuries.FirstOrDefault(i => i.Hediff == hediff);
+ Implant implant = customizations.Implants.FirstOrDefault(i => i.Hediff == hediff);
if (injury != null) {
customizations.Injuries.Remove(injury);
}
- customizations.BodyParts.Remove(part);
- CostAffected?.Invoke();
+ if (implant != null) {
+ customizations.Implants.Remove(implant);
+ }
+ }
+
+ protected void RemoveHediffsWithUnsatisfiedDependencies(CustomizedPawn customizedPawn) {
+ HashSet unsatisifedHediffs = new HashSet();
+ int maxAttempts = 100;
+ int attempt = 0;
+ while (HasHediffsWithUnsatisfiedDependencies(customizedPawn, ref unsatisifedHediffs)) {
+ if (attempt++ > maxAttempts) {
+ return;
+ }
+ foreach (var hediff in unsatisifedHediffs) {
+ RemoveHediff(customizedPawn, hediff);
+ }
+ unsatisifedHediffs.Clear();
+ }
}
- public void RemovePawnHediff(CustomizedPawn customizedPawn, Hediff hediff) {
+
+ protected bool HasHediffsWithUnsatisfiedDependencies(CustomizedPawn customizedPawn, ref HashSet unsatisfiedHediffs) {
Pawn pawn = customizedPawn?.Pawn;
if (pawn == null) {
- return;
+ return false;
}
- pawn.health.RemoveHediff(hediff);
- CostAffected?.Invoke();
+ var options = ProviderHealthOptions.GetOptions(customizedPawn);
+ if (options == null) {
+ return false;
+ }
+ Dictionary dependencies = new Dictionary();
+ foreach (var hediff in pawn.health.hediffSet.hediffs) {
+ var matchingImplantOption = options.FindImplantOptionsThatAddHediff(hediff).FirstOrDefault();
+ if (matchingImplantOption?.Dependency != null) {
+ dependencies[hediff] = matchingImplantOption.Dependency;
+ }
+ }
+ unsatisfiedHediffs = new HashSet();
+ foreach (var pair in dependencies) {
+ if (!pawn.health.hediffSet.hediffs.ContainsAny(h => h.def == pair.Value)) {
+ unsatisfiedHediffs.Add(pair.Key);
+ }
+ }
+ return unsatisfiedHediffs.Count > 0;
}
+
public void UpdateBodyType(CustomizedPawn customizedPawn, BodyTypeDef bodyTypeDef) {
Pawn pawn = customizedPawn?.Pawn;
CustomizationsPawn customizations = customizedPawn?.Customizations;
diff --git a/Source/ManagerRelationships.cs b/Source/ManagerRelationships.cs
index ab63373..0a74dd9 100644
--- a/Source/ManagerRelationships.cs
+++ b/Source/ManagerRelationships.cs
@@ -73,7 +73,7 @@ public void InitializeHiddenPawns(IEnumerable customPawns) {
Pawn otherPawn = r.otherPawn;
if (!customPawnLookup.Contains(otherPawn)) {
if (!hiddenPawns.ContainsAny(c => c.Pawn == otherPawn)) {
- Logger.Debug(" Added hidden pawn: " + otherPawn.Label + ", faction = " + otherPawn.Faction?.Name + ", leader = " + (otherPawn.Faction?.leader == otherPawn ? "true" : "false"));
+ Logger.Debug(" Added hidden pawn: " + otherPawn.LabelShort + ", faction = " + otherPawn.Faction?.Name + ", leader = " + (otherPawn.Faction?.leader == otherPawn ? "true" : "false"));
hiddenPawns.Add(new CustomizedPawn() {
Pawn = otherPawn,
Type = CustomizedPawnType.Hidden,
@@ -381,10 +381,11 @@ public void InitializeWithCustomizedPawns(IEnumerable pawns) {
public void InitializeRelationshipsForStartingPawns(IEnumerable customPawns) {
Logger.Debug("InitializeRelationshipsForStartingPawns(): " + customPawns?.Count());
+ IEnumerable allPawns = customPawns.Concat(hiddenPawns);
// Go through each pawn and check for relationships between it and all other pawns.
- foreach (CustomizedPawn pawn in customPawns) {
- foreach (CustomizedPawn other in customPawns) {
+ foreach (CustomizedPawn pawn in allPawns) {
+ foreach (CustomizedPawn other in allPawns) {
if (pawn == other) {
continue;
}
@@ -535,7 +536,7 @@ public void RemoveAllRelationshipsForPawn(Pawn pawn) {
}
public RelationshipBuilder GetRelationshipBuilder() {
- return new RelationshipBuilder(State.Customizations.Relationships, State.Customizations.ParentChildGroups);
+ return new RelationshipBuilder(State.Customizations.AllPawns, State.Customizations.Relationships, State.Customizations.ParentChildGroups);
}
}
}
diff --git a/Source/MapperPawnToCustomizations.cs b/Source/MapperPawnToCustomizations.cs
index 29bcf36..0257828 100644
--- a/Source/MapperPawnToCustomizations.cs
+++ b/Source/MapperPawnToCustomizations.cs
@@ -71,7 +71,7 @@ private List CreateCustomizedGeneList(Pawn pawn, IEnumerable= 0) {
+ implant.Severity = level.level;
+ }
+ }
implants.Add(implant);
}
- else if (hediff.def.defName != "MissingBodyPart") {
- Logger.Warning("Could not add hediff {" + hediff.def.defName + "} to the pawn because no recipe adds it to the body part {" + (hediff.Part?.def?.defName ?? "WholeBody") + "}");
- }
else {
- Logger.Warning("Could not add hediff {" + hediff.def.defName + "} to the pawn. It is not currently supported");
+ Logger.Warning("Could not add hediff {" + hediff.def.defName + "} to the pawn because found no matching implant option for the body part {" + (hediff.Part?.def?.defName ?? "WholeBody") + "}");
}
}
}
customizations.Injuries.Clear();
customizations.Implants.Clear();
- customizations.BodyParts.Clear();
foreach (var injury in injuries) {
//Logger.Debug("Adding injury: " + injury.Option.Label);
customizations.Injuries.Add(injury);
- customizations.BodyParts.Add(injury);
}
foreach (var implant in implants) {
//Logger.Debug("Adding implant: " + implant.Label);
customizations.Implants.Add(implant);
- customizations.BodyParts.Add(implant);
}
}
diff --git a/Source/Mod.cs b/Source/Mod.cs
index 6aeb3d7..b0c4516 100644
--- a/Source/Mod.cs
+++ b/Source/Mod.cs
@@ -137,6 +137,7 @@ public void Start(Page_ConfigureStartingPawns configureStartingPawnsPage) {
ProviderHeadTypes = providerHeadTypes,
ProviderBodyTypes = providerBodyTypes,
ProviderFactions = providerFactions,
+ ProviderHealthOptions = providerHealthOptions,
AgeModifier = ageModifier,
EquipmentDatabase = equipmentDatabase,
PawnLoader = pawnLoader,
diff --git a/Source/OptionsHealth.cs b/Source/OptionsHealth.cs
index f335be2..d6b7cd7 100644
--- a/Source/OptionsHealth.cs
+++ b/Source/OptionsHealth.cs
@@ -20,16 +20,15 @@ public class UniqueBodyPart {
public class OptionsHealth {
protected List bodyPartList = new List();
protected Dictionary> bodyPartDefLookup = new Dictionary>();
- protected Dictionary> implantRecipeLookup = new Dictionary>();
protected Dictionary bodyPartRecordLookup = new Dictionary();
protected Dictionary> bodyPartGroupLookup = new Dictionary>();
- protected List implantRecipes = new List();
+ protected Dictionary> implantRecipeLookup = new Dictionary>();
+
protected Dictionary injuryOptionsByHediff = new Dictionary();
protected List injuryOptions = new List();
- public OptionsHealth() {
- }
+ public List ImplantOptions { get; private set; } = new List();
public BodyDef BodyDef {
get; set;
}
@@ -131,32 +130,103 @@ public List FindBodyPartsForDef(BodyPartDef def) {
}
}
public IEnumerable FindImplantRecipesThatAddHediff(Hediff hediff) {
- return ImplantRecipes.Where((RecipeDef def) => {
- if (def.addsHediff == null) {
+ return ImplantOptions.Where(o => RecipeAddsHediff(o.RecipeDef, hediff)).Select(o => o.RecipeDef);
+ }
+
+ public IEnumerable FindImplantOptionsThatAddHediff(Hediff hediff) {
+ return ImplantOptions.Where((ImplantOption o) => {
+ if (RecipeAddsHediff(o.RecipeDef, hediff)) {
+ return true;
+ }
+ if (o.HediffDef == null) {
return false;
}
- if (def.addsHediff != hediff.def) {
+ if (o.HediffDef != hediff.def) {
return false;
}
if (hediff.Part != null) {
- if (def.appliedOnFixedBodyParts.Contains(hediff.Part.def)) {
- return true;
+ if (o.BodyPartDefs.NullOrEmpty()) {
+ return false;
}
- foreach (var group in def.appliedOnFixedBodyPartGroups) {
- var parts = this.PartsForBodyPartGroup(group.defName);
- if (parts != null) {
- if (parts.ConvertAll(p => p.Record.def).Contains(hediff.Part.def)) {
- return true;
- }
- }
+ if (!o.BodyPartDefs.Contains(hediff.Part.def)) {
+ return false;
}
}
- else if (def.appliedOnFixedBodyParts.Count == 0 && def.appliedOnFixedBodyPartGroups.Count == 0) {
+ return true;
+ });
+ }
+
+ public ImplantOption FindImplantOptionThatAddsHediffDefToBodyPart(HediffDef hediffDef, BodyPartDef bodyPartDef) {
+ return ImplantOptions.Where(o => {
+ if (o.HediffDef != hediffDef) {
+ return false;
+ }
+ if (bodyPartDef == null && o.BodyPartDefs == null) {
return true;
}
+ return o.BodyPartDefs.Contains(bodyPartDef);
+ }).FirstOrDefault();
+ }
+
+ public ImplantOption FindImplantOptionThatAddsRecipeDefToBodyPart(RecipeDef recipefDef, BodyPartDef bodyPartDef) {
+ if (recipefDef == null) {
+ return null;
+ }
+ return ImplantOptions.Where(o => {
+ return RecipeTargetsBodyPart(recipefDef, bodyPartDef);
+ }).FirstOrDefault();
+ }
+
+ public bool RecipeAddsHediff(RecipeDef recipe, Hediff hediff) {
+ if (recipe == null) {
return false;
- });
+ }
+ if (recipe.addsHediff == null) {
+ return false;
+ }
+ if (recipe.addsHediff != hediff.def) {
+ return false;
+ }
+ if (hediff.Part != null) {
+ if (recipe.appliedOnFixedBodyParts.Contains(hediff.Part.def)) {
+ return true;
+ }
+ foreach (var group in recipe.appliedOnFixedBodyPartGroups) {
+ var parts = this.PartsForBodyPartGroup(group.defName);
+ if (parts != null) {
+ if (parts.ConvertAll(p => p.Record.def).Contains(hediff.Part.def)) {
+ return true;
+ }
+ }
+ }
+ }
+ else if (recipe.appliedOnFixedBodyParts.Count == 0 && recipe.appliedOnFixedBodyPartGroups.Count == 0) {
+ return true;
+ }
+ return false;
+ }
+ public bool RecipeTargetsBodyPart(RecipeDef recipeDef, BodyPartDef bodyPartDef) {
+ if (bodyPartDef == null && !recipeDef.targetsBodyPart) {
+ return true;
+ }
+ if (recipeDef.appliedOnFixedBodyParts != null) {
+ if (recipeDef.appliedOnFixedBodyParts.Contains(bodyPartDef)) {
+ return true;
+ }
+ }
+ if (recipeDef.appliedOnFixedBodyPartGroups != null) {
+ foreach (var group in recipeDef.appliedOnFixedBodyPartGroups) {
+ var parts = this.PartsForBodyPartGroup(group.defName);
+ if (parts != null) {
+ if (parts.Select(p => p.Record.def).Contains(bodyPartDef)) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
}
+
public IEnumerable SkinCoveredBodyParts {
get {
return bodyPartList.Where((UniqueBodyPart p) => { return p.SkinCovered; });
@@ -174,37 +244,52 @@ public IEnumerable SolidBodyParts {
}
public void AddImplantRecipe(RecipeDef recipe, List parts) {
if (parts != null && parts.Count > 0) {
- List partList;
- if (implantRecipeLookup.TryGetValue(recipe, out partList)) {
+ // If we've already added the recipe than just add any new parts to the existing
+ // part list. Otherwise, add the implant option.
+ if (implantRecipeLookup.TryGetValue(recipe, out List partList)) {
partList.AddRange(parts);
}
else {
- implantRecipes.Add(recipe);
+ ImplantOptions.Add(new ImplantOption() {
+ RecipeDef = recipe,
+ HediffDef = recipe.addsHediff
+ });
implantRecipeLookup.Add(recipe, parts.ToList());
}
}
}
- public List FindBodyPartsForImplantRecipe(RecipeDef recipeDef) {
- List partList;
- if (implantRecipeLookup.TryGetValue(recipeDef, out partList)) {
+ public void AddImplantOption(ImplantOption option) {
+ ImplantOptions.Add(option);
+ }
+ public void AddImplantHediffDef(HediffDef hediffDef, BodyPartRecord bodyPartRecord = null) {
+ ImplantOptions.Add(new ImplantOption() {
+ RecipeDef = null,
+ HediffDef = hediffDef,
+ BodyPartRecord = bodyPartRecord,
+ });
+ }
+
+ public IEnumerable FindBodyPartsForImplantRecipe(RecipeDef recipeDef) {
+ if (recipeDef == null) {
+ return Enumerable.Empty();
+ }
+ if (implantRecipeLookup.TryGetValue(recipeDef, out List partList)) {
return partList;
}
else {
- return null;
- }
- }
- public List ImplantRecipes {
- get {
- return implantRecipes;
+ return Enumerable.Empty();
}
}
+
public void Sort() {
SortImplants();
SortInjuries();
}
protected void SortImplants() {
- implantRecipes.Sort((RecipeDef a, RecipeDef b) => {
- return string.Compare(a.LabelCap.Resolve(), b.LabelCap.Resolve());
+ ImplantOptions.Sort((ImplantOption a, ImplantOption b) => {
+ string aLabel = a.RecipeDef?.LabelCap.Resolve() ?? a.HediffDef?.LabelCap ?? "";
+ string bLabel = b.RecipeDef?.LabelCap.Resolve() ?? b.HediffDef?.LabelCap ?? "";
+ return string.Compare(aLabel, bLabel);
});
}
protected void SortInjuries() {
diff --git a/Source/PanelEquipmentAvailable.cs b/Source/PanelEquipmentAvailable.cs
index 58e53d8..e068a59 100644
--- a/Source/PanelEquipmentAvailable.cs
+++ b/Source/PanelEquipmentAvailable.cs
@@ -35,6 +35,9 @@ public class ViewEquipmentList {
protected Rect RectScrollView;
protected Rect RectRow;
protected Rect RectItem;
+ protected Rect RectOverseenLabel;
+ protected Rect RectOverseenSlider;
+ protected Rect RectOverseenPercentLabel;
protected Vector2 AddButtonSize;
protected static Vector2 SizeTextureSortIndicator = new Vector2(8, 4);
protected EquipmentType selectedType = null;
@@ -47,6 +50,7 @@ public class ViewEquipmentList {
private EquipmentOption LastDrawnEquipmentOption = null;
private ThingCategoryDef FilterThingCategory = null;
+ private bool FilterMechs = false;
private string FilterModName = null;
private string FilterSearchTerm = null;
private List FilteredOptions = new List();
@@ -128,6 +132,14 @@ public override void Resize(Rect rect) {
RectRow = new Rect(0, 0, RectScrollView.width, 42);
RectItem = new Rect(10, 2, 38, 38);
+
+ Text.Font = GameFont.Tiny;
+ Vector2 rectOverseenLabelSize = Text.CalcSize("EdB.PC.Equipment.AvailableEquipment.OverseenChanceLabel".Translate("StartOverseenChance".Translate()));
+ Vector2 rectOverseenPercentLabelSize = Text.CalcSize("000%".Translate());
+ Text.Font = GameFont.Small;
+ RectOverseenLabel = new Rect(0, 0, rectOverseenLabelSize.x, 18);
+ RectOverseenSlider = new Rect(RectOverseenLabel.xMax + 8, 3, 240, 12);
+ RectOverseenPercentLabel = new Rect(RectOverseenSlider.xMax + 8, 0, rectOverseenPercentLabelSize.x, 18);
}
protected bool FilterTick() {
@@ -154,6 +166,9 @@ protected void ApplyCurrentFilters() {
else {
options = ProviderEquipment.Equipment;
}
+ if (FilterMechs) {
+ options = ProviderEquipment.EquipmentDatabase.AllMechEquipmentOptions();
+ }
if (FilterModName != null) {
options = ProviderEquipment.EquipmentDatabase.ApplyModNameFilter(options, FilterModName);
}
@@ -164,21 +179,31 @@ protected void ApplyCurrentFilters() {
}
protected void PrepareThingCategoryFilterOptions() {
- ThingCategoryFloatMenuOptions = new List();
- ThingCategoryFloatMenuOptions.Add(new FloatMenuOption("EdB.PC.Equipment.AvailableEquipment.AllCategoriesOption".Translate(), () => {
+ List options = new List();
+ options.Add(new FloatMenuOption("EdB.PC.Equipment.AvailableEquipment.MechCategoryLabel".Translate(), () => {
FilterThingCategory = null;
+ FilterMechs = true;
ApplyCurrentFilters();
}, MenuOptionPriority.Default, null, null, 0, null, null));
foreach (var thingCategory in ProviderEquipment.EquipmentDatabase.ThingCategories) {
if (thingCategory.defName == "Root") {
continue;
}
- ThingCategoryFloatMenuOptions.Add(new FloatMenuOption(LabelForThingCategory(thingCategory), () => {
+ options.Add(new FloatMenuOption(LabelForThingCategory(thingCategory), () => {
FilterThingCategory = thingCategory;
+ FilterMechs = false;
ApplyCurrentFilters();
}, MenuOptionPriority.Default, null, null, 0, null, null));
- ThingCategoryFloatMenuOptions = ThingCategoryFloatMenuOptions.OrderBy(m => m.Label).ToList();
}
+
+ ThingCategoryFloatMenuOptions = new List() {
+ new FloatMenuOption("EdB.PC.Equipment.AvailableEquipment.AllCategoriesOption".Translate(), () => {
+ FilterThingCategory = null;
+ FilterMechs = false;
+ ApplyCurrentFilters();
+ }, MenuOptionPriority.Default, null, null, 0, null, null)
+ };
+ ThingCategoryFloatMenuOptions.AddRange(options.OrderBy(m => m.Label));
}
protected void PrepareModNameFilterOptions() {
ModNameFloatMenuOptions = new List();
@@ -395,6 +420,9 @@ public void SelectOption(EquipmentOption option) {
Count = 1,
Gender = null
};
+ if (option.Mech) {
+ SelectedValues.OverseenChance = 1.0f;
+ }
RecalculateSelectedOptionCost();
}
@@ -409,7 +437,7 @@ public void DrawIconForEquipmentOption(EquipmentOption equipment, float y) {
Widgets.ThingIcon(iconRect, equipment.ThingDef, equipment.ThingDef.defaultStuff);
}
}
- else if (equipment.RandomAnimal) {
+ else if (equipment.RandomAnimal || equipment.RandomMech) {
GUI.color = Style.ColorTextSecondary;
Rect iconRect = new Rect(12f, y + 6, 24f, 24f);
GUI.DrawTexture(iconRect, Textures.TextureButtonRandom);
@@ -532,6 +560,33 @@ public float DrawSelectedRow(float y, float width, int index, EquipmentOption eq
y += 24;
}
+ // Draw overseen chance
+ if (SelectedOption.Mech) {
+ // Draw the slider
+ Text.Font = GameFont.Tiny;
+ GUI.color = Style.ColorText;
+ Text.Anchor = TextAnchor.MiddleLeft;
+ Rect overseenLabelRect = RectOverseenLabel.OffsetBy(insetMargin, y);
+ Widgets.Label(overseenLabelRect, "EdB.PC.Equipment.AvailableEquipment.OverseenChanceLabel".Translate("StartOverseenChance".Translate()));
+ Text.Anchor = TextAnchor.MiddleCenter;
+ Text.Font = GameFont.Tiny;
+ Rect sliderRect = RectOverseenSlider.OffsetBy(insetMargin, y);
+ Rect percentLabelRect = RectOverseenPercentLabel.OffsetBy(insetMargin, y);
+ Widgets.Label(percentLabelRect, String.Format("{0:F0}%", SelectedValues.OverseenChance.Value * 100f));
+ Text.Anchor = TextAnchor.MiddleLeft;
+ GUI.color = Color.white;
+ float value = GUI.HorizontalSlider(sliderRect, SelectedValues.OverseenChance.Value, 0f, 1f);
+ y += sliderRect.height;
+
+ Text.Font = GameFont.Small;
+ GUI.color = Color.white;
+ Text.Anchor = TextAnchor.UpperLeft;
+ y += 8;
+
+ // Update the hit points based on the slider value
+ SelectedValues.OverseenChance = value;
+ }
+
// Add button
Rect addButtonRect = new Rect(insetMargin, y + 4, AddButtonSize.x, AddButtonSize.y);
Text.Font = GameFont.Tiny;
diff --git a/Source/PanelEquipmentSelected.cs b/Source/PanelEquipmentSelected.cs
index 4a541d9..e9e6949 100644
--- a/Source/PanelEquipmentSelected.cs
+++ b/Source/PanelEquipmentSelected.cs
@@ -175,7 +175,7 @@ public float DrawSelectedEquipment(float y, float width, int index, CustomizedEq
}
Widgets.ThingIcon(iconRect, equipment.EquipmentOption.ThingDef, stuff);
}
- else if (equipment.EquipmentOption.RandomAnimal) {
+ else if (equipment.EquipmentOption.RandomAnimal || equipment.EquipmentOption.RandomMech) {
GUI.color = Style.ColorTextSecondary;
Rect iconRect = new Rect(12f, y + 6, 24f, 24f);
GUI.DrawTexture(iconRect, Textures.TextureButtonRandom);
@@ -214,6 +214,12 @@ public float DrawSelectedEquipment(float y, float width, int index, CustomizedEq
string subtitleText = equipment.Gender.Value.GetLabel().CapitalizeFirst();
Widgets.Label(subtitleRect, subtitleText.Truncate(subtitleRect.width - 48));
}
+ else if (equipment.OverseenChance != null) {
+ Text.Font = GameFont.Tiny;
+ string subtitleText = "EdB.PC.Equipment.SelectedEquipment.OverseenChanceLabel"
+ .Translate("StartOverseenChance".Translate(), string.Format("{0:F0}", equipment.OverseenChance.Value * 100f));
+ Widgets.Label(subtitleRect, subtitleText.Truncate(subtitleRect.width - 48));
+ }
else {
labelRect = new Rect(labelLeftMargin, y, rowRect.width - labelLeftMargin, subtitleRect.yMax - labelRect.y);
Text.Anchor = TextAnchor.MiddleLeft;
diff --git a/Source/PanelHealth.cs b/Source/PanelHealth.cs
index 4a0c5cf..e8320ef 100644
--- a/Source/PanelHealth.cs
+++ b/Source/PanelHealth.cs
@@ -14,12 +14,10 @@ public class PanelHealth : PanelModule {
protected static readonly string HediffTypeImplant = "HediffTypeImplant";
public delegate void AddInjuryHandler(Injury injury);
- public delegate void AddImplantHandler(Implant implant);
public delegate void RemoveHediffsHandler(IEnumerable hediffs);
public delegate void UpdateImplantsHandler(IEnumerable implants);
public event AddInjuryHandler InjuryAdded;
- public event AddImplantHandler ImplantAdded;
public event RemoveHediffsHandler HediffsRemoved;
public event UpdateImplantsHandler ImplantsUpdated;
@@ -201,7 +199,6 @@ public void DrawAddButton(float y, float width) {
OptionsHealth healthOptions = ProviderHealth.GetOptions(customizedPawn);
string selectedHediffType = this.selectedHediffType;
- RecipeDef selectedRecipe = null;
InjuryOption selectedInjury = null;
BodyPartRecord selectedBodyPart = null;
bool bodyPartSelectionRequired = true;
@@ -304,9 +301,6 @@ public void DrawAddButton(float y, float width) {
addInjuryAction();
}
}
- else if (selectedHediffType == HediffTypeImplant) {
- ImplantAdded(new Implant(selectedBodyPart, selectedRecipe));
- }
}
};
@@ -315,7 +309,6 @@ public void DrawAddButton(float y, float width) {
CancelButtonLabel = "EdB.PC.Common.Cancel".Translate(),
HeaderLabel = "EdB.PC.Dialog.Injury.Header".Translate(),
NameFunc = (InjuryOption option) => {
- //return option.HediffDef.defName;
return option.Label;
},
DescriptionFunc = (InjuryOption option) => {
@@ -415,15 +408,6 @@ public void DrawAddButton(float y, float width) {
}
}
- protected void ApplyImplantsToPawn(CustomizedPawn pawn, List implants) {
- //Logger.Debug("Updated implants");
- //foreach (var i in implants) {
- // Logger.Debug(" " + i.recipe.LabelCap + ", " + i.PartName + (i.ReplacesPart ? ", replaces part" : ""));
- //}
- // TODO
- //pawn.UpdateImplants(implants);
- }
-
protected void AddInjuryToPawn(InjuryOption option, InjurySeverity severity, BodyPartRecord bodyPart) {
Injury injury = new Injury();
injury.BodyPartRecord = bodyPart;
diff --git a/Source/PanelRelationshipsOther.cs b/Source/PanelRelationshipsOther.cs
index 5e6d90e..4a81e1c 100644
--- a/Source/PanelRelationshipsOther.cs
+++ b/Source/PanelRelationshipsOther.cs
@@ -77,7 +77,7 @@ protected override void DrawPanelContent() {
try {
foreach (CustomizedRelationship relationship in State.Customizations.Relationships) {
// Don't show relationships between two hidden pawns
- if (relationship.Source.Type != CustomizedPawnType.Hidden && relationship.Target.Type != CustomizedPawnType.Hidden) {
+ if (relationship.Source.Type != CustomizedPawnType.Hidden || relationship.Target.Type != CustomizedPawnType.Hidden) {
cursor = DrawRelationship(cursor, relationship);
}
}
diff --git a/Source/PawnCustomizer.cs b/Source/PawnCustomizer.cs
index 5d3c05e..ade0087 100644
--- a/Source/PawnCustomizer.cs
+++ b/Source/PawnCustomizer.cs
@@ -447,17 +447,29 @@ public void ApplyImplantToPawn(Pawn pawn, Implant implant) {
if (pawn == null || implant == null) {
return;
}
- Logger.Debug("Adding implant to pawn, recipe = " + implant.Recipe?.defName + ", hediff = " + implant.HediffDef?.defName);
+ //Logger.Debug("Adding implant to pawn, recipe = " + implant.Recipe?.defName + ", hediff = " + implant.HediffDef?.defName + ", bodyPart = " + implant.BodyPartRecord?.def?.defName);
if (implant.BodyPartRecord == null) {
Logger.Warning("Could not add implant to pawn because no BodyPartRecord is defined");
}
if (implant.Recipe != null) {
implant.Hediff = HediffMaker.MakeHediff(implant.Recipe.addsHediff, pawn, implant.BodyPartRecord);
- pawn.health.AddHediff(implant.Hediff, implant.BodyPartRecord, new DamageInfo?());
+ if (implant.Severity > 0) {
+ implant.Hediff.Severity = implant.Severity;
+ }
+ pawn.health.AddHediff(implant.Hediff, implant.BodyPartRecord);
}
else if (implant.HediffDef != null) {
- implant.Hediff = HediffMaker.MakeHediff(implant.HediffDef, pawn, implant.BodyPartRecord);
- pawn.health.AddHediff(implant.Hediff, implant.BodyPartRecord, new DamageInfo?());
+ var hediff = HediffMaker.MakeHediff(implant.HediffDef, pawn, implant.BodyPartRecord);
+ if (implant.Severity > 0) {
+ if (hediff is Hediff_Level level) {
+ level.level = (int)implant.Severity;
+ }
+ else {
+ hediff.Severity = implant.Severity;
+ }
+ }
+ pawn.health.AddHediff(hediff, implant.BodyPartRecord);
+ implant.Hediff = hediff;
}
else {
Logger.Warning("Could not add implant to pawn because no RecipeDef or HediffDef is defined");
@@ -494,7 +506,7 @@ public void ApplyInjuryToPawn(Pawn pawn, Injury injury) {
injury.Hediff = hediff;
}
else if (injury.Option.HediffDef == HediffDefOf.PsychicAmplifier) {
- Logger.Debug("Adding Psylink with level " + injury.Severity);
+ //Logger.Debug("Adding Psylink with level " + injury.Severity);
Hediff_Psylink mainPsylinkSource = pawn.GetMainPsylinkSource();
HashSet abilitiesBefore = new HashSet(pawn.abilities.AllAbilitiesForReading.Select(a => a.def));
if (mainPsylinkSource == null) {
@@ -518,7 +530,7 @@ public void ApplyInjuryToPawn(Pawn pawn, Injury injury) {
}
}
else {
- Hediff hediff = HediffMaker.MakeHediff(injury.Option.HediffDef, pawn, injury.bodyPartRecord);
+ Hediff hediff = HediffMaker.MakeHediff(injury.Option.HediffDef, pawn, injury.BodyPartRecord);
hediff.Severity = injury.Severity;
if (hediff is Hediff_ChemicalDependency chemicalDependency) {
chemicalDependency.chemical = injury.Chemical;
diff --git a/Source/PawnLoaderV3.cs b/Source/PawnLoaderV3.cs
index b4d7a47..ea6c584 100644
--- a/Source/PawnLoaderV3.cs
+++ b/Source/PawnLoaderV3.cs
@@ -350,22 +350,20 @@ public PawnLoaderResult ConvertSaveRecordToCustomizedPawn(SaveRecordPawnV3 recor
result.AddWarning("Could not add the implant because it could not find the recipe definition \"" + implantRecord.recipe + "\"");
continue;
}
- bool found = false;
- foreach (var p in recipeDef.appliedOnFixedBodyParts) {
- if (p.defName.Equals(bodyPart.def.defName)) {
- found = true;
- break;
- }
+ ImplantOption implantOption = healthOptions.FindImplantOptionThatAddsRecipeDefToBodyPart(recipeDef, bodyPart?.def);
+ if (implantOption != null) {
+ Implant implant = new Implant() {
+ Option = implantOption,
+ Recipe = recipeDef,
+ BodyPartRecord = bodyPart,
+ HediffDef = recipeDef.addsHediff,
+ };
+ implant.label = implant.Label;
+ customizations.Implants.Add(implant);
}
- if (!found) {
- result.AddWarning("Could not apply the saved implant recipe \"" + implantRecord.recipe + "\" to the body part \"" + bodyPart.def.defName + "\". Recipe does not support that part.");
- continue;
+ else {
+ result.AddWarning("Could not add implant to pawn because no matching option was found for specified RecipeDef {" + implantRecord.recipe + "} and BodyPartDef {" + bodyPart?.def?.defName + "}");
}
- Implant implant = new Implant();
- implant.BodyPartRecord = bodyPart;
- implant.Recipe = recipeDef;
- implant.label = implant.Label;
- customizations.Implants.Add(implant);
}
}
diff --git a/Source/PawnLoaderV5.cs b/Source/PawnLoaderV5.cs
index 00fab32..828c237 100644
--- a/Source/PawnLoaderV5.cs
+++ b/Source/PawnLoaderV5.cs
@@ -616,44 +616,39 @@ public PawnLoaderResult ConvertSaveRecordToCustomizedPawn(SaveRecordPawnV5 recor
result.AddWarning("Could not add the implant because it could not find the recipe definition \"" + implantRecord.recipe + "\"");
continue;
}
- bool found = false;
- foreach (var p in recipeDef.appliedOnFixedBodyParts) {
- if (p.defName.Equals(bodyPart.def.defName)) {
- found = true;
- break;
- }
+ ImplantOption implantOption = healthOptions.FindImplantOptionThatAddsRecipeDefToBodyPart(recipeDef, bodyPart?.def);
+ if (implantOption != null) {
+ Implant implant = new Implant() {
+ Option = implantOption,
+ BodyPartRecord = bodyPart,
+ Recipe = recipeDef,
+ HediffDef = recipeDef.addsHediff,
+ };
+ // TODO: This looks weird; something to do with caching the label. Should rework it.
+ implant.label = implant.Label;
+ customizations.Implants.Add(implant);
+ Logger.Debug("Added implant customizations " + recipeDef?.defName);
}
- if (!found) {
- if (recipeDef.appliedOnFixedBodyPartGroups != null) {
- foreach (var g in recipeDef.appliedOnFixedBodyPartGroups) {
- if (bodyPart.IsInGroup(g)) {
- found = true;
- break;
- }
- }
- }
- if (!found) {
- result.AddWarning("Could not apply the saved implant recipe \"" + implantRecord.recipe + "\" to the body part \"" + bodyPart.def.defName + "\". Recipe does not support that part.");
- continue;
- }
+ else {
+ result.AddWarning("Could not add implant to pawn because no matching option was found for specified RecipeDef {" + implantRecord.recipe + "} and BodyPartDef {" + bodyPart?.def?.defName + "}");
}
- Implant implant = new Implant() {
- BodyPartRecord = bodyPart,
- Recipe = recipeDef
- };
- // TODO: This looks weird; something to do with caching the label. Should rework it.
- implant.label = implant.Label;
- customizations.Implants.Add(implant);
- Logger.Debug("Added implant customizations " + recipeDef?.defName);
}
else if (implantRecord.hediffDef != null) {
HediffDef hediffDef = DefDatabase.GetNamedSilentFail(implantRecord.hediffDef);
if (hediffDef != null) {
- Implant implant = new Implant();
- implant.BodyPartRecord = bodyPart;
- implant.label = implant.Label;
- implant.HediffDef = hediffDef;
- customizations.Implants.Add(implant);
+ ImplantOption implantOption = healthOptions.FindImplantOptionThatAddsHediffDefToBodyPart(hediffDef, bodyPart?.def);
+ if (implantOption == null) {
+ result.AddWarning("Could not add implant to pawn because no matching option was found for specified HediffDef {" + implantRecord.hediffDef + "} and BodyPartDef {" + bodyPart?.def?.defName + "}");
+ }
+ else {
+ Implant implant = new Implant();
+ implant.Option = implantOption;
+ implant.BodyPartRecord = bodyPart;
+ implant.label = implant.Label;
+ implant.HediffDef = hediffDef;
+ implant.Severity = implantRecord.severity;
+ customizations.Implants.Add(implant);
+ }
}
else {
result.AddWarning("Could not add implant to pawn because the specified HediffDef {" + implantRecord.hediffDef + "} for the implant was not found");
diff --git a/Source/PresetLoaderV5.cs b/Source/PresetLoaderV5.cs
index 672aedf..e9caf62 100644
--- a/Source/PresetLoaderV5.cs
+++ b/Source/PresetLoaderV5.cs
@@ -230,9 +230,9 @@ protected void LoadParentChildGroups(SaveRecordPresetV5 preset, PresetLoaderResu
}
}
}
- if (group.Parents.Count > 0 && group.Children.Count > 0) {
+
+ if (ValidateParentChildGroup(group)) {
customizations.ParentChildGroups.Add(group);
- Logger.Debug("Loaded parent child group");
}
}
ManagerRelationships.ReassignHiddenPawnIndices();
@@ -243,6 +243,21 @@ protected void LoadParentChildGroups(SaveRecordPresetV5 preset, PresetLoaderResu
}
}
+ protected bool ValidateParentChildGroup(ParentChildGroup group) {
+ if (group == null) {
+ return false;
+ }
+ int parentCount = group.Parents.CountAllowNull();
+ int childCount = group.Children.CountAllowNull();
+ if (parentCount == 0 && childCount < 2) {
+ return false;
+ }
+ if (childCount == 0) {
+ return false;
+ }
+ return true;
+ }
+
protected Dictionary ResolveIdeoMap(SaveRecordPresetV5 preset) {
Dictionary ideoMap = new Dictionary();
Dictionary uniqueSaveRecordsToResolve = new Dictionary();
diff --git a/Source/ProviderHealthOptions.cs b/Source/ProviderHealthOptions.cs
index 4e67d7e..46a920c 100644
--- a/Source/ProviderHealthOptions.cs
+++ b/Source/ProviderHealthOptions.cs
@@ -3,10 +3,12 @@
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
+using System.Security.Cryptography;
using System.Text;
using UnityEngine;
using Verse;
using Verse.Sound;
+using static HarmonyLib.Code;
namespace EdB.PrepareCarefully {
public class ProviderHealthOptions {
@@ -82,12 +84,16 @@ protected void InitializeImplantRecipes(OptionsHealth options, ThingDef pawnThin
if (def.addsHediff != null
&& ((def.appliedOnFixedBodyParts != null && def.appliedOnFixedBodyParts.Count > 0) || (def.appliedOnFixedBodyPartGroups != null && def.appliedOnFixedBodyPartGroups.Count > 0))
&& (def.recipeUsers.NullOrEmpty() || def.recipeUsers.Contains(pawnThingDef))) {
+ //Logger.Debug("Adding implant recipe: " + def.defName);
return true;
}
else {
+ //Logger.Debug("Excluding implant recipe: " + def.defName);
return false;
}
}));
+
+
// Remove duplicates: recipes that apply the same hediff on the same body parts.
HashSet recipeHashes = new HashSet();
@@ -128,6 +134,43 @@ protected void InitializeImplantRecipes(OptionsHealth options, ThingDef pawnThin
}
}
}
+
+ // Add options for thing definitions that have an install implant comp
+ Dictionary implantOptionLookup = new Dictionary();
+ foreach (var def in DefDatabase.AllDefs.Where(d => d.HasComp())) {
+ var useEffectInstallImplant = def.GetCompProperties();
+ var usable = def.GetCompProperties();
+ if (useEffectInstallImplant != null && usable != null) {
+ string hediffDefName = useEffectInstallImplant.hediffDef?.defName;
+ if (hediffDefName == null) {
+ continue;
+ }
+ HediffDef hediffDef = useEffectInstallImplant.hediffDef;
+ // Exclude psychic amplifier because that's added as an injury and requires special handling
+ // to avoid the default behavior that adds a random ability
+ if (hediffDef == HediffDefOf.PsychicAmplifier) {
+ continue;
+ }
+ if (!implantOptionLookup.TryGetValue(hediffDefName, out ImplantOption option)) {
+ option = new ImplantOption() {
+ HediffDef = hediffDef,
+ ThingDef = def,
+ BodyPartDefs = new HashSet(),
+ Dependency = usable.userMustHaveHediff,
+ };
+ if (typeof(Hediff_Level).IsAssignableFrom(hediffDef.hediffClass)) {
+ option.MinSeverity = hediffDef.minSeverity > 0 ? hediffDef.minSeverity : 1;
+ option.MaxSeverity = hediffDef.maxSeverity;
+ Logger.Debug(string.Format("Adding option {0} with severity {1}-{2} from thingDef {3}", hediffDef.defName, option.MinSeverity, option.MaxSeverity, def.defName));
+ }
+ implantOptionLookup.Add(hediffDefName, option);
+ }
+ option.BodyPartDefs.Add(useEffectInstallImplant.bodyPart);
+ }
+ }
+ foreach (var value in implantOptionLookup.Values) {
+ options.AddImplantOption(value);
+ }
}
protected bool InitializeHediffGivenByUseEffect(OptionsHealth options, CompProperties_UseEffectInstallImplant useEffect) {
diff --git a/Source/RelationshipBuilder.cs b/Source/RelationshipBuilder.cs
index dff18db..d93deb0 100644
--- a/Source/RelationshipBuilder.cs
+++ b/Source/RelationshipBuilder.cs
@@ -10,15 +10,13 @@ namespace EdB.PrepareCarefully {
public class RelationshipBuilder {
private List relationships;
private List parentChildGroups;
- FieldInfo directRelationsField = null;
- FieldInfo pawnsWithField = null;
+ private List pawns;
private List compatibilityPool = new List();
- public RelationshipBuilder(List relationships, List parentChildGroups) {
- directRelationsField = typeof(Pawn_RelationsTracker).GetField("directRelations", BindingFlags.Instance | BindingFlags.NonPublic);
- pawnsWithField = typeof(Pawn_RelationsTracker).GetField("pawnsWithDirectRelationsWithMe", BindingFlags.Instance | BindingFlags.NonPublic);
+ public RelationshipBuilder(IEnumerable pawns, List relationships, List parentChildGroups) {
this.relationships = relationships;
this.parentChildGroups = parentChildGroups;
+ this.pawns = pawns.ToList();
int compatibilityPoolSize = Mathf.Max(Mathf.Min(relationships.Count * 6, 12), 50);
this.FillCompatibilityPool(compatibilityPoolSize);
@@ -27,6 +25,9 @@ public RelationshipBuilder(List relationships, List Build() {
// These include all the pawns that have relationships with them.
HashSet relevantPawns = new HashSet();
+ foreach (var pawn in pawns) {
+ relevantPawns.Add(pawn);
+ }
foreach (var rel in relationships) {
relevantPawns.Add(rel.Source);
relevantPawns.Add(rel.Target);
@@ -50,7 +51,7 @@ public List Build() {
}
}
- // Go through each starting pawn and evaluate that any existing relationships need to be remain.
+ // Go through each starting pawn and evaluate that any existing relationships need to remain.
// If not, remove them.
PawnRelationDef parentDef = PawnRelationDefOf.Parent;
foreach (var pawn in relevantPawns) {
@@ -61,10 +62,10 @@ public List Build() {
if (relationCount == 0) {
continue;
}
- Logger.Debug("Checking existing relations for " + pawn.Pawn.LabelCap + ", " + relationCount);
+ Logger.Debug("Checking existing relations for " + pawn.Pawn.LabelShort + ", " + relationCount);
for (int i = 0; i < relationCount; i++) {
var r = pawn.Pawn.relations.DirectRelations[i];
- Logger.Debug(string.Format(" [{0}]: relationship {1} between {2} and {3}", i, r.def.defName, pawn.Pawn.LabelShortCap, r.otherPawn.LabelShortCap));
+ Logger.Debug(string.Format(" [{0}]: relationship {1} between {2} and {3}", i, r.def.defName, pawn.Pawn.LabelShort, r.otherPawn.LabelShort));
}
var validity = new List(Enumerable.Range(0, relationCount).Select(i => false));
foreach (var group in parentChildGroups) {
@@ -74,7 +75,7 @@ public List Build() {
return r.def == parentDef && r.otherPawn == parent.Pawn && child.Pawn == pawn.Pawn;
});
if (index != -1) {
- Logger.Debug(string.Format(" Found direct parent relation between child {0} and parent {1} at index: {2}", pawn.Pawn.LabelShortCap, parent.Pawn.LabelShortCap, index));
+ Logger.Debug(string.Format(" Found direct parent relation between child {0} and parent {1} at index: {2}", pawn.Pawn.LabelShort, parent.Pawn.LabelShort, index));
validity[index] = true;
}
}
@@ -87,20 +88,21 @@ public List Build() {
|| (pawn == relationship.Source && r.otherPawn == relationship.Target.Pawn));
});
if (index != -1) {
- Logger.Debug(string.Format(" Found direct relation {0} between pawn {1} and target {2} at index: {3}", relationship.Def.defName, pawn.Pawn.LabelShortCap, relationship.Source.Pawn.LabelShortCap, index));
+ Logger.Debug(string.Format(" Found direct relation {0} between pawn {1} and target {2} at index: {3}", relationship.Def.defName, pawn.Pawn.LabelShort, relationship.Source.Pawn.LabelShort, index));
validity[index] = true;
}
}
- Logger.Debug(" " + string.Join(", ", validity.Select(v => v ? "1" : "0")));
+ Logger.Debug(" Relationship validity: [" + string.Join(", ", validity.Select(v => v ? "valid" : "invalid")) + "]");
List relationsToRemove = new List();
for (int i=0; i.GetNamedSilentFail(def.defName);
diff --git a/Source/Style.cs b/Source/Style.cs
index 0550d72..8ae62e7 100644
--- a/Source/Style.cs
+++ b/Source/Style.cs
@@ -26,6 +26,8 @@ public static class Style {
public static Color ColorTabViewBackground = new Color(42f / 255f, 43f / 255f, 44f / 255f);
public static Color ColorWindowBackground = new Color(21f / 255f, 25f / 255f, 29f / 255f);
+ public static Color ColorCheckmark = new Color(38f / 255f, 217f / 255f, 38f / 255f);
+ public static Color ColorCheckmarkForcedSelection = ColorCheckmark * 0.8f;
public static readonly float DialogHeaderHeight = 36;
public static readonly Vector2 DialogMargin = new Vector2(10, 18);
diff --git a/Source/Textures.cs b/Source/Textures.cs
index 56e324a..d5d33eb 100644
--- a/Source/Textures.cs
+++ b/Source/Textures.cs
@@ -66,6 +66,8 @@ public static class Textures {
public static Texture2D TextureIconWarning;
public static Texture2D TextureFavoriteColor;
public static Texture2D TextureIdeoColor;
+ public static Texture2D TextureCheckmark;
+ public static Texture2D TextureCheckmarkForcedSelection;
public static Texture2D TextureWhite {
get {
@@ -161,6 +163,9 @@ private static void LoadTextures() {
TextureFavoriteColor = ContentFinder.Get("UI/Icons/ColorSelector/ColorFavourite", true);
TextureIdeoColor = ContentFinder.Get("UI/Icons/ColorSelector/ColorIdeology", true);
+ TextureCheckmark = ContentFinder.Get("EdB/PrepareCarefully/Checkmark", true);
+ TextureCheckmarkForcedSelection = ContentFinder.Get("EdB/PrepareCarefully/CheckmarkForcedSelection", true);
+
loaded = true;
}
}
diff --git a/Source/UtilityEquipmentSpawnType.cs b/Source/UtilityEquipmentSpawnType.cs
index 81f549b..bdb54d4 100644
--- a/Source/UtilityEquipmentSpawnType.cs
+++ b/Source/UtilityEquipmentSpawnType.cs
@@ -20,6 +20,9 @@ public static string LabelForSpawnTypeHeader(EquipmentSpawnType spawnType) {
else if (spawnType == EquipmentSpawnType.Possession) {
return "EdB.PC.Equipment.SelectedEquipment.SpawnType.Possession".Translate();
}
+ else if (spawnType == EquipmentSpawnType.Mech) {
+ return "EdB.PC.Equipment.SelectedEquipment.SpawnType.Mech".Translate();
+ }
else {
return "";
}
diff --git a/Source/Version5/SaveRecordImplantV5.cs b/Source/Version5/SaveRecordImplantV5.cs
index 50035ec..cbf4014 100644
--- a/Source/Version5/SaveRecordImplantV5.cs
+++ b/Source/Version5/SaveRecordImplantV5.cs
@@ -11,6 +11,7 @@ public class SaveRecordImplantV5 : IExposable {
public int? bodyPartIndex = null;
public string recipe = null;
public string hediffDef = null;
+ public float severity = 0f;
public SaveRecordImplantV5() {
}
@@ -19,6 +20,7 @@ public SaveRecordImplantV5(Implant option) {
this.bodyPart = option.BodyPartRecord.def.defName;
this.recipe = option.Recipe != null ? option.Recipe.defName : null;
this.hediffDef = option?.Hediff?.def?.defName;
+ this.severity = option?.Severity ?? 0f;
}
public void ExposeData() {
@@ -26,6 +28,7 @@ public void ExposeData() {
Scribe_Values.Look(ref this.bodyPartIndex, "bodyPartIndex", null, false);
Scribe_Values.Look(ref recipe, "recipe", null, false);
Scribe_Values.Look(ref hediffDef, "hediff", null, false);
+ Scribe_Values.Look(ref severity, "severity", 0f, false);
}
}
}