• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Emptying an assault group

Status
Not open for further replies.
Level 12
Joined
Jun 15, 2016
Messages
472
In any ai script there are two unit groups which the user can control: an attack group and a defense group. The user can control each group issuing commands to a widget called captain. Units are added to each of these two groups via the ai natives AddAssault and AddDefenders.

I created an attack group which is supposed to perform a specific attack then retreat back to base. However, I can't remove units from the attack group after they retreat back to base. So, I want to know if there is a way to remove units from an attack group without them dying, or alternatively a way to truncate the attack group entirely.
 
Level 12
Joined
Jun 15, 2016
Messages
472
That wouldn't work, captain targets aren't the same thing. And I want to do it when the captain is "at home" and has no targets. I tried using InitAssault thinking it would work like InitAssaultGroup but that doesn't work, or I'm using the function incorrectly...
 
Level 18
Joined
Nov 21, 2012
Messages
835
I think it's not possible to remove units from assault group. They are removed upon death.
However depending on what you excatly want to do you may use.
SuicideUnitEx(2, FOOTMAN, 0) does not affect "captain" natives, but you have no control over these units (they die or destroy all Player(0) units)
ResetCaptainLocs() ClearCaptainTargets() CaptainGoHome() with Sleep() allows to order assault group to come back to base.
You add new unit(s) to this group, and reorder to attack (1st call InitAssault()). But I don't know how to empty assault group w/o them die.
I used SuicidePlayer and AttackMoveXY to prepare single attacks but using SuicideUnitEx offers to create more then one waves attacking diffrent players.
 
Level 12
Joined
Jun 15, 2016
Messages
472
I think it's not possible to remove units from assault group. They are removed upon death.

Why Blizzard, why?

I tried recreating the captains. That worked, the problem is I can't set units to the captains again... If anyone's interested, I attached my test map. This is the ai script:

JASS:
//=================================================================================================
//                                    EMPTY ATTACK GROUP TEST
//=================================================================================================

globals
    player user = Player(0)
   
    //DEFENSE HOME
    constant real DEFX = -3200.0
    constant real DEFY = -4900.0
   
    constant real DEFX2 = -4000.0
    constant real DEFY2 = -6750.0
   
    //ATTACK HOME
    constant real ATTX = -2250.0
    constant real ATTY = -5900.0
   
    //ATTACK TARGET
    constant real TARX = -2500.0
    constant real TARY = -4500.0
endglobals

//-------------------------------------------------------------------------------------------------
// BUILD ORDER
//-------------------------------------------------------------------------------------------------

function BuildOrder takes nothing returns nothing
    call SetBuildUnitEx( 1, 1, 1, TOWN_HALL )
    call SetBuildUnitEx( 5,5,5, PEASANT )
    call SetBuildUnitEx( 4, 4, 6, HOUSE )
    call SetBuildUnitEx( 8,8,8, PEASANT )
    call SetBuildUnitEx( 1, 1, 1, BARRACKS )
endfunction

//-------------------------------------------------------------------------------------------------
// ATTACK TEST
//-------------------------------------------------------------------------------------------------

function PerformCommand takes nothing returns nothing
    local integer cmd = GetLastCommand()
   
    if cmd == 1 then
        call DisplayTextToPlayer(user,0,0,"Adding units to attack captain")
        call AddAssault(4, FOOTMAN)
    elseif cmd == 2 then
        call DisplayTextToPlayer(user,0,0,"Attacking")
        call CaptainAttack(TARX,TARY)
    elseif cmd == 3 then
        call DisplayTextToPlayer(user,0,0,"Truncating attack captain")
        call InitAssault()
    elseif cmd == 4 then
        call DisplayTextToPlayer(user,0,0,"Adding units to defense captain")
        call AddDefenders(4, FOOTMAN)
    elseif cmd == 5 then
       
        if CaptainGroupSize() == 4 then
            call DisplayTextToPlayer(user,0,0,"Attack captain full")
        elseif CaptainGroupSize() == 0 then
            call DisplayTextToPlayer(user,0,0,"Attack captain empty")
        else
            call DisplayTextToPlayer(user,0,0,"Something strange is afoot")
        endif
   
    elseif cmd == 6 then
        call DisplayTextToPlayer(user,0,0,"Relocating the defense captain for 5 seconds")
        call SetCaptainHome(DEFENSE_CAPTAIN, DEFX2, DEFY2)
        call Sleep(5)
        call SetCaptainHome(DEFENSE_CAPTAIN, DEFX, DEFY)
   
    elseif cmd == 7 then // FINAL SOLUTION
        call DisplayTextToPlayer(user,0,0,"recreating the captains")
        call CreateCaptains()   
    endif
   
    call PopLastCommand()
