/ Modding / 270 views

[Mount & Blade II: Bannerlord] Modifying game data with dnSpy to alter the recruitment speed of prisoners

As an experienced player who has been playing since the first day of release, I have accumulated nearly 700 hours of gameplay and have explored various genres. In higher difficulties, besides focusing on optimizing the human body flow, the consumption of advanced troops in field battles can be quite significant. I wanted to speed up the recruitment of high-level troops among the captives to quickly replenish my forces. However, I couldn’t find a suitable mod or the desired functionality. Therefore, I would like to share a method of modifying game data using dnSpy, a tool I used.

dnSpy is an open-source .NET assembly decompiler and debugger that can be used to analyze and modify .NET assemblies. It can decompile IL code from .NET assemblies and convert them into C# code for viewing and editing. In addition to decompilation, dnSpy also supports debugging .NET assemblies, including features like step-by-step debugging and breakpoints. With dnSpy, users can gain a deep understanding of the internal implementation of .NET programs and make modifications and optimizations as needed. In this case, we will use dnSpy to modify the TaleWorlds.CampaignSystem.dll file in Mount & Blade II: Bannerlord, which contains the data we want to modify. dnSpy can also be used to modify other games developed using C# or Unity, such as Rain’s Adventure 2.

First, after installing dnSpy, open the following file in the Mount & Blade folder:
Mount & Blade II Bannerlord\bin\Win64_Shipping_Client\TaleWorlds.CampaignSystem.dll
(It’s recommended to make a backup beforehand in case you want to revert the changes). The interface should look like the image below:

Click on the triangle next to TaleWorlds.CampaignSystem.GameComponents on the left side to view the data for certain modules in the game. You can determine which module you want to modify based on its name. For example, DefaultBattleRewardModel defines the rewards obtained after battles, including reputation, lord relations, loot quality and quantity, etc. In this case, we want to modify the DefaultPrisonerRecruitmentCalculationModel, which is responsible for calculating the recruitment of prisoners.

For example, the function GetConformityNeededToRecruitPrisoner calculates the conformity needed to recruit a prisoner soldier. From the function, we can see that this value is only related to the soldier’s level and is calculated as (level + 6) squared – 10. So, using dnSpy, you can also discover the game mechanics behind the scenes.

public override int GetConformityNeededToRecruitPrisoner(CharacterObject character)
{
    return (character.Level + 6) * (character.Level + 6) - 10;
}

In this case, we only want to modify the conformity gained per hour from prisoners. Right-click on the function name and select "Edit Method":

Modify the code as follows:

public override int GetConformityChangePerHour(PartyBase party, CharacterObject troopToBoost)
{
    ExplainedNumber explainedNumber = new ExplainedNumber(10f, false, null);
    if (party.LeaderHero != null)
    {
        explainedNumber.Add((float)party.LeaderHero.GetSkillValue(DefaultSkills.Leadership) * 0.15f, null, null);
        explainedNumber.Add((float)party.LeaderHero.GetSkillValue(DefaultSkills.Charm) * 0.2f, null, null);
        explainedNumber.Add((float)party.LeaderHero.GetSkillValue(DefaultSkills.Steward) * 0.15f, null, null);
    }
    if (troopToBoost.Tier <= 3 && party.MobileParty.HasPerk(DefaultPerks.Leadership.FerventAttacker, true))
    {
        explainedNumber.AddFactor(DefaultPerks.Leadership.FerventAttacker.SecondaryBonus * 0.01f, null);
    }
    if (troopToBoost.Tier >= 4 && party.MobileParty.HasPerk(DefaultPerks.Leadership.StoutDefender, true))
    {
        explainedNumber.AddFactor(DefaultPerks.Leadership.StoutDefender.SecondaryBonus * 0.01f, null);
    }
    if (troopToBoost.Occupation != Occupation.Bandit && party.MobileParty.HasPerk(DefaultPerks.Leadership.LoyaltyAndHonor, true))
    {
        explainedNumber.AddFactor(DefaultPerks.Leadership.LoyaltyAndHonor.SecondaryBonus * 0.01f, null);
    }
    if (troopToBoost.IsInfantry && party.MobileParty.HasPerk(DefaultPerks.Leadership.LeadByExample, false))
    {
        explainedNumber.AddFactor(DefaultPerks.Leadership.LeadByExample.PrimaryBonus * 0.01f, null);
    }
    if (troopToBoost.IsRanged && party.MobileParty.HasPerk(DefaultPerks.Leadership.TrustedCommander, false))
    {
        explainedNumber.AddFactor(DefaultPerks.Leadership.TrustedCommander.PrimaryBonus * 0.01f, null);
    }
    if (troopToBoost.Occupation == Occupation.Bandit && party.MobileParty.HasPerk(DefaultPerks.Roguery.Promises, true))
    {
        explainedNumber.AddFactor(DefaultPerks.Roguery.Promises.SecondaryBonus, null);
    }
    return MathF.Round(explainedNumber.ResultNumber);
}

In this modified code, I have adjusted the base conformity gained per hour for each prisoner based on the leadership, charm, and stewardship skills of the party leader. You can add more options if desired, such as the reputation of the character.

After making the modifications, click on "Compile". If there are no other changes, click on "File" and select "Save Module" to save the file. Now, when you enter the game, the changes should take effect without the need to start a new game.

The above steps outline the process of modifying game data using dnSpy.

Eysent
[Victoria 3] Victorial 3 Mod Tutorial – Modifying Maximum Building Capacity for a Single Building
[Victoria 3] Victorial 3 Mod Tutorial – Modifying Maximum Building Capacity for a Single Building
[DOS2] Detailed Modding Tutorial with Examples 01:Basic Introduction to Tools and Examples of Modifying Skills
[DOS2] Detailed Modding Tutorial with Examples 01:Basic Introduction to Tools and Examples of Modifying Skills
[DoS 2] Repair the bug of  incorrect DamageSourceType in The Divinity Engine 2
[DoS 2] Repair the bug of incorrect DamageSourceType in The Divinity Engine 2

0

  1. This post has no comment yet

Leave a Reply

Your email address will not be published. Required fields are marked *