diff --git a/EdBPrepareCarefully.csproj b/EdBPrepareCarefully.csproj index e2d1ca8..9bbc1c9 100644 --- a/EdBPrepareCarefully.csproj +++ b/EdBPrepareCarefully.csproj @@ -146,6 +146,7 @@ + diff --git a/Resources/CHANGELOG.txt b/Resources/CHANGELOG.txt index 6761b4e..0710a67 100644 --- a/Resources/CHANGELOG.txt +++ b/Resources/CHANGELOG.txt @@ -3,6 +3,7 @@ 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 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/Mod.cs b/Source/Mod.cs index 399891c..b108a11 100644 --- a/Source/Mod.cs +++ b/Source/Mod.cs @@ -79,6 +79,8 @@ public void Start(Page_ConfigureStartingPawns configureStartingPawnsPage) { }; providerEquipmentTypes.PostConstruction(); var providerPawnKinds = new ProviderPawnKinds(); + var providerPassions = new ProviderPassions(); + providerPassions.PostConstruct(); var ageModifier = new AgeModifier(); @@ -94,7 +96,8 @@ public void Start(Page_ConfigureStartingPawns configureStartingPawnsPage) { ProviderHealthOptions = providerHealthOptions, }; var pawnLoaderV5 = new PawnLoaderV5() { - ProviderHealthOptions = providerHealthOptions + ProviderHealthOptions = providerHealthOptions, + ProviderPassions = providerPassions, }; var pawnLoader = new PawnLoader() { PawnLoaderV3 = pawnLoaderV3, @@ -121,7 +124,8 @@ public void Start(Page_ConfigureStartingPawns configureStartingPawnsPage) { PresetLoaderV5 = presetLoaderV5, }; var pawnSaver = new PawnSaver() { - ProviderHealthOptions = providerHealthOptions + ProviderHealthOptions = providerHealthOptions, + ProviderPassions = providerPassions, }; var presetSaver = new PresetSaver() { PawnSaver = pawnSaver @@ -164,6 +168,7 @@ public void Start(Page_ConfigureStartingPawns configureStartingPawnsPage) { Customizer = pawnCustomizer, PawnManager = pawnManager, RelationshipManager = relationshipManager, + ProviderPassions = providerPassions, }; var controllerRelationships = new ControllerTabViewRelationships() { State = state, @@ -277,7 +282,8 @@ public void Start(Page_ConfigureStartingPawns configureStartingPawnsPage) { }; var skillsPanel = new PanelSkills() { State = state, - ViewState = viewState + ViewState = viewState, + ProviderPassions = providerPassions, }; var incapableOfPanel = new PanelIncapableOf() { State = state, 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); } } }