endfunction

function TestLoop takes nothing returns nothing
    if CommandsWaiting()>0 then
        call PerformCommand()
    endif
    call StaggerSleep(3,3)
    loop
        if CommandsWaiting()>0 then
            call PerformCommand()
        endif
       
        call Sleep(0.5)
    endloop
endfunction

//-------------------------------------------------------------------------------------------------
// MAIN FUNCTION
//-------------------------------------------------------------------------------------------------

function main takes nothing returns nothing
    call CampaignAI(HOUSE, null)
    call DoCampaignFarms(false)
   
    call DisplayTextToPlayer(user,0,0,"Script received")
    call SetCaptainChanges(true)
   
    call SetCaptainHome(DEFENSE_CAPTAIN, DEFX, DEFY)
    call SetCaptainHome(ATTACK_CAPTAIN, ATTX, ATTY)
   
    call BuildOrder()
    call CampaignDefenderEx(4,4,4, FOOTMAN)
   
    call TestLoop()
endfunction

It works on commands (which are already in the map), trying to move the 4 footman being built from the attack group to the defense group and vice versa. The commands go like this:

type "1" to add 4 footmen to the attack captain. (both attack and defense captains are in different locations for convenience)
type "2" to add attack a third point with the attack captain.
type "3" to call InitAssault().
type "4" to add 4 footmen to the defense captain.
type "5" to for the script to massage whether the captain is full (CaptainGroupSize() == 4),empty (CaptainGroupSize() == 0) or something else.
type "6" to relocate the defense captain for the next 5 seconds.
type "7" to call CreateCaptains().

Each time you press a command it will display a corresponding text on the screen so it's easy to memorize. If anyone has any idea how to solve this, I'd be very grateful.

However depending on what you excatly want to do you may use.

I created an ai which does normal campaign attack waves, and has a relatively large defense group at base. When an allied base is attacked, the ai is prompted to set out with its defense group (basically switching the attack and defense group) and hunt down enemy units. Once one of the following conditions has been fulfilled (either town is threatened, allied town is no longer under attack while captain is not in combat, etc...) the large group will return to base and normal attack waves will resume. All of this works fine, but the next attack wave has all of the units in the large group.
 

Attachments

  • AI sandboxH.w3m
    117.1 KB · Views: 53
Level 18
Joined
Nov 21, 2012
Messages
835
It may be a litle crooked idea but maybe use AddAssault for normal attack waves. But switch between base and attack point using "defend units" by changing SetCaptainHome(DEFENSE_CAPTAIN, x, y). But I noticed that SetCaptainHome works after new unit has been produced.. or maybe you know a way to update SetCaptainHome w/o creating unit?

Since CreateCaptains() indeed resets "captain" natives (like CaptainIsEmpty(), CaptainIsFull(), CaptainGroupSize()) but units added to assault group are somehow "marked", I didnt found a way to reuse them.
 
Level 12
Joined
Jun 15, 2016
Messages
472
It may be a litle crooked idea but maybe use
AddAssault
for normal attack waves. But switch between base and attack point using "defend units" by changing
SetCaptainHome(DEFENSE_CAPTAIN, x, y)
. But I noticed that SetCaptainHome works after new unit has been produced.. or maybe you know a way to update SetCaptainHome w/o creating unit?

CaptainGoHome does it, but I think this works only for attack captains. Anyway this won't really work here. Once the ai receives a prompt to start hunting, it starts an attack based on CaptainVsUnits, so getting the unit's location is more trouble than its worth (and I don't think it's possible anyway). Technically SetCaptainChanges should do something along these lines as well, no?

Since CreateCaptains() indeed resets "captain" natives (like CaptainIsEmpty(), CaptainIsFull(), CaptainGroupSize()) but units added to assault group are somehow "marked", I didnt found a way to reuse them.

I've been trying out a slightly different version of the script (at the bottom). In this one, after typing command 7 and recreating the captains, the ai builds 2 riflemen as attackers and another footman as a defender (I should say just about now that I use "warpten" and so should you if you want this part to work well). The newly created attack captain will add the two riflemen as attack group units, and if I type command 1 it will add the newly created defense footman as an attacker, but as you said the 4 initial footmen will remain in their place. This newly created attack captain can work without problems, although his "home" resets to default as well.

I have a theory about that, but beware, wild speculations are afoot:


