15 years
edited 6 years
HOW TO MAKE A CAMPAIGN AI.
By Moyack
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]
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.

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
1 globals2 // We put the globals variables here3 endglobals4 5 function blabla takes blabla returns blabla
6 // Custom function stuff7 endfunction8 9 ...
10 11 function main takes nothing returns nothing
12 //The main code goes here13 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
Now we will create the main function
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.
Now we will create the main function
main function
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 NE4 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
1 function ConfigureAI takes nothing returns nothing
2 call SetSlowChopping( false )
3 call SetPeonsRepair( true )
4 endfunction5 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
1 globals2 player MyVictim = Player( 0 )
3 endglobals4 5 function ConfigureAI takes nothing returns nothing
6 call SetSlowChopping( false )
7 call SetPeonsRepair( true )
8 endfunction9 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
1 globals2 player MyVictim = Player( 0 )
3 endglobals4 5 function ConfigureAI takes nothing returns nothing
6 call SetSlowChopping( false )
7 call SetPeonsRepair( true )
8 endfunction9 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.
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]
[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
1 function main takes nothing returns nothing
2 3 // Building code goes here4 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.
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
1 function main takes nothing returns nothing
2 local unit crp
3 // Building code goes here4 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.
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
1 globals2 player MyVictim = Player( 0 )
3 endglobals4 5 function ConfigureAI takes nothing returns nothing
6 call SetSlowChopping( false )
7 call SetPeonsRepair( true )
8 endfunction9 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 Buildings18 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 buildings29 call SetBuildUnit( 1, TREE_AGES )
30 call SetBuildUnitEx( 1, 1, 2, ANCIENT_LORE )
31 call SetBuildUnit( 1, ANCIENT_WIND )
32 // Tier 3 buildings33 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 147 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 252 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 358 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 464 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 571 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 679 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 788 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 895 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
1 globals2 player MyVictim = Player( 0 )
3 endglobals4 5 function ConfigureAI takes nothing returns nothing
6 call SetSlowChopping( false )
7 call SetPeonsRepair( true )
8 endfunction9 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 Buildings18 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 buildings29 call SetBuildUnit( 1, TREE_AGES )
30 call SetBuildUnitEx( 1, 1, 2, ANCIENT_LORE )
31 call SetBuildUnit( 1, ANCIENT_WIND )
32 // Tier 3 buildings33 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 147 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 252 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 358 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 464 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 571 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 680 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 789 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 896 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 endloop107 // **********************************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.
Building + Attacking script with infinite loop + Upgrading scripts. All tiers
1 globals2 player MyVictim = Player( 0 )
3 endglobals4 5 function ConfigureAI takes nothing returns nothing
6 call SetSlowChopping( false )
7 call SetPeonsRepair( true )
8 endfunction9 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 Buildings18 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 buildings29 call SetBuildUnit( 1, TREE_AGES )
30 call SetBuildUnitEx( 1, 1, 2, ANCIENT_LORE )
31 call SetBuildUnit( 1, ANCIENT_WIND )
32 // Tier 3 buildings33 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 minutes42 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 152 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 257 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 363 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 Upgrade70 call SetBuildUpgrEx( 1, 1, 1, UPG_ABOLISH )
71 //*** WAVE 5 *** Between 3 or 4 minutes after Wave 472 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 Upgrade79 call SetBuildUpgrEx( 0, 1, 2, UPG_DRUID_CLAW )
80 //*** WAVE 6 *** Between 3 or 4 minutes after Wave 581 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 Upgrade89 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 692 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 7101 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 8108 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 endloop119 // **********************************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
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 endif9 if level == 2 or level == 4 or level == 7 then
10 set a = MANA_BURN
11 endif12 if level >= 8 then
13 set a = EVASION
14 endif15 if level == 6 then
16 set a = METAMORPHOSIS
17 endif 18 endif19 if hero == MOON_CHICK then
20 if level == 1 or level == 3 or level == 5 then
21 set a = TRUESHOT
22 endif23 if level == 2 or level == 4 or level == 7 then
24 set a = SEARING_ARROWS
25 endif26 if level >= 8 then
27 set a = SCOUT
28 endif29 if level == 6 then
30 set a = STARFALL
31 endif 32 endif33 return a34 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
1 globals2 player MyVictim = Player( 0 )
3 endglobals4 5 function ConfigureAI takes nothing returns nothing
6 call SetSlowChopping( false )
7 call SetPeonsRepair( true )
8 endfunction9 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 endif18 if level == 2 or level == 4 or level == 7 then
19 set a = MANA_BURN
20 endif21 if level >= 8 then
22 set a = EVASION
23 endif24 if level == 6 then
25 set a = METAMORPHOSIS
26 endif 27 endif28 if hero == MOON_CHICK then
29 if level == 1 or level == 3 or level == 5 then
30 set a = TRUESHOT
31 endif32 if level == 2 or level == 4 or level == 7 then
33 set a = SEARING_ARROWS
34 endif35 if level >= 8 then
36 set a = SCOUT
37 endif38 if level == 6 then
39 set a = STARFALL
40 endif 41 endif42 return a43 endfunction44 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 Buildings53 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 buildings64 call SetBuildUnit( 1, TREE_AGES )
65 call SetBuildUnitEx( 1, 2, 2, ANCIENT_LORE )
66 call SetBuildUnit( 1, ANCIENT_WIND )
67 // Tier 3 buildings68 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 minutes77 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 187 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 292 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 398 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 Upgrade105 call SetBuildUpgrEx( 1, 1, 1, UPG_ABOLISH )
106 //*** WAVE 5 *** Between 3 or 4 minutes after Wave 4107 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 Upgrade114 call SetBuildUpgrEx( 0, 1, 2, UPG_DRUID_CLAW )
115 //*** WAVE 6 *** Between 3 or 4 minutes after Wave 5116 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 Upgrade124 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 6127 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 7136 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 8143 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 endloop154 // **********************************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.
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 15 call WaitForSignal() // <== Just waits until the map sends a command
6 7 // Option 28 set cmd = WaitForSignal() // <== Get the command received and makes react the AI accordingly.
9 if cmd == 0 then
10 //do option 011 elseif cmd == 1 then
12 //do option 1. etc13 ...
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.)
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
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.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]
Campaign Complete
Campaign script complete
1 //******************************************************************************2 //* Night Elf Campaign AI *3 //* By Moyack *4 //******************************************************************************5 //*6 globals7 player MyVictim = Player( 0 )
8 endglobals9 10 function ConfigureAI takes nothing returns nothing
11 call SetSlowChopping( false )
12 call SetPeonsRepair( true )
13 endfunction14 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 endif23 if level == 2 or level == 4 or level == 7 then
24 set a = MANA_BURN
25 endif26 if level >= 8 then
27 set a = EVASION
28 endif29 if level == 6 then
30 set a = METAMORPHOSIS
31 endif 32 endif33 if hero == MOON_CHICK then
34 if level == 1 or level == 3 or level == 5 then
35 set a = TRUESHOT
36 endif37 if level == 2 or level == 4 or level == 7 then
38 set a = SEARING_ARROWS
39 endif40 if level >= 8 then
41 set a = SCOUT
42 endif43 if level == 6 then
44 set a = STARFALL
45 endif 46 endif47 return a48 endfunction49 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 Buildings58 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 buildings69 call SetBuildUnit( 1, TREE_AGES )
70 call SetBuildUnitEx( 1, 2, 2, ANCIENT_LORE )
71 call SetBuildUnit( 1, ANCIENT_WIND )
72 // Tier 3 buildings73 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 minutes82 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 192 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 297 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 3103 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 Upgrade110 call SetBuildUpgrEx( 1, 1, 1, UPG_ABOLISH )
111 //*** WAVE 5 *** Between 3 or 4 minutes after Wave 4112 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 Upgrade119 call SetBuildUpgrEx( 0, 1, 2, UPG_DRUID_CLAW )
120 //*** WAVE 6 *** Between 3 or 4 minutes after Wave 5121 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 Upgrade129 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 6132 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 7141 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 8149 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 endloop160 // **********************************161 // * Attack Strategy never ends *162 // **********************************163 endfunction