How to make a Campaign AI

Jass Tutorials

15 years
edited 6 years
HOW TO MAKE A CAMPAIGN AI.
By Moyack

Index.


       
  • [goto=intro]Introduction[/goto]
  • [goto=aitypes]AI Types[/goto]
  • [goto=tools]Tools Needed[/goto]
  • [goto=whatisjass]What is JASS AI???[/goto]
  • [goto=start]Let's Start[/goto]
  • [goto=building]Building Strategy[/goto]
  • [goto=attacking]Attacking Strategy[/goto]
  • [goto=upgrading]Upgrading Strategy[/goto]
  • [goto=hero]Hero Abilities[/goto]
  • [goto=triggering]Controlling the AI via triggers[/goto]
  • [goto=testing]Testing the AI[/goto]
[point]intro[/point]
Introduction.

The main objective with this tutorial is to give an introduction in the development of a simple AI, focused in attack one player following an attack sequence, a building sequence and an upgrade sequence.

[point]aitypes[/point]
AI Types

Before starting, I want to clarify that there are two kind of AI: Campaign AI and Standard AI. The Campaign AI is the simplest AI that can be made, because it follows a rigid and predictable behaviour. An standard AI, in the other hand, is focused in simulate the human behaviour, so it will be more random, sometimes more agressive and many times extremely difficult to debug. :P

So if we want to begin with JASS AI, it's recommended to start working with a campaign AI, that is easy to debug.

[point]tools[/point]
Tools needed.

If you want to make an Standard AI, you have the WE with the AI editor, with its easy but slow interface, but if you want to do a Campaign AI, you can do it with notepad.

I strongly suggest to use JASSCRAFT because this program let us access the common.ai commands easily, the syntax highlithing, etc.

[point]whatisjass[/point]
What is JASS AI??

JASS AI is the language used by BLIZZARD to make AI programming. JASS AI uses the same JASS syntaxis and variable types, so if you are familiar with JASS, you will understand JASS AI perfectly.

The commands focused in AI are contained in the file common.ai file that can be found in the war3.mpq and war3x.mpq pack files. It's important to clarify that this functions are not the only that can be used to work with this scripting, you can use perfectly functions from common.j (well, it's the base file for programming with JASS language after all). Anyways, I've found that some functions from common.j just don't work in a JASS AI script, and the only way to get those functions is by practice.

[point]start[/point]
Let's start

Well, I think I've talked a lot, so let's start the AI.

Open JASSCRAFT or JASS SHOP PRO and open a new document. Before begin writing, we must know how the code is arranged in JASS.

JASS Structure
Code (jass) Select
1
globals
2
    // We put the globals variables here
3
endglobals
4
5
function blabla takes blabla returns blabla
6
    // Custom function stuff
7
endfunction
8
9
...
10
11
function main takes nothing returns nothing
12
    //The main code goes here
13
endfunction


For people who are new with JASS, the code is arranged in a global section, where we declare the global variables, then we put the custom functions that will be used in the script and the last function called main, which will use the globals and the functions that we have writen before and will be the function that will be executed by the game.


With those definitions, we can put to work with this script. First we're going to begin the AI code creating at the global section a global variable that will point the player which will be attacked by the AI, we will call it MyVictim

Global variables
Code (jass) Select
1
globals
2
    player MyVictim = Player(0) // This is the player 1 (red)
3
endglobals


Now we will create the main function
Code (jass) Select
1
function main takes nothing returns nothing
2
    call CampaignAI( <Farm ID>, null )
3
endfunction


The CampaignAI function initializes and configures the AI in order to have a behaviour that fits with campaign maps. This function has two arguments, the farm unitID, which help the function to define the food provider unit, and the hero code which makes reference to a function that will manage the hero abilities that a hero will have when it increases its level. This option will be treated later, so at the moment we are going to set this parameter as null.

now we're going to set some parameters into the AI. Campaign AIs have this caracteristics by default:


  • They don't give attack priority to heroes.
  • Units don't flee
  • Peons only repair buildings in insane mode
  • Gather resources very slowly (each peon gather 1 gold and 1 lumber to the town hall)

This characteristics are given in this way to the AI because in campaign maps, you need the AI player keeps alive in the game until it's destroyed, so the AI will "simulate" a gathering, and you will control the AI resources via triggers. Other thing is units can't flee because the function of this kind of AI is to put difficulty or taunting the user player.

So if you need to change these behaviours you need to configure them with some ai functions. I'm going to list some of the most used:

