From db4656848f8b3a101d58bb1bf3cfbd641b36641f Mon Sep 17 00:00:00 2001 From: Silvergriffon Date: Fri, 27 Feb 2026 14:12:05 -0500 Subject: [PATCH 1/2] initial - Option for all magical thrown weapons to return to the thrower's hand --- .../Displays/CraftingAndItems.cs | 7 +++++ .../Models/CustomItemsContext.cs | 27 ++++++++++++++++++- SolastaUnfinishedBusiness/Settings.cs | 1 + .../Translations/en/Settings-en.txt | 1 + 4 files changed, 35 insertions(+), 1 deletion(-) diff --git a/SolastaUnfinishedBusiness/Displays/CraftingAndItems.cs b/SolastaUnfinishedBusiness/Displays/CraftingAndItems.cs index 79c0d682a3..ec4fcd0eb5 100644 --- a/SolastaUnfinishedBusiness/Displays/CraftingAndItems.cs +++ b/SolastaUnfinishedBusiness/Displays/CraftingAndItems.cs @@ -143,6 +143,13 @@ private static void DisplayGeneral() CustomItemsContext.SwitchAllowClubsToBeThrown(); } + toggle = Main.Settings.AllMagicThrownReturn; + if (UI.Toggle(Gui.Localize("ModUi/&AllMagicThrownReturn"), ref toggle, UI.AutoWidth())) + { + Main.Settings.AllMagicThrownReturn = toggle; + CustomItemsContext.AllMagicThrownReturn(); + } + toggle = Main.Settings.UseOfficialFoodRationsWeight; if (UI.Toggle(Gui.Localize("ModUi/&UseOfficialFoodRationsWeight"), ref toggle, UI.AutoWidth())) { diff --git a/SolastaUnfinishedBusiness/Models/CustomItemsContext.cs b/SolastaUnfinishedBusiness/Models/CustomItemsContext.cs index e79bc4f3cd..298d9b78ff 100644 --- a/SolastaUnfinishedBusiness/Models/CustomItemsContext.cs +++ b/SolastaUnfinishedBusiness/Models/CustomItemsContext.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Linq; using SolastaUnfinishedBusiness.Api.GameExtensions; +using SolastaUnfinishedBusiness.Behaviors.Specific; using SolastaUnfinishedBusiness.Builders; using SolastaUnfinishedBusiness.Builders.Features; using SolastaUnfinishedBusiness.Interfaces; @@ -17,7 +18,14 @@ internal static class CustomItemsContext private static readonly Dictionary Tags = []; private static ItemDefinition _helmOfAwareness; private static ItemDefinition _glovesOfThievery; - + private static FeatureDefinitionAttributeModifier featureAllMagicThrownReturn = FeatureDefinitionAttributeModifierBuilder + .Create($"AttributeModifierAllMagicThrownReturn") + .SetGuiPresentationNoContent() + .AddCustomSubFeatures(ReturningWeapon.AlwaysValid) + .AddToDB(); + private static readonly ItemPropertyDescription itemPropertyAllMagicThrownReturn = ItemPropertyDescriptionBuilder + .From(featureAllMagicThrownReturn, true) + .Build(); internal static ItemDefinition HelmOfAwareness => _helmOfAwareness ??= BuildHelmOfAwareness(); internal static ItemDefinition GlovesOfThievery => _glovesOfThievery ??= BuildGlovesOfThievery(); @@ -31,6 +39,7 @@ internal static void Load() SwitchAllowClubsToBeThrown(); SwitchUniversalSylvanArmorAndLightbringer(); SwitchMagicStaffFoci(); + AllMagicThrownReturn(); } private static ItemDefinition BuildHelmOfAwareness() @@ -215,6 +224,22 @@ internal static void SwitchMagicStaffFoci() } } + internal static void AllMagicThrownReturn() + { + + foreach (var item in DatabaseRepository.GetDatabase() + .Where(x => x.IsWeapon && + x.Magical && + x.WeaponDescription.WeaponTags.Contains("Thrown"))) + { + if (Main.Settings.AllMagicThrownReturn && + !item.HasSubFeatureOfType()) + { + item.staticProperties.Add(itemPropertyAllMagicThrownReturn); + } + } + } + internal static bool IsAttackModeInvalid(RulesetCharacter character, RulesetAttackMode mode) { if (character is not RulesetCharacterHero hero) diff --git a/SolastaUnfinishedBusiness/Settings.cs b/SolastaUnfinishedBusiness/Settings.cs index 4300c00511..688a255016 100644 --- a/SolastaUnfinishedBusiness/Settings.cs +++ b/SolastaUnfinishedBusiness/Settings.cs @@ -272,6 +272,7 @@ public class Settings : UnityModManager.ModSettings public bool RemoveAttunementRequirements { get; set; } public bool AllowAnyClassToWearSylvanArmor { get; set; } public bool AllowClubsToBeThrown { get; set; } + public bool AllMagicThrownReturn { get; set; } [Tag(Type = TagType.T2014)] public bool UseOfficialFoodRationsWeight { get; set; } public bool MakeAllMagicStaveArcaneFoci { get; set; } [Tag(Type = TagType.T2014)] public bool FixRingOfRegenerationHealRate { get; set; } diff --git a/SolastaUnfinishedBusiness/Translations/en/Settings-en.txt b/SolastaUnfinishedBusiness/Translations/en/Settings-en.txt index 7c1f5a73db..874f514b53 100644 --- a/SolastaUnfinishedBusiness/Translations/en/Settings-en.txt +++ b/SolastaUnfinishedBusiness/Translations/en/Settings-en.txt @@ -17,6 +17,7 @@ ModUi/&EnemySpellcastersDropScribedSpellbooks=Enemy spellcasters drop scribed sp ModUi/&AddToStore=Add {0} ModUi/&Advanced=Advanced: [Requires Restart] ModUi/&AdvancedHelp=• ATTENTION: These settings will require the player to have this mod installed +ModUi/&AllMagicThrownReturn=All magic thrown weapons return to the thrower [Requires Restart To Remove] ModUi/&AllowAllPlayersOnNarrativeSequences=+ Allow all players on narrative sequences ModUi/&AllowAlliesToPerceiveRangerGloomStalkerInNaturalDarkness=Allow allies to perceive GloomStalker when in natural darkness ModUi/&AllowAnyClassToWearSylvanArmor=Allow any class to wear Sylvan Armor or Lightbringer Clothes From 1864f887450feb6c0483c2927c7b28f423078e1c Mon Sep 17 00:00:00 2001 From: Silvergriffon Date: Mon, 9 Mar 2026 16:28:30 -0400 Subject: [PATCH 2/2] convert to a proper switch --- .../Displays/CraftingAndItems.cs | 2 +- .../Models/CustomItemsContext.cs | 35 +++++++++++++------ 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/SolastaUnfinishedBusiness/Displays/CraftingAndItems.cs b/SolastaUnfinishedBusiness/Displays/CraftingAndItems.cs index ec4fcd0eb5..27dc272b90 100644 --- a/SolastaUnfinishedBusiness/Displays/CraftingAndItems.cs +++ b/SolastaUnfinishedBusiness/Displays/CraftingAndItems.cs @@ -147,7 +147,7 @@ private static void DisplayGeneral() if (UI.Toggle(Gui.Localize("ModUi/&AllMagicThrownReturn"), ref toggle, UI.AutoWidth())) { Main.Settings.AllMagicThrownReturn = toggle; - CustomItemsContext.AllMagicThrownReturn(); + CustomItemsContext.SwitchAllMagicThrownReturn(); } toggle = Main.Settings.UseOfficialFoodRationsWeight; diff --git a/SolastaUnfinishedBusiness/Models/CustomItemsContext.cs b/SolastaUnfinishedBusiness/Models/CustomItemsContext.cs index 298d9b78ff..0eb69cc485 100644 --- a/SolastaUnfinishedBusiness/Models/CustomItemsContext.cs +++ b/SolastaUnfinishedBusiness/Models/CustomItemsContext.cs @@ -11,6 +11,7 @@ using static SolastaUnfinishedBusiness.Api.DatabaseHelper.CharacterClassDefinitions; using static SolastaUnfinishedBusiness.Api.DatabaseHelper.ItemDefinitions; + namespace SolastaUnfinishedBusiness.Models; internal static class CustomItemsContext @@ -18,7 +19,7 @@ internal static class CustomItemsContext private static readonly Dictionary Tags = []; private static ItemDefinition _helmOfAwareness; private static ItemDefinition _glovesOfThievery; - private static FeatureDefinitionAttributeModifier featureAllMagicThrownReturn = FeatureDefinitionAttributeModifierBuilder + private static readonly FeatureDefinitionAttributeModifier featureAllMagicThrownReturn = FeatureDefinitionAttributeModifierBuilder .Create($"AttributeModifierAllMagicThrownReturn") .SetGuiPresentationNoContent() .AddCustomSubFeatures(ReturningWeapon.AlwaysValid) @@ -39,7 +40,7 @@ internal static void Load() SwitchAllowClubsToBeThrown(); SwitchUniversalSylvanArmorAndLightbringer(); SwitchMagicStaffFoci(); - AllMagicThrownReturn(); + SwitchAllMagicThrownReturn(); } private static ItemDefinition BuildHelmOfAwareness() @@ -224,18 +225,32 @@ internal static void SwitchMagicStaffFoci() } } - internal static void AllMagicThrownReturn() + internal static void SwitchAllMagicThrownReturn() { - foreach (var item in DatabaseRepository.GetDatabase() - .Where(x => x.IsWeapon && - x.Magical && - x.WeaponDescription.WeaponTags.Contains("Thrown"))) + .Where(x => x.IsWeapon && + x.Magical && + x.WeaponDescription.WeaponTags.Contains("Thrown"))) { - if (Main.Settings.AllMagicThrownReturn && - !item.HasSubFeatureOfType()) + bool hasProperty = item.StaticProperties + .Exists(p => p.FeatureDefinition.Name.Contains("AttributeModifierAllMagicThrownReturn")); + + if (Main.Settings.AllMagicThrownReturn) + { + // ENABLED → add if missing + if (!hasProperty) + { + item.staticProperties.Add(itemPropertyAllMagicThrownReturn); + } + } + else { - item.staticProperties.Add(itemPropertyAllMagicThrownReturn); + // DISABLED → remove if present + if (hasProperty) + { + item.staticProperties + .RemoveAll(p => p.FeatureDefinition.Name.Contains("AttributeModifierAllMagicThrownReturn")); + } } } }