From 2b7abb0462803ec1cb0f0b18aa13cf7465874ffe Mon Sep 17 00:00:00 2001 From: BuckAMayzing <19292614+BuckAMayzing@users.noreply.github.com> Date: Thu, 25 May 2023 18:17:08 -0400 Subject: [PATCH 1/8] Fixed spell number calculation for spontaneous casters --- ToyBox/classes/Infrastructure/CasterHelpers.cs | 14 ++++++++++++++ .../MonkeyPatchin/Multiclass/LevelUP+Multiclass.cs | 3 +++ 2 files changed, 17 insertions(+) diff --git a/ToyBox/classes/Infrastructure/CasterHelpers.cs b/ToyBox/classes/Infrastructure/CasterHelpers.cs index ca1509b49..75fd6b6e7 100644 --- a/ToyBox/classes/Infrastructure/CasterHelpers.cs +++ b/ToyBox/classes/Infrastructure/CasterHelpers.cs @@ -177,6 +177,7 @@ public static void HandleAddAllSpellsOnPartyEditor(UnitDescriptor unit) { #if true // TODO: the else case of this #if has a patch that fixes the level for spontaneous spell casters learning scrolls but causes the gestalt feature to stop working by causing spells to not show up for spell casting classes like oracle and sorc when you try to select/gestalt them after choosing say a scaled fist monk public static int GetActualSpellsLearnedForClass(UnitDescriptor unit, Spellbook spellbook, int level) { Mod.Trace($"GetActualSpellsLearnedForClass - unit: {unit?.CharacterName} spellbook: {spellbook?.Blueprint.DisplayName} level:{level}"); + // Get all +spells known facts for this spellbook's class so we can ignore them when getting spell counts var spellsToIgnore = unit.Facts.List.SelectMany(x => x.BlueprintComponents.Where(y => y is AddKnownSpell)).Select(z => z as AddKnownSpell) @@ -201,6 +202,19 @@ public static int GetActualSpellsLearned(Spellbook spellbook, int level, List sp.IsTemporary + || sp.CopiedFromScroll + || sp.IsFromMythicSpellList + || sp.SourceItem != null + || sp.SourceItemEquipmentBlueprint != null + || sp.SourceItemUsableBlueprint != null + || sp.IsMysticTheurgeCombinedSpell).Count(); + } + #else public static int GetActualSpellsLearnedForClass(UnitDescriptor unit, Spellbook spellbook, int level) { Mod.Trace($"GetActualSpellsLearnedForClass - unit: {unit?.CharacterName} spellbook: {spellbook?.Blueprint.DisplayName} level:{level}"); diff --git a/ToyBox/classes/MonkeyPatchin/Multiclass/LevelUP+Multiclass.cs b/ToyBox/classes/MonkeyPatchin/Multiclass/LevelUP+Multiclass.cs index 7fe9a7222..8285d7fa3 100644 --- a/ToyBox/classes/MonkeyPatchin/Multiclass/LevelUP+Multiclass.cs +++ b/ToyBox/classes/MonkeyPatchin/Multiclass/LevelUP+Multiclass.cs @@ -200,6 +200,9 @@ public static bool Apply(LevelUpState state, UnitDescriptor unit) { var spellsKnown = spellbook1.Blueprint.SpellsKnown; var expectedCount = spellsKnown.GetCount(casterLevelAfter, index); var actual = CasterHelpers.GetActualSpellsLearnedForClass(unit, spellbook1, index); + if(spellbook1.Blueprint.Spontaneous) { + actual -= CasterHelpers.CountExternallyAddedSpells(spellbook1, index); + } int learnabl = spellbook1.GetSpellsLearnableOfLevel(index).Count(); int spelladd = Math.Max(0, Math.Min(expectedCount - actual, learnabl)); #if DEBUG From fb020bbde2d294b103e910f202d97be2b72f4aff Mon Sep 17 00:00:00 2001 From: BuckAMayzing <19292614+BuckAMayzing@users.noreply.github.com> Date: Thu, 25 May 2023 18:29:54 -0400 Subject: [PATCH 2/8] whitespace --- ToyBox/classes/Infrastructure/CasterHelpers.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/ToyBox/classes/Infrastructure/CasterHelpers.cs b/ToyBox/classes/Infrastructure/CasterHelpers.cs index 75fd6b6e7..34b4c7328 100644 --- a/ToyBox/classes/Infrastructure/CasterHelpers.cs +++ b/ToyBox/classes/Infrastructure/CasterHelpers.cs @@ -177,7 +177,6 @@ public static void HandleAddAllSpellsOnPartyEditor(UnitDescriptor unit) { #if true // TODO: the else case of this #if has a patch that fixes the level for spontaneous spell casters learning scrolls but causes the gestalt feature to stop working by causing spells to not show up for spell casting classes like oracle and sorc when you try to select/gestalt them after choosing say a scaled fist monk public static int GetActualSpellsLearnedForClass(UnitDescriptor unit, Spellbook spellbook, int level) { Mod.Trace($"GetActualSpellsLearnedForClass - unit: {unit?.CharacterName} spellbook: {spellbook?.Blueprint.DisplayName} level:{level}"); - // Get all +spells known facts for this spellbook's class so we can ignore them when getting spell counts var spellsToIgnore = unit.Facts.List.SelectMany(x => x.BlueprintComponents.Where(y => y is AddKnownSpell)).Select(z => z as AddKnownSpell) From 433e036540202ad8bc4e3d866d19e6bac2d68d8a Mon Sep 17 00:00:00 2001 From: BuckAMayzing <19292614+BuckAMayzing@users.noreply.github.com> Date: Thu, 25 May 2023 18:33:52 -0400 Subject: [PATCH 3/8] get rid of the old code --- .../classes/Infrastructure/CasterHelpers.cs | 62 ------------------- 1 file changed, 62 deletions(-) diff --git a/ToyBox/classes/Infrastructure/CasterHelpers.cs b/ToyBox/classes/Infrastructure/CasterHelpers.cs index 34b4c7328..481737187 100644 --- a/ToyBox/classes/Infrastructure/CasterHelpers.cs +++ b/ToyBox/classes/Infrastructure/CasterHelpers.cs @@ -214,68 +214,6 @@ public static int CountExternallyAddedSpells(Spellbook spellbook, int level) { || sp.IsMysticTheurgeCombinedSpell).Count(); } -#else - public static int GetActualSpellsLearnedForClass(UnitDescriptor unit, Spellbook spellbook, int level) { - Mod.Trace($"GetActualSpellsLearnedForClass - unit: {unit?.CharacterName} spellbook: {spellbook?.Blueprint.DisplayName} level:{level}"); - // Get all +spells known facts for this spellbook's class so we can ignore them when getting spell counts - var spellsToIgnore = unit.Facts.List.SelectMany(x => - x.BlueprintComponents.Where(y => y is AddKnownSpell)).Select(z => z as AddKnownSpell) - .Where(x => x.CharacterClass == spellbook.Blueprint.CharacterClass && (x.Archetype == null || unit.Progression.IsArchetype(x.Archetype))).Select(y => y.Spell) - .ToList(); - Spellbook spellbookOfNormalUnit = null; - if (unit.TryGetPartyMemberForLevelUpVersion(out var ch)) { // get the real units spellbook, the levelup version does not contain flags like CopiedFromScroll - if (ch?.Spellbooks?.Count() > 0) - spellbookOfNormalUnit = ch.Spellbooks.First(s => s.Blueprint == spellbook.Blueprint); - } - return GetActualSpellsLearned(spellbook, level, spellsToIgnore, spellbookOfNormalUnit); - } - - /// - /// Calculates the number of spells selected via levelup, excluding spells from items, learned from scrolls and similar. - /// If the spellbook comes from a UnitDescriptor thats part of a levelup, you need to specify spellbookOfNormalUnit as the base units spellbook. - /// (Because levelup logic does not copy any AbilityData flags.) (see GetActualSpellsLearnedForClass as example.) - /// - /// - /// - /// - /// - /// - public static int GetActualSpellsLearned(Spellbook spellbook, int level, List spellsToIgnore, Spellbook spellbookOfNormalUnit = null) { - Mod.Trace($"GetActualSpellsLearned - spellbook: {spellbook?.Blueprint.DisplayName} level:{level}"); - - Func normalSpellbookCondition = x => true; - if (spellbookOfNormalUnit != null) { - var normalSpellsOfLevel = spellbookOfNormalUnit.SureKnownSpells(level); - normalSpellbookCondition = x => { - var sp = normalSpellsOfLevel.First(a => a.Blueprint == x.Blueprint); - if (sp == null) - return true; - return !sp.IsTemporary - && !sp.CopiedFromScroll - && !sp.IsFromMythicSpellList - && sp.SourceItem == null - && sp.SourceItemEquipmentBlueprint == null - && sp.SourceItemUsableBlueprint == null - && !sp.IsMysticTheurgeCombinedSpell; - }; - } - var known = spellbook.SureKnownSpells(level) - .Where(x => !x.IsTemporary - && !x.CopiedFromScroll - && !x.IsFromMythicSpellList - && x.SourceItem == null - && x.SourceItemEquipmentBlueprint == null - && x.SourceItemUsableBlueprint == null - && !x.IsMysticTheurgeCombinedSpell - && !spellsToIgnore.Contains(x.Blueprint) - && normalSpellbookCondition(x)) - .Distinct() - .ToList(); - - return known.Count; - } -#endif - public static IEnumerable MergableClasses(this UnitEntityData unit) { var spellbookCandidates = unit.Spellbooks .Where(sb => sb.IsStandaloneMythic && sb.Blueprint.CharacterClass != null) From 928ad84ce6a04abd3e3c63d515b21f9562eda6b2 Mon Sep 17 00:00:00 2001 From: BuckAMayzing <19292614+BuckAMayzing@users.noreply.github.com> Date: Fri, 26 May 2023 09:01:10 -0400 Subject: [PATCH 4/8] Adjust logic to use real spellbook --- ToyBox/classes/Infrastructure/CasterHelpers.cs | 9 +++++++-- .../MonkeyPatchin/Multiclass/LevelUP+Multiclass.cs | 3 ++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/ToyBox/classes/Infrastructure/CasterHelpers.cs b/ToyBox/classes/Infrastructure/CasterHelpers.cs index 481737187..311f526fd 100644 --- a/ToyBox/classes/Infrastructure/CasterHelpers.cs +++ b/ToyBox/classes/Infrastructure/CasterHelpers.cs @@ -10,6 +10,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Kingmaker.Utility; #if Wrath using Kingmaker.Blueprints.Classes.Selection; using Kingmaker.Blueprints.Classes.Spells; @@ -202,10 +203,14 @@ public static int GetActualSpellsLearned(Spellbook spellbook, int level, List s.Blueprint == spellbook.Blueprint, out var unitSpellbook)) return 0; if(spellbook?.SureKnownSpells(level) == null) return 0; - return spellbook.SureKnownSpells(level).Where(sp => sp.IsTemporary + return unitSpellbook.SureKnownSpells(level).Where(sp => sp.IsTemporary || sp.CopiedFromScroll || sp.IsFromMythicSpellList || sp.SourceItem != null diff --git a/ToyBox/classes/MonkeyPatchin/Multiclass/LevelUP+Multiclass.cs b/ToyBox/classes/MonkeyPatchin/Multiclass/LevelUP+Multiclass.cs index 8285d7fa3..a695d92a5 100644 --- a/ToyBox/classes/MonkeyPatchin/Multiclass/LevelUP+Multiclass.cs +++ b/ToyBox/classes/MonkeyPatchin/Multiclass/LevelUP+Multiclass.cs @@ -201,7 +201,8 @@ public static bool Apply(LevelUpState state, UnitDescriptor unit) { var expectedCount = spellsKnown.GetCount(casterLevelAfter, index); var actual = CasterHelpers.GetActualSpellsLearnedForClass(unit, spellbook1, index); if(spellbook1.Blueprint.Spontaneous) { - actual -= CasterHelpers.CountExternallyAddedSpells(spellbook1, index); + var toReduce = CasterHelpers.CountExternallyAddedSpells(unit, spellbook1, index); + actual -= toReduce < 0 ? 0 : toReduce; } int learnabl = spellbook1.GetSpellsLearnableOfLevel(index).Count(); int spelladd = Math.Max(0, Math.Min(expectedCount - actual, learnabl)); From 5f683500cb9ea1ee30841740a8cdbf0065400ca5 Mon Sep 17 00:00:00 2001 From: BuckAMayzing <19292614+BuckAMayzing@users.noreply.github.com> Date: Fri, 26 May 2023 09:08:55 -0400 Subject: [PATCH 5/8] Check the correct spellbook for null --- ToyBox/classes/Infrastructure/CasterHelpers.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ToyBox/classes/Infrastructure/CasterHelpers.cs b/ToyBox/classes/Infrastructure/CasterHelpers.cs index 311f526fd..96319103b 100644 --- a/ToyBox/classes/Infrastructure/CasterHelpers.cs +++ b/ToyBox/classes/Infrastructure/CasterHelpers.cs @@ -208,7 +208,7 @@ public static int CountExternallyAddedSpells(UnitDescriptor unit, Spellbook spel if (!unit.TryGetPartyMemberForLevelUpVersion(out var ch)) return 0; if (ch?.Spellbooks?.Count() <= 0) return 0; if (!ch.Spellbooks.TryFind(s => s.Blueprint == spellbook.Blueprint, out var unitSpellbook)) return 0; - if(spellbook?.SureKnownSpells(level) == null) return 0; + if(unitSpellbook?.SureKnownSpells(level) == null) return 0; return unitSpellbook.SureKnownSpells(level).Where(sp => sp.IsTemporary || sp.CopiedFromScroll From d5ab573a2c2cd58d695c3fd1080ff63669188e31 Mon Sep 17 00:00:00 2001 From: BuckAMayzing <19292614+BuckAMayzing@users.noreply.github.com> Date: Fri, 26 May 2023 09:24:22 -0400 Subject: [PATCH 6/8] Added some logic to avoid double counting --- .../classes/Infrastructure/CasterHelpers.cs | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/ToyBox/classes/Infrastructure/CasterHelpers.cs b/ToyBox/classes/Infrastructure/CasterHelpers.cs index 96319103b..37918d471 100644 --- a/ToyBox/classes/Infrastructure/CasterHelpers.cs +++ b/ToyBox/classes/Infrastructure/CasterHelpers.cs @@ -208,15 +208,23 @@ public static int CountExternallyAddedSpells(UnitDescriptor unit, Spellbook spel if (!unit.TryGetPartyMemberForLevelUpVersion(out var ch)) return 0; if (ch?.Spellbooks?.Count() <= 0) return 0; if (!ch.Spellbooks.TryFind(s => s.Blueprint == spellbook.Blueprint, out var unitSpellbook)) return 0; - if(unitSpellbook?.SureKnownSpells(level) == null) return 0; + if (unitSpellbook?.SureKnownSpells(level) == null) return 0; - return unitSpellbook.SureKnownSpells(level).Where(sp => sp.IsTemporary - || sp.CopiedFromScroll - || sp.IsFromMythicSpellList - || sp.SourceItem != null - || sp.SourceItemEquipmentBlueprint != null - || sp.SourceItemUsableBlueprint != null - || sp.IsMysticTheurgeCombinedSpell).Count(); + var IsExternal = (AbilityData spell) => { + return spell.IsTemporary + || spell.CopiedFromScroll + || spell.IsFromMythicSpellList + || spell.SourceItem != null + || spell.SourceItemEquipmentBlueprint != null + || spell.SourceItemUsableBlueprint != null + || spell.IsMysticTheurgeCombinedSpell; + }; + + //If copiedCount has records here, we've already taken them into account in GetActualSpellsLearned, and would be double counting here. + var copiedCount = spellbook.SureKnownSpells(level).Where(IsExternal).Count(); + if (copiedCount > 0) return 0; + + return unitSpellbook.SureKnownSpells(level).Where(IsExternal).Count(); } public static IEnumerable MergableClasses(this UnitEntityData unit) { From f8fca2c4ce15d569861c200c883ce5c415dae5fb Mon Sep 17 00:00:00 2001 From: BuckAMayzing <19292614+BuckAMayzing@users.noreply.github.com> Date: Thu, 25 May 2023 18:17:08 -0400 Subject: [PATCH 7/8] Fixed spell number calculation for spontaneous casters --- ToyBox/classes/Infrastructure/CasterHelpers.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ToyBox/classes/Infrastructure/CasterHelpers.cs b/ToyBox/classes/Infrastructure/CasterHelpers.cs index 37918d471..225eea87a 100644 --- a/ToyBox/classes/Infrastructure/CasterHelpers.cs +++ b/ToyBox/classes/Infrastructure/CasterHelpers.cs @@ -11,6 +11,7 @@ using System.Collections.Generic; using System.Linq; using Kingmaker.Utility; +using ToyBox.Multiclass; #if Wrath using Kingmaker.Blueprints.Classes.Selection; using Kingmaker.Blueprints.Classes.Spells; @@ -175,9 +176,9 @@ public static void HandleAddAllSpellsOnPartyEditor(UnitDescriptor unit) { selectedSpellbook.RemoveSpellsOfLevel(level); } #if Wrath -#if true // TODO: the else case of this #if has a patch that fixes the level for spontaneous spell casters learning scrolls but causes the gestalt feature to stop working by causing spells to not show up for spell casting classes like oracle and sorc when you try to select/gestalt them after choosing say a scaled fist monk public static int GetActualSpellsLearnedForClass(UnitDescriptor unit, Spellbook spellbook, int level) { Mod.Trace($"GetActualSpellsLearnedForClass - unit: {unit?.CharacterName} spellbook: {spellbook?.Blueprint.DisplayName} level:{level}"); + // Get all +spells known facts for this spellbook's class so we can ignore them when getting spell counts var spellsToIgnore = unit.Facts.List.SelectMany(x => x.BlueprintComponents.Where(y => y is AddKnownSpell)).Select(z => z as AddKnownSpell) From 2daea8b5a2f22d05622fd4b7062ae891d018ac85 Mon Sep 17 00:00:00 2001 From: BuckAMayzing <19292614+BuckAMayzing@users.noreply.github.com> Date: Thu, 25 May 2023 18:29:54 -0400 Subject: [PATCH 8/8] whitespace --- ToyBox/classes/Infrastructure/CasterHelpers.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/ToyBox/classes/Infrastructure/CasterHelpers.cs b/ToyBox/classes/Infrastructure/CasterHelpers.cs index 225eea87a..c1d0e5611 100644 --- a/ToyBox/classes/Infrastructure/CasterHelpers.cs +++ b/ToyBox/classes/Infrastructure/CasterHelpers.cs @@ -178,7 +178,6 @@ public static void HandleAddAllSpellsOnPartyEditor(UnitDescriptor unit) { #if Wrath public static int GetActualSpellsLearnedForClass(UnitDescriptor unit, Spellbook spellbook, int level) { Mod.Trace($"GetActualSpellsLearnedForClass - unit: {unit?.CharacterName} spellbook: {spellbook?.Blueprint.DisplayName} level:{level}"); - // Get all +spells known facts for this spellbook's class so we can ignore them when getting spell counts var spellsToIgnore = unit.Facts.List.SelectMany(x => x.BlueprintComponents.Where(y => y is AddKnownSpell)).Select(z => z as AddKnownSpell)