[BTABLE]
Basic configuration functions

  • SetTargetHeroes(Boolean): makes the AI to give attack priority toward heroes
  • SetUnitsFlee(Boolean): If units are seriously damaged, they will retreat
  • SetHeroesFlee(Boolean): The same but with heroes
  • SetGroupsFlee(Boolean): The same but with the attacking group in general (I really don't recommend to set true this option, the AI behaves like a chicken)
  • SetSlowChopping(Boolean): Workers gather very few resources
  • SetPeonsRepair(Boolean): Workers will repair damaged mechanical units
  • SetHeroesBuyItems(Boolean): Make heroes buy items from their racial shop and sell items.
  • SetHeroesTakeItems(Boolean): Make heroes to take items on the ground.
For testing, I'm going to set some options in the main code.[/BTABLE]

Now we will create the main function

main function
Code (jass) Select
1
function main takes nothing returns nothing
2
    call CampaignAI( MOON_WELL, null ) // I like the Night elf race, 
3
                                       // so this AI will train NE
4
    call SetSlowChopping( false ) //AI will do a normal harvesting
5
    call SetPeonsRepair( true ) //AI will repair damaged structures
6
endfunction


Note
[BTABLE]probably you've noticed that in the function call CampaignAI( MOON_WELL, null ) we set the name of the unit instead of its rawcode. All the units used in the Warcraft Campaigns have this constant names. If you create a modified race with custom units, you have to use the rawcode. This function can be written in this way:
call CampaignAI( 'emow', null )
And is perfectly equivalent. I will use this constant names in all this tutorial so it can be more readable.[/BTABLE]

How to get the unit, ability, buff and upgrade rawcode?? easy, open the object editor and press CTRL+D, you will see that all the units , items, abilities, upgrades names are shown by their rawcode. To change again pres again CTRL+D

If you want to be more organized, we can create a custom configuration function and then we will call it in the main function:

main function
Code (jass) Select
1
function ConfigureAI takes nothing returns nothing
2
    call SetSlowChopping( false )
3
    call SetPeonsRepair( true )
4
endfunction
5
6
function main takes nothing returns nothing
7
    call CampaignAI( MOON_WELL, null )
8
    call ConfigureAI( )
9
endfunction


[point]building[/point]
Building Strategy.

It's time to put this AI to build structures. First we must take in account the order and the dependencies, for example, in the case of this Night Elf AI, we can't build an ancient protector without have built a Huntress Hall.

With this idea in mind, we're going to set the building order in the script.

NE Campaign AI - only Buildings
Code (jass) Select
1
globals
2
    player MyVictim = Player( 0 )
3
endglobals
4
5
function ConfigureAI takes nothing returns nothing
6
    call SetSlowChopping( false )
7
    call SetPeonsRepair( true )
8
endfunction
9
10
function main takes nothing returns nothing
11
    call CampaignAI( MOON_WELL, null )
12
    call ConfigureAI( )
13
    // **********************************
14
    // *      Building Strategy         *
15
    // **********************************
16
    call SetBuildUnitEx( 1, 1, 1, TREE_LIFE )
17
    call SetBuildUnit( 15, WISP )
18
    call SetBuildUnitEx( 1, 2, 3, MOON_WELL )
19
    call SetBuildUnitEx( 1, 1, 2, ANCIENT_WAR )
20
    call SetBuildUnit( 1, ELF_ALTAR )
21
    call SetBuildUnit( 1, HUNTERS_HALL )
22
    // **********************************
23
    // *    End Building Strategy       *
24
    // **********************************
25
endfunction


Now we've done the basic tier 1 buildings. :emote_grin:  Let's see the new functions. SetBuildUnit( n, UnitID ) is easy to read, this function orders to AI to build or train n units of type UnitID. SetBuildUnitEx( e, n, i, UnitID ) is the same but better, becasue it lets you set how many units will be trained in easy, normal and insane mode.

Now we need to build the units that will defend our town, so we're going to train this units adding this functions to the AI.

NE Campaign AI - Buildings and defensive units
Code (jass) Select
1
globals
2
    player MyVictim = Player( 0 )
3
endglobals
4
5
function ConfigureAI takes nothing returns nothing
6
    call SetSlowChopping( false )
7
    call SetPeonsRepair( true )
8
endfunction
9
10
function main takes nothing returns nothing
11
    call CampaignAI( MOON_WELL, null )
12
    call ConfigureAI( )
13
    // **********************************
14
    // *      Building Strategy         *
15
    // **********************************
16
    call SetReplacements( 1, 2, 3 ) // <==(1)
17
    call SetBuildUnitEx( 1, 1, 1, TREE_LIFE )
18
    call SetBuildUnit( 15, WISP )
19
    call SetBuildUnitEx( 1, 2, 3, MOON_WELL )
20
    call SetBuildUnitEx( 1, 1, 2, ANCIENT_WAR )
21
    call SetBuildUnit( 1, ELF_ALTAR )
22
    call SetBuildUnit( 1, HUNTERS_HALL )
23
    call SetBuildUnitEx( 0, 1, 2, ANCIENT_PROTECT )
24
    call CampaignDefenderEx( 2, 2, 3, ARCHER ) // <==(2)
25
    call CampaignDefenderEx( 1, 1, 1, HUNTRESS ) 
26
    // **********************************
27
    // *    End Building Strategy       *
28
    // **********************************
29
endfunction


Let's explain the new functions:

       
  • SetReplacements(e, n, i): Set how many times the AI replaces preplaced units of the same type, in the code above, it makes this replacement up to one unit, up to 2 units for normal mode and up to 3 units of a type in insane mode. (thanks Starquizer for the discovery :) )
  • CampaignDefenderEx(e, n, i, UnitID): similar to SetUnitBuild, but the units trained with this function will be replaced if they're killed n times according with the function SetReplacements.
Now the defensive strategy for this AI is arranged (at the moment) as:

Defensive Strategy
[BTABLE][c]Easy[c]Normal[c]Insane[r]Archers[c]2[c]2[c]3[r]Huntress[c]1[c]1[c]1[r]Ancient Protector[c]0[c]1[c]2[/BTABLE]

[point]attacking[/point]
Attacking Strategy

Now this baby is ready to fight, so we need to make the AI takes some units and order them to attack a target. The function structure is as follows:

Attack Function Arrangement
Code (jass) Select
1
function main takes nothing returns nothing
2
3
// Building code goes here
4
5
//*** WAVE 1 *** 
6
    call InitAssaultGroup() // <==(1)
7
    call CampaignAttackerEx( 2, 3, 3, ARCHER ) // <==(2)
8
    call CampaignAttackerEx( 0, 1, 2, HUNTRESS ) 
9
    call CampaignAttackerEx( 0, 1, 1, BALLISTA ) 
10
    call SuicideOnPlayerEx( M2, M3, M3, MyVictim ) // <==(3)
11
endfunction


These functions do the following:

       
  • InitAssaultGroup(): Clear any previous assault group and creates a new empty one.
  • CampaignAttackerEx( e, n, i, UnitID ): Like SetBuildUnitEx but adds these units to the assault group.
  • SuicideOnPlayerEx( te, tn, ti, TargetPlayer ): Waits te seconds in easy mode, tn seconds in normal mode and ti seconds in insane mode to attack the specified player.
One question is: what does it mean M2, M3??? well, M2 is two minutes (2*60 sec.), M3 is three minutes (3*60 sec.) an so on. We can use values from M1 to M15. You can check it out these constants in the common.ai file.

Note
[btable]There are other ways to get enemies to attack. SuicideOnPlayerEx gets the main player town hall (player start location), but probably you want to take a specific unit, so you will need to use a function like AttackMoveKillA( TargetUnit ). as an example, this script will attack a creep camp, targeting a specific creep:

Attack script for creeping
Code (jass) Select
1
function main takes nothing returns nothing
2
    local unit crp
3
// Building code goes here
4
5
//*** WAVE 1 *** 
6
    call InitAssaultGroup()
7
    set crp = GetCreepCamp(0,9,false) // Stores the target unit
8
    call CampaignAttackerEx( 2, 3, 3, ARCHER ) 
9
    call CampaignAttackerEx( 0, 1, 2, HUNTRESS ) 
10
    call Sleep( M3 ) // Waits 3 minutes before attacking
11
    call AttackMoveKillA(crp) // Order assault group to attack that unit
12
endfunction


Where:

       
  • GetCreepCamp( min, max, flyers ): Get a creep unit in a camp with a strength between min and max including (flyers=true) or not including (flyers=false) flying creeps.
  • Sleep( n ): put the script to wait n seconds.
  • AttackMoveKillA( Unit ): Order assault group to attack that unit.
[/btable]

Now we have this wave working. the idea is to add more waves, incrementing the amount of units or their type (for example one wave with tier 1 units, other with more tier 1 units, the next with tier 1 and 2 units and casters, etc). check this example:

Building + Attacking script. All tiers
Code (jass) Select
1
globals
2
    player MyVictim = Player( 0 )
3
endglobals
4
5
function ConfigureAI takes nothing returns nothing
6
    call SetSlowChopping( false )
7
    call SetPeonsRepair( true )
8
endfunction
9
10
function main takes nothing returns nothing
11
    call CampaignAI( MOON_WELL, null )
12
    call ConfigureAI( )
13
    // **********************************
14
    // *      Building Strategy         *
15
    // **********************************
16
    //
17
    // Tier 1 Buildings
18
    call SetReplacements( 1, 2, 3 )
19
    call SetBuildUnitEx( 1, 1, 1, TREE_LIFE )
20
    call SetBuildUnit( 15, WISP )
21
    call SetBuildUnitEx( 1, 2, 3, MOON_WELL )
22
    call SetBuildUnitEx( 1, 1, 2, ANCIENT_WAR )
23
    call SetBuildUnit( 1, ELF_ALTAR )
24
    call SetBuildUnit( 1, HUNTERS_HALL )
