AI Battle Agent

Users who are viewing this thread

Hexnibbler

Recruit
I observed that the agent individual AI often behave dangerously in battles.
There also is this tendency to "gather around" the same target. It can be easily seen when the enemies is routed or during a "charge".
Often, two similar blocks of similar infantry simultanously win a flank and lose the other due to formation not being aligned for some reason. And it allow to observe the same issue : massive amount of troops on both sides "grinding" their way to the middle to face the opposite team's group of soldiers that won his side of the clash.

I wrote a little mod to get a better idea of what is going on during battle with the targets.
So I have a custom "CustomBattleAgentLogic" class to make tests in custom battles. Overiding "public override void OnAgentHit(Agent affectedAgent, Agent affectorAgent, int damage, in MissionWeapon attackerWeapon)" and the "tick(float dt)".

I used 200vs200 imperial default infantry to gather various data.
The first batch of data was about "is the agent being struck (A) was himself targetting his attacker (B)?"
So I have 4 categories of answers :
A was targetting B and B was targetting A. This is "On Target".
A was not targetting B and B was targetting A. This if "Not Target" (or Off Target)
2 more cases : Collateral damage.
A was not targetting B and B was not targetting A either but hit him. This is "Not Target Coll" for collateral.
And the funny case of A was targetting B and B was not targetting A but struck him : On Target collateral.
any time a hit occured, I select his category and increase a counter for this category. Then I divide by the amount of hit of all category so far.

I collected data point over the course of a battle (which is reduce to a frontal clash of two similar formations) and plotted it. It's not a scientifically accurate work, but I found it interresting so I share :

Kj6DeU2.png


(note, you can right click and "get image url" to have a full scale view of those links if you have trouble reading the digits)

Both upper represent "On Target", lower represent "Off Target", Left side is "Intentional", Right side if "collateral". And the 5th one is the total of all hit ovetime.
Adding all value for the 4 graphs sums up to 1.0 : the total quantity of hits.
Ticks were recorded at 16ms.

1) The proportion of "intentional" hits increase over time because overtime casualties makes collateral damage less likely. Similarly, the collateral (right) decrease overtime.
2) The proportion of "OnTarget" is very low and the proportion of "OffTarget" is very high.
At tick 500, the OnTarget are only 13% + 8% for the collateral and the OffTarget are 39%+40%.
This means 2 things : in 79% of the cases, the agent being hit wasn't targetting his attacker. And in 48% the attacker himself wasn't targetting his victim.
It is important to note that it is "accumulated" : what matters is the "trend". It shows that 80% of the hit SO FAR have been landed on target that weren't "targetting" whoever struck them, and in 48% it was by accident. While this 48% is big and raise questions, it simply shows the chaotic mess of the first moment of the "clash". It still is believable behvior : any player who has played "on foot" in those melee knows that you just "smash whoever is somewhere there" without knowing or targetting anyone in particular.
3) the fifth curve shows as expected that the slope decrease overtime : less and less hit because there are less and less valid targets.

I came up with another question : How many people are targetting whoever is being struck ?
I simply maintained a list of agent that was updated at each tick for each agent : if his target has changed, I update the list of his old and his new target so that I can count how many agent are in those lists.
When a hit occured, I checked its category and added the size of that list to a counteer for that category. So that I can have an estimate of how many agent were targetting the victim of the strike when it got hit. The layout is the same : OnTarget, OnTargetColl, OffTarget, OffTargetColl and Total.

rG2av4V.png


First, there is a difference in shape between the "Intentional" and the "Collateral" : the intentional Off target especially looks like the "total" : it's big at first, then decrease and then rise a bit.
The collateral are relatively stable after the initial clash. Which makes sense : the less people targetting you, the more likely that being hit will be an accident. It stabilize overtime meaning those accident are less frequent at the end, which makes sense : the density of people lowers, which lowers the accidents rate.
Both "OnTarget" have lower enemy count than "OffTarget", which is to be expected : it is more likely to be hit by someone that is not your target if there are more people trying to hit you.
The value of the total is interresting too : it is confirms that in most cases, you are hit when you are targetted by more than 1 person. So it is consitent with the first set of plots where: AI Agent get hit by Agent that they do not target themselves. If 10 people fight 10 people ,but each strike was the result of a 5 vs 1, it means that at least 4 agents in each team attack someone that is already attacked while 4 agents are not being targetted at all. Note that the way it is counted doesn't imply that all agent "targetting" that victim were in any capacity of playing an active role. But it seems reasonable to assume they do based on empiric observation.

So I asked myself another question : how many attackers are targetting whoever managed to land a hit in this mess ?
I did a similar count, but this time instead of counting the "attacker" in the list of the victim, I counted those in the list of the attacker himself.

WkxumhD.png


All plots have the same shape. Sharp at first, and decrease overtime.

the collateral one will stay above 1 and will be higher than the "intentional" (more likely to hit someone by accident if the density is higher, and if the density is higher it is more likely to be a target.)
The initial clashes expose whoever is in a position to land a hit to many enemies which explains the high values, but it decreases super fast.
The "OffTarget" are interresting : the intentional one shows a sharp decline of the quantity of attackers an attacker that landed a hit has.
at 500 it is around 1 and decreasing, meaning there is on average LESS than one attacker for the agent that landed a hit. At tick 1000 it is below and decreasing.


