BL Coding Is there a way to create new Behaviors from BehaviorComponent?

Currently viewing this thread:

AshenWaltz

Recruit
Hello everyone,
I am currently working on a mod that aims to overhaul the battle AI currently implemented on Bannerlord. I am using Harmony and I already know what I need to do in order to change the AI during a battle. I have created my own tactics which use the behaviors already implemented by the native code. I, however, find the amount of formation behaviors (classes which implement the BehaviorComponent class and are used by the FormationAI) extremely limiting. With that in mind, I wanted to create behaviors of my own just like I did my own tactics, however, the class BehaviorComponent has two constructors, one empty construtor and another which receives the Formation it will be working upon. The first is marked as protected and I can access it from my own code, but the one which receives a formation is marked as Internal and is, therefore, unreachable from my code. Without the main constructor, I am unable to set and access the behaviors' formation and thus can't properly set its behavior.
I want to know if there is a way to bypass this problem and create custom behaviors or if I am wasting my time and can just override the already existing ones.

Thank you in advance,
Ashenwaltz
 
Solution
Hi @AshenWaltz
I have been working on custom tactics and behaviors and this is how I approached this problem.

First, as skoomy said, it is better to inherit from an existing Behavior so the formation is properly set in the part of the code you cannot reach.
If you inherit classes such as BehaviorDefend or BehaviorCharge, there will be a public constructor taking the formation parameter.
This is the start of my CustomBehavior class:
C#:
internal class CustomBehavior : BehaviorDefend
{
    public CustomBehavior(Formation formation) : base(formation)
    {
    }

    // more stuff
}

Then, I create my own Formation attribute inside my CustomBehavior to be able to mess around with the formation methods...
So I looked at the BehaviorComponent class and see what you mean: there are two constructors, one taking a Formation object as input and just a regular BehaviorComponent() constructor. Okay, so I had a look at another class that derives from BehaviorComponent (I used BehaviorCharge, for example) and its constructor is written as:

public BehaviorCharge(Formation formation)
: base(formation)
{
CalculateCurrentOrder();
base.BehaviorCoherence = 0.5f;

}

The BehaviorCoherence member belongs to the base class and it is defined as internal float BehaviorCoherence, so I'm assuming that it would be possible to modify internal Formation formation through the child class's constructor like this:

public BehaviorCharge(Formation formation)
: base(formation)
{

base.formation = formation;
// other stuff ...
}


I dunno if this is more or less what you're looking for, but I do hope it helps!
 
Upvote 0

AshenWaltz

Recruit
Hey thanks for the response. That was more or less what I've been trying to do but the problem is the internal keyword exactly. In other classes which extend BehaviorComponent, they always extend the base class with reference to the formation such as:
public BehaviorCharge(Formation formation)
: base(formation)
{
CalculateCurrentOrder();
base.BehaviorCoherence = 0.5f;

}
But, since we are not working on the taleworlds.mountandblade.dll we cannot access both the behaviorComponent(Formation formation) constructor and the base.formation. I have tried what you sugested but my IDE doesn't even recognize those methods. It says there is no constructor which takes one argument for BehaviorComponent.
erL2C9T.png
 
Upvote 0

Kazet

Recruit
Hi @AshenWaltz
I have been working on custom tactics and behaviors and this is how I approached this problem.

First, as skoomy said, it is better to inherit from an existing Behavior so the formation is properly set in the part of the code you cannot reach.
If you inherit classes such as BehaviorDefend or BehaviorCharge, there will be a public constructor taking the formation parameter.
This is the start of my CustomBehavior class:
C#:
internal class CustomBehavior : BehaviorDefend
{
    public CustomBehavior(Formation formation) : base(formation)
    {
    }

    // more stuff
}

Then, I create my own Formation attribute inside my CustomBehavior to be able to mess around with the formation methods and attributes.
(this attribute will basically be a duplicate of the unreachable one)
This is in my CustomBehavior class:
C#:
private void DoStuffExample()
{
    Formation.MovementOrder = MovementOrder.MovementOrderAdvance;
    Formation.FacingOrder = FacingOrder.FacingOrderLookAtEnemy;
    Formation.ArrangementOrder = ArrangementOrder.ArrangementOrderShieldWall;
    Formation.FiringOrder = FiringOrder.FiringOrderFireAtWill;
    Formation.WeaponUsageOrder = WeaponUsageOrder.WeaponUsageOrderUseAny;

    Formation.ApplyActionOnEachUnit(ProcessAgent);
}

public Formation Formation;

Then, when I assign this behavior to a formation (in a Tactic class), I set the attribute.
This is in my CustomTactic class:
C#:
CustomBehavior behavior = _mainInfantry.AI.SetBehaviorWeight<CustomBehavior>(1f);
behavior.Formation = _mainInfantry;

Hope it helps.
 
Upvote 1
Solution

AshenWaltz

Recruit
Hello @Kazet,
Thank you so much for your answer. It actually worked and I managed to get a behavior working. Thank you so much. I am a little frustrated because your solution is quite similar to a solution I originally tried but was unsuccessful. Turns out I only had to change a little detail in my original solution to get to yours and have it working. Thank you so very much for your help! I've been having this issue for weeks now.
 
Upvote 0
Top Bottom