diff --git a/EdBPrepareCarefully.csproj b/EdBPrepareCarefully.csproj index ab9ccd0..9bbc1c9 100644 --- a/EdBPrepareCarefully.csproj +++ b/EdBPrepareCarefully.csproj @@ -64,6 +64,7 @@ + @@ -145,6 +146,7 @@ + diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs index bc6abb2..d9cae45 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.11")] +[assembly: AssemblyFileVersion("1.5.12")] diff --git a/Resources/About/About.xml b/Resources/About/About.xml index b55159a..9c6a9f6 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.11] +[Version 1.5.12]
  • net.pardeike.rimworld.mod.harmony
  • diff --git a/Resources/About/Manifest.xml b/Resources/About/Manifest.xml index 1e2058f..5d75442 100644 --- a/Resources/About/Manifest.xml +++ b/Resources/About/Manifest.xml @@ -1,7 +1,7 @@ EdB.PrepareCarefully - 1.5.11 + 1.5.12 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 eb37680..0710a67 100644 --- a/Resources/CHANGELOG.txt +++ b/Resources/CHANGELOG.txt @@ -1,3 +1,12 @@ + _____________________________________________________________________________ + + Version 1.5.12 + _____________________________________________________________________________ + + - Added support for the additional passions in Vanilla Skills Expanded + - Bug fixes: + - Fixed problems with temporary pawns in the Relationships tab + _____________________________________________________________________________ Version 1.5.11 diff --git a/Source/ControllerTabViewPawns.cs b/Source/ControllerTabViewPawns.cs index ee4a0ee..09849e8 100644 --- a/Source/ControllerTabViewPawns.cs +++ b/Source/ControllerTabViewPawns.cs @@ -15,6 +15,7 @@ public class ControllerTabViewPawns { public PawnCustomizer Customizer { get; set; } public ManagerPawns PawnManager { get; set; } public ManagerRelationships RelationshipManager { get; set; } + public ProviderPassions ProviderPassions { get; set; } protected Dictionary PawnLayerOptionUpdateHandlers { get; set; } = new Dictionary(); protected Dictionary PawnLayerColorUpdateHandlers { get; set; } = new Dictionary(); @@ -251,14 +252,11 @@ public void AdjustSkillPassion(SkillDef skill, int direction) { } Passion currentPassion = record.passion; Passion nextPassion = currentPassion; - if (currentPassion == Passion.None) { - nextPassion = direction > 0 ? Passion.Minor : Passion.Major; + if (direction > 0) { + nextPassion = ProviderPassions.NextPassionValue(currentPassion); } - else if (currentPassion == Passion.Minor) { - nextPassion = direction > 0 ? Passion.Major : Passion.None; - } - else if (currentPassion == Passion.Major) { - nextPassion = direction > 0 ? Passion.None : Passion.Minor; + else { + nextPassion = ProviderPassions.PreviousPassionValue(currentPassion); } PawnManager.UpdatePawnSkillPassion(customizedPawn, skill, nextPassion); } diff --git a/Source/ExtensionsPawnRelationDef.cs b/Source/ExtensionsPawnRelationDef.cs new file mode 100644 index 0000000..1a9e76d --- /dev/null +++ b/Source/ExtensionsPawnRelationDef.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using RimWorld; +using Verse; + +namespace EdB.PrepareCarefully { + public static class ExtensionsPawnRelationDef { + + public static string GetGenderSpecificLabelCap(this PawnRelationDef relationDef, CustomizedPawn customizedPawn) { + Pawn pawn = customizedPawn?.Pawn; + if (pawn != null) { + return relationDef.GetGenderSpecificLabelCap(pawn); + } + else if (customizedPawn.TemporaryPawn != null && customizedPawn.TemporaryPawn.Gender == Gender.Female && !relationDef.labelFemale.NullOrEmpty()) { + return relationDef.labelFemale.CapitalizeFirst(); + } + else { + return relationDef.label.CapitalizeFirst(); + } + } + } +} diff --git a/Source/ManagerRelationships.cs b/Source/ManagerRelationships.cs index 0a74dd9..d599a80 100644 --- a/Source/ManagerRelationships.cs +++ b/Source/ManagerRelationships.cs @@ -51,13 +51,13 @@ public void InitializeWithPawns(IEnumerable customPawns) { InitializeHiddenPawns(customPawns); State.Customizations.ParentChildGroups = InitializeParentChildGroupsForStartingPawns(customPawns); InitializeRelationshipsForStartingPawns(customPawns); - // Add a male and a female pawn to the new hidden pawn list. - temporaryPawns.Add(CreateNewTemporaryPawn(Gender.Female)); - temporaryPawns.Add(CreateNewTemporaryPawn(Gender.Male)); // Assign indices to hidden pawns (indices are used to name pawns, i.e. "Unknown 1" and "Unknown 2"). // We do this here (and not when we initially created the hidden pawns) so that the initial indices will // start at 1 and count up from there as they are displayed from left to right in the UI. ReassignHiddenPawnIndices(); + // Add a male and a female pawn to the new temporary pawn list. + temporaryPawns.Add(CreateNewTemporaryPawn(Gender.Female)); + temporaryPawns.Add(CreateNewTemporaryPawn(Gender.Male)); } // If there are any world pawns that our starting pawns have a relationship with, then store @@ -261,8 +261,33 @@ private List SortAndDedupeParentChildGroups(IEnumerable { - return def.GetGenderSpecificLabelCap(sourceParentChildPawn.Pawn); + return def.GetGenderSpecificLabelCap(sourceParentChildPawn); }, SelectedFunc = (PawnRelationDef def) => { return def == selectedRelationship; @@ -373,7 +373,7 @@ protected void ShowAddRelationshipDialogs() { return def; }).ToList(); relationDefs.Sort((PawnRelationDef a, PawnRelationDef b) => { - return a.GetGenderSpecificLabelCap(sourceParentChildPawn.Pawn).CompareTo(b.GetGenderSpecificLabelCap(sourceParentChildPawn.Pawn)); + return a.GetGenderSpecificLabelCap(sourceParentChildPawn).CompareTo(b.GetGenderSpecificLabelCap(sourceParentChildPawn)); }); relationshipDialog.Options = relationDefs; Find.WindowStack.Add(relationshipDialog); diff --git a/Source/PanelRelationshipsParentChild.cs b/Source/PanelRelationshipsParentChild.cs index a6a27c5..9ddf31f 100644 --- a/Source/PanelRelationshipsParentChild.cs +++ b/Source/PanelRelationshipsParentChild.cs @@ -307,7 +307,6 @@ protected string GetPawnShortName(CustomizedPawn customizedPawn) { } return pawn.LabelShortCap; } - } protected string GetTooltipText(CustomizedPawn pawn) { @@ -352,7 +351,7 @@ protected void ShowParentDialogForGroup(ParentChildGroup group, CustomizedPawn s } }); rowGroups.Add(new WidgetTable.RowGroup("" + "EdB.PC.AddParentChild.Header.SelectWorldPawn".Translate() + "", - RelationshipManager.AvailableWorldPawns)); + RelationshipManager.AvailableWorldPawns.Concat(sortedHiddenPawns))); WidgetTable.RowGroup newPawnGroup = new WidgetTable.RowGroup("" + "EdB.PC.AddParentChild.Header.CreateTemporaryPawn".Translate() + "", RelationshipManager.TemporaryPawns); rowGroups.Add(newPawnGroup); var pawnDialog = new DialogSelectParentChildPawn() { diff --git a/Source/PanelSkills.cs b/Source/PanelSkills.cs index 6bc82ca..ec145a9 100644 --- a/Source/PanelSkills.cs +++ b/Source/PanelSkills.cs @@ -26,6 +26,7 @@ public class PanelSkills : PanelBase { protected WidgetScrollViewVertical scrollView = new WidgetScrollViewVertical(); public ModState State { get; set; } public ViewState ViewState { get; set; } + public ProviderPassions ProviderPassions { get; set; } public PanelSkills() { } @@ -219,19 +220,7 @@ public Texture2D GetPassionTextureForSkill(SkillRecord skillRecord) { if (skillRecord == null) { return null; } - Passion passion = skillRecord.passion; - if (passion == Passion.Minor) { - return Textures.TexturePassionMinor; - } - else if (passion == Passion.Major) { - return Textures.TexturePassionMajor; - } - else if (passion == Passion.None) { - return Textures.TexturePassionNone; - } - else { - return null; - } + return ProviderPassions.TextureForPassion(skillRecord.passion); } public static void FillableBar(Rect rect, float fillPercent, Texture2D fillTex) { diff --git a/Source/PawnLoaderV5.cs b/Source/PawnLoaderV5.cs index 85ccd3a..557c87b 100644 --- a/Source/PawnLoaderV5.cs +++ b/Source/PawnLoaderV5.cs @@ -11,6 +11,7 @@ namespace EdB.PrepareCarefully { public class PawnLoaderV5 { public ProviderHealthOptions ProviderHealthOptions { get; set; } + public ProviderPassions ProviderPassions { get; set; } // Maintain lists of definitions that were replaced in newer versions of the game. public Dictionary thingDefReplacements = new Dictionary(); @@ -534,12 +535,13 @@ public PawnLoaderResult ConvertSaveRecordToCustomizedPawn(SaveRecordPawnV5 recor result.AddWarning("Could not load skill definition \"" + skill.name + "\" from saved preset"); continue; } + Passion passion = ProviderPassions.MapFromString(skill.passion); customizations.Skills.Add(new CustomizationsSkill() { SkillDef = def, Level = skill.value, OriginalLevel = skill.value, - Passion = skill.passion, - OriginalPassion = skill.passion, + Passion = passion, + OriginalPassion = passion, } ); } diff --git a/Source/PawnSaver.cs b/Source/PawnSaver.cs index 66ec09e..f780ffb 100644 --- a/Source/PawnSaver.cs +++ b/Source/PawnSaver.cs @@ -8,6 +8,7 @@ namespace EdB.PrepareCarefully { public class PawnSaver { public ProviderHealthOptions ProviderHealthOptions { get; set; } + public ProviderPassions ProviderPassions { get; set; } public void SaveToFile(CustomizedPawn customizedPawn, string colonistName) { if (customizedPawn?.Customizations == null) { @@ -233,7 +234,7 @@ public void ConvertSkills(SaveRecordPawnV5 result, CustomizationsPawn customizat result.skills.Add(new SaveRecordSkillV4() { name = skill.SkillDef?.defName, value = skill.Level, - passion = skill.Passion + passion = ProviderPassions.MapToString(skill.Passion), }); } } diff --git a/Source/ProviderPassions.cs b/Source/ProviderPassions.cs new file mode 100644 index 0000000..8a26308 --- /dev/null +++ b/Source/ProviderPassions.cs @@ -0,0 +1,166 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using RimWorld; +using UnityEngine; +using Verse; + +namespace EdB.PrepareCarefully { + public class ProviderPassions { + public Type PassionManagerType { get; set; } + public List Icons { get; set; } = new List(); + public List PassionDefs { get; set; } = new List(); + public List NextValues { get; set; } = new List() { 1, 2, 0 }; + public List PreviousValues { get; set; } = new List() { 2, 0, 1 }; + public int PassionCount { get; set; } = 3; + public void PostConstruct() { + InitializeExtendedPassions(); + } + public bool UsingExtendedPassions { + get { + return PassionManagerType != null; + } + } + public void InitializeExtendedPassions() { + //Logger.Debug("InitializeExtendedPassions()"); + PassionManagerType = ReflectionUtil.TypeByName("VSE.Passions.PassionManager"); + if (PassionManagerType == null) { + //Logger.Debug(" Didn't find VSE.Passions.PassionManager class"); + return; + } + //Logger.Debug(" Found VFE PassionManager class"); + Array passionDefArray = ReflectionUtil.GetStaticFieldValue(PassionManagerType, "Passions"); + if (passionDefArray == null) { + Logger.Debug(" Didn't find PassionManager.Passions array"); + return; + } + //Logger.Debug(" Found VFE PassionManager.Passions array with " + passionDefArray.Length + " items"); + PassionCount = passionDefArray.Length; + for (int i = 0; i < PassionCount; i++) { + Texture2D icon = Textures.TexturePassionNone; + Def passionDef = passionDefArray.GetValue(i) as Def; + if (passionDef != null) { + if (passionDef.defName == "None") { + icon = Textures.TexturePassionNone; + } + else { + icon = ReflectionUtil.GetPropertyValue(passionDef, "Icon"); + } + if (icon != null) { + //Logger.Debug(" Found icon for passion " + i + ", " + passionDef.defName + ": " + (icon?.name ?? "no name")); + } + else { + //Logger.Debug(" Did not find icon for passion " + i + ", " + passionDef.defName); + } + } + else { + //Logger.Debug(" Did not find passion def for index " + i); + } + PassionDefs.Add(passionDef); + Icons.Add(icon); + } + + if (PassionCount == 6 + && PassionDefs[0]?.defName == "None" + && PassionDefs[1]?.defName == "Minor" + && PassionDefs[2]?.defName == "Major" + && PassionDefs[3]?.defName == "VSE_Apathy" + && PassionDefs[4]?.defName == "VSE_Natural" + && PassionDefs[5]?.defName == "VSE_Critical") { + NextValues = new List { + 1, 2, 5, 0, 3, 4 + }; + PreviousValues = new List { + 3, 0, 1, 4, 5, 2 + }; + } + else { + NextValues.Clear(); + for (int i=0; i= 0 && value < Icons.Count) { + return Icons[value]; + } + } + return Textures.TexturePassionNone; + } + + public Passion NextPassionValue(Passion passion) { + int value = (int)passion; + if (value < 0 || value >= NextValues.Count) { + return Passion.None; + } + return (Passion)NextValues[value]; + } + + public Passion PreviousPassionValue(Passion passion) { + int value = (int)passion; + if (value < 0 || value >= PreviousValues.Count) { + return Passion.None; + } + return (Passion)PreviousValues[value]; + } + + public Passion MapFromString(string value) { + if (UsingExtendedPassions && PassionDefs.CountAllowNull() > 0) { + int index = PassionDefs.FindIndex(d => d.defName == value); + if (index != -1) { + return (Passion)index; + } + else { + return Passion.None; + } + } + else { + Passion? passion = null; + try { + passion = (Passion)Enum.Parse(typeof(Passion), value); + } + catch (Exception) { } + if (passion.HasValue) { + return passion.Value; + } + if (value == "VSE_Critical" || value == "VSE_Natural") { + return Passion.Major; + } + return Passion.None; + } + } + + public string MapToString(Passion passion) { + int index = (int)passion; + if (UsingExtendedPassions && PassionDefs.CountAllowNull() > index) { + return PassionDefs[index].defName; + } + else { + return passion.ToString(); + } + } + } +} diff --git a/Source/ReflectionUtil.cs b/Source/ReflectionUtil.cs index 9c73b13..a982b8a 100644 --- a/Source/ReflectionUtil.cs +++ b/Source/ReflectionUtil.cs @@ -190,6 +190,29 @@ public static T GetFieldValue(object target, string name) { return default(T); } + public static T GetStaticFieldValue(Type target, string name) { + if (target == null) { + Logger.Warning("Could not get value from static field {" + name + "} using reflection because the target type was null"); + return default(T); + } + FieldInfo field = Field(target, name); + if (field == null) { + Logger.Warning("Could not get value from static field {" + name + "} using reflection because we could not find the field on the target type"); + return default(T); + } + object o = field.GetValue(null); + if (o == null) { + return default(T); + } + if (typeof(T).IsAssignableFrom(o.GetType())) { + return (T)field.GetValue(target); + } + else { + Logger.Warning("Could not cast the value from static field {" + name + "} whose type is {" + o.GetType().FullName + "} to the specified type {" + typeof(T).FullName + "}"); + } + return default(T); + } + public static T GetPropertyValue(object target, string name) { if (target == null) { Logger.Warning("Could not get value from property {" + name + "} using reflection because the target was null"); diff --git a/Source/Version4/SaveRecordSkillV4.cs b/Source/Version4/SaveRecordSkillV4.cs index af5189f..7e74d52 100644 --- a/Source/Version4/SaveRecordSkillV4.cs +++ b/Source/Version4/SaveRecordSkillV4.cs @@ -1,4 +1,4 @@ -using RimWorld; +using RimWorld; using System; using System.Collections.Generic; using System.Linq; @@ -9,12 +9,12 @@ namespace EdB.PrepareCarefully { public class SaveRecordSkillV4 : IExposable { public string name; public int value; - public Passion passion; + public string passion; public void ExposeData() { Scribe_Values.Look(ref this.name, "name", null, true); Scribe_Values.Look(ref this.value, "value", 0, true); - Scribe_Values.Look(ref this.passion, "passion", Passion.None, true); + Scribe_Values.Look(ref this.passion, "passion", "None", true); } } }