Settlement Modding - Research and Development

Users who are viewing this thread

Successful in enabling artisan in recruitment window, will post for future reference.

Step one, add notable to TaleWorlds.CampaignSysytem.Hero like below;
C#:
        // Token: 0x1700062A RID: 1578
        // (get) Token: 0x06001309 RID: 4873 RVA: 0x0000C959 File Offset: 0x0000AB59
        public bool CanHaveRecruits
        {
            get
            {
                return this.IsPreacher || this.IsRuralNotable || this.IsMercenary || this.IsGangLeader || this.IsMerchant || this.IsArtisan || this.IsHeadman;
            }
        }

Step two, add notable too TaleWorlds.CampaignSysytem.ViewModelCollection.GameMenu.RecruitmentVM
C#:
        // Token: 0x06000E01 RID: 3585 RVA: 0x0003C628 File Offset: 0x0003A828
        public void RefreshScreen()
        {
            this.VolunteerList.Clear();
            this.TroopsInCart.Clear();
            int num = 0;
            this.InitialPartySize = PartyBase.MainParty.NumberOfAllMembers;
            this.RefreshPartyProperties();
            foreach (Hero hero in Settlement.CurrentSettlement.Notables)
            {
                if (hero.IsPreacher || hero.IsGangLeader || hero.IsRuralNotable || hero.IsMerchant || hero.IsArtisan || hero.IsHeadman)
                {
                    MBTextManager.SetTextVariable("INDIVIDUAL_NAME", hero.Name, false);
                    List<CharacterObject> volunteerTroopsOfHeroForRecruitment = HeroHelper.GetVolunteerTroopsOfHeroForRecruitment(hero);
                    RecruitVolunteerVM item = new RecruitVolunteerVM(hero, volunteerTroopsOfHeroForRecruitment, new Action<RecruitVolunteerVM, RecruitVolunteerTroopVM>(this.OnRecruit), new Action<RecruitVolunteerVM, RecruitVolunteerTroopVM>(this.OnRemoveFromCart));
                    this.VolunteerList.Add(item);
                    num++;
                }
            }
            this.TotalWealth = Hero.MainHero.Gold;
            this.UpdateRecruitAllProperties();
        }

And with my earlier post can have artisans give any recruits you want.
 
Is it possible to add a secondary production to villages? like making one village that makes Hardwood produce a bit of Clay if the hearth count becomes high enough?
 
Tonight's testing.

By applying a custom culture to a village it didn't crash, only a town. I've noticed there are no notable villagers at that village. I'm not completely sure where noteable villagers are defined (are they in specialnpcs?) or why they aren't spawning. Going to continue down this path of experimentation tomorrow. I believe the reason Towns are crashing is possibly because they are reliant on those notables possibly existing.

Update: Confirming. Missing Special Character Notables (Outlaws, etc.) from your custom culture WILL CRASH TOWNS. You need to define the various hooligans to populate towns or else it won't function.

Saw a mod on the nexus that might help shed more light on these crashes - Better Exception Window
 
Is it possible to add a secondary production to villages? like making one village that makes Hardwood produce a bit of Clay if the hearth count becomes high enough?
@luisedgm my first post talks about adding additional production to villages, you can add as many and change their output for each resource.
 
my first post talks about adding additional production to villages, you can add as many and change their output for each resource.
Oh sorry i missed that, this is great news, so a mod where the player invests money to add secondary productions to a village is possible, good news. Can the secondary production be removed afterwards? So if the village is raided then the secondary production is lost or something, otherwise it would feel like cheating.
 
Oh sorry i missed that, this is great news, so a mod where the player invests money to add secondary productions to a village is possible, good news. Can the secondary production be removed afterwards? So if the village is raided then the secondary production is lost or something, otherwise it would feel like cheating.
It could be possible, there are references in the code for village hearth levels from 0 (0-199),1 (199-499), and 2 (500+). I can see it being possible but beyond my capabilities.
Edit: Corrected Hearth level values
 
Last edited:
C#:
            this.AddProductions(this.VillageTypeSilverMine, new ValueTuple<string, float>[]
            {
                new ValueTuple<string, float>("silver", 3f)
            if (this.HearthLevel() >= 2)
            {
                new ValueTuple<string, float>("cotton", 3f)
            }
            });

If I knew more about coding I could add something like this, were if the village was at max level hearth it could produce another resource.
 
Has anyone managed to find a workaround to the fact Settlements revert to their vanilla owners? All other submodule changes work (names, cultures, etc.) but the clan that owns the town seems to revert to vanilla no matter which town it was.
 