25
    call CampaignDefenderEx( 2, 2, 3, ARCHER ) 
26
    call CampaignDefenderEx( 1, 1, 1, HUNTRESS )
27
    call CampaignDefenderEx( 0, 1, 2, ANCIENT_PROTECT )
28
    // Tier 2 buildings
29
    call SetBuildUnit( 1, TREE_AGES )
30
    call SetBuildUnitEx( 1, 1, 2, ANCIENT_LORE )
31
    call SetBuildUnit( 1, ANCIENT_WIND )
32
    // Tier 3 buildings
33
    call SetBuildUnit( 1, TREE_ETERNITY )
34
    call SetBuildUnitEx( 0, 1, 1, CHIMAERA_ROOST )
35
    // **********************************
36
    // *    End Building Strategy       *
37
    // **********************************
38
    // **********************************
39
    // *       Attack Strategy          *
40
    // **********************************
41
    //*** WAVE 1 *** 
42
    call InitAssaultGroup()
43
    call CampaignAttackerEx( 2, 3, 3, ARCHER )
44
    call CampaignAttackerEx( 0, 1, 2, HUNTRESS )  
45
    call SuicideOnPlayerEx( M3, M2, M2, MyVictim )
46
    //*** WAVE 2 *** Between 2 or 3 minutes after Wave 1
47
    call InitAssaultGroup()
48
    call CampaignAttackerEx( 3, 4, 4, ARCHER )
49
    call CampaignAttackerEx( 1, 2, 3, HUNTRESS )  
50
    call SuicideOnPlayerEx( M3, M2, M2, MyVictim )
51
    //*** WAVE 3 *** Between 2 or 3 minutes after Wave 2
52
    call InitAssaultGroup()
53
    call CampaignAttackerEx( 3, 4, 4, ARCHER )
54
    call CampaignAttackerEx( 1, 2, 3, HUNTRESS )
55
    call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )
56
    call SuicideOnPlayerEx( M3, M2, M2, MyVictim )
57
    //*** WAVE 4 *** Between 2 or 3 minutes after Wave 3
58
    call InitAssaultGroup()
59
    call CampaignAttackerEx( 3, 4, 4, ARCHER )
60
    call CampaignAttackerEx( 1, 2, 3, HUNTRESS )
61
    call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )
62
    call SuicideOnPlayerEx( M3, M2, M2, MyVictim )
63
    //*** WAVE 5 *** Between 3 or 4 minutes after Wave 4
64
    call InitAssaultGroup()
65
    call CampaignAttackerEx( 3, 3, 3, ARCHER )
66
    call CampaignAttackerEx( 2, 2, 2, HUNTRESS )
67
    call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )
68
    call CampaignAttackerEx( 0, 1, 2, DRYAD )
69
    call SuicideOnPlayerEx( M4, M3, M3, MyVictim )
70
    //*** WAVE 6 *** Between 3 or 4 minutes after Wave 5
71
    call InitAssaultGroup()
72
    call CampaignAttackerEx( 2, 2, 2, HUNTRESS )
73
    call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )
74
    call CampaignAttackerEx( 1, 1, 1, MOON_CHICK )
75
    call CampaignAttackerEx( 1, 2, 3, DRYAD )
76
    call CampaignAttackerEx( 0, 1, 2, DRUID_CLAW )
77
    call SuicideOnPlayerEx( M4, M3, M3, MyVictim )
78
    //*** WAVE 7 *** Between 3 or 5 minutes after Wave 6
79
    call InitAssaultGroup()
80
    call CampaignAttackerEx( 2, 2, 2, HUNTRESS )
81
    call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )
82
    call CampaignAttackerEx( 1, 1, 1, MOON_CHICK )
83
    call CampaignAttackerEx( 1, 2, 3, DRYAD )
84
    call CampaignAttackerEx( 0, 1, 2, DRUID_CLAW )
85
    call CampaignAttackerEx( 0, 1, 2, MOUNTAIN_GIANT )
86
    call SuicideOnPlayerEx( M5, M4, M3, MyVictim )
87
    //*** WAVE 8 *** Between 3 or 5 minutes after Wave 7
88
    call InitAssaultGroup()
89
    call CampaignAttackerEx( 2, 2, 2, HUNTRESS )
90
    call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )
91
    call CampaignAttackerEx( 1, 1, 1, MOON_CHICK )
92
    call CampaignAttackerEx( 1, 2, 3, DRYAD )
93
    call CampaignAttackerEx( 0, 1, 2, DRUID_CLAW )
94
    //*** WAVE 9 *** Between 4 or 6 minutes after Wave 8
95
    call InitAssaultGroup()
96
    call CampaignAttackerEx( 2, 2, 2, HUNTRESS )
97
    call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )
98
    call CampaignAttackerEx( 1, 1, 1, MOON_CHICK )
99
    call CampaignAttackerEx( 1, 2, 3, DRYAD )
100
    call CampaignAttackerEx( 0, 1, 2, DRUID_CLAW )
101
    call CampaignAttackerEx( 0, 1, 2, MOUNTAIN_GIANT )
102
    call CampaignAttackerEx( 1, 1, 2, FAERIE_DRAGON )
103
    call CampaignAttackerEx( 0, 1, 2, CHIMAERA ) 
104
    call SuicideOnPlayerEx( M6, M5, M4, MyVictim )
105
    // **********************************
106
    // *      End Attack Strategy       *
107
    // **********************************
108
endfunction


After training the last wave, the script is finished and the AI won't send more units to attack the target player. If you require the the attack never ends we can add a loop to the script, so it will repeat for example the last three waves. The scripts will look like this:

Building + Attacking script with infinite loop. All tiers
Code (jass) Select
1
globals
2
    player MyVictim = Player( 0 )
3
endglobals
4
5
function ConfigureAI takes nothing returns nothing
6
    call SetSlowChopping( false )
7
    call SetPeonsRepair( true )
8
endfunction
9
10
function main takes nothing returns nothing
11
    call CampaignAI( MOON_WELL, null )
12
    call ConfigureAI( )
13
    // **********************************
14
    // *      Building Strategy         *
15
    // **********************************
16
    //
17
    // Tier 1 Buildings
18
    call SetReplacements( 1, 2, 3 )
19
    call SetBuildUnitEx( 1, 1, 1, TREE_LIFE )
20
    call SetBuildUnit( 15, WISP )
21
    call SetBuildUnitEx( 1, 2, 3, MOON_WELL )
22
    call SetBuildUnitEx( 1, 1, 2, ANCIENT_WAR )
23
    call SetBuildUnit( 1, ELF_ALTAR )
24
    call SetBuildUnit( 1, HUNTERS_HALL )
25
    call CampaignDefenderEx( 2, 2, 3, ARCHER ) 
26
    call CampaignDefenderEx( 1, 1, 1, HUNTRESS )
27
    call CampaignDefenderEx( 0, 1, 2, ANCIENT_PROTECT )
28
    // Tier 2 buildings
29
    call SetBuildUnit( 1, TREE_AGES )
30
    call SetBuildUnitEx( 1, 1, 2, ANCIENT_LORE )
31
    call SetBuildUnit( 1, ANCIENT_WIND )
32
    // Tier 3 buildings