Another good info would be to record how many people that landed a hit were themselves struck. But I haven't done it. I think this already offer a confirmation and an explanation of what is going on in melee :

AI targets on a variation of "enemy closest to me". It might weight in various thing.
1) we know that those being hit are more often hit by an agent they were not targetting themselves.
2) we know that those being hit are more often the target of many ennemies, leaving others without a threat.
3) we know that most hit that are being landed comes from those who were "left alone" so to speak.

It confirms that AI agent lack a mechanic to better select their target which ultimately leads to behaviors that are bad for its own health and not "believable".
Agent behavior are nice (1v1 tournament they show they can be challenging), but all that is useless in the melee clashes because of that targetting issue and I find that a bit sad that an existing feature that is already good is being wasted because of this "small" issue (yeah I know AI is easy to fix until yuo have to actually fix it without breaking what was working otherwise :p, but still)

Sadly I couldn't find a way to overwrite the individual agent "TargetAgent" which I assume is the property used by the engine to direct the individual agents to a target.
I assume that a method such as SetTargetAgent is not an option (or not an easy one) for various technical reason (otherwise I would wonder why it isn't exposed)
 

Hexnibbler

Recruit
added : It might be one of the reasons melee cavalry struggle so much versus infantry.

- horsemen are very ineffective when they "gather" around the same target (especially with spears/lances), and may block each other's momentum when running toward the same target

infantry are very effective when gathered around a single horseman.
 

froggyluv

Grandmaster Knight
NW
Wow nice science applied approach -well done. Couldnt if be possible that the reason is that A is attacking C while B lands successful blow to his unguarded flank or back?

Meaning, in a large battle if 2 soldiers in a sense "squared off" - orienting their direction to each other to exchange mortal blows - shields and blocking would prevent many initial successful attacks but if either of them get attacked by a 3rd party from an off center (not guarded) direction that will most likely be a successful hit?
 

Aurex

Veteran
WB
I collected data point over the course of a battle (which is reduce to a frontal clash of two similar formations) and plotted it. It's not a scientifically accurate work, but I found it interesting so I share
I will be honest, math and graphs hurt my brain. But I still read all your post, and I thank you for your insight into something that might very well be the main reason the AI feels so off and performs so badly, especially when it comes to cavalry.
I hope the power that be™ take notice of your discovery there. Could be that they know already, could be they don't. In case they don't, this would go a long way in fixing the battle AI.
 

Hexnibbler

Recruit
[...]Could be that they know already, could be they don't. In case they don't, this would go a long way in fixing the battle AI.
in both case I would like to have a way to "set" battle agent target in mod. I think many modders who have work a bit on that front will agree.
Now I understand a setTarget might be problematic to implement (because of *reasons*)
but the alternative would be that the C++ engine is left unchanged but call an overridable callback method in the c# world.
Such a callback would have a signature such as Agent CallbackSetAgent(...).
And the desired behavior would be that the C++ engine set the target of the agent in its own way, but once it assign the value to its internal parameters, call the callback and uses the Agent returned by that callback to override its own choice. This way modders can still modify the Agent target and the engine still control the issue of concurrent writing to its variables. I don't know how to ask devs for this and if it is do-able tho
 

Dejan

Community Manager
WBNWVCM&B
Interesting thread @Hexnibbler, awesome to see you dig into our combat AI mechanics from a more statistics-based perspective! Thumbs up on the effort. I've forwarded your thread to the combat team.
 

Hexnibbler

Recruit
Interesting thread @Hexnibbler, awesome to see you dig into our combat AI mechanics from a more statistics-based perspective! Thumbs up on the effort. I've forwarded your thread to the combat team.
good to know !

the above link point to a thread containing other stuff :
throwing weps stats
stats showing difference of "friendly blocking a hit" between "long" 1H, "short" 1H and 2H making short 1H & 2H better in melee, which is consistent with the unit empiric prowesses (I.E. maces of the legionaries, flax, etc)

and a link to "here" and to "bodypart being hit" stats (explaining the overwhelming effect of body/head armor):
Also had plots measuring the relative effectivness of sturgian shield vs projectiles in shieldwall vs empire shields (was signifcant.)
 

Antaeus

Sergeant at Arms
I'd hazard a guess that this is the root cause of some people's dislike for looters - particularly against melee cavalry. They can inadvertently isolate and overwhelm individual units within larger groups leading to the deaths of T5 units and even the player even when a battle is lopsided against the looters.
 

Hexnibbler

Recruit
I'd hazard a guess that this is the root cause of some people's dislike for looters - particularly against melee cavalry. They can inadvertently isolate and overwhelm individual units within larger groups leading to the deaths of T5 units and even the player even when a battle is lopsided against the looters.
yes AI trying to attack a looter (or anyone) next to another looter will ignore the danger of the "other" enemy, ending up being struck.
I sometimes even use "looters" in my army melee formation because they are fast and get "ahead", becoming the threat the enemy focus on and making my "real soldiers" safer through it.
 
Top Bottom