From a64acb201d98f61fdf610f4df3e6c864f7384efa Mon Sep 17 00:00:00 2001 From: 3ger <41837307+3ger@users.noreply.github.com> Date: Wed, 27 Dec 2023 09:38:18 +0100 Subject: [PATCH 1/2] Added relation based war declaration "prevention". --- .../GenericConditions/BadRelationCondition.cs | 42 +++++++++++++++++++ .../WarPeace/DeclareWarConditions.cs | 3 +- .../Extensions/ClanExtensions.cs | 7 ++++ .../Extensions/HeroExtensions.cs | 34 +++++++++++++++ src/Bannerlord.Diplomacy/Settings.cs | 16 +++++++ .../Languages/std_module_strings_xml.xml | 16 +++++-- 6 files changed, 114 insertions(+), 4 deletions(-) create mode 100644 src/Bannerlord.Diplomacy/DiplomaticAction/GenericConditions/BadRelationCondition.cs diff --git a/src/Bannerlord.Diplomacy/DiplomaticAction/GenericConditions/BadRelationCondition.cs b/src/Bannerlord.Diplomacy/DiplomaticAction/GenericConditions/BadRelationCondition.cs new file mode 100644 index 00000000..4cf6ed14 --- /dev/null +++ b/src/Bannerlord.Diplomacy/DiplomaticAction/GenericConditions/BadRelationCondition.cs @@ -0,0 +1,42 @@ +using Diplomacy.Extensions; + +using TaleWorlds.CampaignSystem; +using TaleWorlds.Localization; + +namespace Diplomacy.DiplomaticAction.GenericConditions +{ + internal sealed class BadRelationCondition : IDiplomacyCondition + { + public bool ApplyCondition(Kingdom kingdom, + Kingdom otherKingdom, + out TextObject? textObject, + bool forcePlayerCosts = false, + bool bypassCosts = false) + { + textObject = null; + + // if kingdom leaders are friends, do not allow war + if (Settings.Instance!.NoWarBetweenFriends && kingdom.Leader.IsFriend(otherKingdom.Leader)) + { + textObject = new TextObject("{=9aaZ8Ed4}Cannot declare war, kingdom leaders are friends."); + return false; + } + + // if relations are above "good" do not start wars + if (Settings.Instance!.NoWarOnGoodRelations && kingdom.Leader.GetRelation(otherKingdom.Leader) >= Settings.Instance!.NoWarOnGoodRelationsThreshold) + { + textObject = new TextObject("{=Zimavbgw}Cannot declare war, kingdom leaders personal relations are excellent."); + return false; + } + + // if leading clans have marriages between them => no wars + if (Settings.Instance!.NoWarWhenMarriedLeaderClans && kingdom.RulingClan.HasMarriedClanLeaderRelation(otherKingdom.RulingClan)) + { + textObject = new TextObject("{=pXD8Uf2e}Cannot declare war, kingdom leader clans have close family marriages."); + return false; + } + + return true; + } + } +} \ No newline at end of file diff --git a/src/Bannerlord.Diplomacy/DiplomaticAction/WarPeace/DeclareWarConditions.cs b/src/Bannerlord.Diplomacy/DiplomaticAction/WarPeace/DeclareWarConditions.cs index f9f569dd..f87619ef 100644 --- a/src/Bannerlord.Diplomacy/DiplomaticAction/WarPeace/DeclareWarConditions.cs +++ b/src/Bannerlord.Diplomacy/DiplomaticAction/WarPeace/DeclareWarConditions.cs @@ -16,7 +16,8 @@ internal sealed class DeclareWarConditions : AbstractConditionEvaluator GetRebelFactions(this Clan clan) { return default; } + } + + public static bool HasMarriedClanLeaderRelation(this Clan clan, Clan other) + { + // if any relatives are alive and married to other clan => "related by marriage" + return clan.Leader.Spouse?.AllRelatedHeroes().Any(ownSpouseFamMember => ownSpouseFamMember.Clan == other) ?? false + || clan.Leader.AllRelatedHeroes().Any(famMember => famMember.IsAlive && (famMember.Spouse?.AllRelatedHeroes().Any(spouseFamMember => spouseFamMember.Clan == other) ?? false)); } } } \ No newline at end of file diff --git a/src/Bannerlord.Diplomacy/Extensions/HeroExtensions.cs b/src/Bannerlord.Diplomacy/Extensions/HeroExtensions.cs index 6bae39cb..1020a9cf 100644 --- a/src/Bannerlord.Diplomacy/Extensions/HeroExtensions.cs +++ b/src/Bannerlord.Diplomacy/Extensions/HeroExtensions.cs @@ -12,6 +12,40 @@ public static float GetNormalizedTraitValue(this Hero hero, TraitObject trait) var zeroMinMaxTraitLevel = (float) Math.Abs(trait.MinValue) + trait.MaxValue; var zeroMinTraitLevel = hero.GetTraitLevel(trait) + Math.Abs(trait.MinValue); return zeroMinTraitLevel / zeroMinMaxTraitLevel; + } + + public static IEnumerable AllRelatedHeroes(this Hero inHero, bool includeExSpouses = false) + { + if (inHero.Father != null) + { + yield return inHero.Father; + + // father side uncles/aunts are close family + foreach (Hero hero3 in inHero.Father.Siblings) + yield return hero3; + } + + if (inHero.Mother != null) + { + yield return inHero.Mother; + + // mother side uncles/aunts are close family + foreach (Hero hero4 in inHero.Mother.Siblings) + yield return hero4; + } + + if (inHero.Spouse != null) + yield return inHero.Spouse; + + foreach (Hero hero in inHero.Children) + yield return hero; + + foreach (Hero hero2 in inHero.Siblings) + yield return hero2; + + if (includeExSpouses) + foreach (Hero hero3 in inHero.ExSpouses) + yield return hero3; } } } \ No newline at end of file diff --git a/src/Bannerlord.Diplomacy/Settings.cs b/src/Bannerlord.Diplomacy/Settings.cs index a1df160e..aa372298 100644 --- a/src/Bannerlord.Diplomacy/Settings.cs +++ b/src/Bannerlord.Diplomacy/Settings.cs @@ -80,6 +80,22 @@ class Settings : AttributeGlobalSettings [SettingPropertyGroup(HeadingKingdomDiplomacy)] public bool PlayerDiplomacyControl { get; set; } = false; + [SettingPropertyBool(displayName: "{=dRyU9E7Z}No Wars Between Friends", Order = 1001, RequireRestart = false, HintText = "{=XyXJSTKr}If active, kingdom leaders that are friends will not start wars with each other. Default value is enabled.")] + [SettingPropertyGroup(HeadingKingdomDiplomacy)] + public bool NoWarBetweenFriends { get; set; } = true; + + [SettingPropertyBool(displayName: "{=pWoKQ6HO}No Wars If Good Relations", Order = 1002, RequireRestart = false, HintText = "{=bOuGhbPt}If active, wars between leaders of kingdoms will not be allowed if relations are above war start relations. Default value is enabled.")] + [SettingPropertyGroup(HeadingKingdomDiplomacy)] + public bool NoWarOnGoodRelations { get; set; } = true; + + [SettingPropertyInteger("{=x0Aoiomr}No Wars Good Relations Threshold", 0, 100, Order = 1003, RequireRestart = false, HintText = "{=aH6rpjt6}The relation value of kingdom leaders after which kingdoms will not start wars with each other. Default value is 30.")] + [SettingPropertyGroup(HeadingKingdomDiplomacy)] + public int NoWarOnGoodRelationsThreshold { get; set; } = 30; + + [SettingPropertyInteger("{=jwNKk8P7}No Wars When Married", 0, 100, Order = 1004, RequireRestart = false, HintText = "{=xcMzKH48}If active, kingdom leader clans that have a marriage between each other will not start wars. Default value is active.")] + [SettingPropertyGroup(HeadingKingdomDiplomacy)] + public bool NoWarWhenMarriedLeaderClans { get; set; } = true; + // Messengers [SettingPropertyBool("{=nwTyegdV}Enable Messengers Accidents", Order = 0, RequireRestart = false, HintText = "{=T7yybpw3}If enabled, adds a small chance of failure for messengers. The longer the journey, the higher the chance of an accident on the road. Default value is enabled.")] diff --git a/src/Bannerlord.Diplomacy/_Module/ModuleData/Languages/std_module_strings_xml.xml b/src/Bannerlord.Diplomacy/_Module/ModuleData/Languages/std_module_strings_xml.xml index 61012399..13187f6e 100644 --- a/src/Bannerlord.Diplomacy/_Module/ModuleData/Languages/std_module_strings_xml.xml +++ b/src/Bannerlord.Diplomacy/_Module/ModuleData/Languages/std_module_strings_xml.xml @@ -14,10 +14,13 @@ + + + + - @@ -136,7 +139,7 @@ - + @@ -184,6 +187,14 @@ + + + + + + + + @@ -245,7 +256,6 @@ - From 8408c0c4ed8b67379a48a7e8f9a009971a943f29 Mon Sep 17 00:00:00 2001 From: 3ger <41837307+3ger@users.noreply.github.com> Date: Wed, 27 Dec 2023 10:38:26 +0100 Subject: [PATCH 2/2] Missing using fixed --- src/Bannerlord.Diplomacy/Extensions/HeroExtensions.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Bannerlord.Diplomacy/Extensions/HeroExtensions.cs b/src/Bannerlord.Diplomacy/Extensions/HeroExtensions.cs index 1020a9cf..49477f74 100644 --- a/src/Bannerlord.Diplomacy/Extensions/HeroExtensions.cs +++ b/src/Bannerlord.Diplomacy/Extensions/HeroExtensions.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using TaleWorlds.CampaignSystem; using TaleWorlds.CampaignSystem.CharacterDevelopment;