33
    call SetBuildUnit( 1, TREE_ETERNITY )
34
    call SetBuildUnitEx( 0, 1, 1, CHIMAERA_ROOST )
35
    // **********************************
36
    // *    End Building Strategy       *
37
    // **********************************
38
    // **********************************
39
    // *       Attack Strategy          *
40
    // **********************************
41
    //*** WAVE 1 *** 
42
    call InitAssaultGroup()
43
    call CampaignAttackerEx( 2, 3, 3, ARCHER )
44
    call CampaignAttackerEx( 0, 1, 2, HUNTRESS )  
45
    call SuicideOnPlayerEx( M3, M2, M2, MyVictim )
46
    //*** WAVE 2 *** Between 2 or 3 minutes after Wave 1
47
    call InitAssaultGroup()
48
    call CampaignAttackerEx( 3, 4, 4, ARCHER )
49
    call CampaignAttackerEx( 1, 2, 3, HUNTRESS )  
50
    call SuicideOnPlayerEx( M3, M2, M2, MyVictim )
51
    //*** WAVE 3 *** Between 2 or 3 minutes after Wave 2
52
    call InitAssaultGroup()
53
    call CampaignAttackerEx( 3, 4, 4, ARCHER )
54
    call CampaignAttackerEx( 1, 2, 3, HUNTRESS )
55
    call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )
56
    call SuicideOnPlayerEx( M3, M2, M2, MyVictim )
57
    //*** WAVE 4 *** Between 2 or 3 minutes after Wave 3
58
    call InitAssaultGroup()
59
    call CampaignAttackerEx( 3, 4, 4, ARCHER )
60
    call CampaignAttackerEx( 1, 2, 3, HUNTRESS )
61
    call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )
62
    call SuicideOnPlayerEx( M3, M2, M2, MyVictim )
63
    //*** WAVE 5 *** Between 3 or 4 minutes after Wave 4
64
    call InitAssaultGroup()
65
    call CampaignAttackerEx( 3, 3, 3, ARCHER )
66
    call CampaignAttackerEx( 2, 2, 2, HUNTRESS )
67
    call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )
68
    call CampaignAttackerEx( 0, 1, 2, DRYAD )
69
    call SuicideOnPlayerEx( M4, M3, M3, MyVictim )
70
    //*** WAVE 6 *** Between 3 or 4 minutes after Wave 5
71
    call InitAssaultGroup()
72
    call CampaignAttackerEx( 2, 2, 2, HUNTRESS )
73
    call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )
74
    call CampaignAttackerEx( 1, 1, 1, MOON_CHICK )
75
    call CampaignAttackerEx( 1, 2, 3, DRYAD )
76
    call CampaignAttackerEx( 0, 1, 2, DRUID_CLAW )
77
    call SuicideOnPlayerEx( M4, M3, M3, MyVictim )
78
    loop //Init the infinite attack loop
79
    //*** WAVE 7 *** Between 3 or 5 minutes after Wave 6
80
        call InitAssaultGroup()
81
        call CampaignAttackerEx( 2, 2, 2, HUNTRESS )
82
        call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )
83
        call CampaignAttackerEx( 1, 1, 1, MOON_CHICK )
84
        call CampaignAttackerEx( 1, 2, 3, DRYAD )
85
        call CampaignAttackerEx( 0, 1, 2, DRUID_CLAW )
86
        call CampaignAttackerEx( 0, 1, 2, MOUNTAIN_GIANT )
87
        call SuicideOnPlayerEx( M5, M4, M3, MyVictim )
88
        //*** WAVE 8 *** Between 3 or 5 minutes after Wave 7
89
        call InitAssaultGroup()
90
        call CampaignAttackerEx( 2, 2, 2, HUNTRESS )
91
        call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )
92
        call CampaignAttackerEx( 1, 1, 1, MOON_CHICK )
93
        call CampaignAttackerEx( 1, 2, 3, DRYAD )
94
        call CampaignAttackerEx( 0, 1, 2, DRUID_CLAW )
95
        //*** WAVE 9 *** Between 4 or 6 minutes after Wave 8
96
        call InitAssaultGroup()
97
        call CampaignAttackerEx( 2, 2, 2, HUNTRESS )
98
        call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )
99
        call CampaignAttackerEx( 1, 1, 1, MOON_CHICK )
100
        call CampaignAttackerEx( 1, 2, 3, DRYAD )
101
        call CampaignAttackerEx( 0, 1, 2, DRUID_CLAW )
102
        call CampaignAttackerEx( 0, 1, 2, MOUNTAIN_GIANT )
103
        call CampaignAttackerEx( 1, 1, 2, FAERIE_DRAGON )
104
        call CampaignAttackerEx( 0, 1, 2, CHIMAERA ) 
105
        call SuicideOnPlayerEx( M6, M5, M4, MyVictim )
106
    endloop
107
    // **********************************
108
    // *   Attack Strategy never ends   *
109
    // **********************************
110
endfunction



[point]upgrading[/point]
Upgrading Strategy.

We have almost all the AI. Now it's time to add the upgrades. They can be put in any place inside the code, but I suggest to put this upgrades between each wave, so the AI has a progressive evolution in damage and looks more natural.

Let's see the functions that we're going to use:


       
  • SetBuildUpgrEx( e, n, i, UpgradeID ): Sets the levels of the upgrade that will be done by the AI in easy, normal and insane mode.
The script now will look in this way:

Building + Attacking script with infinite loop + Upgrading scripts. All tiers
Code (jass) Select
1
globals
2
    player MyVictim = Player( 0 )
3
endglobals
4
5
function ConfigureAI takes nothing returns nothing
6
    call SetSlowChopping( false )
7
    call SetPeonsRepair( true )
8
endfunction
9
10
function main takes nothing returns nothing
11
    call CampaignAI( MOON_WELL, null )
12
    call ConfigureAI( )
13
    // **********************************
14
    // *      Building Strategy         *
15
    // **********************************
16
    //
17
    // Tier 1 Buildings
18
    call SetReplacements( 1, 2, 3 )
19
    call SetBuildUnitEx( 1, 1, 1, TREE_LIFE )
20
    call SetBuildUnit( 15, WISP )
21
    call SetBuildUnitEx( 1, 2, 3, MOON_WELL )
22
    call SetBuildUnitEx( 1, 1, 2, ANCIENT_WAR )
23
    call SetBuildUnit( 1, ELF_ALTAR )
24
    call SetBuildUnit( 1, HUNTERS_HALL )
25
    call CampaignDefenderEx( 2, 2, 3, ARCHER ) 
26
    call CampaignDefenderEx( 1, 1, 1, HUNTRESS )
27
    call SetBuildUnitEx( 0, 1, 2, ANCIENT_PROTECT )
28
    // Tier 2 buildings
29
    call SetBuildUnit( 1, TREE_AGES )
30
    call SetBuildUnitEx( 1, 1, 2, ANCIENT_LORE )
31
    call SetBuildUnit( 1, ANCIENT_WIND )
32
    // Tier 3 buildings
33
    call SetBuildUnit( 1, TREE_ETERNITY )
34
    call SetBuildUnitEx( 0, 1, 1, CHIMAERA_ROOST )
35
    // **********************************
