• Check out the results of the Techtree Contest #19!
  • Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.
  • Create a void inspired texture for Warcraft 3 and enter Hive's 34th Texturing Contest: Void! Click here to enter!
  • The Hive's 22nd Icon Contest: Creep Abilities is now concluded, time to vote for your favourite set of icons! Click here to vote!

[AI] Problems with Custom Campaign AI

Level 7
Joined
Oct 19, 2024
Messages
55
Hello! I have been trying to use Jass to make an AI for a Custom Campaign. However, once the level starts and the appropiate triggers are detonated, the computer does nothing?

Here is the code:

JASS:
//------------------------------------------------
//              GLOBALS
//------------------------------------------------

globals
    player user = PlayerEx(1)
    
endglobals

//------------------------------------------------
//              MAIN
//------------------------------------------------

function main takes nothing returns nothing
    call CampaignAI(ZIGGURAT_1, null)
    call DoCampaignFarms(true)
    
    call SetHeroesFlee(false)
    call SetGroupsFlee(false)
    call SetReplacements(1, 1, 1)
    call SetSlowChopping(true)
    call SetPeonsRepair(true)
    
    call SetBuildUnitEx(1, 1, 1, NECROPOLIS_2)
    call SetBuildUnitEx(1, 1, 1, UNDEAD_MINE)
    call SetBuildUnitEx(6, 6, 6, ACOLYTE)
    call SetBuildUnitEx(2, 2, 2, CRYPT)
    call SetBuildUnitEx(2, 2, 3, GHOUL)
    call SetBuildUnitEx(1, 1, 1, UNDEAD_ALTAR)
    call SetBuildUnitEx(1, 1, 1, DAMNED_TEMPLE)
    call SetBuildUnitEx(1, 1, 1, GRAVEYARD)
    call SetBuildUnitEx(6, 6, 7, ZIGGURAT_2)
    
    call CampaignDefenderEx(3, 3, 4, GHOUL)
    call CampaignDefenderEx(1, 1, 2, NECRO)
    call CampaignDefenderEx(1, 2, 2, CRYPT_FIEND)
    call CampaignDefenderEx(0, 1, 1, BANSHEE)
    
    call WaitForSignal()
    
    // WAVE 1
    
    call InitAssaultGroup()
    call CampaignAttackerEx(4, 4, 4, GHOUL)
    call SuicideOnPlayerEx(180, 180, 150, user)
    
    // WAVE 2
    
    call InitAssaultGroup()
    call CampaignAttackerEx(3, 3, 4, GHOUL)
    call CampaignAttackerEx(1, 1, 2, NECRO)
    call SuicideOnPlayerEx(180, 180, 180, user)
    
    // WAVE 3
    
    call InitAssaultGroup()
    call CampaignAttackerEx(4, 4, 5, GHOUL)
    call CampaignAttackerEx(1, 2, 2, CRYPT_FIEND)
    call SuicideOnPlayerEx(180, 180, 180, user)
    
    // WAVE 4
    
    call InitAssaultGroup()
    call CampaignAttackerEx(4, 4, 5, GHOUL)
    call CampaignAttackerEx(1, 1, 2, BANSHEE)
    call SuicideOnPlayerEx(180, 180, 180, user)
    
    // WAVE 5
    
    call InitAssaultGroup()
    call CampaignAttackerEx(3, 4, 4, GHOUL)
    call CampaignAttackerEx(1, 1, 2, NECRO)
    call CampaignAttackerEx(0, 1, 1, BANSHEE)
    call SuicideOnPlayerEx(180, 180, 180, user)
    
    loop
        
        // WAVE A
    
        call InitAssaultGroup()
        call CampaignAttackerEx(5, 5, 6, GHOUL)
        call CampaignAttackerEx(1, 1, 2, NECRO)
        call CampaignAttackerEx(0, 0, 1, MEAT_WAGON)
        call SuicideOnPlayerEx(180, 180, 180, user)
        
        // WAVE B
    
        call InitAssaultGroup()
        call CampaignAttackerEx(4, 4, 6, GHOUL)
        call CampaignAttackerEx(2, 2, 2, CRYPT_FIEND)
        call CampaignAttackerEx(1, 1, 1, BANSHEE)
        call SuicideOnPlayerEx(180, 180, 180, user)
        
        // WAVE C
    
        call InitAssaultGroup()
        call CampaignAttackerEx(7, 7, 9, GHOUL)
        call CampaignAttackerEx(0, 1, 2, CRYPT_FIEND)
        call CampaignAttackerEx(0, 0, 2, MEAT_WAGON)
        call SuicideOnPlayerEx(180, 180, 180, user)
        
        // WAVE D
    
        call InitAssaultGroup()
        call CampaignAttackerEx(4, 4, 4, GHOUL)
        call CampaignAttackerEx(0, 1, 2, CRYPT_FIEND)
        call CampaignAttackerEx(1, 2, 2, NECRO)
        call CampaignAttackerEx(0, 1, 1, BANSHEE)
        call SuicideOnPlayerEx(180, 180, 180, user)        
        
    endloop
