[General] AI trains way more defenders than I've ordered it to

Level 27
Joined
Dec 3, 2020
Messages
881
So I made an .ai script for a human bot.
I order the AI to have 2 footmen, 1 footman archer, 1 sorceress, 1 captain and 1 Doril Aran (custom unit, non hero) as campaign defenders.
Initially it's fine but after like 16 minutes I update the defenders by making them ---> 3 footmen, 2 footman archers, 2 sorceresses, 1 knight, 1 captain and 1 Doril Aran.
When this happens, the AI just uses 20 units as defenders, way more than I have told it to use!

1736372821328.png


As you can see, it even uses Dwarven Battlepriests as campaign defenders.
Is there a way to easily fix this???
I've attached the .ai file on this thread.

And yes, before anyone asks, I do call the call WaitForSignal() command 4 times in the trigger editor, with a 4 minute delay between each one and the AddGuard commands also work properly.
 

Attachments

  • TheDarkNight_blue.ai
    3.3 KB · Views: 6
Level 29
Joined
Aug 29, 2012
Messages
1,317
Careful you have a few calls that are turned into comments and thus won't work, not sure if that was intended

1736373266998.png


Do AddGuardPost truly work properly without calling FillGuardPosts afterward?

I'm not sure 100% sure but my only lead would be that sending a command triggers all WaitForSignals at the same time, I'm really not sure if you can use it several times in a script, can't remember seeing it in a Blizzard script at least

You'd probably need to use different command (1, 2, 3, whatever), retrieve them with GetLastCommand and do each block separately, but it's a bit tricky
 
Level 27
Joined
Dec 3, 2020
Messages
881
Careful you have a few calls that are turned into comments and thus won't work, not sure if that was intended

View attachment 507652

Do AddGuardPost truly work properly without calling FillGuardPosts afterward?

I'm not sure 100% sure but my only lead would be that sending a command triggers all WaitForSignals at the same time, I'm really not sure if you can use it several times in a script, can't remember seeing it in a Blizzard script at least

You'd probably need to use different command (1, 2, 3, whatever), retrieve them with GetLastCommand and do each block separately, but it's a bit tricky
Ah yes, I will uncomment this line and others that may be needed to uncomment
Do AddGuardPost truly work properly without calling FillGuardPosts afterward?
I'm sure they do because I already use it in other scripts. It works because of this ---> call SetReplacements(9,9,9)
I have used addGuardPost in other scripts the same way. I literally have the exact same script but also with attack waves and that one works good.
Tomorrow I will be on my PC again so I could show it.

I'm not sure 100% sure but my only lead would be that sending a command triggers all WaitForSignals at the same time, I'm really not sure if you can use it several times in a script, can't remember seeing it in a Blizzard script at least
As previously stated, it does work in that other script I mentioned. I can also show the triggers there (and the ones I use here), but tomorrow!

Thank you for the heads up for that comment on the farms, I missed that one completely lol
 
Level 20
Joined
Mar 16, 2008
Messages
824
You should use conditions to limit to the right number of units before 20 mins. After 20 mins, you can use a trigger to prompt the ai into "tier 2" which would increase the units. I got this idea from InsaneMonster's AI guide.

Here are some excepts from the King AI scripts in Kings and Knights that use the "tier" feature:

JASS:
globals
    integer                 Tier                       = 0
endglobals

//===========================================================================
// Sleep delays for each attack wave
//===========================================================================
function AttackWaveDelay takes integer inWave returns nothing
    if (inWave < nextDelay) then
        return
    endif
    if (inWave == 0) then
        call Sleep( 90 )
    elseif (inWave == 1) then
        call Sleep( 70 )
    elseif ((inWave == 2) and (Tier == 1)) then    
        call Sleep( 45 )
    elseif ((inWave == 2) and (Tier == 2)) then   
        call Sleep( 120 )
    elseif ((inWave == 2) and (Tier == 3)) then   
        call Sleep( 180 )
    endif
    set nextDelay = inWave + 1
endfunction

//===========================================================================
// AI Command Function
//===========================================================================

function TierCondition takes nothing returns nothing
    if CommandsWaiting() > 0 then
        set Tier = GetLastCommand()
        call PopLastCommand()
        call InitBuildArray()
    endif
endfunction

function ConditionLoop takes nothing returns nothing
    call TierCondition()
    call StaggerSleep(1,5)
    loop
        call TierCondition()
        call Sleep(16)
    endloop
endfunction