Done! Was able to successfully add multiple branches of which you can recruit from notables in town, below is what I've done.

So I don't have any modding experience so I'm not sure if this is possible, but that post gives me optimism. Basically I'm envisioning a mod that changes settlements from going "All In" on one culture's recruits, to one that is homogeneous based on the cultures that have ruled it, and how long they ruled it for. So a Battanian village that gets conquered by Vlandia would initially keep giving Battanian recruits, but over time, it would pull from a mix of Battanian and Vlandian recruits, with the latter increasing the longer Vlandia rules the fief. It would take a long time for the original culture to completely die out, or perhaps it never would completely die out but diminish greatly.

Again, no coding/modding experience but I imagine it working like this based on my extremely rudimentary perception of how these things work?

  • BaseCulture = the original culture of a Settlement, defined as soon as the game starts by looking at the owner of each Settlement
    • example: a Village owned by Battania would have a BaseCulture = Battania
    • This would never change regardless of the status of the Culture as a whole
  • ForeignCulture = any culture other than the BaseCulture
  • CurrentCulture = the Culture of the Current owner of each Settlement

  • CulturePopulation = number from 0 - 10000, that determines how relevant a certain culture is within a settlement, and therefore the likelihood of a recruit being from that culture
    • At start of game, set the following values for each settlement:
      • CulturePopulation for the BaseCulture: 10000
      • CulturePopulation for every ForeignCulture: 0
    • Every Day, make the following changes to every Settlement's CulturePopulation
      • Increase CulturePopulation of the CurrentCulture
        • If CurrentCulture = BaseCulture, Increase CurrentPopulation of CurrentCulture by 20, to a max of 10000
        • If CurrentCulture = ForeignCulture, Increase CurrentPopulation of CurrentCulture by 15, to a max of 10000
      • Decrease CulturePopulation of all Cultures other than CurrentCulture
        • If Culture = BaseCulture, Decrease CurrentPopulation of Culture by 5, to a minimum of "500"
        • If Culture = ForeignCulture, Decrease CurrentPopulation of Culture by 10, to a minimum of "250"

  • GetDailyVolunteerProductionProbability
    • For each individual Recruit, randomize Culture by pulling a Probability of each Culture's CurrentPopulation
      • Example: A Battanian Village that was first conquered by [Vlandia for 300 days], then taken over by [[Aserai for 100 days]], then reclaimed by [[[Battania for 30 days]]]
        • CurrentPopulation of Battania = 8600
          • 10000 + [-5 * 300] + [[-5 * 100]] + [[[20 * 30]]] = 8600
        • CurrentPopulation of Vlandia = 3200
          • 0 + [15 * 300] + [[-10 * 100]] + [[[-10 * 30]]] = 3200
        • CurrentPopulation of Aserai = 1200
          • 0 + [0] + [[15 * 100]] + [[[-10 * 30]]] = 1200
        • CurrentPopulation of Khuzait = 0
        • CurrentPopulation of Empire = 0
        • CurrentPopulation of Sturgia = 0
      • TotalPopulation = Sum of each Culture's CurrentPopulation
      • VolunteerCulture = Random number (min = 1, max = TotalPopulation) where each Culture is assigned to a range (ie. Battania would be (1, through CurrentPopulation.Battania), Vlandia would be (CurrentPopulation.Battania + 1, through CurrentPopulation.Battania + CurrentPopulation.Vlandia), and so on...
        • I don't know how Randoms or Probability work in code so there may be a more elegant solution
    • Based on the Culture of the Recruit, you'd then apply the other aspects like Elite, Bandit, etc.
Just kind of spitballing and seeing if any of this would be possible. I think having diverse recruits based on the history of the specific campaign would add a ton of depth.
 
Yeah seems like that is all very possible, pretty good psuedocode!

Have we figured out how to extend settlements as opposed to completely overwriting the base modules yet?
 
I'd love to make a mod to add interiors and new NPC into existing vanilla towns, fief and castles. I expect will open up when game is fully released. Modding these now may only cause more issues than its worth. Could have TW chasing bugs related only to mods.
 
I'd love to make a mod to add interiors and new NPC into existing vanilla towns, fief and castles. I expect will open up when game is fully released. Modding these now may only cause more issues than its worth. Could have TW chasing bugs related only to mods.
Me too. I have been scouring the code to see how items can be added to scenes and I think that MissionObject holds the key. You can also see how they are programmatically adding characters to the tavern scene in TavernEmployeesCampaignBehaviour (I think I got that name right not sure)
 
So a Battanian village that gets conquered by Vlandia would initially keep giving Battanian recruits, but over time, it would pull from a mix of Battanian and Vlandian recruits, with the latter increasing the longer Vlandia rules the fief.
Unfortunately what you are describing is implementing a whole new mechanic (population) into the game, which would require some serious black magic without modding tools. However something similar was done in Prophesy of Pendor mod were recruit culture was tied to the owner's culture, which may be more plausible to have the settlement reflect the current lord's(Clan?) culture?
C#:
        private static void UpdateVolunteersOfNotables(bool initialRunning = false)
        {
            foreach (Settlement settlement in Campaign.Current.Settlements)
            {
                if ((settlement.IsTown && !settlement.Town.IsRebeling) || (settlement.IsVillage && !settlement.Village.Bound.Town.IsRebeling))
                {
                    foreach (Hero hero in settlement.Notables)
                    {
                        if (hero.CanHaveRecruits)
                        {
                            bool flag = false;
                            CultureObject cultureObject = (hero.CurrentSettlement != null) ? hero.CurrentSettlement.Culture : hero.Clan.Culture;
                            CharacterObject basicTroop = cultureObject.BasicTroop;
                            double num = (hero.IsRuralNotable && hero.Power >= 200) ? 1.5 : 0.5;
                            float num2 = 200f;
                            for (int i = 0; i < 6; i++)
                            {
Above is the chunk of code basing notable culture to current settlement culture, might be easier to change the code to reflect current owner's culture. Although not as in depth as what you are describing but would create the same end result, making conquered settlements make recruits based off of current owner's culture.
 
Found where to mod settlement buildings within TaleWorlds.CampaignSystem.DefaultBuildingTypes;
C#:
            this._buildingSettlementGarrisonBarracks.Initialize(new TextObject("{=54vkRuHo}Garrison Barracks", null), new TextObject("{=DHm1MBsj}Logding for the garrisoned troops. Each level increases garrison capacity of the stronghold.", null), new int[]
            {
                520,
                650,
                780
            }, BuildingLocation.Settlement, new Dictionary<BuildingEffect, IReadOnlyList<int>>
            {
                {
                    DefaultBuildingEffects.GarrisonCapacity,
                    new List<int>
                    {
                        50,
                        75,
                        100
                    }
                }
            }, 0);
            this._buildingSettlementTradingFields.Initialize(new TextObject("{=BkTiRPT4}Training Fields", null), new TextObject("{=otWlERkc}A field for military drills that increase the daily experience gain of all garrisoned units.", null), new int[]
            {
                390,
                520,
                650
            }, BuildingLocation.Settlement, new Dictionary<BuildingEffect, IReadOnlyList<int>>
            {
                {
                    DefaultBuildingEffects.Experience,
                    new List<int>
                    {
                        1,
                        2,
                        4
                    }
                }
            }, 0);
With this you should easily mod building effects and add more, however if you want to mod in new buildings you will undoubtedly have to find and mod the building UI.
 
Unfortunately what you are describing is implementing a whole new mechanic (population) into the game, which would require some serious black magic without modding tools. However something similar was done in Prophesy of Pendor mod were recruit culture was tied to the owner's culture, which may be more plausible to have the settlement reflect the current lord's(Clan?) culture?
C#:
        private static void UpdateVolunteersOfNotables(bool initialRunning = false)
        {
            foreach (Settlement settlement in Campaign.Current.Settlements)
            {
                if ((settlement.IsTown && !settlement.Town.IsRebeling) || (settlement.IsVillage && !settlement.Village.Bound.Town.IsRebeling))
                {
                    foreach (Hero hero in settlement.Notables)
                    {
                        if (hero.CanHaveRecruits)
                        {
                            bool flag = false;
                            CultureObject cultureObject = (hero.CurrentSettlement != null) ? hero.CurrentSettlement.Culture : hero.Clan.Culture;
                            CharacterObject basicTroop = cultureObject.BasicTroop;
                            double num = (hero.IsRuralNotable && hero.Power >= 200) ? 1.5 : 0.5;
                            float num2 = 200f;
                            for (int i = 0; i < 6; i++)
                            {
Above is the chunk of code basing notable culture to current settlement culture, might be easier to change the code to reflect current owner's culture. Although not as in depth as what you are describing but would create the same end result, making conquered settlements make recruits based off of current owner's culture.

There is this mod (https://www.nexusmods.com/mountandblade2bannerlord/mods/510) that "automatically changes settlement culture to the owning kingdoms' culture. Culture is recalculated each time you load a save, on settlement capture, and on clan changing kingdoms." So the PoP (<3) style is certainly available which is nice, I'll probably use it for the time being.

Just out of curiosity, if the "Population" that I described was simply a number in the background, and not something that had to be displayed as part of the UI, would it still not be able to work? I started looking into C# last night just so I could get decent sense of what I was reading when looking at some of the mods out there. So obviously my understanding is a glass of water in the ocean!

I'm not sure if this would make sense and I certainly don't have the ability to put it into action, but my general idea based on the TaleWorlds.CampaignSysytem.SandBox.CampaignBehaviours.RecruitCampaignBehaviour and the UpdateVolunteersOfNotables method would be:

  • Utilize the core of the mod linked above to automatically change the currentCulture of each settlement to the Owner's Culture, upon Loading Save, Settlement Capture, or Clan Changing Kingdoms

  • Method "SetCultures" that runs at the very beginning of the campaign and never again
    • Foreach Settlement (Town or Village)
      • string baseCulture = Owner's Culture
      • Create List of all Cultures containing
        • string CultureName = Culture
        • int Population = 0
      • Foreach Culture
        • if Culture = baseCulture
          • Population += 10000
  • Method "UpdateCulturePopulation" that runs every day to update the Population numbers within the list that created
    • Foreach Settlement (Town or Village)
      • Foreach Culture
        • if Culture = currentCulture
          • if Culture = baseCulture
            • Population += 20
              • if Population > 10000
                • Population = 10000
          • else
            • Population += 15
              • if Population > 10000
                • Population = 10000
        • else
          • if Culture = baseCulture
            • Population -= 5
            • if Population < 500
              • Population = 500
          • else
            • Population -= 10
            • if Population < 250
              • Population = 250
  • In the UpdateVolunteersOfNotable method
    • Change this: CultureObject cultureObject = (hero.CurrentSettlement != null) ? hero.CurrentSettlement.Culture : hero.Clan.Culture;
    • To: a "Weighted Random" selection that adds the Populations from the list of cultures, returning one of the cultures that has a non-zero Population. I'm not sure exactly how this works but it seems like this would be the right path.
That would, as far as I can tell, change the cultureObject of each Notable each time recruits get updated, so it would allow different Notables within the same Settlement to have different cultureObject, which would then change what becomes available from cultureObject.BasicTroop or cultureObject.EliteBasicTroop.

I tried to throw this together in VS just as a test for myself. Obviously when applying it to the actual game the list would need to use each of the Cultures from the campaign rather than manually entering them.


C#:
 class Culture
    {
        public string CultureName { get; set; }
        public int Population { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
           
            // Instead of writing new Culture() lines manually these would be created foreach Culture and get assigned a starting Population of 0
            List<Culture> listOfCultures = new List<Culture>()
            {
                new Culture() { CultureName = "Aserai", Population = 8000},
                new Culture() { CultureName = "Battania", Population = 4000},
                new Culture() { CultureName = "Vlandia", Population = 500},
            };

           
            // Just a test to verify that the Population count can be changed
            // Instead of altering the Population of [1] (Battania) this would look at each Culture and increase/decrease as necessary
            listOfCultures[1].Population += 15;

            for (int i = 0; i < listOfCultures.Count; i++)
            {
                Console.WriteLine(listOfCultures[i].CultureName + " has a population of " + listOfCultures[i].Population + ".");
            }
           
            // Summing all of the Population amounts to totalPopulation which will serve as the max value when using the Weighted Random
            int totalPopulation = listOfCultures.Sum(Culture => Culture.Population);
            Console.WriteLine(totalPopulation);
        }
    }
 
Hey OP did you ever figure out how to add new notables to a town? I would like to add a new "X the tanner" type character, with whom I can create new quests
 
Hey guys. I wrote a Patcher that allows adding new settlements (villages, towns and castles) to the game through separate modules. This is a slightly dirty solution. Source code, brief explanation of how it works, caveats and an example module can be found on the github page. Let me know if you have any questions via DM on discord (Trucker#3350)

 
Does anyone know how i can increase a reputation with someone i recruit from a settlement / village / town / city. I have found out how to increase the reputations of all notables in a settlement but cant work out how to target only one or how to get it to actually work when only recruiting from the leaders ect.
 
Are we limited to the 3 types of 'settlement' on the map? City, village, and castle? It would be nice to have a variety of different types, big, small versions on the map, and maybe additional things in a historical mod, like monasteries, abbeys etc.
 
Back
Top Bottom