COMPANION SPAWNING EXPLANATION
Hey so I am not a programmer or know anything C# but I have managed to crack the number limit of companions. Here is the explanation of how it works. Apologies for bad coding or explaining things wrong.
AT THE START IT CREATES A NEW LIST
so here, it creates companion templates list and selects all the NPC character that have is template = "true" and occupation= "wanderer"
C#:
// Token: 0x060025A2 RID: 9634
public void OnNewGameCreated(CampaignGameStarter campaignGameStarter)
{
this._companionTemplates = new List<CharacterObject>(from x in CharacterObject.Templates
where x.Occupation == Occupation.Wanderer
select x);
this._nextRandomCompanionSpawnDate = CampaignTime.WeeksFromNow(this._randomCompanionSpawnFrequencyInWeeks);
this.SpawnUrbanCharacters();
}
SPAWNING YOUR COMPANIONS
So here it spawns the companions and essentially a clamp randomiser varying to the size of your list. It essentially gives you around 25 (+/-5) companions.
C#:
// Token: 0x060025B2 RID: 9650
private void SpawnUrbanCharacters()
{
int count = this._companionTemplates.Count;
float num5 = MathF.Clamp(25f / (float)count, 0.33f, 1f);
foreach (CharacterObject companionTemplate in this._companionTemplates)
{
if (MBRandom.RandomFloat < num5)
{
this.CreateCompanion(companionTemplate);
}
}
this._companions.Shuffle<Hero>();
}
SETTING COMPANION LIMIT
so I changed the code into a loop and used another method of creating a companion from the "weeklytick" So here I can have as much as I want with the exact number. AWESOME!
C#:
// Token: 0x060025B2 RID: 9650
private void SpawnUrbanCharacters()
{
int num5 = 200;
for (int n = 0; n < num5; n++)
{
CharacterObject randomElement = (from x in this._companionTemplates
where !this._companions.Contains(x.HeroObject)
select x).GetRandomElement<CharacterObject>();
this.CreateCompanion(randomElement ?? this._companionTemplates.GetRandomElement<CharacterObject>());
}
this._companions.Shuffle<Hero>();
}
BUT I CAN'T FIND MY COMPANION, THEY ARE NOT THERE
The reason why you can find your companions is they are not activated yet. They don't exist yet. What is happening is an encyclopedia bug. On the create companion method, they have a part where they randomise a settlement to each new companion created.
After a short while of running. The encyclopedia updates show these locations which can also be castles. Just to give information out I guess.
C#:
// Token: 0x06003365 RID: 13157
private void CreateCompanion(CharacterObject companionTemplate)
{
settlement3 = ((list.Any<Settlement>() ? list.GetRandomElement<Settlement>().Village.Bound : settlement3) ?? Settlement.All.GetRandomElement<Settlement>());
}
HOW THEY ARE ACTUALLY ACTIVATED
Companions are actually activated when you enter a town and nothing else using this code. Essentially the IF is if the main party is in a town and the companionsettlement list show there are no companions here but they are companion still need to be activated,
spawn a new companion from the list.
The chose of a companion of again randomised but chosen to fit closest the settlement you in by the culture and settlement they were assigned. So unfortunately until they are actually activated you can not look in your encyclopedia at the beginning choose the one you want. Only once you have gone into a town and they are randomly chosen will you be able to get them.
C#:
// TaleWorlds.CampaignSystem.SandBox.CampaignBehaviors.UrbanCharactersCampaignBehavior
// Token: 0x060025AE RID: 9646
public void OnSettlementEntered(MobileParty mobileParty, Settlement settlement, Hero hero)
{
if (mobileParty == MobileParty.MainParty && settlement.IsTown && !this._companionSettlements.ContainsKey(settlement) && this._companions.Count > 0)
{
int index = 0;
MBRandom.ChooseWeighted<Hero>(this._companions, (Hero x) => (float)((x.Culture == settlement.Culture) ? 5 : 1), out index);
Hero hero2 = this._companions[index];
hero2.ChangeState(Hero.CharacterStates.Active);
EnterSettlementAction.ApplyForCharacterOnly(hero2, settlement);
this._companionSettlements.Add(settlement, CampaignTime.Now);
this._companions.Remove(hero2);
}
}
THE PROBLEM
So the problem with this code is that what is happening is after you active the COMPANION it puts in a _companionSettlements.list . assigning that town to be full. Even if you recruit that companion. So after you enter a town for the first it won't spawn another companion until the next _nextRandomCompanionSpawnDate. whish is as default 6 weeks. This is the idea to make look like the companions are moving around but in reality what the code does is. It removes the _companionSettlements.list and deactivated the companions that are in the town and start all over again. So essentially it will be like you never been in that town before.
So essentially the only way to get all your companions is you visit the very single town once will spawn a new companion until your companion number is finished.
THE FIX
So simple fix for this is to simply remove this part of the code and it just stops the activation adding the settlement onto the list. The IF query still thinks it's empty and will spawn another one. So going into a town, leaving and going back in again does the trick and brings out your companions!! ( banner lord essential mod is great here as allows you to click to leave. )
C#:
this._companionSettlements.Add(settlement, CampaignTime.Now);
AND THERE YOU HAVE IT!!!! 200 companions filling the towns!!
NEED YOUR HELP
now I actually need your help. So I have altered the code and everything but no idea how to make it into a standalone mod. I managed to create a project but no idea how to override the code or why it won't reference the method that is in the same class. Ive put the project in github but trust me it probably horrible wrong. I also tried to use harmony by copying clantweaker mod but yeah its probably all wrong.
https://github.com/haybie/CompanionHoarder
I have also made a mod here with the campaignsystem.dll so you can all see it as well.
https://www.nexusmods.com/mountandblade2bannerlord/mods/170
KNOWN ISSUES
So the only main issue I have tested is that the tavern has only 5 slots available. If you keep going in and out of the same town then they start to populate the actual main town where merchants and gang leaders are. Which again is fine but of course there are only a set amount of character paths so after a while they all do start bunching together.
Once however you get to page 10 of the characters so around 50 visits...... the GUI breaks and puts all the characters into one slot.
The real question is WHY THE HELL YOU VISITING THE SAME TOWN MORE THAN 60 times in one go.
LAST THING
Oh last thing I did as well. When the 6 weeks happened there also code to spawn a new companion every time so I just turned this over. But the loop you can spawn as many as you want every 6 weeks, I tried 25- 50 everytime. But you might want to set a limit.
C#:
if (this._nextRandomCompanionSpawnDate.IsPast)
{
int num = 0;
for (int i = 0; i < num; i++)
{
CharacterObject randomElement = (from x in this._companionTemplates
where !this._companions.Contains(x.HeroObject)
select x).GetRandomElement<CharacterObject>();
this.CreateCompanion(randomElement ?? this._companionTemplates.GetRandomElement<CharacterObject>());
this._nextRandomCompanionSpawnDate = CampaignTime.WeeksFromNow(this._randomCompanionSpawnFrequencyInWeeks);
}
}
FURTHER TESTING NEEDED
I haven't actually tried to hire 200 companions yet so I don't actually if this breaks the game.
I haven't tried going into battle with 200 companions so again do not know if this will break the game.
FIXES I HAVE TRIED
A couple of different things I have already tried and it crashed.
Increase the number of companions spawned in a tavern at a time
I tried adding a simple loop around the spawning part and no matter what I do it just crashes as soon as you enter the town.
I also tried just copying the entire block so its just repeat process but same effect.
C#:
// Token: 0x06003360 RID: 13152 RVA: 0x000D56C8 File Offset: 0x000D38C8
public void OnSettlementEntered(MobileParty mobileParty, Settlement settlement, Hero hero)
{
if (mobileParty == MobileParty.MainParty && settlement.IsTown && !this._companionSettlements.ContainsKey(settlement) && this._companions.Count > 0)
{
int num5 = 2;
for (int n = 0; n < num; n++)
{
int index = 0;
MBRandom.ChooseWeighted<Hero>(this._companions, (Hero x) => (float)((x.Culture == settlement.Culture) ? 5 : 1), out index);
Hero hero2 = this._companions[index];
hero2.ChangeState(Hero.CharacterStates.Active);
EnterSettlementAction.ApplyForCharacterOnly(hero2, settlement);
this._companions.Remove(hero2);
}
}
}
ACTIVATE COMPANIONS WHEN THEY ARE CREATED
I tried moving the activation process when the companion is created which work great and even allowed companions to spawn on the castles they were assigned and the encyclopedia was correct as soon as the game started.
Unforntately , this only works for a maximum of 15-20 companions. Assuming the coding is too linear and a lot to process as campaign starts, It crashes when you start new games and loads very slow when you try with 10 companions but just about works.
C#:
// Token: 0x060025B3 RID: 9651
private void CreateCompanion(CharacterObject companionTemplate)
int index = 0;
hero = this._companions[index];
hero.ChangeState(Hero.CharacterStates.Active);
EnterSettlementAction.ApplyForCharacterOnly(hero, settlement3);
this._companionSettlements.Add(settlement3, CampaignTime.Now);
this._companions.Remove(hero);
} {
WELL, I HOPE THIS HELPS!!
I don't mind people making their own limit, I just ask to be credited for this haha. Glad to help people understand this part more.