//===========================================================================
// Initiates an attack based on target priorities
//===========================================================================
function LaunchAttack takes nothing returns nothing
    local unit target = null
    local boolean setAlly = true
    // Don't launch any attack while town is threatened
    if (TownThreatened()) then
        call Sleep( 2 )
        return
    endif

    // Target Priority #1
    if (Tier < 3) then
        if (target == null) then
            set target = GetCreepCamp( 0, 9, false )
        endif
    endif

  • AI Tier 1 Start
    • Events
      • Time - Elapsed game time is 300.00 seconds
    • Conditions
    • Actions
      • AI - Send Player 1 (Red) the AI Command (1, 0)
      • AI - Send Player 2 (Blue) the AI Command (1, 0)
      • AI - Send Player 3 (Teal) the AI Command (1, 0)
      • AI - Send Player 4 (Purple) the AI Command (1, 0)
  • AI Tier 2 Start
    • Events
      • Time - Elapsed game time is 900.00 seconds
    • Conditions
    • Actions
      • AI - Send Player 1 (Red) the AI Command (2, 0)
      • AI - Send Player 2 (Blue) the AI Command (2, 0)
      • AI - Send Player 3 (Teal) the AI Command (2, 0)
      • AI - Send Player 4 (Purple) the AI Command (2, 0)
 
Level 27
Joined
Dec 3, 2020
Messages
881
You should use conditions to limit to the right number of units before 20 mins. After 20 mins, you can use a trigger to prompt the ai into "tier 2" which would increase the units. I got this idea from InsaneMonster's AI guide.

Here are some excepts from the King AI scripts in Kings and Knights that use the "tier" feature:

JASS:
globals
    integer                 Tier                       = 0
endglobals

//===========================================================================
// Sleep delays for each attack wave
//===========================================================================
function AttackWaveDelay takes integer inWave returns nothing
    if (inWave < nextDelay) then
        return
    endif
    if (inWave == 0) then
        call Sleep( 90 )
    elseif (inWave == 1) then
        call Sleep( 70 )
    elseif ((inWave == 2) and (Tier == 1)) then   
        call Sleep( 45 )
    elseif ((inWave == 2) and (Tier == 2)) then  
        call Sleep( 120 )
    elseif ((inWave == 2) and (Tier == 3)) then  
        call Sleep( 180 )
    endif
    set nextDelay = inWave + 1
endfunction

//===========================================================================
// AI Command Function
//===========================================================================

function TierCondition takes nothing returns nothing
    if CommandsWaiting() > 0 then
        set Tier = GetLastCommand()
        call PopLastCommand()
        call InitBuildArray()
    endif
endfunction

function ConditionLoop takes nothing returns nothing
    call TierCondition()
    call StaggerSleep(1,5)
    loop
        call TierCondition()
        call Sleep(16)
    endloop
endfunction

//===========================================================================
// Initiates an attack based on target priorities
//===========================================================================
function LaunchAttack takes nothing returns nothing
    local unit target = null
    local boolean setAlly = true
    // Don't launch any attack while town is threatened
    if (TownThreatened()) then
        call Sleep( 2 )
        return
    endif

    // Target Priority #1
    if (Tier < 3) then
        if (target == null) then
            set target = GetCreepCamp( 0, 9, false )
        endif
    endif

  • AI Tier 1 Start
    • Events
      • Time - Elapsed game time is 300.00 seconds
    • Conditions
    • Actions
      • AI - Send Player 1 (Red) the AI Command (1, 0)
      • AI - Send Player 2 (Blue) the AI Command (1, 0)
      • AI - Send Player 3 (Teal) the AI Command (1, 0)
      • AI - Send Player 4 (Purple) the AI Command (1, 0)
  • AI Tier 2 Start
    • Events
      • Time - Elapsed game time is 900.00 seconds
    • Conditions
    • Actions
      • AI - Send Player 1 (Red) the AI Command (2, 0)
      • AI - Send Player 2 (Blue) the AI Command (2, 0)
      • AI - Send Player 3 (Teal) the AI Command (2, 0)
      • AI - Send Player 4 (Purple) the AI Command (2, 0)
Interesting!

The one think I actually wanna know is where could I put the:

if (TownThreatened()) then
call Sleep( 2 )
return
endif

in a normal blizzard campaign AI, such as the one attached below?
 

Attachments

  • TheHammerFalls_lightblue.ai
    7.9 KB · Views: 1
Level 27
Joined
Dec 3, 2020
Messages
881
So nothing really worked, except for limiting the amount of units the AI can train (14 footmen, 6 riflemen... (for example)). It was easy to count them at least.

I will not mark the thread as solved for now though, as this isn't a valid solution for the problem in my opinion.

Also, @Gnuoy, I tried your method with the AI Command(0, 0) , AI Command(1, 0) etc...
It seemed to work exactly as always sending it the (0, 0) command always, instead of incrementing the value of the first index's value by 1 each time.
I wonder what will happen if I increment the value of the second index by 1 each time.
 
Top