36
    // *    End Building Strategy       *
37
    // **********************************
38
    // **********************************
39
    // *       Attack Strategy          *
40
    // **********************************
41
    //*** WAVE 1 *** AI will begin to attack in 5 minutes
42
    call InitAssaultGroup()
43
    call CampaignAttackerEx( 2, 3, 3, ARCHER )
44
    call CampaignAttackerEx( 0, 1, 2, HUNTRESS )  
45
    call SuicideOnPlayerEx( M5, M5, M5, MyVictim )
46
    //*** Basic upgrades from HUNTERS HALL ***
47
    call SetBuildUpgrEx( 1, 2, 3, UPG_STR_MOON )
48
    call SetBuildUpgrEx( 1, 2, 3, UPG_MOON_ARMOR )
49
    call SetBuildUpgrEx( 1, 2, 3, UPG_STR_WILD )
50
    call SetBuildUpgrEx( 1, 2, 3, UPG_HIDES )
51
    //*** WAVE 2 *** Between 2 or 3 minutes after Wave 1
52
    call InitAssaultGroup()
53
    call CampaignAttackerEx( 3, 4, 4, ARCHER )
54
    call CampaignAttackerEx( 1, 2, 3, HUNTRESS )  
55
    call SuicideOnPlayerEx( M3, M2, M2, MyVictim )
56
    //*** WAVE 3 *** Between 2 or 3 minutes after Wave 2
57
    call InitAssaultGroup()
58
    call CampaignAttackerEx( 3, 4, 4, ARCHER )
59
    call CampaignAttackerEx( 1, 2, 3, HUNTRESS )
60
    call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )
61
    call SuicideOnPlayerEx( M3, M2, M2, MyVictim )
62
    //*** WAVE 4 *** Between 2 or 3 minutes after Wave 3
63
    call InitAssaultGroup()
64
    call CampaignAttackerEx( 3, 4, 4, ARCHER )
65
    call CampaignAttackerEx( 1, 2, 3, HUNTRESS )
66
    call CampaignAttackerEx( 0, 1, 1, BALLISTA )
67
    call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )
68
    call SuicideOnPlayerEx( M3, M2, M2, MyVictim )
69
    //*** Dryad Upgrade
70
    call SetBuildUpgrEx( 1, 1, 1, UPG_ABOLISH )
71
    //*** WAVE 5 *** Between 3 or 4 minutes after Wave 4
72
    call InitAssaultGroup()
73
    call CampaignAttackerEx( 3, 3, 3, ARCHER )
74
    call CampaignAttackerEx( 2, 2, 2, HUNTRESS )
75
    call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )
76
    call CampaignAttackerEx( 0, 1, 2, DRYAD )
77
    call SuicideOnPlayerEx( M4, M3, M3, MyVictim )
78
    //*** Druid of the Claw Upgrade
79
    call SetBuildUpgrEx( 0, 1, 2, UPG_DRUID_CLAW )
80
    //*** WAVE 6 *** Between 3 or 4 minutes after Wave 5
81
    call InitAssaultGroup()
82
    call CampaignAttackerEx( 2, 2, 2, HUNTRESS )
83
    call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )
84
    call CampaignAttackerEx( 1, 1, 1, MOON_CHICK )
85
    call CampaignAttackerEx( 1, 2, 3, DRYAD )
86
    call CampaignAttackerEx( 0, 1, 2, DRUID_CLAW )
87
    call SuicideOnPlayerEx( M4, M3, M3, MyVictim )
88
    //*** chimaera Upgrade
89
    call SetBuildUpgrEx( 0, 0, 1, UPG_CHIM_ACID )
90
    loop //Init the infinite attack loop
91
    //*** WAVE 7 *** Between 3 or 5 minutes after Wave 6
92
        call InitAssaultGroup()
93
        call CampaignAttackerEx( 2, 2, 2, HUNTRESS )
94
        call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )
95
        call CampaignAttackerEx( 1, 1, 1, MOON_CHICK )
96
        call CampaignAttackerEx( 1, 2, 3, DRYAD )
97
        call CampaignAttackerEx( 0, 1, 2, DRUID_CLAW )
98
        call CampaignAttackerEx( 0, 1, 2, MOUNTAIN_GIANT )
99
        call SuicideOnPlayerEx( M5, M4, M3, MyVictim )
100
        //*** WAVE 8 *** Between 3 or 5 minutes after Wave 7
101
        call InitAssaultGroup()
102
        call CampaignAttackerEx( 2, 2, 2, HUNTRESS )
103
        call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )
104
        call CampaignAttackerEx( 1, 1, 1, MOON_CHICK )
105
        call CampaignAttackerEx( 1, 2, 3, DRYAD )
106
        call CampaignAttackerEx( 0, 1, 2, DRUID_CLAW )
107
        //*** WAVE 9 *** Between 4 or 6 minutes after Wave 8
108
        call InitAssaultGroup()
109
        call CampaignAttackerEx( 2, 2, 2, HUNTRESS )
110
        call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )
111
        call CampaignAttackerEx( 1, 1, 1, MOON_CHICK )
112
        call CampaignAttackerEx( 1, 2, 3, DRYAD )
113
        call CampaignAttackerEx( 0, 1, 2, DRUID_CLAW )
114
        call CampaignAttackerEx( 0, 1, 2, MOUNTAIN_GIANT )
115
        call CampaignAttackerEx( 1, 1, 2, FAERIE_DRAGON )
116
        call CampaignAttackerEx( 0, 1, 2, CHIMAERA ) 
117
        call SuicideOnPlayerEx( M6, M5, M4, MyVictim )
118
    endloop
119
    // **********************************
120
    // *   Attack Strategy never ends   *
121
    // **********************************
122
endfunction



[point]hero[/point]
Hero Abilities.

If we test this AI, we can notice that heroes don't learn any abilities, the question is how can we make that??? the answer is adding the ability learning script to the function CampaignAI. This function will have an effect when the hero has ability levels avaliable. I made this script so it can fix with the example, which trains a Demon Hunter and a Priestress of the Moon.

Hero Leveling Script
Code (jass) Select
1
function hero_levels takes nothing returns integer
2
    local integer hero  = GetHeroId()
3
    local integer level = GetHeroLevelAI()
4
    local integer a = 0
5
    if hero == DEMON_HUNTER then
6
        if level == 1 or level == 3 or level == 5 then
7
            set a = IMMOLATION
8
        endif
9
        if level == 2 or level == 4 or level == 7 then
10
            set a = MANA_BURN
11
        endif
12
        if level >= 8 then
13
            set a = EVASION
14
        endif
15
        if level == 6 then
16
            set a = METAMORPHOSIS
17
        endif 
18
    endif
19
    if hero == MOON_CHICK then
20
        if level == 1 or level == 3 or level == 5 then
21
            set a = TRUESHOT
22
        endif
23
        if level == 2 or level == 4 or level == 7 then
24
            set a = SEARING_ARROWS
25
        endif
26
        if level >= 8 then
27
            set a = SCOUT
28
        endif
29
        if level == 6 then
30
            set a = STARFALL
31
        endif 
32
    endif
33
    return a
34
endfunction