endfunction

Now, I had a similar issue in the past, which was due to a Syntax Error. However, I've run this code over the few Syntax Checkers I managed to get working, and they didn't report anything out of the ordinary. Could someone please tell me where the mistake is?
 
You may want to specify this for their workers (whatever values fit your map)

JASS:
set campaign_gold_peons = 5
set campaign_wood_peons = 4

"DoCampaignFarms" I don't think I've ever seen used, although Blizzard does this:

JASS:
set do_campaign_farms = true

I'm not sure about PlayerEx(1), have you tried Player(1)? Also remember that Player 1 in the script = Player 2 in the editor.
Finally, do you send a command so that it can respond to WaitForSignal()?
 
So, after trying the suggestions, the script doesn't still doesn't work.

JASS:
//------------------------------------------------
//              GLOBALS
//------------------------------------------------

globals
    player user = Player(0)
    
endglobals

//------------------------------------------------
//              MAIN
//------------------------------------------------

function main takes nothing returns nothing

    call CampaignAI(ZIGGURAT_1, null)
    set do_campaign_farms = true
    
    call SetHeroesFlee(false)
    call SetGroupsFlee(false)
    call SetReplacements(1, 1, 1)
    call SetSlowChopping(true)
    call SetPeonsRepair(true)
    
    set campaign_gold_peons = 5
    set campaign_wood_peons = 4
        
    call SetBuildUnitEx(1, 1, 1, NECROPOLIS_2)
    call SetBuildUnitEx(1, 1, 1, UNDEAD_MINE)
    call SetBuildUnitEx(6, 6, 6, ACOLYTE)
    call SetBuildUnitEx(2, 2, 2, CRYPT)
    call SetBuildUnitEx(2, 2, 3, GHOUL)
    call SetBuildUnitEx(1, 1, 1, UNDEAD_ALTAR)
    call SetBuildUnitEx(1, 1, 1, DAMNED_TEMPLE)
    call SetBuildUnitEx(1, 1, 1, GRAVEYARD)
    call SetBuildUnitEx(6, 6, 7, ZIGGURAT_2)
    
    call CampaignDefenderEx(3, 3, 4, GHOUL)
    call CampaignDefenderEx(1, 1, 2, NECRO)
    call CampaignDefenderEx(1, 2, 2, CRYPT_FIEND)
    call CampaignDefenderEx(0, 1, 1, BANSHEE)
    
    call WaitForSignal()
    
    // WAVE 1
    
    call InitAssaultGroup()
    call CampaignAttackerEx(4, 4, 4, GHOUL)
    call SuicideOnPlayerEx(180, 180, 150, user)
    
    // WAVE 2
    
    call InitAssaultGroup()
    call CampaignAttackerEx(3, 3, 4, GHOUL)
    call CampaignAttackerEx(1, 1, 2, NECRO)
    call SuicideOnPlayerEx(180, 180, 180, user)
    
    // WAVE 3
    
    call InitAssaultGroup()
    call CampaignAttackerEx(4, 4, 5, GHOUL)
    call CampaignAttackerEx(1, 2, 2, CRYPT_FIEND)
    call SuicideOnPlayerEx(180, 180, 180, user)
    
    // WAVE 4
    
    call InitAssaultGroup()
    call CampaignAttackerEx(4, 4, 5, GHOUL)
    call CampaignAttackerEx(1, 1, 2, BANSHEE)
    call SuicideOnPlayerEx(180, 180, 180, user)
    
    // WAVE 5
    
    call InitAssaultGroup()
    call CampaignAttackerEx(3, 4, 4, GHOUL)
    call CampaignAttackerEx(1, 1, 2, NECRO)
    call CampaignAttackerEx(0, 1, 1, BANSHEE)
    call SuicideOnPlayerEx(180, 180, 180, user)
    
    loop
        
        // WAVE A
    
        call InitAssaultGroup()
        call CampaignAttackerEx(5, 5, 6, GHOUL)
        call CampaignAttackerEx(1, 1, 2, NECRO)
        call CampaignAttackerEx(0, 0, 1, MEAT_WAGON)
        call SuicideOnPlayerEx(180, 180, 180, user)
        
        // WAVE B
    
        call InitAssaultGroup()
        call CampaignAttackerEx(4, 4, 6, GHOUL)
        call CampaignAttackerEx(2, 2, 2, CRYPT_FIEND)
        call CampaignAttackerEx(1, 1, 1, BANSHEE)
        call SuicideOnPlayerEx(180, 180, 180, user)
        
        // WAVE C
    
        call InitAssaultGroup()
        call CampaignAttackerEx(7, 7, 9, GHOUL)
        call CampaignAttackerEx(0, 1, 2, CRYPT_FIEND)
        call CampaignAttackerEx(0, 0, 2, MEAT_WAGON)
        call SuicideOnPlayerEx(180, 180, 180, user)
        
        // WAVE D
    
        call InitAssaultGroup()
        call CampaignAttackerEx(4, 4, 4, GHOUL)
        call CampaignAttackerEx(0, 1, 2, CRYPT_FIEND)
        call CampaignAttackerEx(1, 2, 2, NECRO)
        call CampaignAttackerEx(0, 1, 1, BANSHEE)
        call SuicideOnPlayerEx(180, 180, 180, user)        
        
    endloop
