Page 1 of 1

Static script attacks

PostPosted: 02 Jan 2014, 13:52
by The Dark Lord
I just tested TNL 7, and something odd occured and it took me a while to figure out what it was.
I use these attacks in the script for player A:
  Code:
!SET_AI_ATTACK TYPE 0 !SET_AI_ATTACK TOTAL_AMOUNT 36 !SET_AI_ATTACK TROUP_AMOUNT 0 1 !SET_AI_ATTACK TROUP_AMOUNT 1 2 !SET_AI_ATTACK TROUP_AMOUNT 2 0 !SET_AI_ATTACK TROUP_AMOUNT 3 0 !SET_AI_ATTACK TARGET 2 SET_AI_ATTACK POSITION 133 35 !COPY_AI_ATTACK 0 !SET_AI_ATTACK TYPE 0 !SET_AI_ATTACK TOTAL_AMOUNT 36 !SET_AI_ATTACK TROUP_AMOUNT 0 1 !SET_AI_ATTACK TROUP_AMOUNT 1 1 !SET_AI_ATTACK TROUP_AMOUNT 2 1 !SET_AI_ATTACK TROUP_AMOUNT 3 0 !SET_AI_ATTACK TARGET 2 SET_AI_ATTACK POSITION 133 35 !COPY_AI_ATTACK 1
At the start of the mission, nothing happens. Quite early in the mission, this player (A) gets attacked. And after the attack, somehow these two attacks got triggered. The AI had only 26 units on defence positions with importance 1 so that seemed impossible to me. However, after/during the attack on player A, he apparently swapped the defence position of a group of 5 knights with a group of 15 knights, and that counts up to exactly 36 units.
Now here is the thing: as it is now, TOTAL_AMOUNT is the total amount of units on defence positions with importance 1. What TOTAL_AMOUNT should be is the total amount of units that attack. So with the first attack, the AI should attack with 36 soldiers spread out over 2 groups of anti-cavalry units and 1 group of melee. Whether that's 35 pikemen and 1 sword fighter doesn't matter, but it must be 36 units. What happens in the Remake is that the AI attacks with 16 units (4 crossbowmen, 8 pikemen, 4 sword fighters, both attacks get triggered).

Re: Static script attacks

PostPosted: 02 Jan 2014, 15:19
by Lewin
You're right, there are some issues here.

However, the way you suggested it should work is a bit vague. How does the AI choose whether to take 1 pikemen and 35 swordsmen or 33 pikemen and 3 swordsmen or something else? What should the AI do if they are asked to bring 36 men in 1 mounted group, and in defence positions they have two groups of 20 knights (defence formations is set to 20 men per group). Take 20 from one group and 16 from the other then link them together and attack? What if those two groups are far apart? Those rules start getting very complicated, it would be very messy to program it like that. It would also be quite unpredictable for the mission author with all the splitting and linking, and choosing whether to take 35 pikemen and 1 swordsmen or some other random arrangement.

What do we want from the attack system? It doesn't need to match TSK/TPR exactly since we'll never get the AI behaviour exactly the same so missions need testing anyway, but it would be nice if it matches TSK/TPR closely so most of the time the attacks will just work. It should also be predictable for the mission author, not splitting and linking two far away groups then launching the attack. And the rules should be fairly simple, both so that mission authors can understand it and so that the code is understandable and maintainable for us.

Maybe we can do something similar that is a bit more predictable?

1. Attacks should only be launched when the AI has TOTAL_AMOUNT soldiers of any of the types specified by TROUP_AMOUNT, instead of when it has TOTAL_AMOUNT of ANY soldier which is how it works now. It must also have the number of groups of each type specified by TROUP_AMOUNT (regardless of how many units are in the groups).

2. The AI will not split or link groups to get the numbers exactly right, it will take the number of groups of each type specified by TROUP_AMOUNT, always choosing the largest group within each type first. The mission author should set the defence formations so that the right amount of troops will be taken (if they ask for 36 to be taken in one group but set the formations to 10 per group, then only 10 will be taken)

3. The TakeAll command means the AI will choose groups at random until it has at least TOTAL_AMOUNT soldiers. Is that correct? I've never understood TakeAll really. Currently it makes the AI take ALL available groups to attack, that's how I thought it worked since the name implies it, I guess a better name would be "choose groups randomly".

This should work fairly similarly to the way you described, and yet with much simpler rules and requirements. Or maybe you have a better idea? What do you think?