As you can see, this function takes nothing and returns the ability Rawcode that the hero must learn. REMEMBER: This function MUST return an integer ALWAYS.

Now that we have this function configured, we are going to add to the script, remeber that it must be put bafore the main function so it can call it. To set the function in the main script, we write it in this way:
call CampaignAI( MOON_WELL, function hero_levels )
And the whole code will llook like this:

Building + Attacking script with infinite loop + Upgrading (including heroes) scripts. All tiers
Code (jass) Select
1
globals
2
    player MyVictim = Player( 0 )
3
endglobals
4
5
function ConfigureAI takes nothing returns nothing
6
    call SetSlowChopping( false )
7
    call SetPeonsRepair( true )
8
endfunction
9
10
function hero_levels takes nothing returns integer
11
    local integer hero  = GetHeroId()
12
    local integer level = GetHeroLevelAI()
13
    local integer a = 0
14
    if hero == DEMON_HUNTER then
15
        if level == 1 or level == 3 or level == 5 then
16
            set a = IMMOLATION
17
        endif
18
        if level == 2 or level == 4 or level == 7 then
19
            set a = MANA_BURN
20
        endif
21
        if level >= 8 then
22
            set a = EVASION
23
        endif
24
        if level == 6 then
25
            set a = METAMORPHOSIS
26
        endif 
27
    endif
28
    if hero == MOON_CHICK then
29
        if level == 1 or level == 3 or level == 5 then
30
            set a = TRUESHOT
31
        endif
32
        if level == 2 or level == 4 or level == 7 then
33
            set a = SEARING_ARROWS
34
        endif
35
        if level >= 8 then
36
            set a = SCOUT
37
        endif
38
        if level == 6 then
39
            set a = STARFALL
40
        endif 
41
    endif
42
    return a
43
endfunction
44
45
function main takes nothing returns nothing
46
    call CampaignAI( MOON_WELL, function hero_levels ) //<== Now this function upgrades heroes
47
    call ConfigureAI( )
48
    // **********************************
49
    // *      Building Strategy         *
50
    // **********************************
51
    //
52
    // Tier 1 Buildings
53
    call SetReplacements( 1, 2, 3 )
54
    call SetBuildUnitEx( 1, 1, 1, TREE_LIFE )
55
    call SetBuildUnit( 15, WISP )
56
    call SetBuildUnitEx( 1, 2, 3, MOON_WELL )
57
    call SetBuildUnitEx( 1, 2, 2, ANCIENT_WAR )
58
    call SetBuildUnit( 1, ELF_ALTAR )
59
    call SetBuildUnit( 1, HUNTERS_HALL )
60
    call CampaignDefenderEx( 2, 2, 3, ARCHER ) 
61
    call CampaignDefenderEx( 1, 1, 1, HUNTRESS )
62
    call SetBuildUnitEx( 1, 2, 3, ANCIENT_PROTECT )
63
    // Tier 2 buildings
64
    call SetBuildUnit( 1, TREE_AGES )
65
    call SetBuildUnitEx( 1, 2, 2, ANCIENT_LORE )
66
    call SetBuildUnit( 1, ANCIENT_WIND )
67
    // Tier 3 buildings
68
    call SetBuildUnit( 1, TREE_ETERNITY )
69
    call SetBuildUnitEx( 0, 1, 1, CHIMAERA_ROOST )
70
    // **********************************
71
    // *    End Building Strategy       *
72
    // **********************************
73
    // **********************************
74
    // *       Attack Strategy          *
75
    // **********************************
76
    //*** WAVE 1 *** AI will begin to attack in 5 minutes
77
    call InitAssaultGroup()
78
    call CampaignAttackerEx( 2, 3, 3, ARCHER )
79
    call CampaignAttackerEx( 0, 1, 2, HUNTRESS )  
80
    call SuicideOnPlayerEx( M5, M5, M5, MyVictim )
81
    //*** Basic upgrades from HUNTERS HALL ***
82
    call SetBuildUpgrEx( 1, 2, 3, UPG_STR_MOON )
83
    call SetBuildUpgrEx( 1, 2, 3, UPG_MOON_ARMOR )
84
    call SetBuildUpgrEx( 1, 2, 3, UPG_STR_WILD )
85
    call SetBuildUpgrEx( 1, 2, 3, UPG_HIDES )
86
    //*** WAVE 2 *** Between 2 or 3 minutes after Wave 1
87
    call InitAssaultGroup()
88
    call CampaignAttackerEx( 3, 4, 4, ARCHER )
89
    call CampaignAttackerEx( 1, 2, 3, HUNTRESS )  
90
    call SuicideOnPlayerEx( M3, M2, M2, MyVictim )
91
    //*** WAVE 3 *** Between 2 or 3 minutes after Wave 2
92
    call InitAssaultGroup()
93
    call CampaignAttackerEx( 3, 4, 4, ARCHER )
94
    call CampaignAttackerEx( 1, 2, 3, HUNTRESS )
95
    call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )
96
    call SuicideOnPlayerEx( M3, M2, M2, MyVictim )
97
    //*** WAVE 4 *** Between 2 or 3 minutes after Wave 3
98
    call InitAssaultGroup()
99
    call CampaignAttackerEx( 3, 4, 4, ARCHER )
100
    call CampaignAttackerEx( 1, 2, 3, HUNTRESS )
101
    call CampaignAttackerEx( 0, 1, 1, BALLISTA )
102
    call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )
103
    call SuicideOnPlayerEx( M3, M2, M2, MyVictim )
104
    //*** Dryad Upgrade
105
    call SetBuildUpgrEx( 1, 1, 1, UPG_ABOLISH )
106
    //*** WAVE 5 *** Between 3 or 4 minutes after Wave 4
107
    call InitAssaultGroup()
108
    call CampaignAttackerEx( 3, 3, 3, ARCHER )
109
    call CampaignAttackerEx( 2, 2, 2, HUNTRESS )
110
    call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )
111
    call CampaignAttackerEx( 0, 1, 2, DRYAD )
112
    call SuicideOnPlayerEx( M4, M3, M3, MyVictim )
113
    //*** Druid of the Claw Upgrade
114
    call SetBuildUpgrEx( 0, 1, 2, UPG_DRUID_CLAW )
115
    //*** WAVE 6 *** Between 3 or 4 minutes after Wave 5
116
    call InitAssaultGroup()
117
    call CampaignAttackerEx( 2, 2, 2, HUNTRESS )
118
    call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )
119
    call CampaignAttackerEx( 1, 1, 1, MOON_CHICK )
120
    call CampaignAttackerEx( 1, 2, 3, DRYAD )
121
    call CampaignAttackerEx( 0, 1, 2, DRUID_CLAW )
122
    call SuicideOnPlayerEx( M4, M3, M3, MyVictim )
123
    //*** chimaera Upgrade
124
    call SetBuildUpgrEx( 0, 0, 1, UPG_CHIM_ACID )
125
    loop //Init the infinite attack loop
126
    //*** WAVE 7 *** Between 3 or 5 minutes after Wave 6
127
        call InitAssaultGroup()
128
        call CampaignAttackerEx( 2, 2, 2, HUNTRESS )
129
        call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )
130
        call CampaignAttackerEx( 1, 1, 1, MOON_CHICK )