endfunction

The weird thing about this, though, is that a code nearly identical to the original one does work on a normal non-campaign map, so I'm not really sure of what's happening here.

As for the triggers, both seem to be working properly: The AI is loaded in with the player's resources, and the signal is sent when the heroes are loaded in; which as far as I can tell, are running without an issue.

As for what it does... well, nothing! The acolytes don't harves the mine, the ghouls don't chop trees, and it doesn't train anything: Nor garrison nor attack waves.
 
Well, but that's the issue. All those variables and functions, as far as I am aware, are pre-defined in JassCraft, so they shouldn't be giving trouble. Now, JassCraft's own Syntax Checker (F9) tells me none of those functions are defined... but it says the same thing for a Script that does work correctly, so I don't know what I'm doing wrong here.
 
If you look at Blizzard AI for Undead, they do this
JASS:
    call SetBuildUnitEx( 1,1,1, ACOLYTE           )
    call SetBuildUnitEx( 0,0,1, NECROPOLIS_1      )
    call SetBuildUnitEx( 0,0,1, CRYPT             )
    call SetBuildUnitEx( 0,0,1, GRAVEYARD         )
    // etc

Notice the 1 acolyte before the town hall, maybe that makes a difference. Also I've just noticed that you order to build a NECROPOLIS_2 but no sign of NECROPOLIS_1, it could be that the AI is stuck at this very point because of the missing link
 
Same problem with the Temple of the Damned, you must build a Graveyard before. Also for spirit towers you must make the AI build the base buildings first, the ziggurat whose constant is ZIGGURAT_1.
 
Okay, so I've tried the proposed solutions... and it still does nothing! I've checked the triggers three times over, tried moving the Actions around a little... and still nothing. I've also applied the corrections of the buildings, but it doesn't work.

I also tried the script in a normal, non-campaing map... and it works! The acolytes start harvesting gold, they start to summon buildings... so I must be importing the AI wrong somehow. Is there anything to be taken into consideration when importing and running an AI script in a campaing?
 