Re: Static script attacks

PostPosted: 02 Jan 2014, 19:26
by The Dark Lord
How does the AI choose whether to take 1 pikemen and 35 swordsmen or 33 pikemen and 3 swordsmen or something else?
That depends on how he recruits them. The thing is: as soon as he has those 36 troops he should attack.
What should the AI do if they are asked to bring 36 men in 1 mounted group, and in defence positions they have two groups of 20 knights (defence formations is set to 20 men per group). Take 20 from one group and 16 from the other then link them together and attack?
Depends: if they have those 40 knights from the start, they should attack with all 40. If they recruit them, attack as soon as there are 36 mounted units. (At least that's how it was in TPR.)
So in my opinion, there doesn't have to be any linking and splitting. :)
1. Attacks should only be launched when the AI has TOTAL_AMOUNT soldiers of any of the types specified by TROUP_AMOUNT, instead of when it has TOTAL_AMOUNT of ANY soldier which is how it works now. It must also have the number of groups of each type specified by TROUP_AMOUNT (regardless of how many units are in the groups).

2. The AI will not split or link groups to get the numbers exactly right, it will take the number of groups of each type specified by TROUP_AMOUNT, always choosing the largest group within each type first. The mission author should set the defence formations so that the right amount of troops will be taken (if they ask for 36 to be taken in one group but set the formations to 10 per group, then only 10 will be taken)

3. The TakeAll command means the AI will choose groups at random until it has at least TOTAL_AMOUNT soldiers. Is that correct? I've never understood TakeAll really. Currently it makes the AI take ALL available groups to attack, that's how I thought it worked since the name implies it, I guess a better name would be "choose groups randomly".
I fully agree with everything behind 1.
Concerning 2: I don't think they should take the largest group, but the first or last in the script (with defence importance 1 (or without defence positions!)). I don't remember whether it was the first or last in TPR, but it was certainly either of those. If you just take the largest group there might be holes in the AI's defence. I also think an attack just should not happen if the author asks for something impossible (36 units in 1 group with TROUP_PARAM < 36).
Concerning 3: That's mostly right, indeed. TAKE_ALL was probably meant as a lazy but very handy way for having to script just one attack instead of several attacks. I will show you how TAKE_ALL works (in TPR!) with an example:
  Code:
!SET_AI_ATTACK TYPE 2 !SET_AI_ATTACK TOTAL_AMOUNT 72 !SET_AI_ATTACK TAKEALL !SET_AI_ATTACK TARGET 0 !COPY_AI_ATTACK 1
If the AI has 72 soldiers or more, he will attack and keep attacking (because it's a TYPE 2 attack) until his total amount of 'free' troops < 72.
If TOTAL_AMOUNT would have been 1, the AI would attack with just one group (I'm not completely sure which one. Again, probably the first or last in the script with defence importance 1). However, this attack gets triggered every time attacks are updated (once again I have no idea how often that is) as long as the AI has > 0 soldier(s). And actually, the AI will take all free soldiers eventually... Even when the previous group isn't dead, the AI might already select a new group to attack with and so he will attack with more groups simultaneously. So even if you would use !SET_AI_ATTACK TOTAL_AMOUNT 72 but the AI has 300 free troops at the start... in TPR he would send 72 troops at first and with the next 'update' 72 more, etcetera.
So all in all: using a TOTAL_AMOUNT of 1 is a nice way to make sure the AI keeps attacking with everything until his whole army is completely destroyed. And using a higher TOTAL_AMOUNT is nice if the AI still has to recruit troops. That's how it should be, but I would like it even more extreme. I think it would be even better if the AI just took ALL free soldiers, even if TOTAL_AMOUNT is only 1. It does not look good when first one group attacks, and then another one, and another one, and so forth. It would fit the name of TAKE_ALL better, and if you really want to attack with 72 units while the AI has more than that, just use a TYPE 0 or TYPE 1 attack. :)

Re: Static script attacks

PostPosted: 03 Jan 2014, 02:51
by Lewin
Thanks for your response :)
What should the AI do if they are asked to bring 36 men in 1 mounted group, and in defence positions they have two groups of 20 knights (defence formations is set to 20 men per group). Take 20 from one group and 16 from the other then link them together and attack?
Depends: if they have those 40 knights from the start, they should attack with all 40. If they recruit them, attack as soon as there are 36 mounted units. (At least that's how it was in TPR.)
So in my opinion, there doesn't have to be any linking and splitting. :)
Wait, so you're saying that if I order an attack with 1 mounted group, the AI could send 2 groups in order to reach the required TOTAL_AMOUNT? Below you said:
I also think an attack just should not happen if the author asks for something impossible (36 units in 1 group with TROUP_PARAM < 36).
which makes sense.

But what if we had a situation like this:
AI Attack: 36 men in 2 mounted groups
Groups available to the AI, ones that should be used first at the top:
5 knights
20 knights
20 knights

The AI would try to send the groups 5 + 20, but then realise that doesn't equal 36 so abort the attack. The group to be used first could be the one that the AI is still equipping so it only has 5 men. Should partial groups always be a lower priority than full groups? (so 20+20 is taken) That could leave gaps in the AI's defences like you said...
That's how it should be, but I would like it even more extreme. I think it would be even better if the AI just took ALL free soldiers, even if TOTAL_AMOUNT is only 1. It does not look good when first one group attacks, and then another one, and another one, and so forth. It would fit the name of TAKE_ALL better, and if you really want to attack with 72 units while the AI has more than that, just use a TYPE 0 or TYPE 1 attack. :)
That's actually how TAKE_ALL works at the moment, if the AI has TOTAL_AMOUNT or more troops, it sends all available troops to attack. So no change necessary there :)

Re: Static script attacks

PostPosted: 03 Jan 2014, 09:12
by The Dark Lord
Wait, so you're saying that if I order an attack with 1 mounted group, the AI could send 2 groups in order to reach the required TOTAL_AMOUNT?
My bad, that's not right. The attack would never happen. If the attack asked for 2 groups they would take 40 knights.
But what if we had a situation like this:
AI Attack: 36 men in 2 mounted groups
Groups available to the AI, ones that should be used first at the top:
5 knights
20 knights
20 knights

The AI would try to send the groups 5 + 20, but then realise that doesn't equal 36 so abort the attack. The group to be used first could be the one that the AI is still equipping so it only has 5 men. Should partial groups always be a lower priority than full groups? (so 20+20 is taken) That could leave gaps in the AI's defences like you said...
That's a mistake of the author. He should change TOTAL_AMOUNT to 35 or put the 5 knights below the others in the script. If partial groups CAN be taken for an attack, it should be done, because partial groups are usually the one with lowest priority (since the AI recruits troops and adds them to the ones with highest priority first). However, if there are 2 free groups with 20 knights already and it's the only way of getting 36 or more than 36 troops to attack with, those will be taken.

Re: Static script attacks

PostPosted: 03 Jan 2014, 10:12
by Lewin
But what if we had a situation like this:
AI Attack: 36 men in 2 mounted groups
Groups available to the AI, ones that should be used first at the top:
5 knights
20 knights
20 knights

The AI would try to send the groups 5 + 20, but then realise that doesn't equal 36 so abort the attack. The group to be used first could be the one that the AI is still equipping so it only has 5 men. Should partial groups always be a lower priority than full groups? (so 20+20 is taken) That could leave gaps in the AI's defences like you said...
That's a mistake of the author. He should change TOTAL_AMOUNT to 35 or put the 5 knights below the others in the script. If partial groups CAN be taken for an attack, it should be done, because partial groups are usually the one with lowest priority (since the AI recruits troops and adds them to the ones with highest priority first). However, if there are 2 free groups with 20 knights already and it's the only way of getting 36 or more than 36 troops to attack with, those will be taken.
It's not a mistake of the author if those groups all started empty and the AI equipped them himself. In that situation the lowest priority defence position will be the last to be filled so it's likely that won't be completely full.

The algorithm to choose the which groups to take would become very complicated like that. Imagine a situation like this:
Choose 3 groups that add up to at least 36 soldiers: (groups at the start of the list should be taken if possible)
6, 9, 12, 10, 17, 20

There's lots of ways of solving this, and you run into awkward questions like "is 6 + 10 + 20 a better choice than 9 + 12 + 17?" I know it's an unlikely situation but to implement it the way you described I need to make it handle ANY situation. I'd rather simplify things, because at the end of the day it's really doesn't make that much of a difference which groups are selected, as long as under "normal" circumstances (when the top groups have enough units) the groups at the top of the list are taken.

What about something like this? When required to take X number groups: "Try the top X groups on the list. If they doesn't have enough soldiers, take the X largest groups from the list. If they don't have enough then abort the attack" This means if the author is placing the groups he can make sure it works how he expects, but if the AI is equipping the groups and ends up with some small ones the attack will still happen.

In regards to ending up with holes in the AI's defence, higher priority defence positions will be automatically restocked from lower priority positions, so it doesn't really matter.

Re: Static script attacks

PostPosted: 03 Jan 2014, 11:04
by The Dark Lord
It's not a mistake of the author if those groups all started empty and the AI equipped them himself.
If the AI equipped those troops, he would attack as soon as there are 36 (20+16), so 20 + 20 + 5 would never happen. UNLESS you use a TYPE 1 attack, which is silly because you can't predict how much troops the AI has (TYPE 1 attacks use a COUNTER and thus are timed).
Your solution sounds okay to me. I will just make sure my script uses the right attacks so a situation like you described will never occur. :P

Re: Static script attacks

PostPosted: 30 Apr 2014, 12:45
by Lewin
@The Dark Lord:
Ok, I finally got around to implementing this :) I did it slightly differently than we discussed.

First we exclude all the groups that can't attack (in important/front line defence positions). Groups are also sorted in priority order, so the last (lowest priority) defence positions will be used first.

Conditions for attack to occur:
1. Count the total number of units in groups of the types requested by the attack (or all groups if TAKEALL). That number must be at least TOTAL_MEN (so if the AI has 100 knights but the attack only takes melee groups, then those knights won't be counted against TOTAL_MEN).
2. [only if not TAKEALL] Must have at least the number of each group requested by the attack (so if attack requests 2 melee 1 ranged, AI must have at least that many of those groups)

How TAKEALL attack is ordered:
Repeatedly send one group of each type (one melee, one ranged, one mounted, one anti-horse, then another melee, another ranged, etc.), stopping as soon as we have sent TOTAL_MEN number of units.

How non-TAKEALL attack is ordered:
1. Send the number of groups of each type requested by the attack.
2. If the total number of units sent in step 1 is less than TOTAL_MEN, we keep sending 1 extra group of each type requested by the attack stopping immediately once we reach TOTAL_MEN number of units.

So as an example of step 2 for a non-TAKEALL attack:
Attack asks for 20 units, 1 melee group and 2 ranged group.
Groups available (in order of priority): 10 militia, 10 knights, 6 militia, 3 bowmen, 3 bowmen
In step 1 we send the 10 militia and 2x groups of 3 bowmen, since the attack asked for that many groups of each of those types.
In step 2 we see that the total units we sent is only 16, which is less than 20. So we send the next available group, the 6 militia. Now we have sent enough units so we stop. Note that step 2 doesn't take the knights because the attack only asked for melee and ranged.

How does that sound? It means the AI can send more groups than you asked for, but only when they haven't sent TOTAL_MEN number of units. But if you setup your attacks properly that shouldn't happen anyway.

When the RC comes out, can you please test this system on your TNL missions to make sure it is working as you would expect it to? You understand how the AI should behave better than I do so I'd really appreciate your help :)

Re: Static script attacks

PostPosted: 30 Apr 2014, 16:08
by pawel95
I didn´t read the whole topic about, sorry but I´m lazy these days :?
Can you just tell me if this, what you just implemented will bring any consequences to the TSK and TPR Campaign?

Re: Static script attacks

PostPosted: 01 May 2014, 01:52
by Lewin
I didn´t read the whole topic about, sorry but I´m lazy these days :?
Can you just tell me if this, what you just implemented will bring any consequences to the TSK and TPR Campaign?
I don't blame you, this topic is quite long and boring :P

Yes these changes will have consequences for the campaigns. The AI attacks should now behave much more like TPR. The biggest change is probably that TAKEALL attacks used to bring ALL soldiers, now they will only take the amount the attack specifies. So it might make those attacks smaller. However for normal attacks they might be made bigger in some situations, because previously an attack like this:
Total amount: 36
Groups: 1 melee, 1 ranged, 1 mounted
Could be launched with just 1 militia, 1 bowmen and 1 scout (in the worst case). Now it will take at least 36 soldiers on the attack as intended.

So hopefully these changes will improve the campaigns, but of course it needs testing. I did some basic testing of a few campaign missions and the attacks seemed to be working nicely. But when the RC comes out I'd appreciate it if people who know the campaigns better than I do could test it and make sure they're still balanced.