I think that the native CreateCaptains does not actually create the captains and that's it. It creates two widgets of type captain, and assigns each one to a variable, and both of them together to another variable (see common ai lines 666-668). Calling CreateCaptains again does not remove the existing captains, but rather overwrites their variables with the newly created captains, as evidence some "residue" of a former attack captain remains in the form of units which cannot be reassigned to a different captain.

I know that the captain is a widget of a different type that is discernible in a map because somebody already made a test of that here, and found a way to ping the captain locations. Unfortunately he did not share how he did that, so I can't try that. But if anyone has an idea how to do this, I bet they'll see 4 locations pinged on the map. Another way to test it relies on the idea that if captains do accumulate, then they essentially leak memory. So if I'll have some spare time I will try using a script which will call CreateCaptains every couple of minutes and see if/when the game crashes. Hopefully my computer won't burst in flames.


Oh also here's the script:

JASS:
//=================================================================================================
//                                    EMPTY ATTACK GROUP TEST
//=================================================================================================

globals
    player user = Player(0)
   
    //DEFENSE HOME
    constant real DEFX = -3200.0
    constant real DEFY = -4900.0
   
    constant real DEFX2 = -4000.0
    constant real DEFY2 = -6750.0
   
    //ATTACK HOME
    constant real ATTX = -2250.0
    constant real ATTY = -5900.0
   
    //ATTACK TARGET
    constant real TARX = -2500.0
    constant real TARY = -4500.0
endglobals

//-------------------------------------------------------------------------------------------------
// BUILD ORDER
//-------------------------------------------------------------------------------------------------

function BuildOrder takes nothing returns nothing
    call SetBuildUnitEx( 1, 1, 1, TOWN_HALL )
    call SetBuildUnitEx( 5,5,5, PEASANT )
    call SetBuildUnitEx( 4, 4, 6, HOUSE )
    call SetBuildUnitEx( 8,8,8, PEASANT )
    call SetBuildUnitEx( 1, 1, 1, BARRACKS )
    call SetBuildUnitEx( 1, 1, 1, BLACKSMITH )
endfunction

//-------------------------------------------------------------------------------------------------
// ATTACK TEST
//-------------------------------------------------------------------------------------------------

function PerformCommand takes nothing returns nothing
    local integer cmd = GetLastCommand()
   
    if cmd == 1 then
        call DisplayTextToPlayer(user,0,0,"Adding units to attack captain")
        call AddAssault(4, FOOTMAN)
    elseif cmd == 2 then
        call DisplayTextToPlayer(user,0,0,"Attacking")
        call CaptainAttack(TARX,TARY)
    elseif cmd == 3 then
        call DisplayTextToPlayer(user,0,0,"Truncating attack captain")
        call InitAssault()
    elseif cmd == 4 then
        call DisplayTextToPlayer(user,0,0,"Adding units to defense captain")
        call AddDefenders(4, FOOTMAN)
    elseif cmd == 5 then
       
        if CaptainGroupSize() == 4 then
            call DisplayTextToPlayer(user,0,0,"Attack captain full")
        elseif CaptainGroupSize() == 0 then
            call DisplayTextToPlayer(user,0,0,"Attack captain empty")
        else
            call DisplayTextToPlayer(user,0,0,"Something strange is afoot")
        endif
   
    elseif cmd == 6 then
        call DisplayTextToPlayer(user,0,0,"Relocating the defense captain for 5 seconds")
        call SetCaptainHome(DEFENSE_CAPTAIN, DEFX2, DEFY2)
        call Sleep(5)
        call SetCaptainHome(DEFENSE_CAPTAIN, DEFX, DEFY)
   
    elseif cmd == 7 then // FINAL SOLUTION
        call DisplayTextToPlayer(user,0,0,"recreating the captains")
        call CreateCaptains()
       
        call CampaignDefenderEx(5,5,5, FOOTMAN)
        call CampaignAttackerEx(2,2,2, RIFLEMAN)
        call BuildAttackers()
        call Sleep(10)
        call DisplayTextToPlayer(user,0,0,"Sleep is over, try using a captain")
        call AddAssault(2,RIFLEMAN)
    endif
   
    call PopLastCommand()
endfunction

function TestLoop takes nothing returns nothing
    if CommandsWaiting()>0 then
        call PerformCommand()
    endif
    call StaggerSleep(3,3)
    loop
        if CommandsWaiting()>0 then
            call PerformCommand()
        endif
       
        call Sleep(0.5)
    endloop
endfunction

//-------------------------------------------------------------------------------------------------
// MAIN FUNCTION
//-------------------------------------------------------------------------------------------------