131
        call CampaignAttackerEx( 1, 2, 3, DRYAD )
132
        call CampaignAttackerEx( 0, 1, 2, DRUID_CLAW )
133
        call CampaignAttackerEx( 0, 1, 2, MOUNTAIN_GIANT )
134
        call SuicideOnPlayerEx( M5, M4, M3, MyVictim )
135
        //*** WAVE 8 *** Between 3 or 5 minutes after Wave 7
136
        call InitAssaultGroup()
137
        call CampaignAttackerEx( 2, 2, 2, HUNTRESS )
138
        call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )
139
        call CampaignAttackerEx( 1, 1, 1, MOON_CHICK )
140
        call CampaignAttackerEx( 1, 2, 3, DRYAD )
141
        call CampaignAttackerEx( 0, 1, 2, DRUID_CLAW )
142
        //*** WAVE 9 *** Between 4 or 6 minutes after Wave 8
143
        call InitAssaultGroup()
144
        call CampaignAttackerEx( 2, 2, 2, HUNTRESS )
145
        call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )
146
        call CampaignAttackerEx( 1, 1, 1, MOON_CHICK )
147
        call CampaignAttackerEx( 1, 2, 3, DRYAD )
148
        call CampaignAttackerEx( 0, 1, 2, DRUID_CLAW )
149
        call CampaignAttackerEx( 0, 1, 2, MOUNTAIN_GIANT )
150
        call CampaignAttackerEx( 1, 1, 2, FAERIE_DRAGON )
151
        call CampaignAttackerEx( 0, 1, 2, CHIMAERA ) 
152
        call SuicideOnPlayerEx( M6, M5, M4, MyVictim )
153
    endloop
154
    // **********************************
155
    // *   Attack Strategy never ends   *
156
    // **********************************
157
endfunction



[point]triggering[/point]
Controlling the AI via triggers.

when we're creating a campaign, we need to keep the AI controlled in some way, for example we need that the AI attacks when an unit enters on a region or the player kills some unit. As an example, We are going to create a trigger that will start the AI attacks when an unit enters in one region.

[TRIGGER]Start AI attack
    Events
        Unit - A unit enters Militia birth1 <gen>
    Conditions
        (Owner of (Triggering unit)) Equal to Player 1 (Red)
    Actions
        AI - Send Player 2 (Blue) the AI Command (0, 0)
        Custom script:   call DestroyTrigger( GetTriggeringTrigger() )
[/TRIGGER]

And now we need that the AI begins when it receives this AI Command, it can be done putting the function WaitForSignal() before the attacking script in the AI. This function takes nothing and returns an integer that is the command received. So we can use this function in two ways.

Code (jass) Select
1
function main takes nothing returns nothing
2
    local integer cmd // <==Only set it if you are going to use the option 2
3
    ... // Your building code here
4
    // Option 1
5
    call WaitForSignal() // <== Just waits until the map sends a command
6
7
    // Option 2
8
    set cmd = WaitForSignal() // <== Get the command received and makes react the AI accordingly.
9
    if cmd == 0 then
10
        //do option 0
11
    elseif cmd == 1 then
12
        //do option 1. etc
13
    ...
14
    endif 
15
endfunction

       
  • The second option is the most interesting because we can make react the AI in different ways (for example, that one time attack the player 1 and in other time attack the player 3, etc.)


[point]testing[/point]
Testing the AI.

Now the most important part. If we want to test this AI there's two ways, the slowest but the most accurate, which we attach the AI file inside the map and run it to check how it bahaves (check this tutorial from Av3n about AI importing) or the fastest one. I'll explain the fastest one.



       
  • Save your AI script as an *.AI file.
  • Open WE
  • Press F8 or make click on the button AI Editor.
  • With the AI Editor open, select the fourth tab Test Configuration
  • Here, set the game speed in 3X (Now you understand why it's the fastest way)
  • Set the map where you want to test your AI. By default, WE sets the PlunderIsle map. You can change it pressing the button [BUTTON]Set Map[/BUTTON].
  • Set your Players. Remember that if you configure the AI to attack player 1 (Player(0) in JASS) you MUST use a slot different to 1 so it can works. it sounds redundant, but sometimes we forget it.
  • Set the race of your AI accordingly (don't put human or random race in a Night Elf AI fr example).
  • for the slot where our AI will work, change in the AI option to Custom. when you do that, it activates a button with label [BUTTON]Set[/BUTTON]. Press it, and you can select the AI file that you have created.
  • Set the target player as a computer with a current AI.
  • Ensure that your AI player and the target player are in different teams.
  • Set an user player as an observer in the team selection.
  • Press CTRL + F9 or the button Test AI
Here's an AI Editor screenshot that shows how you should have configured this test:
And the test will run. If the AI works fine you will see the workers starting buildings. :emote_grin:

If you see workers only gathering resources and don't do anything else, it means that you have a JASS error in you file, check the syntax, save and test again, remember that JASS is case sensitive so a lower case letter will do the AI fail.

[BTABLE=Final Thoughts]I Hope this tutorial can be helpful to everybody. If I have time, I'll try to do other tutorial about Standard AI. Suggestions and questions are welcome.

Meanwhile, play with this AI, change the units, do experiments with it, it is the only way to get more knowledge about the Wacraft AI.[/BTABLE]
PS: Because I'm still learning English, I could have commited some mistakes, please let me know about that and I will fix them ASAP.


Campaign Complete
Campaign script complete
Code (jass) Select
1
//******************************************************************************
2
//*                           Night Elf Campaign AI                            *
3
//*                                 By Moyack                                  *
4
//******************************************************************************
5
//*
6
globals
7
    player MyVictim = Player( 0 )
8
endglobals
9
10
function ConfigureAI takes nothing returns nothing
11
    call SetSlowChopping( false )
12
    call SetPeonsRepair( true )
13
endfunction
14
15
function hero_levels takes nothing returns integer
16
    local integer hero  = GetHeroId()
17
    local integer level = GetHeroLevelAI()
18
    local integer a = 0
19
    if hero == DEMON_HUNTER then
20
        if level == 1 or level == 3 or level == 5 then
21
            set a = IMMOLATION
22
        endif
23
        if level == 2 or level == 4 or level == 7 then
24
            set a = MANA_BURN
25
        endif
26
        if level >= 8 then
27
            set a = EVASION
28
        endif
29
        if level == 6 then
30
            set a = METAMORPHOSIS
31
        endif 
32
    endif
33
    if hero == MOON_CHICK then
34
        if level == 1 or level == 3 or level == 5 then
35
            set a = TRUESHOT
36
        endif
37
        if level == 2 or level == 4 or level == 7 then
38
            set a = SEARING_ARROWS
39
        endif
40
        if level >= 8 then
41
            set a = SCOUT
42
        endif
43
        if level == 6 then
44
            set a = STARFALL
45
        endif 
46
    endif
47
    return a
48
endfunction
49
50
function main takes nothing returns nothing
51
    call CampaignAI( MOON_WELL, function hero_levels )
52
    call ConfigureAI( )
53
    // **********************************
54
    // *      Building Strategy         *
55
    // **********************************
56
    //
57
    // Tier 1 Buildings
58
    call SetReplacements( 1, 2, 3 )
59
    call SetBuildUnitEx( 1, 1, 1, TREE_LIFE )
60
    call SetBuildUnit( 15, WISP )
61
    call SetBuildUnitEx( 1, 2, 3, MOON_WELL )
62
    call SetBuildUnitEx( 1, 2, 2, ANCIENT_WAR )
63
    call SetBuildUnit( 1, ELF_ALTAR )
64
    call SetBuildUnit( 1, HUNTERS_HALL )
65
    call CampaignDefenderEx( 2, 2, 3, ARCHER ) 
66
    call CampaignDefenderEx( 1, 1, 1, HUNTRESS )
67
    call SetBuildUnitEx( 1, 2, 3, ANCIENT_PROTECT )
68
    // Tier 2 buildings
69
    call SetBuildUnit( 1, TREE_AGES )
70
    call SetBuildUnitEx( 1, 2, 2, ANCIENT_LORE )
71
    call SetBuildUnit( 1, ANCIENT_WIND )
72
    // Tier 3 buildings
73
    call SetBuildUnit( 1, TREE_ETERNITY )
74
    call SetBuildUnitEx( 0, 1, 1, CHIMAERA_ROOST )
75
    // **********************************
76
    // *    End Building Strategy       *
77
    // **********************************
78
    // **********************************
79
    // *       Attack Strategy          *
80
    // **********************************
81
    //*** WAVE 1 *** AI will begin to attack in 5 minutes
82
    call InitAssaultGroup()
83
    call CampaignAttackerEx( 2, 3, 3, ARCHER )
84
    call CampaignAttackerEx( 0, 1, 2, HUNTRESS )  
85
    call SuicideOnPlayerEx( M5, M5, M5, MyVictim )
86
    //*** Basic upgrades from HUNTERS HALL ***
87
    call SetBuildUpgrEx( 1, 2, 3, UPG_STR_MOON )
88
    call SetBuildUpgrEx( 1, 2, 3, UPG_MOON_ARMOR )
89
    call SetBuildUpgrEx( 1, 2, 3, UPG_STR_WILD )
90
    call SetBuildUpgrEx( 1, 2, 3, UPG_HIDES )
91
    //*** WAVE 2 *** Between 2 or 3 minutes after Wave 1
92
    call InitAssaultGroup()
93
    call CampaignAttackerEx( 3, 4, 4, ARCHER )
94
    call CampaignAttackerEx( 1, 2, 3, HUNTRESS )  
95
    call SuicideOnPlayerEx( M3, M2, M2, MyVictim )
96
    //*** WAVE 3 *** Between 2 or 3 minutes after Wave 2
97
    call InitAssaultGroup()
98
    call CampaignAttackerEx( 3, 4, 4, ARCHER )
99
    call CampaignAttackerEx( 1, 2, 3, HUNTRESS )
100
    call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )
101
    call SuicideOnPlayerEx( M3, M2, M2, MyVictim )
102
    //*** WAVE 4 *** Between 2 or 3 minutes after Wave 3
103
    call InitAssaultGroup()
104
    call CampaignAttackerEx( 3, 4, 4, ARCHER )
105
    call CampaignAttackerEx( 1, 2, 3, HUNTRESS )
106
    call CampaignAttackerEx( 0, 1, 1, BALLISTA )
107
    call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )
108
    call SuicideOnPlayerEx( M3, M2, M2, MyVictim )
109
    //*** Dryad Upgrade
110
    call SetBuildUpgrEx( 1, 1, 1, UPG_ABOLISH )
111
    //*** WAVE 5 *** Between 3 or 4 minutes after Wave 4
112
    call InitAssaultGroup()
113
    call CampaignAttackerEx( 3, 3, 3, ARCHER )
114
    call CampaignAttackerEx( 2, 2, 2, HUNTRESS )
115
    call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )
116
    call CampaignAttackerEx( 0, 1, 2, DRYAD )
117
    call SuicideOnPlayerEx( M4, M3, M3, MyVictim )
118
    //*** Druid of the Claw Upgrade
119
    call SetBuildUpgrEx( 0, 1, 2, UPG_DRUID_CLAW )
120
    //*** WAVE 6 *** Between 3 or 4 minutes after Wave 5
121
    call InitAssaultGroup()
122
    call CampaignAttackerEx( 2, 2, 2, HUNTRESS )
123
    call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )
124
    call CampaignAttackerEx( 1, 1, 1, MOON_CHICK )
125
    call CampaignAttackerEx( 1, 2, 3, DRYAD )
126
    call CampaignAttackerEx( 0, 1, 2, DRUID_CLAW )
127
    call SuicideOnPlayerEx( M4, M3, M3, MyVictim )
128
    //*** chimaera Upgrade
129
    call SetBuildUpgrEx( 0, 0, 1, UPG_CHIM_ACID )
130
    loop //Init the infinite attack loop
131
    //*** WAVE 7 *** Between 3 or 5 minutes after Wave 6
132
        call InitAssaultGroup()
133
        call CampaignAttackerEx( 2, 2, 2, HUNTRESS )
134
        call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )
135
        call CampaignAttackerEx( 1, 1, 1, MOON_CHICK )
136
        call CampaignAttackerEx( 1, 2, 3, DRYAD )
137
        call CampaignAttackerEx( 0, 1, 2, DRUID_CLAW )
138
        call CampaignAttackerEx( 0, 1, 2, MOUNTAIN_GIANT )
139
        call SuicideOnPlayerEx( M5, M4, M3, MyVictim )
140
        //*** WAVE 8 *** Between 3 or 5 minutes after Wave 7
141
        call InitAssaultGroup()
142
        call CampaignAttackerEx( 2, 2, 2, HUNTRESS )
143
        call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )
144
        call CampaignAttackerEx( 1, 1, 1, MOON_CHICK )
145
        call CampaignAttackerEx( 1, 2, 3, DRYAD )
146
        call CampaignAttackerEx( 0, 1, 2, DRUID_CLAW )
147
        call SuicideOnPlayerEx( M5, M4, M3, MyVictim )
148
        //*** WAVE 9 *** Between 4 or 6 minutes after Wave 8
149
        call InitAssaultGroup()
150
        call CampaignAttackerEx( 2, 2, 2, HUNTRESS )
151
        call CampaignAttackerEx( 1, 1, 1, DEMON_HUNTER )
152
        call CampaignAttackerEx( 1, 1, 1, MOON_CHICK )
153
        call CampaignAttackerEx( 1, 2, 3, DRYAD )
154
        call CampaignAttackerEx( 0, 1, 2, DRUID_CLAW )
155
        call CampaignAttackerEx( 0, 1, 2, MOUNTAIN_GIANT )
156
        call CampaignAttackerEx( 1, 1, 2, FAERIE_DRAGON )
157
        call CampaignAttackerEx( 0, 1, 2, CHIMAERA ) 
158
        call SuicideOnPlayerEx( M6, M5, M4, MyVictim )
159
    endloop
160
    // **********************************
161
    // *   Attack Strategy never ends   *
162
    // **********************************
163
endfunction
  • AI Editor SC.jpg (55.9 KB)
13 years
edited 9 years
Updated with a fix in the definition of a function. Thanks Starquizer :D