I've tried both solutions: The pause/unpause was already correctly placed, but just to be safe, I moved to run after the cinematic plays/is skipped. Here's the trigger at hand (the only relevant triggers are at the end, everything else is loading up the cache):

  • Events
  • Conditions
  • Actions
    • Game Cache - Create a game cache from BattleforMulgore.w3v
    • Set TempLoc = (Center of Cairne <gen>)
    • Game Cache - Restore CairneBloodhoof of SecondMission from (Last created game cache) for Player 1 (red) at TempLoc facing 0.00
    • Set Cairne = (Last restored unit)
    • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      • If - Conditions
        • Cairne Equal to No Unit
      • Then - Actions
        • Unit - Create 1 Chieftain (Tauren) for Player 1 (red) at TempLoc facing Building Preset degrees
        • Set Cairne = (Last created unit)
        • Hero - Set Cairne Hero-level to 2, Hide level-up graphics
        • Hero - Learn skill for Cairne: Shockwave
      • Else - Actions
        • Do nothing
    • Custom script: call RemoveLocation(udg_TempLoc)
    • Set TempLoc = (Center of Perith <gen>)
    • Game Cache - Restore PerithStormhoof of SecondMission from (Last created game cache) for Player 1 (red) at TempLoc facing 0.00
    • Set Perith = (Last restored unit)
    • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
      • If - Conditions
        • Cairne Equal to No Unit
      • Then - Actions
        • Unit - Create 1 Holy Strider for Player 1 (red) at TempLoc facing Building Preset degrees
        • Set Perith = (Last created unit)
        • Hero - Set Perith Hero-level to 2, Hide level-up graphics
        • Hero- Learn skill for Cairne: Scroll of Swiftness
      • Else - Actions
        • Do nothing
    • Custom script: call RemoveLocation(udg_TempLoc)
    • AI - Start campaign AI script for Player 2 (blue): war3campImported\Chapter2UndeadTest6.ai
    • AI - Send Player 2 (blue) the AI Command (0, 0)
This trigger runs perfectly fine, as far as I can tell. Except... the AI still does nothing, so there must be something wrong somewhere.
 
Try commenting out these lines of code except for the Acolytes. And I suggest putting the acolyte count to 5, not 6 (just in case).
This kinda looks wrong so to say.
Like this:


JASS:
//call SetBuildUnitEx(1, 1, 1, NECROPOLIS_2)
    //call SetBuildUnitEx(1, 1, 1, UNDEAD_MINE)
    call SetBuildUnitEx(5, 5, 5, ACOLYTE)
    //call SetBuildUnitEx(2, 2, 2, CRYPT)
    //call SetBuildUnitEx(2, 2, 3, GHOUL)
    //call SetBuildUnitEx(1, 1, 1, UNDEAD_ALTAR)
    //call SetBuildUnitEx(1, 1, 1, DAMNED_TEMPLE)
    //call SetBuildUnitEx(1, 1, 1, GRAVEYARD)
    //call SetBuildUnitEx(6, 6, 7, ZIGGURAT_2)
 
I've managed to make it work! The issue seemed to be in the configuration of the map: If you do not place the AI on a different force than the player, then the script does not run in any form or manner.

However, the bad news is that the moment that I ask the script to usa a custom unit, it stops working. Again.

Here is the line:

JASS:
globals
    player user = Player(0)
    constant integer MAR = 'U600:Udre'
    
endglobals

Where the MAR is the unit in question. It's nothing more than a slightly modified dreadlord. Everything should be properly written: I got the code from by Ctlr+D in the object editor, and as far as I am aware, that's how it's supposed to be called in the script? Does somebody know how to make it recognise the custom unit?
 
I've managed to make it work! The issue seemed to be in the configuration of the map: If you do not place the AI on a different force than the player, then the script does not run in any form or manner.
I highly doubt this was the source of the specific issue otherwise you would not be able to make AIs that work with computer players allied to the player (in the same force).
 
You don't need the :Udre part, it's just the code of the unit that served as a base

Simply try with integer MAR = 'U600'
Yeah, that worked. Thanks.

I highly doubt this was the source of the specific issue otherwise you would not be able to make AIs that work with computer players allied to the player (in the same force).
Well, maybe instead of that it could be the "Fixed player settings"? If I had to bet, it would be that, mainly because the races I preassigned to the Player and AI only started working properly as well once I clicked that option on. So maybe the editor wasn't assigning a computer to player 2, and henceforth could not run the AI? I'm not really sure....
 
You must check the forces box in custom player properties if you want one or more AIs to be activated.
 
Last edited by a moderator:
Back
Top