function main takes nothing returns nothing
    call CampaignAI(HOUSE, null)
    call DoCampaignFarms(false)
   
    call DisplayTextToPlayer(user,0,0,"Script received")
    call SetCaptainHome(DEFENSE_CAPTAIN, DEFX, DEFY)
    call SetCaptainHome(ATTACK_CAPTAIN, ATTX, ATTY)
   
    call BuildOrder()
    call CampaignDefenderEx(4,4,4, FOOTMAN)
   
    call TestLoop()
endfunction
 
Level 18
Joined
Nov 21, 2012
Messages
835
Thinking of what you are trying to achieve let me try to do that this way:
1. normal attack waves: execute it by (example) call SuicideUnitEx(3, FOOTMAN, 2) 3 footmans will attack Player(2)
2. stationary AI base defence: CampaignDefenderEx( 2, 2, 2, KNIGHT ) normal basic action
3. large defense group at base that suppose to react when allied based is attacked:
use assault group that normally stays in base

JASS:
function ResetCaptainLocs_Ex takes nothing returns nothing
    call Trace_Ex("reseting captain locs..")
    call ResetCaptainLocs()
    call Sleep(5.00)      
    call SetCaptainHome(ATTACK_CAPTAIN, ATT_TARGET_X, ATT_TARGET_Y)
    call SetCaptainHome(DEFENSE_CAPTAIN, DEF_TARGET_X, DEF_TARGET_Y)  
    call Sleep(5.00)
endfunction
function AttackCaptain_ForceGoBack takes nothing returns nothing
    loop  // force go back
        call Trace_Ex("attack captain CaptainGoHome() ...")
        call CaptainGoHome() // attack captain goes to his "CaptainHome" location          
        call Sleep(1.00)
        exitwhen CaptainIsHome() and (not CaptainInCombat(true))
    endloop  
endfunction
//------------------------------------------
function main takes nothing returns nothing
    local integer cmd
    local real x=0.00
    local real y=0.00  
    call CampaignAI(AI_FARM, null ) //farm
    call SetTargetHeroes(true)
    call SetUnitsFlee(false)
    call SetGroupsFlee(false)
    call SetSlowChopping(false)
    call SetPeonsRepair(true) 
    call SetHarvestLumber(true)
    call SetCaptainChanges(true)
    call SetCaptainHome(DEFENSE_CAPTAIN, DEF_TARGET_X, DEF_TARGET_Y)
    call SetCaptainHome(ATTACK_CAPTAIN, ATT_TARGET_X, ATT_TARGET_Y)
  
    call SetBuildUnitEx( 6, 6, 6, PEASANT )          
    call SetBuildUnitEx( 2, 2, 2, AI_FARM )
    call SetBuildUnitEx( 2, 2, 2, BARRACKS )  
    call CampaignDefenderEx( 2, 2, 2, FOOTMAN )
    call CampaignDefenderEx( 2, 2, 2, KNIGHT )
    call CampaignDefenderEx( 2, 2, 2, RIFLEMAN )      
    loop
        exitwhen GetUnitCount(RIFLEMAN)>=2
        call Sleep(2.00)
    endloop
    call SuicideUnitEx(2, FOOTMAN, 2)// 2 footmans attack Player(2); does not affect captain natives          
  
    //call StartThread(function AI_Info)  
    call Trace_Ex("init assault + attack 2 KNIGHTS ----------------------------")
    call InitAssault()    
    call AddAssault(2,KNIGHT)
    //call AttackMoveXY(ATT_TARGET_X, ATT_TARGET_Y)
    call CaptainVsUnits(HumanPlayer)   
    call Sleep(20.00)
  
    call ResetCaptainLocs_Ex()  
    call AttackCaptain_ForceGoBack()      
    call Sleep(15.00)            
  
    //attack new target
    call Trace_Ex("ATTACK NEW TARGET ---------------------------")  
    call InitAssault()    
    call AddAssault(1,RIFLEMAN)
    //call CaptainAttack(PLAYER_RED_X, PLAYER_RED_Y)
    call CaptainVsUnits(HumanPlayer)   
    call Sleep(30.00)

    call ResetCaptainLocs_Ex()  
    call AttackCaptain_ForceGoBack()          
    call Sleep(35.00)            
    call Trace_Ex("2 ATTACKS FINISHED")

only problem is control units in assault group but you can use GetUnitCount
of course when I used 2 custom functions to force go back attacking captain it requires some conditions also to be sure when troops should come back
 
Status
Not open for further replies.
Top