The search keyword must be a single word (no spaces).

common.ai

1
//==================================================================================================
2
//  $Id: common.ai,v 1.68 2003/05/12 02:34:18 bfitch Exp $
3
//==================================================================================================
4
native DebugS               takes string str                            returns nothing
5
native DebugFI              takes string str, integer val               returns nothing
6
native DebugUnitID          takes string str, integer val               returns nothing
7
native DisplayText          takes integer p, string str                 returns nothing
8
native DisplayTextI         takes integer p, string str, integer val    returns nothing
9
native DisplayTextII        takes integer p, string str, integer v1, integer v2 returns nothing
10
native DisplayTextIII       takes integer p, string str, integer v1, integer v2, integer v3 returns nothing
11
native DoAiScriptDebug      takes nothing                               returns boolean
12
13
native GetAiPlayer          takes nothing                               returns integer
14
native GetHeroId            takes nothing                               returns integer
15
native GetHeroLevelAI       takes nothing                               returns integer
16
17
native GetUnitCount         takes integer unitid                        returns integer
18
native GetPlayerUnitTypeCount takes player p, integer unitid            returns integer
19
native GetUnitCountDone     takes integer unitid                        returns integer
20
native GetTownUnitCount     takes integer id, integer tn, boolean dn    returns integer
21
native GetUnitGoldCost      takes integer unitid                        returns integer
22
native GetUnitWoodCost      takes integer unitid                        returns integer
23
native GetUnitBuildTime     takes integer unitid                        returns integer
24
25
native GetMinesOwned        takes nothing                               returns integer
26
native GetGoldOwned         takes nothing                               returns integer
27
native TownWithMine         takes nothing                               returns integer
28
native TownHasMine          takes integer townid                        returns boolean
29
native TownHasHall          takes integer townid                        returns boolean
30
31
native GetUpgradeLevel      takes integer id                            returns integer
32
native GetUpgradeGoldCost   takes integer id                            returns integer
33
native GetUpgradeWoodCost   takes integer id                            returns integer
34
native GetNextExpansion     takes nothing                               returns integer
35
native GetMegaTarget        takes nothing                               returns unit
36
native GetBuilding          takes player p                              returns unit
37
native GetEnemyPower        takes nothing                               returns integer
38
native SetAllianceTarget    takes unit id                               returns nothing
39
native GetAllianceTarget    takes nothing                               returns unit
40
41
native SetProduce           takes integer qty, integer id, integer town returns boolean
42
native Unsummon             takes unit unitid                           returns nothing
43
native SetExpansion         takes unit peon, integer id                 returns boolean
44
native SetUpgrade           takes integer id                            returns boolean
45
native SetHeroLevels        takes code func                             returns nothing
46
native SetNewHeroes         takes boolean state                         returns nothing
47
native PurchaseZeppelin     takes nothing                               returns nothing
48
49
native MergeUnits           takes integer qty, integer a, integer b, integer make returns boolean
50
native ConvertUnits         takes integer qty, integer id               returns boolean
51
52
native SetCampaignAI        takes nothing                               returns nothing
53
native SetMeleeAI           takes nothing                               returns nothing
54
native SetTargetHeroes      takes boolean state                         returns nothing
55
native SetPeonsRepair       takes boolean state                         returns nothing
56
native SetRandomPaths       takes boolean state                         returns nothing
57
native SetDefendPlayer      takes boolean state                         returns nothing
58
native SetHeroesFlee        takes boolean state                         returns nothing
59
native SetHeroesBuyItems    takes boolean state                         returns nothing
60
native SetWatchMegaTargets  takes boolean state                         returns nothing
61
native SetIgnoreInjured     takes boolean state                         returns nothing
62
native SetHeroesTakeItems   takes boolean state                         returns nothing
63
native SetUnitsFlee         takes boolean state                         returns nothing
64
native SetGroupsFlee        takes boolean state                         returns nothing
65
native SetSlowChopping      takes boolean state                         returns nothing
66
native SetCaptainChanges    takes boolean allow                         returns nothing
67
native SetSmartArtillery    takes boolean state                         returns nothing
68
native SetReplacementCount  takes integer qty                           returns nothing
69
native GroupTimedLife       takes boolean allow                         returns nothing
70
native RemoveInjuries       takes nothing                               returns nothing
71
native RemoveSiege          takes nothing                               returns nothing
72
73
native InitAssault          takes nothing                               returns nothing
74
native AddAssault           takes integer qty, integer id               returns boolean
75
native AddDefenders         takes integer qty, integer id               returns boolean
76
77
native GetCreepCamp         takes integer min, integer max, boolean flyers_ok returns unit
78
79
native StartGetEnemyBase    takes nothing                               returns nothing
80
native WaitGetEnemyBase     takes nothing                               returns boolean
81
native GetEnemyBase         takes nothing                               returns unit
82
native GetExpansionFoe      takes nothing                               returns unit
83
native GetEnemyExpansion    takes nothing                               returns unit
84
native GetExpansionX        takes nothing                               returns integer
85
native GetExpansionY        takes nothing                               returns integer
86
native SetStagePoint        takes real x, real y                        returns nothing
87
native AttackMoveKill       takes unit target                           returns nothing
88
native AttackMoveXY         takes integer x, integer y                  returns nothing
89
native LoadZepWave          takes integer x, integer y                  returns nothing
90
native SuicidePlayer        takes player id, boolean check_full         returns boolean
91
native SuicidePlayerUnits   takes player id, boolean check_full         returns boolean
92
native CaptainInCombat      takes boolean attack_captain                returns boolean
93
native IsTowered            takes unit target                           returns boolean
94
95
native ClearHarvestAI       takes nothing                               returns nothing
96
native HarvestGold          takes integer town, integer peons           returns nothing
97
native HarvestWood          takes integer town, integer peons           returns nothing
98
native GetExpansionPeon     takes nothing                               returns unit
99
100
native StopGathering        takes nothing                               returns nothing
101
native AddGuardPost         takes integer id, real x, real y            returns nothing
102
native FillGuardPosts       takes nothing                               returns nothing
103
native ReturnGuardPosts     takes nothing                               returns nothing
104
native CreateCaptains       takes nothing                               returns nothing
105
native SetCaptainHome       takes integer which, real x, real y         returns nothing
106
native ResetCaptainLocs     takes nothing                               returns nothing
107
native ShiftTownSpot        takes real x, real y                        returns nothing
108
native TeleportCaptain      takes real x, real y                        returns nothing
109
native ClearCaptainTargets  takes nothing                               returns nothing
110
native CaptainAttack        takes real x, real y                        returns nothing
111
native CaptainVsUnits       takes player id                             returns nothing
112
native CaptainVsPlayer      takes player id                             returns nothing
113
native CaptainGoHome        takes nothing                               returns nothing
114
native CaptainIsHome        takes nothing                               returns boolean
115
native CaptainIsFull        takes nothing                               returns boolean
116
native CaptainIsEmpty       takes nothing                               returns boolean
117
native CaptainGroupSize     takes nothing                               returns integer
118
native CaptainReadiness     takes nothing                               returns integer
119
native CaptainRetreating    takes nothing                               returns boolean
120
native CaptainReadinessHP   takes nothing                               returns integer
121
native CaptainReadinessMa   takes nothing                               returns integer
122
native CaptainAtGoal        takes nothing                               returns boolean
123
native CreepsOnMap          takes nothing                               returns boolean
124
native SuicideUnit          takes integer count, integer unitid         returns nothing
125
native SuicideUnitEx        takes integer ct, integer uid, integer pid  returns nothing
126
native StartThread          takes code func                             returns nothing
127
native Sleep                takes real seconds                          returns nothing
128
native UnitAlive            takes unit id                               returns boolean
129
native UnitInvis            takes unit id                               returns boolean
130
native IgnoredUnits         takes integer unitid                        returns integer
131
native TownThreatened       takes nothing                               returns boolean
132
native DisablePathing       takes nothing                               returns nothing
133
native SetAmphibious        takes nothing                               returns nothing
134
135
native CommandsWaiting      takes nothing                               returns integer
136
native GetLastCommand       takes nothing                               returns integer
137
native GetLastData          takes nothing                               returns integer
138
native PopLastCommand       takes nothing                               returns nothing
139
native MeleeDifficulty      takes nothing                               returns integer
140
141
//============================================================================
142
//  Globals for all AI scripts
143
//============================================================================
144
globals
145
146
    //--------------------------------------------------------------------
147
    //  HUMANS
148
    //--------------------------------------------------------------------
149
150
    // human heroes
151
    constant integer ARCHMAGE           = 'Hamg'
152
    constant integer PALADIN            = 'Hpal'
153
    constant integer MTN_KING           = 'Hmkg'
154
    constant integer BLOOD_MAGE         = 'Hblm'
155
156
    // human hero abilities
157
    constant integer AVATAR             = 'AHav'
158
    constant integer BASH               = 'AHbh'
159
    constant integer THUNDER_BOLT       = 'AHtb'
160
    constant integer THUNDER_CLAP       = 'AHtc'
161
162
    constant integer DEVOTION_AURA      = 'AHad'
163
    constant integer DIVINE_SHIELD      = 'AHds'
164
    constant integer HOLY_BOLT          = 'AHhb'
165
    constant integer RESURRECTION       = 'AHre'
166
167
    constant integer BLIZZARD           = 'AHbz'
168
    constant integer BRILLIANCE_AURA    = 'AHab'
169
    constant integer MASS_TELEPORT      = 'AHmt'
170
    constant integer WATER_ELEMENTAL    = 'AHwe'
171
172
    constant integer BANISH             = 'AHbn'
173
    constant integer FLAME_STRIKE       = 'AHfs'
174
    constant integer SUMMON_PHOENIX     = 'AHpx'
175
    constant integer SIPHON_MANA        = 'AHdr'
176
177
    // special human heroes
178
    constant integer JAINA              = 'Hjai'
179
    constant integer MURADIN            = 'Hmbr'
180
    constant integer GARITHOS           = 'Hlgr'
181
    constant integer KAEL               = 'Hkal'
182
183
    // human units
184
    constant integer COPTER             = 'hgyr'
185
    constant integer GYRO               =  COPTER
186
    constant integer ELEMENTAL          = 'hwat'
187
    constant integer FOOTMAN            = 'hfoo'
188
    constant integer FOOTMEN            =  FOOTMAN
189
    constant integer GRYPHON            = 'hgry'
190
    constant integer KNIGHT             = 'hkni'
191
    constant integer MORTAR             = 'hmtm'
192
    constant integer PEASANT            = 'hpea'
193
    constant integer PRIEST             = 'hmpr'
194
    constant integer RIFLEMAN           = 'hrif'
195
    constant integer RIFLEMEN           =  RIFLEMAN
196
    constant integer SORCERESS          = 'hsor'
197
    constant integer TANK               = 'hmtt'
198
    constant integer STEAM_TANK         =  TANK
199
    constant integer ROCKET_TANK        = 'hrtt'
200
    constant integer MILITIA            = 'hmil'
201
    constant integer SPELL_BREAKER      = 'hspt'
202
    constant integer HUMAN_DRAGON_HAWK  = 'hdhw'
203
204
    // special human units
205
    constant integer BLOOD_PRIEST       = 'hbep'
206
    constant integer BLOOD_SORCERESS    = 'hbes'
207
    constant integer BLOOD_PEASANT      = 'nhew'
208
209
    // human buildings
210
    constant integer AVIARY             = 'hgra'
211
    constant integer BARRACKS           = 'hbar'
212
    constant integer BLACKSMITH         = 'hbla'
213
    constant integer CANNON_TOWER       = 'hctw'
214
    constant integer CASTLE             = 'hcas'
215
    constant integer CHURCH             = 'htws'
216
    constant integer MAGE_TOWER         =  CHURCH
217
    constant integer GUARD_TOWER        = 'hgtw'
218
    constant integer HOUSE              = 'hhou'
219
    constant integer HUMAN_ALTAR        = 'halt'
220
    constant integer KEEP               = 'hkee'
221
    constant integer LUMBER_MILL        = 'hlum'
222
    constant integer SANCTUM            = 'hars'
223
    constant integer ARCANE_SANCTUM     =  SANCTUM
224
    constant integer TOWN_HALL          = 'htow'
225
    constant integer WATCH_TOWER        = 'hwtw'
226
    constant integer WORKSHOP           = 'harm'
227
    constant integer ARCANE_VAULT       = 'hvlt'
228
    constant integer ARCANE_TOWER       = 'hatw'
229
230
    // human upgrades
231
    constant integer UPG_MELEE          = 'Rhme'
232
    constant integer UPG_RANGED         = 'Rhra'
233
    constant integer UPG_ARTILLERY      = 'Rhaa'
234
    constant integer UPG_ARMOR          = 'Rhar'
235
    constant integer UPG_GOLD           = 'Rhmi'
236
    constant integer UPG_MASONRY        = 'Rhac'
237
    constant integer UPG_SIGHT          = 'Rhss'
238
    constant integer UPG_DEFEND         = 'Rhde'
239
    constant integer UPG_BREEDING       = 'Rhan'
240
    constant integer UPG_PRAYING        = 'Rhpt'
241
    constant integer UPG_SORCERY        = 'Rhst'
242
    constant integer UPG_LEATHER        = 'Rhla'
243
    constant integer UPG_GUN_RANGE      = 'Rhri'
244
    constant integer UPG_WOOD           = 'Rhlh'
245
    constant integer UPG_SENTINEL       = 'Rhse'
246
    constant integer UPG_SCATTER        = 'Rhsr'
247
    constant integer UPG_BOMBS          = 'Rhgb'
248
    constant integer UPG_HAMMERS        = 'Rhhb'
249
    constant integer UPG_CONT_MAGIC     = 'Rhss'
250
    constant integer UPG_FRAGS          = 'Rhfs'
251
    constant integer UPG_TANK           = 'Rhrt'
252
    constant integer UPG_FLAK           = 'Rhfc'
253
    constant integer UPG_CLOUD          = 'Rhcd'
254
255
    //--------------------------------------------------------------------
256
    //  ORCS
257
    //--------------------------------------------------------------------
258
259
    // orc heroes
260
    constant integer BLADE_MASTER       = 'Obla'
261
    constant integer FAR_SEER           = 'Ofar'
262
    constant integer TAUREN_CHIEF       = 'Otch'
263
    constant integer SHADOW_HUNTER      = 'Oshd'
264
265
    // special orc heroes
266
    constant integer GROM               = 'Ogrh'
267
    constant integer THRALL             = 'Othr'
268
269
    // orc hero abilities
270
    constant integer CRITICAL_STRIKE    = 'AOcr'
271
    constant integer MIRROR_IMAGE       = 'AOmi'
272
    constant integer BLADE_STORM        = 'AOww'
273
    constant integer WIND_WALK          = 'AOwk'
274
275
    constant integer CHAIN_LIGHTNING    = 'AOcl'
276
    constant integer EARTHQUAKE         = 'AOeq'
277
    constant integer FAR_SIGHT          = 'AOfs'
278
    constant integer SPIRIT_WOLF        = 'AOsf'
279
280
    constant integer ENDURANE_AURA      = 'AOae'
281
    constant integer REINCARNATION      = 'AOre'
282
    constant integer SHOCKWAVE          = 'AOsh'
283
    constant integer WAR_STOMP          = 'AOws'
284
285
    constant integer HEALING_WAVE       = 'AOhw'
286
    constant integer HEX                = 'AOhx'
287
    constant integer SERPENT_WARD       = 'AOsw'
288
    constant integer VOODOO             = 'AOvd'
289
290
    // orc units
291
    constant integer GUARDIAN           = 'oang'
292
    constant integer CATAPULT           = 'ocat'
293
    constant integer WITCH_DOCTOR       = 'odoc'
294
    constant integer GRUNT              = 'ogru'
295
    constant integer HEAD_HUNTER        = 'ohun'
296
    constant integer BERSERKER          = 'otbk'
297
    constant integer KODO_BEAST         = 'okod'
298
    constant integer PEON               = 'opeo'
299
    constant integer RAIDER             = 'orai'
300
    constant integer SHAMAN             = 'oshm'
301
    constant integer TAUREN             = 'otau'
302
    constant integer WYVERN             = 'owyv'
303
    constant integer BATRIDER           = 'otbr'
304
    constant integer SPIRIT_WALKER      = 'ospw'
305
    constant integer SPIRIT_WALKER_M    = 'ospm'
306
307
    // orc buildings
308
    constant integer ORC_ALTAR          = 'oalt'
309
    constant integer ORC_BARRACKS       = 'obar'
310
    constant integer BESTIARY           = 'obea'
311
    constant integer FORGE              = 'ofor'
312
    constant integer FORTRESS           = 'ofrt'
313
    constant integer GREAT_HALL         = 'ogre'
314
    constant integer LODGE              = 'osld'
315
    constant integer STRONGHOLD         = 'ostr'
316
    constant integer BURROW             = 'otrb'
317
    constant integer TOTEM              = 'otto'
318
    constant integer ORC_WATCH_TOWER    = 'owtw'
319
    constant integer VOODOO_LOUNGE      = 'ovln'
320
321
    // orc upgrades
322
    constant integer UPG_ORC_MELEE      = 'Rome'
323
    constant integer UPG_ORC_RANGED     = 'Rora'
324
    constant integer UPG_ORC_ARTILLERY  = 'Roaa'
325
    constant integer UPG_ORC_ARMOR      = 'Roar'
326
    constant integer UPG_ORC_WAR_DRUMS  = 'Rwdm'
327
    constant integer UPG_ORC_PILLAGE    = 'Ropg'
328
    constant integer UPG_ORC_BERSERK    = 'Robs'
329
    constant integer UPG_ORC_PULVERIZE  = 'Rows'
330
    constant integer UPG_ORC_ENSNARE    = 'Roen'
331
    constant integer UPG_ORC_VENOM      = 'Rovs'
332
    constant integer UPG_ORC_DOCS       = 'Rowd'
333
    constant integer UPG_ORC_SHAMAN     = 'Rost'
334
    constant integer UPG_ORC_SPIKES     = 'Rosp'
335
    constant integer UPG_ORC_BURROWS    = 'Rorb'
336
    constant integer UPG_ORC_REGEN      = 'Rotr'
337
    constant integer UPG_ORC_FIRE       = 'Rolf'
338
    constant integer UPG_ORC_SWALKER    = 'Rowt'
339
    constant integer UPG_ORC_BERSERKER  = 'Robk'
340
    constant integer UPG_ORC_NAPTHA     = 'Robf'
341
    constant integer UPG_ORC_CHAOS      = 'Roch'
342
343
    // Warcraft 2 orc units
344
    constant integer OGRE_MAGI          = 'nomg'
345
    constant integer ORC_DRAGON         = 'nrwm'
346
    constant integer SAPPER             = 'ngsp'
347
    constant integer ZEPPLIN            = 'nzep'
348
    constant integer ZEPPELIN           =  ZEPPLIN
349
    constant integer W2_WARLOCK         = 'nw2w'
350
    constant integer PIG_FARM           = 'npgf'
351
    constant integer FOREST_TROLL       = 'nftr'
352
    constant integer DRAGON_ROOST       = 'ndrb'
353
354
    // special orc units
355
    constant integer CHAOS_GRUNT        = 'nchg'
356
    constant integer CHAOS_WARLOCK      = 'nchw'
357
    constant integer CHAOS_RAIDER       = 'nchr'
358
    constant integer CHAOS_PEON         = 'ncpn'
359
    constant integer CHAOS_KODO         = 'nckb'
360
    constant integer CHAOS_GROM         = 'Opgh'
361
    constant integer CHAOS_BLADEMASTER  = 'Nbbc'
362
    constant integer CHAOS_BURROW       = 'ocbw'
363
364
    //--------------------------------------------------------------------
365
    //  UNDEAD
366
    //--------------------------------------------------------------------
367
368
    // undead heroes
369
    constant integer DEATH_KNIGHT       = 'Udea'
370
    constant integer DREAD_LORD         = 'Udre'
371
    constant integer LICH               = 'Ulic'
372
    constant integer CRYPT_LORD         = 'Ucrl'
373
374
    // special undead heroes
375
    constant integer MALGANIS           = 'Umal'
376
    constant integer TICHONDRIUS        = 'Utic'
377
    constant integer PIT_LORD           = 'Npld'
378
    constant integer DETHEROC           = 'Udth'
379
380
    // undead hero abilities
381
    constant integer SLEEP              = 'AUsl'
382
    constant integer VAMP_AURA          = 'AUav'
383
    constant integer CARRION_SWARM      = 'AUcs'
384
    constant integer INFERNO            = 'AUin'
385
386
    constant integer DARK_RITUAL        = 'AUdr'
387
    constant integer DEATH_DECAY        = 'AUdd'
388
    constant integer FROST_ARMOR        = 'AUfu'
389
    constant integer FROST_NOVA         = 'AUfn'
390
391
    constant integer ANIM_DEAD          = 'AUan'
392
    constant integer DEATH_COIL         = 'AUdc'
393
    constant integer DEATH_PACT         = 'AUdp'
394
    constant integer UNHOLY_AURA        = 'AUau'
395
396
    constant integer CARRION_SCARAB     = 'AUcb'
397
    constant integer IMPALE             = 'AUim'
398
    constant integer LOCUST_SWARM       = 'AUls'
399
    constant integer THORNY_SHIELD      = 'AUts'
400
401
    // undead units
402
    constant integer ABOMINATION        = 'uabo'
403
    constant integer ACOLYTE            = 'uaco'
404
    constant integer BANSHEE            = 'uban'
405
    constant integer PIT_FIEND          = 'ucry'
406
    constant integer CRYPT_FIEND        =  PIT_FIEND
407
    constant integer FROST_WYRM         = 'ufro'
408
    constant integer GARGOYLE           = 'ugar'
409
    constant integer GARGOYLE_MORPH     = 'ugrm'
410
    constant integer GHOUL              = 'ugho'
411
    constant integer MEAT_WAGON         = 'umtw'
412
    constant integer NECRO              = 'unec'
413
    constant integer SKEL_WARRIOR       = 'uske'
414
    constant integer SHADE              = 'ushd'
415
    constant integer UNDEAD_BARGE       = 'uarb'
416
    constant integer OBSIDIAN_STATUE    = 'uobs'
417
    constant integer OBS_STATUE         =  OBSIDIAN_STATUE
418
    constant integer BLK_SPHINX         = 'ubsp'
419
420
    // undead buildings
421
    constant integer UNDEAD_MINE        = 'ugol'
422
    constant integer UNDEAD_ALTAR       = 'uaod'
423
    constant integer BONEYARD           = 'ubon'
424
    constant integer GARG_SPIRE         = 'ugsp'
425
    constant integer NECROPOLIS_1       = 'unpl'    // normal
426
    constant integer NECROPOLIS_2       = 'unp1'    // upgraded once
427
    constant integer NECROPOLIS_3       = 'unp2'    // full upgrade
428
    constant integer SAC_PIT            = 'usap'
429
    constant integer CRYPT              = 'usep'
430
    constant integer SLAUGHTERHOUSE     = 'uslh'
431
    constant integer DAMNED_TEMPLE      = 'utod'
432
    constant integer ZIGGURAT_1         = 'uzig'    // normal
433
    constant integer ZIGGURAT_2         = 'uzg1'    // upgraded
434
    constant integer ZIGGURAT_FROST     = 'uzg2'    // frost tower
435
    constant integer GRAVEYARD          = 'ugrv'
436
    constant integer TOMB_OF_RELICS     = 'utom'
437
438
    // undead upgrades
439
    constant integer UPG_UNHOLY_STR     = 'Rume'
440
    constant integer UPG_CR_ATTACK      = 'Rura'
441
    constant integer UPG_UNHOLY_ARMOR   = 'Ruar'
442
    constant integer UPG_CANNIBALIZE    = 'Ruac'
443
    constant integer UPG_GHOUL_FRENZY   = 'Rugf'
444
    constant integer UPG_FIEND_WEB      = 'Ruwb'
445
    constant integer UPG_ABOM           = 'Ruab'
446
    constant integer UPG_STONE_FORM     = 'Rusf'
447
    constant integer UPG_NECROS         = 'Rune'
448
    constant integer UPG_BANSHEE        = 'Ruba'
449
    constant integer UPG_MEAT_WAGON     = 'Rump'
450
    constant integer UPG_WYRM_BREATH    = 'Rufb'
451
    constant integer UPG_SKEL_LIFE      = 'Rusl'
452
    constant integer UPG_SKEL_MASTERY   = 'Rusm'
453
    constant integer UPG_EXHUME         = 'Ruex'
454
    constant integer UPG_SACRIFICE      = 'Rurs'
455
    constant integer UPG_ABOM_EXPL      = 'Ruax'
456
    constant integer UPG_CR_ARMOR       = 'Rucr'
457
    constant integer UPG_PLAGUE         = 'Rupc'
458
    constant integer UPG_BLK_SPHINX     = 'Rusp'
459
    constant integer UPG_BURROWING      = 'Rubu'
460
461
    //--------------------------------------------------------------------
462
    //  ELVES
463
    //--------------------------------------------------------------------
464
465
    // elf heroes
466
    constant integer DEMON_HUNTER       = 'Edem'
467
    constant integer DEMON_HUNTER_M     = 'Edmm'
468
    constant integer KEEPER             = 'Ekee'
469
    constant integer MOON_CHICK         = 'Emoo'
470
    constant integer MOON_BABE          =  MOON_CHICK
471
    constant integer MOON_HONEY         =  MOON_CHICK
472
    constant integer WARDEN             = 'Ewar'
473
474
    // special elf heroes
475
    constant integer SYLVANUS           = 'Hvwd'
476
    constant integer CENARIUS           = 'Ecen'
477
    constant integer ILLIDAN            = 'Eevi'
478
    constant integer ILLIDAN_DEMON      = 'Eevm'
479
    constant integer MAIEV              = 'Ewrd'
480
481
    // elf hero abilities
482
    constant integer FORCE_NATURE       = 'AEfn'
483
    constant integer ENT_ROOTS          = 'AEer'
484
    constant integer THORNS_AURA        = 'AEah'
485
    constant integer TRANQUILITY        = 'AEtq'
486
487
    constant integer EVASION            = 'AEev'
488
    constant integer IMMOLATION         = 'AEim'
489
    constant integer MANA_BURN          = 'AEmb'
490
    constant integer METAMORPHOSIS      = 'AEme'
491
492
    constant integer SEARING_ARROWS     = 'AHfa'
493
    constant integer SCOUT              = 'AEst'
494
    constant integer STARFALL           = 'AEsf'
495
    constant integer TRUESHOT           = 'AEar'
496
497
    constant integer BLINK              = 'AEbl'
498
    constant integer FAN_KNIVES         = 'AEfk'
499
    constant integer SHADOW_TOUCH       = 'AEsh'
500
    constant integer VENGEANCE          = 'AEsv'
501
502
    // elf units
503
    constant integer WISP               = 'ewsp'
504
    constant integer ARCHER             = 'earc'
505
    constant integer DRUID_TALON        = 'edot'
506
    constant integer DRUID_TALON_M      = 'edtm'
507
    constant integer BALLISTA           = 'ebal'
508
    constant integer DRUID_CLAW         = 'edoc'
509
    constant integer DRUID_CLAW_M       = 'edcm'
510
    constant integer DRYAD              = 'edry'
511
    constant integer HIPPO              = 'ehip'
512
    constant integer HIPPO_RIDER        = 'ehpr'
513
    constant integer HUNTRESS           = 'esen'
514
    constant integer CHIMAERA           = 'echm'
515
    constant integer ENT                = 'efon'
516
    constant integer MOUNTAIN_GIANT     = 'emtg'
517
    constant integer FAERIE_DRAGON      = 'efdr'
518
519
    // special elf units
520
    constant integer HIGH_ARCHER        = 'nhea'
521
    constant integer HIGH_FOOTMAN       = 'hcth'
522
    constant integer HIGH_FOOTMEN       =  HIGH_FOOTMAN
523
    constant integer HIGH_SWORDMAN      = 'hhes'
524
    constant integer DRAGON_HAWK        = 'nws1'
525
    constant integer CORRUPT_TREANT     = 'nenc'
526
    constant integer POISON_TREANT      = 'nenp'
527
    constant integer PLAGUE_TREANT      = 'nepl'
528
    constant integer SHANDRIS           = 'eshd'
529
530
    // elf buildings
531
    constant integer ANCIENT_LORE       = 'eaoe'
532
    constant integer ANCIENT_WAR        = 'eaom'
533
    constant integer ANCIENT_WIND       = 'eaow'
534
    constant integer TREE_AGES          = 'etoa'
535
    constant integer TREE_ETERNITY      = 'etoe'
536
    constant integer TREE_LIFE          = 'etol'
537
    constant integer ANCIENT_PROTECT    = 'etrp'
538
    constant integer ELF_ALTAR          = 'eate'
539
    constant integer BEAR_DEN           = 'edol'
540
    constant integer CHIMAERA_ROOST     = 'edos'
541
    constant integer HUNTERS_HALL       = 'edob'
542
    constant integer MOON_WELL          = 'emow'
543
    constant integer ELF_MINE           = 'egol'
544
    constant integer DEN_OF_WONDERS     = 'eden'
545
546
    // special elf buildings
547
    constant integer ELF_FARM           = 'nefm'
548
    constant integer ELF_GUARD_TOWER    = 'negt'
549
    constant integer HIGH_SKY           = 'negm'
550
    constant integer HIGH_EARTH         = 'negf'
551
    constant integer HIGH_TOWER         = 'negt'
552
    constant integer ELF_HIGH_BARRACKS  = 'nheb'
553
    constant integer CORRUPT_LIFE       = 'nctl'
554
    constant integer CORRUPT_AGES       = 'ncta'
555
    constant integer CORRUPT_ETERNITY   = 'ncte'
556
    constant integer CORRUPT_WELL       = 'ncmw'
557
    constant integer CORRUPT_PROTECTOR  = 'ncap'
558
    constant integer CORRUPT_WAR        = 'ncaw'
559
560
    // elf upgrades
561
    constant integer UPG_STR_MOON       = 'Resm'
562
    constant integer UPG_STR_WILD       = 'Resw'
563
    constant integer UPG_MOON_ARMOR     = 'Rema'
564
    constant integer UPG_HIDES          = 'Rerh'
565
    constant integer UPG_ULTRAVISION    = 'Reuv'
566
    constant integer UPG_BLESSING       = 'Renb'
567
    constant integer UPG_SCOUT          = 'Resc'
568
    constant integer UPG_GLAIVE         = 'Remg'
569
    constant integer UPG_BOWS           = 'Reib'
570
    constant integer UPG_MARKSMAN       = 'Remk'
571
    constant integer UPG_DRUID_TALON    = 'Redt'
572
    constant integer UPG_DRUID_CLAW     = 'Redc'
573
    constant integer UPG_ABOLISH        = 'Resi'
574
    constant integer UPG_CHIM_ACID      = 'Recb'
575
    constant integer UPG_HIPPO_TAME     = 'Reht'
576
    constant integer UPG_BOLT           = 'Repd'
577
    constant integer UPG_MARK_CLAW      = 'Reeb'
578
    constant integer UPG_MARK_TALON     = 'Reec'
579
    constant integer UPG_HARD_SKIN      = 'Rehs'
580
    constant integer UPG_RESIST_SKIN    = 'Rers'
581
    constant integer UPG_WELL_SPRING    = 'Rews'
582
583
    //--------------------------------------------------------------------
584
    // Neutral
585
    //--------------------------------------------------------------------
586
    constant integer DEMON_GATE         = 'ndmg'
587
    constant integer FELLHOUND          = 'nfel'
588
    constant integer INFERNAL           = 'ninf'
589
    constant integer DOOMGUARD          = 'nbal'
590
    constant integer SATYR              = 'nsty'
591
    constant integer TRICKSTER          = 'nsat'
592
    constant integer SHADOWDANCER       = 'nsts'
593
    constant integer SOULSTEALER        = 'nstl'
594
    constant integer HELLCALLER         = 'nsth'
595
    constant integer SKEL_ARCHER        = 'nska'
596
    constant integer SKEL_MARKSMAN      = 'nskm'
597
    constant integer SKEL_BURNING       = 'nskf'
598
    constant integer SKEL_GIANT         = 'nskg'
599
    constant integer FURBOLG            = 'nfrl'
600
    constant integer FURBOLG_TRACKER    = 'nfrb'
601
    constant integer FURBOLG_SHAMAN     = 'nfrs'
602
    constant integer FURBOLG_CHAMP      = 'nfrg'
603
    constant integer FURBOLG_ELDER      = 'nfre'
604
605
    //--------------------------------------------------------------------
606
    // NAGA
607
    //--------------------------------------------------------------------
608
609
    // naga heroes
610
    constant integer NAGA_SORCERESS     = 'Nngs'
611
    constant integer NAGA_VASHJ         = 'Hvsh'
612
613
    // naga units
614
    constant integer NAGA_DRAGON        = 'nsnp'        // old names
615
    constant integer NAGA_WITCH         = 'nnsw'
616
    constant integer NAGA_SERPENT       = 'nwgs'
617
    constant integer NAGA_HYDRA         = 'nhyc'
618
619
    constant integer NAGA_SLAVE         = 'nmpe'        // peon
620
    constant integer NAGA_SNAP_DRAGON   =  NAGA_DRAGON  // weak ranged
621
    constant integer NAGA_COUATL        =  NAGA_SERPENT // weak air
622
    constant integer NAGA_SIREN         =  NAGA_WITCH   // caster
623
    constant integer NAGA_MYRMIDON      = 'nmyr'        // knight
624
    constant integer NAGA_REAVER        = 'nnmg'        // footman
625
    constant integer NAGA_TURTLE        =  NAGA_HYDRA   // siege
626
    constant integer NAGA_ROYAL         = 'nnrg'        // royal guard
627
628
    // naga buildings
629
    constant integer NAGA_TEMPLE        = 'nntt'        // town hall
630
    constant integer NAGA_CORAL         = 'nnfm'        // farm
631
    constant integer NAGA_SHRINE        = 'nnsa'        // sirens & couatls
632
    constant integer NAGA_SPAWNING      = 'nnsg'        // myrm, snap dragon, hydra
633
    constant integer NAGA_GUARDIAN      = 'nntg'        // tower
634
    constant integer NAGA_ALTAR         = 'nnad'        // altar
635
636
    // naga upgrades
637
    constant integer UPG_NAGA_ARMOR     = 'Rnam'
638
    constant integer UPG_NAGA_ATTACK    = 'Rnat'
639
    constant integer UPG_NAGA_ABOLISH   = 'Rnsi'
640
    constant integer UPG_SIREN          = 'Rnsw'
641
    constant integer UPG_NAGA_ENSNARE   = 'Rnen'
642
643
644
    //--------------------------------------------------------------------
645
    constant integer M1                 =    60
646
    constant integer M2                 =  2*60
647
    constant integer M3                 =  3*60
648
    constant integer M4                 =  4*60
649
    constant integer M5                 =  5*60
650
    constant integer M6                 =  6*60
651
    constant integer M7                 =  7*60
652
    constant integer M8                 =  8*60
653
    constant integer M9                 =  9*60
654
    constant integer M10                = 10*60
655
    constant integer M11                = 11*60
656
    constant integer M12                = 12*60
657
    constant integer M13                = 13*60
658
    constant integer M14                = 14*60
659
    constant integer M15                = 15*60
660
661
    constant integer EASY               = 1
662
    constant integer NORMAL             = 2
663
    constant integer HARD               = 3
664
    constant integer INSANE             = 4 // not used
665
666
    constant integer MELEE_NEWBIE       = 1
667
    constant integer MELEE_NORMAL       = 2
668
    constant integer MELEE_INSANE       = 3
669
670
    constant integer ATTACK_CAPTAIN     = 1
671
    constant integer DEFENSE_CAPTAIN    = 2
672
    constant integer BOTH_CAPTAINS      = 3
673
674
    constant integer BUILD_UNIT         = 1
675
    constant integer BUILD_UPGRADE      = 2
676
    constant integer BUILD_EXPAND       = 3
677
678
    constant integer UPKEEP_TIER1       = 50
679
    constant integer UPKEEP_TIER2       = 80
680
681
    //--------------------------------------------------------------------
682
683
    player  ai_player
684
685
    integer sleep_seconds
686
    integer total_gold              = 0
687
    integer total_wood              = 0
688
    integer gold_buffer             = 0 // usually for potion money
689
    integer difficulty              = NORMAL
690
    integer exp_seen                = 0
691
    integer racial_farm             = 'hhou'
692
    integer hero_id                 = 'Hamg'
693
    integer hero_id2                = 'Hmkg'
694
    integer hero_id3                = 'Hpal'
695
    integer array skill
696
    integer array skills1
697
    integer array skills2
698
    integer array skills3
699
    integer max_hero_level          = 0
700
701
    integer array harass_qty
702
    integer array harass_max
703
    integer array harass_units
704
    integer harass_length           = 0
705
706
    integer array defense_qty
707
    integer array defense_units
708
    integer defense_length          = 0
709
710
    integer array build_qty
711
    integer array build_type
712
    integer array build_item
713
    integer array build_town
714
    integer build_length            = 0
715
716
    integer campaign_gold_peons     = 5
717
    integer campaign_wood_peons     = 3
718
    integer campaign_basics_speed   = 5
719
720
    integer min_creeps              = -1
721
    integer max_creeps              = -1
722
723
    boolean harvest_town1           = true
724
    boolean harvest_town2           = true
725
    boolean harvest_town3           = true
726
    boolean do_campaign_farms       = true
727
    boolean two_heroes              = false
728
    boolean allow_air_creeps        = false
729
    boolean take_exp                = false
730
    boolean allow_signal_abort      = false
731
    boolean ready_for_zeppelin      = true
732
    boolean get_zeppelin            = false
733
734
    boolean build_campaign_attackers = true
735
736
    boolean do_debug_cheats         = false
737
    boolean trace_on                = true
738
    boolean zep_next_wave           = false
739
    boolean form_group_timeouts     = true
740
endglobals
741
742
//============================================================================
743
function PlayerEx takes integer slot returns player
744
    return Player(slot-1)
745
endfunction
746
747
//============================================================================
748
function Trace takes string message returns nothing
749
    if trace_on then
750
        call DisplayText(GetAiPlayer(),message)
751
    endif
752
endfunction
753
754
//============================================================================
755
function TraceI takes string message, integer val returns nothing
756
    if trace_on then
757
        call DisplayTextI(GetAiPlayer(),message,val)
758
    endif
759
endfunction
760
761
//============================================================================
762
function TraceII takes string message, integer v1, integer v2 returns nothing
763
    if trace_on then
764
        call DisplayTextII(GetAiPlayer(),message,v1,v2)
765
    endif
766
endfunction
767
768
//============================================================================
769
function TraceIII takes string message, integer v1, integer v2, integer v3 returns nothing
770
    if trace_on then
771
        call DisplayTextIII(GetAiPlayer(),message,v1,v2,v3)
772
    endif
773
endfunction
774
775
//============================================================================
776
function InitAI takes nothing returns nothing
777
    set ai_player = Player(GetAiPlayer())
778
    set sleep_seconds = 0
779
    call StopGathering()
780
endfunction
781
782
//============================================================================
783
function StandardAI takes code heroes, code peons, code attacks returns nothing
784
785
    local boolean isNewbie = (MeleeDifficulty() == MELEE_NEWBIE)
786
787
    call InitAI()
788
789
    call SetMeleeAI()
790
791
    call SetDefendPlayer(true)
792
    call SetGroupsFlee(not isNewbie)
793
    call SetHeroesBuyItems(not isNewbie)
794
    call SetHeroesFlee(true)
795
    call SetHeroesTakeItems(true)
796
    call SetIgnoreInjured(true)
797
    call SetPeonsRepair(true)
798
    call SetSmartArtillery(not isNewbie)
799
    call SetTargetHeroes(not isNewbie)
800
    call SetUnitsFlee(not isNewbie)
801
    call SetWatchMegaTargets(true)
802
803
    call CreateCaptains()
804
805
    call SetHeroLevels(heroes)
806
807
    call Sleep(0.1)
808
    call StartThread(peons)
809
    call StartThread(attacks)
810
endfunction
811
812
//============================================================================
813
//  Utility Functions
814
//============================================================================
815
function Min takes integer A, integer B returns integer
816
    if A < B then
817
        return A
818
    else
819
        return B
820
    endif
821
endfunction
822
823
function Max takes integer A, integer B returns integer
824
    if A > B then
825
        return A
826
    else
827
        return B
828
    endif
829
endfunction
830
831
function SetZepNextWave takes nothing returns nothing
832
    set zep_next_wave = true
833
endfunction
834
835
function SuicideSleep takes integer seconds returns nothing
836
    set sleep_seconds = sleep_seconds - seconds
837
    loop
838
        exitwhen seconds <= 0
839
        exitwhen allow_signal_abort and CommandsWaiting() != 0
840
841
        if seconds >= 5 then
842
            call Sleep(5)
843
            set seconds = seconds - 5
844
        else
845
            call Sleep(seconds)
846
            set seconds = 0
847
        endif
848
    endloop
849
endfunction
850
851
//============================================================================
852
function WaitForSignal takes nothing returns integer
853
    local integer cmd
854
    local boolean display = false //xxx
855
    loop
856
        exitwhen CommandsWaiting() != 0
857
858
        //xxx
859
        call Trace("waiting for a signal to begin AI script...\n")
860
        set display = true
861
        call Sleep(2)
862
        exitwhen CommandsWaiting() != 0
863
        call Sleep(2)
864
        exitwhen CommandsWaiting() != 0
865
        call Sleep(2)
866
        exitwhen CommandsWaiting() != 0
867
        call Sleep(2)
868
        exitwhen CommandsWaiting() != 0
869
        call Sleep(2)
870
        //xxx
871
872
    endloop
873
874
    //xxx
875
    if display then
876
        call Trace("signal received, beginning AI script\n")
877
    endif
878
    //xxx
879
880
    set cmd = GetLastCommand()
881
    call PopLastCommand()
882
    return cmd
883
endfunction
884
885
//============================================================================
886
function SetWoodPeons takes integer count returns nothing
887
    set campaign_wood_peons = count
888
endfunction
889
890
//============================================================================
891
function SetGoldPeons takes integer count returns nothing
892
    set campaign_gold_peons = count
893
endfunction
894
895
//============================================================================
896
function SetHarvestLumber takes boolean harvest returns nothing
897
    if harvest then
898
        set campaign_wood_peons = 3
899
    else
900
        set campaign_wood_peons = 0
901
    endif
902
endfunction
903
904
//============================================================================
905
function SetFormGroupTimeouts takes boolean state returns nothing
906
    set form_group_timeouts = state
907
endfunction
908
909
//============================================================================
910
function DoCampaignFarms takes boolean state returns nothing
911
    set do_campaign_farms = state
912
endfunction
913
914
//============================================================================
915
function GetMinorCreep takes nothing returns unit
916
    return GetCreepCamp(0,9,false)
917
endfunction
918
919
//============================================================================
920
function GetMajorCreep takes nothing returns unit
921
    return GetCreepCamp(10,100,allow_air_creeps)
922
endfunction
923
924
//============================================================================
925
function GetGold takes nothing returns integer
926
    return GetPlayerState(ai_player,PLAYER_STATE_RESOURCE_GOLD)
927
endfunction
928
929
//============================================================================
930
function GetWood takes nothing returns integer
931
    return GetPlayerState(ai_player,PLAYER_STATE_RESOURCE_LUMBER)
932
endfunction
933
934
//============================================================================
935
function InitBuildArray takes nothing returns nothing
936
    set build_length = 0
937
endfunction
938
939
//============================================================================
940
function InitAssaultGroup takes nothing returns nothing
941
    set harass_length = 0
942
endfunction
943
944
//============================================================================
945
function InitDefenseGroup takes nothing returns nothing
946
    set defense_length = 0
947
endfunction
948
949
//============================================================================
950
function InitMeleeGroup takes nothing returns nothing
951
    call InitAssaultGroup()
952
    call RemoveInjuries()
953
    call RemoveSiege()
954
endfunction
955
956
//============================================================================
957
function PrepFullSuicide takes nothing returns nothing
958
    call InitAssaultGroup()
959
    call InitDefenseGroup()
960
    set campaign_gold_peons = 0
961
    set campaign_wood_peons = 0
962
endfunction
963
964
//============================================================================
965
function SetReplacements takes integer easy, integer med, integer hard returns nothing
966
    if difficulty == EASY then
967
        call SetReplacementCount(easy)
968
    elseif difficulty == NORMAL then
969
        call SetReplacementCount(med)
970
    else
971
        call SetReplacementCount(hard)
972
    endif
973
endfunction
974
975
//============================================================================
976
function StartTownBuilder takes code func returns nothing
977
    call StartThread(func)
978
endfunction
979
980
//============================================================================
981
function SetBuildAll takes integer t, integer qty, integer unitid, integer town returns nothing
982
    if qty > 0 then
983
        set build_qty[build_length] = qty
984
        set build_type[build_length] = t
985
        set build_item[build_length] = unitid
986
        set build_town[build_length] = town
987
        set build_length = build_length + 1
988
    endif
989
endfunction
990
991
//============================================================================
992
function SetBuildUnit takes integer qty, integer unitid returns nothing
993
    call SetBuildAll(BUILD_UNIT,qty,unitid,-1)
994
endfunction
995
996
//============================================================================
997
function SetBuildNext takes integer qty, integer unitid returns nothing
998
    local integer has = GetUnitCount(unitid)
999
    if has >= qty then
1000
        return
1001
    endif
1002
    call SetBuildAll(BUILD_UNIT,GetUnitCountDone(unitid)+1,unitid,-1)
1003
endfunction
1004
1005
//============================================================================
1006
function SetBuildUnitEx takes integer easy, integer med, integer hard, integer unitid returns nothing
1007
    if difficulty == EASY then
1008
        call SetBuildAll(BUILD_UNIT,easy,unitid,-1)
1009
    elseif difficulty == NORMAL then
1010
        call SetBuildAll(BUILD_UNIT,med,unitid,-1)
1011
    else
1012
        call SetBuildAll(BUILD_UNIT,hard,unitid,-1)
1013
    endif
1014
endfunction
1015
1016
//============================================================================
1017
function SecondaryTown takes integer town, integer qty, integer unitid returns nothing
1018
    call SetBuildAll(BUILD_UNIT,qty,unitid,town)
1019
endfunction
1020
1021
//============================================================================
1022
function SecTown takes integer town, integer qty, integer unitid returns nothing
1023
    call SetBuildAll(BUILD_UNIT,qty,unitid,town)
1024
endfunction
1025
1026
//============================================================================
1027
function SetBuildUpgr takes integer qty, integer unitid returns nothing
1028
    if MeleeDifficulty() != MELEE_NEWBIE or qty == 1 then
1029
        call SetBuildAll(BUILD_UPGRADE,qty,unitid,-1)
1030
    endif
1031
endfunction
1032
1033
//============================================================================
1034
function SetBuildUpgrEx takes integer easy, integer med, integer hard, integer unitid returns nothing
1035
    if difficulty == EASY then
1036
        call SetBuildAll(BUILD_UPGRADE,easy,unitid,-1)
1037
    elseif difficulty == NORMAL then
1038
        call SetBuildAll(BUILD_UPGRADE,med,unitid,-1)
1039
    else
1040
        call SetBuildAll(BUILD_UPGRADE,hard,unitid,-1)
1041
    endif
1042
endfunction
1043
1044
//============================================================================
1045
function SetBuildExpa takes integer qty, integer unitid returns nothing
1046
    call SetBuildAll(BUILD_EXPAND,qty,unitid,-1)
1047
endfunction
1048
1049
//============================================================================
1050
function StartUpgrade takes integer level, integer upgid returns boolean
1051
    local integer gold_cost
1052
    local integer wood_cost
1053
1054
    if GetUpgradeLevel(upgid) >= level then
1055
        return true
1056
    endif
1057
1058
    set gold_cost = GetUpgradeGoldCost(upgid)
1059
    if total_gold < gold_cost then
1060
        return false
1061
    endif
1062
1063
    set wood_cost = GetUpgradeWoodCost(upgid)
1064
    if total_wood < wood_cost then
1065
        return false
1066
    endif
1067
1068
    return SetUpgrade(upgid)
1069
endfunction
1070
1071
//============================================================================
1072
function BuildFactory takes integer unitid returns nothing
1073
    if GetGold() > 1000 and GetWood() > 500 then
1074
        call SetBuildUnit( 2, unitid )
1075
    else
1076
        call SetBuildUnit( 1, unitid )
1077
    endif
1078
endfunction
1079
1080
//============================================================================
1081
function HallsCompleted takes integer unitid returns boolean
1082
    return GetUnitCount(unitid) == GetUnitCountDone(unitid)
1083
endfunction
1084
1085
//============================================================================
1086
function GuardSecondary takes integer townid, integer qty, integer unitid returns nothing
1087
    if TownHasHall(townid) and TownHasMine(townid) then
1088
        call SecondaryTown( townid, qty, unitid )
1089
    endif
1090
endfunction
1091
1092
//============================================================================
1093
function GetUnitCountEx takes integer unitid, boolean only_done, integer townid returns integer
1094
    if townid == -1 then
1095
        if only_done then
1096
            return GetUnitCountDone(unitid)
1097
        else
1098
            return GetUnitCount(unitid)
1099
        endif
1100
    else
1101
        return GetTownUnitCount(unitid,townid,only_done)
1102
    endif
1103
endfunction
1104
1105
//============================================================================
1106
function TownCountEx takes integer unitid, boolean only_done, integer townid returns integer
1107
1108
    local integer have_qty = GetUnitCountEx(unitid,only_done,townid)
1109
1110
    if unitid == TOWN_HALL then
1111
        set have_qty = have_qty + GetUnitCountEx(KEEP,false,townid) + GetUnitCountEx(CASTLE,false,townid)
1112
    elseif unitid == KEEP then
1113
        set have_qty = have_qty  + GetUnitCountEx(CASTLE,false,townid)
1114
1115
    elseif unitid == WATCH_TOWER then
1116
        set have_qty = have_qty + GetUnitCountEx(GUARD_TOWER,false,townid) + GetUnitCountEx(CANNON_TOWER,false,townid) + GetUnitCountEx(ARCANE_TOWER,false,townid)
1117
1118
    elseif unitid == PEASANT then
1119
        set have_qty = have_qty + GetUnitCountEx(MILITIA,false,townid)
1120
1121
    elseif unitid == GREAT_HALL then
1122
        set have_qty = have_qty + GetUnitCountEx(STRONGHOLD,false,townid) + GetUnitCountEx(FORTRESS,false,townid)
1123
    elseif unitid == STRONGHOLD then
1124
        set have_qty = have_qty + GetUnitCountEx(FORTRESS,false,townid)
1125
1126
    elseif unitid == HEAD_HUNTER then
1127
        set have_qty = have_qty + GetUnitCountEx(BERSERKER,false,townid)
1128
1129
    elseif unitid == SPIRIT_WALKER then
1130
        set have_qty = have_qty + GetUnitCountEx(SPIRIT_WALKER_M,false,townid)
1131
    elseif unitid == SPIRIT_WALKER_M then
1132
        set have_qty = have_qty + GetUnitCountEx(SPIRIT_WALKER,only_done,townid)
1133
1134
    elseif unitid == NECROPOLIS_1 then
1135
        set have_qty = have_qty + GetUnitCountEx(NECROPOLIS_2,false,townid) + GetUnitCountEx(NECROPOLIS_3,false,townid)
1136
    elseif unitid == NECROPOLIS_2 then
1137
        set have_qty = have_qty + GetUnitCountEx(NECROPOLIS_3,false,townid)
1138
1139
    elseif unitid == ZIGGURAT_1 then
1140
        set have_qty = have_qty + GetUnitCountEx(ZIGGURAT_2,false,townid) + GetUnitCountEx(ZIGGURAT_FROST,false,townid)
1141
1142
    elseif unitid == GARGOYLE then
1143
        set have_qty = have_qty + GetUnitCountEx(GARGOYLE_MORPH,false,townid)
1144
1145
    elseif unitid == TREE_LIFE then
1146
        set have_qty = have_qty + GetUnitCountEx(TREE_AGES,false,townid) + GetUnitCountEx(TREE_ETERNITY,false,townid)
1147
    elseif unitid == TREE_AGES then
1148
        set have_qty = have_qty + GetUnitCountEx(TREE_ETERNITY,false,townid)
1149
1150
    elseif unitid == DRUID_TALON then
1151
        set have_qty = have_qty + GetUnitCountEx(DRUID_TALON_M,false,townid)
1152
    elseif unitid == DRUID_TALON_M then
1153
        set have_qty = have_qty + GetUnitCountEx(DRUID_TALON,only_done,townid)
1154
1155
    elseif unitid == DRUID_CLAW then
1156
        set have_qty = have_qty + GetUnitCountEx(DRUID_CLAW_M,false,townid)
1157
    elseif unitid == DRUID_CLAW_M then
1158
        set have_qty = have_qty + GetUnitCountEx(DRUID_CLAW,only_done,townid)
1159
1160
    elseif unitid == ILLIDAN then
1161
        set have_qty = have_qty + GetUnitCountEx(ILLIDAN_DEMON,false,townid)
1162
1163
    endif
1164
    return have_qty
1165
endfunction
1166
1167
//============================================================================
1168
function TownCountDone takes integer base returns integer
1169
    return TownCountEx(base,true,-1)
1170
endfunction
1171
1172
//============================================================================
1173
function TownCount takes integer base returns integer
1174
    return TownCountEx(base,false,-1)
1175
endfunction
1176
1177
//============================================================================
1178
function BasicExpansion takes boolean build_it, integer unitid returns nothing
1179
    if build_it and HallsCompleted(unitid) then
1180
        call SetBuildExpa( TownCount(unitid)+1, unitid )
1181
    endif
1182
endfunction
1183
1184
//============================================================================
1185
function UpgradeAll takes integer baseid, integer newid returns nothing
1186
    call SetBuildUnit( TownCountDone(baseid), newid )
1187
endfunction
1188
1189
//============================================================================
1190
function TownCountTown takes integer base, integer townid returns integer
1191
    return TownCountEx(base,false,townid)
1192
endfunction
1193
1194
//============================================================================
1195
//  FoodPool
1196
//============================================================================
1197
function FoodPool takes integer food, boolean weak, integer id1, integer use1, boolean strong, integer id2, integer use2 returns nothing
1198
    if strong then
1199
        call SetBuildUnit( (food - use1 * TownCount(id1)) / use2, id2 )
1200
    elseif weak then
1201
        call SetBuildUnit( (food - use2 * TownCount(id2)) / use1, id1 )
1202
    endif
1203
endfunction
1204
1205
//============================================================================
1206
//  MeleeTownHall
1207
//============================================================================
1208
function MeleeTownHall takes integer townid, integer unitid returns nothing
1209
    if TownHasMine(townid) and not TownHasHall(townid) then
1210
        call SecondaryTown ( townid, 1, unitid )
1211
    endif
1212
endfunction
1213
1214
//============================================================================
1215
function WaitForUnits takes integer unitid, integer qty returns nothing
1216
    loop
1217
        exitwhen TownCountDone(unitid) == qty
1218
        call Sleep(2)
1219
    endloop
1220
endfunction
1221
1222
//============================================================================
1223
function StartUnit takes integer ask_qty, integer unitid, integer town returns boolean
1224
    local integer have_qty
1225
    local integer need_qty
1226
    local integer afford_gold
1227
    local integer afford_wood
1228
    local integer afford_qty
1229
    local integer gold_cost
1230
    local integer wood_cost
1231
1232
    //------------------------------------------------------------------------
1233
    // if we have all we're asking for then make nothing
1234
    //
1235
    if town == -1 then
1236
        set have_qty = TownCount(unitid)
1237
    else
1238
        set have_qty = TownCountTown(unitid,town)
1239
    endif
1240
1241
    if have_qty >= ask_qty then
1242
        return true
1243
    endif
1244
    set need_qty = ask_qty - have_qty
1245
1246
    //------------------------------------------------------------------------
1247
    // limit the qty we're requesting to the amount of resources available
1248
    //
1249
    set gold_cost = GetUnitGoldCost(unitid)
1250
    set wood_cost = GetUnitWoodCost(unitid)
1251
1252
    if gold_cost == 0 then
1253
        set afford_gold = need_qty
1254
    else
1255
        set afford_gold = total_gold / gold_cost
1256
    endif
1257
    if afford_gold < need_qty then
1258
        set afford_qty = afford_gold
1259
    else
1260
        set afford_qty = need_qty
1261
    endif
1262
1263
    if wood_cost == 0 then
1264
        set afford_wood = need_qty
1265
    else
1266
        set afford_wood = total_wood / wood_cost
1267
    endif
1268
    if afford_wood < afford_qty then
1269
        set afford_qty = afford_wood
1270
    endif
1271
1272
    // if we're waiting on gold/wood; pause build orders
1273
    if afford_qty < 1 then
1274
        return false
1275
    endif
1276
1277
    //------------------------------------------------------------------------
1278
    // whether we make right now what we're requesting or not, assume we will
1279
    // and deduct the cost of the units from our fake gold total right away
1280
    //
1281
    set total_gold = total_gold - gold_cost * need_qty
1282
    set total_wood = total_wood - wood_cost * need_qty
1283
1284
    if total_gold < 0 then
1285
        set total_gold = 0
1286
    endif
1287
    if total_wood < 0 then
1288
        set total_wood = 0
1289
    endif
1290
1291
    //------------------------------------------------------------------------
1292
    // give the AI a chance to make the units (it may not be able to right now
1293
    // but that doesn't stop us from trying other units after this as long
1294
    // as we have enough money to make this AND the needed, unbuilt ones)
1295
    //
1296
    return SetProduce(afford_qty,unitid,town)
1297
endfunction
1298
1299
//============================================================================
1300
function WaitForTown takes integer towns, integer townid returns nothing
1301
    local integer i = 0
1302
    loop
1303
        call Sleep(10)
1304
        exitwhen TownCount(townid) >= towns
1305
        set i = i + 1
1306
        exitwhen i == 12
1307
    endloop
1308
endfunction
1309
1310
//============================================================================
1311
function StartExpansion takes integer qty, integer hall returns boolean
1312
    local integer count
1313
    local integer town
1314
    local unit    peon
1315
    local integer gold_cost
1316
1317
    set count = TownCount(hall)
1318
    if count >= qty then
1319
        return true
1320
    endif
1321
1322
    set town = GetNextExpansion()
1323
    if town == -1 then
1324
        return true
1325
    endif
1326
1327
    set take_exp = true
1328
1329
    set gold_cost = GetUnitGoldCost(hall)
1330
    if gold_cost > total_gold then
1331
        return false
1332
    endif
1333
    set total_gold = total_gold - gold_cost
1334
1335
    if GetExpansionFoe() != null then
1336
        return true
1337
    endif
1338
1339
    set peon = GetExpansionPeon()
1340
    if peon != null then
1341
        return SetExpansion(peon,hall)
1342
    endif
1343
1344
    return true
1345
endfunction
1346
1347
//============================================================================
1348
function OneBuildLoop takes nothing returns nothing
1349
    local integer index = 0
1350
    local integer qty
1351
    local integer id
1352
    local integer tp
1353
1354
    set total_gold = GetGold() - gold_buffer
1355
    set total_wood = GetWood()
1356
1357
    loop
1358
        exitwhen index == build_length
1359
1360
        set qty = build_qty [index]
1361
        set id  = build_item[index]
1362
        set tp  = build_type[index]
1363
1364
        //--------------------------------------------------------------------
1365
        if tp == BUILD_UNIT then
1366
            if not StartUnit(qty,id,build_town[index]) then
1367
                return
1368
            endif
1369
1370
        //--------------------------------------------------------------------
1371
        elseif tp == BUILD_UPGRADE then
1372
            call StartUpgrade(qty,id)
1373
1374
        //--------------------------------------------------------------------
1375
        else // tp == BUILD_EXPAND
1376
            if not StartExpansion(qty,id) then
1377
                return
1378
            endif
1379
        endif
1380
1381
        set index = index + 1
1382
    endloop
1383
endfunction
1384
1385
//============================================================================
1386
function StaggerSleep takes real base, real spread returns nothing
1387
    call Sleep(base + spread * I2R(GetAiPlayer()) / I2R(GetPlayers()))
1388
endfunction
1389
1390
//============================================================================
1391
function BuildLoop takes nothing returns nothing
1392
    call OneBuildLoop()
1393
    call StaggerSleep(1,2)
1394
    loop
1395
        call OneBuildLoop()
1396
        call Sleep(2)
1397
    endloop
1398
endfunction
1399
1400
//============================================================================
1401
function StartBuildLoop takes nothing returns nothing
1402
    call StartThread(function BuildLoop)
1403
endfunction
1404
1405
//============================================================================
1406
function SetInitialWave takes integer seconds returns nothing
1407
    set sleep_seconds = seconds
1408
endfunction
1409
1410
//============================================================================
1411
function AddSleepSeconds takes integer seconds returns nothing
1412
    set sleep_seconds = sleep_seconds + seconds
1413
endfunction
1414
1415
//============================================================================
1416
function SleepForever takes nothing returns nothing
1417
    call Trace("going to sleep forever\n") //xxx
1418
    loop
1419
        call Sleep(100)
1420
    endloop
1421
endfunction
1422
1423
//============================================================================
1424
function PlayGame takes nothing returns nothing
1425
    call StartBuildLoop()
1426
    call SleepForever()
1427
endfunction
1428
1429
//============================================================================
1430
function ConvertNeeds takes integer unitid returns nothing
1431
    if GetUnitCount(unitid) < 1 then
1432
        call StartUnit(1,unitid,-1)
1433
    endif
1434
endfunction
1435
1436
//============================================================================
1437
function Conversions takes integer desire, integer unitid returns nothing
1438
1439
    if GetUnitCount(unitid) >= desire then
1440
        return
1441
    endif
1442
1443
    if unitid == HIPPO_RIDER then
1444
        call ConvertNeeds(ARCHER)
1445
        call ConvertNeeds(HIPPO)
1446
        call MergeUnits(desire,ARCHER,HIPPO,HIPPO_RIDER)
1447
1448
    elseif unitid == BLK_SPHINX then
1449
        call ConvertNeeds(OBS_STATUE)
1450
        call ConvertUnits(desire,OBS_STATUE)
1451
    endif
1452
endfunction
1453
1454
//============================================================================
1455
function SetAssaultGroup takes integer qty, integer max, integer unitid returns nothing
1456
    call Conversions(max,unitid)
1457
1458
    if qty <= 0 and TownCountDone(unitid) == 0 then
1459
        return
1460
    endif
1461
    set harass_qty[harass_length] = qty
1462
    set harass_max[harass_length] = max
1463
    set harass_units[harass_length] = unitid
1464
    set harass_length = harass_length + 1
1465
endfunction
1466
1467
//============================================================================
1468
function Interleave3 takes integer e1, integer m1, integer h1, integer u1, integer e2, integer m2, integer h2, integer u2, integer e3, integer m3, integer h3, integer u3 returns nothing
1469
    local integer i1 = 1
1470
    local integer i2 = 1
1471
    local integer i3 = 1
1472
    local integer q1
1473
    local integer q2
1474
    local integer q3
1475
1476
    if difficulty == EASY then
1477
        set q1 = e1
1478
        set q2 = e2
1479
        set q3 = e3
1480
    elseif difficulty == NORMAL then
1481
        set q1 = m1
1482
        set q2 = m2
1483
        set q3 = m3
1484
    else // difficulty == HARD
1485
        set q1 = h1
1486
        set q2 = h2
1487
        set q3 = h3
1488
    endif
1489
1490
    loop
1491
        exitwhen q1<=0 and q2<=0 and q3<=0
1492
1493
        if q1 > 0 then
1494
            call SetAssaultGroup(i1,i1,u1)
1495
            set q1 = q1 - 1
1496
            set i1 = i1 + 1
1497
        endif
1498
1499
        if q2 > 0 then
1500
            call SetAssaultGroup(i2,i2,u2)
1501
            set q2 = q2 - 1
1502
            set i2 = i2 + 1
1503
        endif
1504
1505
        if q3 > 0 then
1506
            call SetAssaultGroup(i3,i3,u3)
1507
            set q3 = q3 - 1
1508
            set i3 = i3 + 1
1509
        endif
1510
    endloop
1511
endfunction
1512
1513
//============================================================================
1514
function SetMeleeGroup takes integer unitid returns nothing
1515
    if unitid == hero_id then
1516
        call SetAssaultGroup(1,9,unitid)
1517
    else
1518
        call SetAssaultGroup((TownCountDone(unitid)*3)/4,20,unitid)
1519
    endif
1520
endfunction
1521
1522
//============================================================================
1523
function CampaignDefender takes integer level, integer qty, integer unitid returns nothing
1524
    if qty > 0 and difficulty >= level then
1525
        set defense_qty[defense_length] = qty
1526
        set defense_units[defense_length] = unitid
1527
        set defense_length = defense_length + 1
1528
        call Conversions(qty,unitid)
1529
        call SetBuildUnit(qty,unitid)
1530
    endif
1531
endfunction
1532
1533
//============================================================================
1534
function CampaignDefenderEx takes integer easy, integer med, integer hard, integer unitid returns nothing
1535
    if difficulty == EASY then
1536
        call CampaignDefender(EASY,easy,unitid)
1537
    elseif difficulty == NORMAL then
1538
        call CampaignDefender(NORMAL,med,unitid)
1539
    else
1540
        call CampaignDefender(HARD,hard,unitid)
1541
    endif
1542
endfunction
1543
1544
//============================================================================
1545
function CampaignAttacker takes integer level, integer qty, integer unitid returns nothing
1546
    if qty > 0 and difficulty >= level then
1547
        call SetAssaultGroup(qty,qty,unitid)
1548
    endif
1549
endfunction
1550
1551
//============================================================================
1552
function CampaignAttackerEx takes integer easy, integer med, integer hard, integer unitid returns nothing
1553
    if difficulty == EASY then
1554
        call CampaignAttacker(EASY,easy,unitid)
1555
    elseif difficulty == NORMAL then
1556
        call CampaignAttacker(NORMAL,med,unitid)
1557
    else
1558
        call CampaignAttacker(HARD,hard,unitid)
1559
    endif
1560
endfunction
1561
1562
//============================================================================
1563
function FormGroup takes integer seconds, boolean testReady returns nothing
1564
    local integer index
1565
    local integer count
1566
    local integer unitid
1567
    local integer desire
1568
    local integer readyPercent
1569
1570
    // normally test for CaptainReadiness() of 50%
1571
    if testReady == true then
1572
        set readyPercent = 50
1573
        call Trace("forming group, requiring healthy guys\n") //xxx
1574
    else
1575
        set readyPercent = 0
1576
        call Trace("forming group, unit health not important\n") //xxx
1577
    endif
1578
1579
    call Trace("trying to gather forces\n") //xxx
1580
1581
    loop
1582
        call SuicideSleep(seconds)
1583
        call InitAssault()
1584
1585
        set index = 0
1586
        loop
1587
            exitwhen index == harass_length
1588
1589
            set unitid = harass_units[index]
1590
            set desire = harass_max[index]
1591
            set count  = TownCountDone(unitid)
1592
1593
            call Conversions(desire,unitid)
1594
1595
            if count >= desire then
1596
                call AddAssault(desire,unitid)
1597
            else
1598
                set desire = harass_qty[index]
1599
1600
                if count < desire then
1601
                    call AddAssault(desire,unitid)
1602
                else
1603
                    call AddAssault(count,unitid)
1604
                endif
1605
            endif
1606
1607
            set index = index + 1
1608
        endloop
1609
1610
        //xxx
1611
        if form_group_timeouts and (sleep_seconds < -60) then
1612
            call Trace("exit form group -- timeout\n")
1613
        elseif CaptainInCombat(true) then
1614
            call Trace("exit form group -- can't form while already in combat\n")
1615
        elseif CaptainIsFull() and CaptainReadiness() >= readyPercent then
1616
            call Trace("exit form group -- ready\n")
1617
        endif
1618
        //xxx
1619
1620
        // time out and send group anyway if time has already expired
1621
        exitwhen form_group_timeouts and (sleep_seconds < -60)
1622
        exitwhen CaptainInCombat(true)
1623
        exitwhen CaptainIsFull() and CaptainReadiness() >= readyPercent
1624
    endloop
1625
endfunction
1626
1627
//============================================================================
1628
function WavePrepare takes integer unitid returns integer
1629
    return GetUnitBuildTime(unitid)
1630
endfunction
1631
1632
//============================================================================
1633
function PrepTime takes nothing returns integer
1634
    local integer unitid
1635
    local integer missing
1636
    local integer prep
1637
    local integer count
1638
    local integer largest = 30
1639
    local integer index = 0
1640
1641
    loop
1642
        exitwhen index == harass_length
1643
1644
        set unitid  = harass_units[index]
1645
        set missing = harass_qty[index] + IgnoredUnits(unitid) - TownCount(unitid)
1646
        set prep    = WavePrepare(unitid) * missing
1647
1648
        if prep > largest then
1649
            set largest = prep
1650
        endif
1651
1652
        set index = index + 1
1653
    endloop
1654
    call TraceI("next wave will require around %d seconds to build and gather\n",largest) //xxx
1655
1656
    return largest
1657
endfunction
1658
1659
//============================================================================
1660
function PrepSuicideOnPlayer takes integer seconds returns boolean
1661
    local integer wave_prep   = PrepTime()
1662
    local integer save_length
1663
1664
    set save_length = harass_length
1665
    set harass_length = 0
1666
1667
    call AddSleepSeconds(seconds)
1668
    if sleep_seconds-wave_prep > 0 then
1669
        call TraceI("going to sleep for %d seconds before gathering next attack wave\n",sleep_seconds-wave_prep) //xxx
1670
        call SuicideSleep(sleep_seconds-wave_prep)
1671
    endif
1672
1673
    call Trace("preparing suicide attack wave\n") //xxx
1674
1675
    set harass_length = save_length
1676
    if harass_length < 1 then
1677
        call Trace("ERROR - no units specificed, exiting early\n") //xxx
1678
        return false
1679
    endif
1680
1681
    return true
1682
endfunction
1683
1684
//============================================================================
1685
function SleepUntilAtGoal takes nothing returns nothing
1686
    loop
1687
        exitwhen CaptainRetreating()
1688
        exitwhen CaptainAtGoal()        // reached goal
1689
        exitwhen CaptainIsHome()        // failed to path and returned home
1690
        exitwhen CaptainIsEmpty()       // all units died
1691
        call SuicideSleep(3)
1692
    endloop
1693
endfunction
1694
1695
//============================================================================
1696
function SleepInCombat takes nothing returns nothing
1697
    local integer count = 0
1698
    debug call Trace("SleepInCombat\n")
1699
    loop
1700
        loop
1701
            exitwhen not CaptainInCombat(true)  // goal is cleared
1702
            exitwhen CaptainIsEmpty()           // duh
1703
            call SuicideSleep(1)
1704
        endloop
1705
1706
        set count = count + 1
1707
        exitwhen count >= 8
1708
1709
        //xxx this is what it should have been; do this for next patch?
1710
        //call SuicideSleep(1)
1711
    endloop
1712
    debug call Trace("exit SleepInCombat\n")
1713
endfunction
1714
1715
//============================================================================
1716
function AttackMoveXYA takes integer x, integer y returns nothing
1717
1718
    if zep_next_wave then
1719
        call LoadZepWave(x,y)
1720
        set zep_next_wave = false
1721
    endif
1722
1723
    call AttackMoveXY(x,y)
1724
    call SleepUntilAtGoal()
1725
    call SleepInCombat()
1726
endfunction
1727
1728
//============================================================================
1729
function SuicideOnPlayerWave takes nothing returns nothing
1730
    call Trace("waiting for attack wave to enter combat\n") //xxx
1731
    loop
1732
        //xxx
1733
        if allow_signal_abort and CommandsWaiting() != 0 then
1734
            call Trace("ABORT -- attack wave override\n")
1735
        endif
1736
1737
        if CaptainInCombat(true) then
1738
            call Trace("done - captain has entered combat\n")
1739
        endif
1740
1741
        if CaptainIsEmpty() then
1742
            call Trace("done - all units are dead\n")
1743
        endif
1744
1745
        if sleep_seconds < -300 then
1746
            call Trace("done - timeout, took too long to reach engage the enemy\n")
1747
        endif
1748
        //xxx
1749
1750
        exitwhen allow_signal_abort and CommandsWaiting() != 0
1751
1752
        exitwhen CaptainInCombat(true)
1753
        exitwhen CaptainIsEmpty()
1754
        call SuicideSleep(10)
1755
        exitwhen sleep_seconds < -300
1756
    endloop
1757
1758
    call Trace("waiting for attack wave to die\n") //xxx
1759
    loop
1760
        //xxx
1761
        if allow_signal_abort and CommandsWaiting() != 0 then
1762
            call Trace("ABORT - attack wave override\n")
1763
        endif
1764
1765
        if CaptainIsEmpty() then
1766
            call Trace("done - all units are dead\n")
1767
        endif
1768
1769
        if sleep_seconds < -300 then
1770
            call Trace("done - timeout, took too long to reach engage the enemy\n")
1771
        endif
1772
        //xxx
1773
1774
        exitwhen allow_signal_abort and CommandsWaiting() != 0
1775
1776
        exitwhen CaptainIsEmpty()
1777
        call SuicideSleep(10)
1778
        exitwhen sleep_seconds < -300
1779
    endloop
1780
endfunction
1781
1782
//--------------------------------------------------------------------------------------------------
1783
function CommonSuicideOnPlayer takes boolean standard, boolean bldgs, integer seconds, player p, integer x, integer y returns nothing
1784
    local integer save_peons
1785
1786
    if not PrepSuicideOnPlayer(seconds) then
1787
        return
1788
    endif
1789
1790
    set save_peons = campaign_wood_peons
1791
    set campaign_wood_peons = 0
1792
1793
    loop
1794
        //xxx
1795
        if allow_signal_abort and CommandsWaiting() != 0 then
1796
            call Trace("ABORT -- attack wave override\n")
1797
        endif
1798
        //xxx
1799
1800
        exitwhen allow_signal_abort and CommandsWaiting() != 0
1801
1802
        loop
1803
            exitwhen allow_signal_abort and CommandsWaiting() != 0
1804
1805
            call FormGroup(5,true)
1806
            exitwhen sleep_seconds <= 0
1807
            call TraceI("waiting %d seconds before suicide\n",sleep_seconds) //xxx
1808
        endloop
1809
1810
        if standard then
1811
            if bldgs then
1812
                exitwhen SuicidePlayer(p,sleep_seconds >= -60)
1813
            else
1814
                exitwhen SuicidePlayerUnits(p,sleep_seconds >= -60)
1815
            endif
1816
        else
1817
            call AttackMoveXYA(x,y)
1818
        endif
1819
1820
        call TraceI("waiting %d seconds before timeout\n",60+sleep_seconds) //xxx
1821
        call SuicideSleep(5)
1822
    endloop
1823
1824
    set campaign_wood_peons = save_peons
1825
    set harass_length = 0
1826
1827
    call SuicideOnPlayerWave()
1828
endfunction
1829
1830
//--------------------------------------------------------------------------------------------------
1831
function SuicideOnPlayer takes integer seconds, player p returns nothing
1832
    call CommonSuicideOnPlayer(true,true,seconds,p,0,0)
1833
endfunction
1834
1835
//--------------------------------------------------------------------------------------------------
1836
function SuicideOnUnits takes integer seconds, player p returns nothing
1837
    call CommonSuicideOnPlayer(true,false,seconds,p,0,0)
1838
endfunction
1839
1840
//--------------------------------------------------------------------------------------------------
1841
function SuicideOnPoint takes integer seconds, player p, integer x, integer y returns nothing
1842
    call CommonSuicideOnPlayer(false,false,seconds,p,x,y)
1843
endfunction
1844
1845
//============================================================================
1846
function SuicideUntilSignal takes integer seconds, player p returns nothing
1847
    local integer save
1848
    local integer wave_prep = PrepTime()
1849
1850
    loop
1851
        call AddSleepSeconds(seconds)
1852
        if sleep_seconds-wave_prep > 0 then
1853
            call SuicideSleep(sleep_seconds-wave_prep)
1854
        endif
1855
1856
        set save = campaign_wood_peons
1857
        set campaign_wood_peons = 0
1858
        loop
1859
            loop
1860
                call FormGroup(5, true)
1861
                exitwhen sleep_seconds <= 0
1862
                exitwhen CommandsWaiting() != 0
1863
            endloop
1864
            exitwhen SuicidePlayer(p,sleep_seconds >= -60)
1865
            exitwhen CommandsWaiting() != 0
1866
            call SuicideSleep(3)
1867
        endloop
1868
        set campaign_wood_peons = save
1869
1870
        loop
1871
            exitwhen CaptainIsEmpty()
1872
            exitwhen CommandsWaiting() != 0
1873
            call SuicideSleep(5)
1874
        endloop
1875
        exitwhen CommandsWaiting() != 0
1876
    endloop
1877
endfunction
1878
1879
//--------------------------------------------------------------------------------------------------
1880
function SuicideOnce takes integer easy, integer med, integer hard, integer unitid returns nothing
1881
    if difficulty == EASY then
1882
        call SuicideUnit(easy,unitid)
1883
    elseif difficulty == NORMAL then
1884
        call SuicideUnit(med,unitid)
1885
    else
1886
        call SuicideUnit(hard,unitid)
1887
    endif
1888
endfunction
1889
1890
//--------------------------------------------------------------------------------------------------
1891
function SuicideUnitA takes integer unitid returns nothing
1892
    if unitid != 0 then
1893
        call SuicideUnit(1,unitid)
1894
    endif
1895
    call Sleep(0.1)
1896
endfunction
1897
1898
//--------------------------------------------------------------------------------------------------
1899
function SuicideUnitB takes integer unitid, integer playerid returns nothing
1900
    if unitid != 0 then
1901
        call SuicideUnitEx(1,unitid,playerid)
1902
    endif
1903
    call Sleep(0.1)
1904
endfunction
1905
1906
//--------------------------------------------------------------------------------------------------
1907
function SuicideUnits takes integer u1, integer u2, integer u3, integer u4, integer u5, integer u6, integer u7, integer u8, integer u9, integer uA returns nothing
1908
    call Trace("MASS SUICIDE - this script is now technically done\n") //xxx
1909
1910
    call PrepFullSuicide()
1911
    loop
1912
        call SuicideUnitA(u1)
1913
        call SuicideUnitA(u2)
1914
        call SuicideUnitA(u3)
1915
        call SuicideUnitA(u4)
1916
        call SuicideUnitA(u5)
1917
        call SuicideUnitA(u6)
1918
        call SuicideUnitA(u7)
1919
        call SuicideUnitA(u8)
1920
        call SuicideUnitA(u9)
1921
        call SuicideUnitA(uA)
1922
    endloop
1923
endfunction
1924
1925
//--------------------------------------------------------------------------------------------------
1926
function SuicideUnitsEx takes integer playerid, integer u1, integer u2, integer u3, integer u4, integer u5, integer u6, integer u7, integer u8, integer u9, integer uA returns nothing
1927
    call Trace("MASS SUICIDE - this script is now technically done\n") //xxx
1928
1929
    call PrepFullSuicide()
1930
    loop
1931
        call SuicideUnitB(u1,playerid)
1932
        call SuicideUnitB(u2,playerid)
1933
        call SuicideUnitB(u3,playerid)
1934
        call SuicideUnitB(u4,playerid)
1935
        call SuicideUnitB(u5,playerid)
1936
        call SuicideUnitB(u6,playerid)
1937
        call SuicideUnitB(u7,playerid)
1938
        call SuicideUnitB(u8,playerid)
1939
        call SuicideUnitB(u9,playerid)
1940
        call SuicideUnitB(uA,playerid)
1941
    endloop
1942
endfunction
1943
1944
//--------------------------------------------------------------------------------------------------
1945
function SuicideOnPlayerEx takes integer easy, integer med, integer hard, player p returns nothing
1946
    if difficulty == EASY then
1947
        call SuicideOnPlayer(easy,p)
1948
    elseif difficulty == NORMAL then
1949
        call SuicideOnPlayer(med,p)
1950
    else
1951
        call SuicideOnPlayer(hard,p)
1952
    endif
1953
endfunction
1954
1955
//--------------------------------------------------------------------------------------------------
1956
function SuicideOnUnitsEx takes integer easy, integer med, integer hard, player p returns nothing
1957
    if difficulty == EASY then
1958
        call SuicideOnUnits(easy,p)
1959
    elseif difficulty == NORMAL then
1960
        call SuicideOnUnits(med,p)
1961
    else
1962
        call SuicideOnUnits(hard,p)
1963
    endif
1964
endfunction
1965
1966
//--------------------------------------------------------------------------------------------------
1967
function SuicideOnPointEx takes integer easy, integer med, integer hard, player p, integer x, integer y returns nothing
1968
    if difficulty == EASY then
1969
        call SuicideOnPoint(easy,p,x,y)
1970
    elseif difficulty == NORMAL then
1971
        call SuicideOnPoint(med,p,x,y)
1972
    else
1973
        call SuicideOnPoint(hard,p,x,y)
1974
    endif
1975
endfunction
1976
1977
//============================================================================
1978
function ForeverSuicideOnPlayer takes integer seconds, player p returns nothing
1979
    local integer length = harass_length
1980
    loop
1981
        exitwhen allow_signal_abort and CommandsWaiting() != 0
1982
        call SuicideOnPlayer(seconds,p)
1983
        set harass_length = length
1984
    endloop
1985
endfunction
1986
1987
//============================================================================
1988
function CommonSleepUntilTargetDead takes unit target, boolean reform returns nothing
1989
    loop
1990
        exitwhen CaptainRetreating()
1991
        exitwhen CaptainReadinessHP() <= 40
1992
1993
        exitwhen not UnitAlive(target)
1994
        exitwhen UnitInvis(target) and not IsUnitDetected(target,ai_player)
1995
1996
        if not TownThreatened() then
1997
            call AttackMoveKill(target)
1998
        endif
1999
2000
        call SuicideSleep(3)
2001
2002
        if reform and sleep_seconds < -40 then
2003
            if CaptainInCombat(true) then
2004
                set sleep_seconds = sleep_seconds + 5
2005
            else
2006
                set sleep_seconds = 0
2007
                call FormGroup(1,false)
2008
            endif
2009
        endif
2010
    endloop
2011
endfunction
2012
2013
//============================================================================
2014
function SleepUntilTargetDead takes unit target returns nothing
2015
    call CommonSleepUntilTargetDead(target,false)
2016
endfunction
2017
2018
//============================================================================
2019
function ReformUntilTargetDead takes unit target returns nothing
2020
    debug call Trace("ReformUntilTargetDead\n")
2021
    call CommonSleepUntilTargetDead(target,true)
2022
endfunction
2023
2024
//============================================================================
2025
function AttackMoveKillA takes unit target returns nothing
2026
    if target == null then
2027
        call SuicideSleep(3)
2028
        return
2029
    endif
2030
2031
    debug call Trace("AttackMoveKillA\n")
2032
    call AttackMoveKill(target)
2033
    call ReformUntilTargetDead(target)
2034
    call SleepInCombat()
2035
endfunction
2036
2037
//============================================================================
2038
function MinorCreepAttack takes nothing returns nothing
2039
    local unit target = GetMinorCreep()
2040
    call SetAllianceTarget(target)
2041
    call FormGroup(3, true)
2042
    call AttackMoveKillA(target)
2043
endfunction
2044
2045
//============================================================================
2046
function MajorCreepAttack takes nothing returns nothing
2047
    local unit target = GetMajorCreep()
2048
    call SetAllianceTarget(target)
2049
    call FormGroup(3,true)
2050
    call AttackMoveKillA(target)
2051
endfunction
2052
2053
//============================================================================
2054
function CreepAttackEx takes nothing returns nothing
2055
    local unit target = GetCreepCamp(min_creeps,max_creeps,allow_air_creeps)
2056
    call SetAllianceTarget(target)
2057
    call FormGroup(3,true)
2058
    call AttackMoveKillA(target)
2059
endfunction
2060
2061
//============================================================================
2062
function AnyPlayerAttack takes nothing returns nothing
2063
    local unit hall
2064
2065
    set hall = GetEnemyExpansion()
2066
    if hall == null then
2067
        call StartGetEnemyBase()
2068
        loop
2069
            exitwhen not WaitGetEnemyBase()
2070
            call SuicideSleep(1)
2071
        endloop
2072
        set hall = GetEnemyBase()
2073
    endif
2074
2075
    call SetAllianceTarget(hall)
2076
    call FormGroup(3,true)
2077
    call AttackMoveKillA(hall)
2078
endfunction
2079
2080
//============================================================================
2081
function ExpansionAttack takes nothing returns nothing
2082
    local unit creep = GetExpansionFoe()
2083
    local integer x
2084
2085
    call FormGroup(3, true)
2086
    if creep == null then
2087
        set x = GetExpansionX()
2088
        if x != -1 then
2089
            call AttackMoveXYA(x,GetExpansionY())
2090
        endif
2091
    else
2092
        call AttackMoveKillA(creep)
2093
    endif
2094
endfunction
2095
2096
//============================================================================
2097
//  AddSiege
2098
//============================================================================
2099
function AddSiege takes nothing returns nothing
2100
    call SetAssaultGroup( 0, 9, SHADE       )
2101
    call SetAssaultGroup( 0, 9, MEAT_WAGON  )
2102
    call SetAssaultGroup( 0, 9, MORTAR      )
2103
    call SetAssaultGroup( 0, 9, TANK        )
2104
    call SetAssaultGroup( 0, 9, BALLISTA    )
2105
    call SetAssaultGroup( 0, 9, CATAPULT    )
2106
endfunction
2107
2108
//===========================================================================
2109
//  GetAllyCount
2110
//============================================================================
2111
function GetAllyCount takes player whichPlayer returns integer
2112
    local integer    playerIndex = 0
2113
    local integer    count = 0
2114
    local player     indexPlayer
2115
2116
    loop
2117
        set indexPlayer = Player(playerIndex)
2118
2119
        if whichPlayer != indexPlayer then
2120
            if GetPlayerAlliance(whichPlayer,indexPlayer,ALLIANCE_PASSIVE) then
2121
                if GetPlayerAlliance(indexPlayer,whichPlayer,ALLIANCE_PASSIVE) then
2122
                    if GetPlayerStructureCount(indexPlayer,true) > 0 then
2123
                        set count = count + 1
2124
                    endif
2125
                endif
2126
            endif
2127
        endif
2128
2129
        set playerIndex = playerIndex + 1
2130
        exitwhen playerIndex == 12
2131
    endloop
2132
2133
    return count
2134
endfunction
2135
2136
//============================================================================
2137
//  SingleMeleeAttack
2138
//============================================================================
2139
function SingleMeleeAttack takes boolean needs_exp, boolean has_siege, boolean major_ok, boolean air_units returns nothing
2140
    local boolean   can_siege
2141
    local real      daytime
2142
    local unit      hall
2143
    local unit      mega
2144
    local unit      creep
2145
    local unit      common
2146
    local integer   minimum
2147
    local boolean   allies
2148
2149
    call Trace("===SingleMeleeAttack===\n") //xxx
2150
2151
    if TownThreatened() then
2152
        call Trace("sleep 2, town threatened\n") //xxx
2153
        call Sleep(2)
2154
        return
2155
    endif
2156
2157
    // purchase zeppelins
2158
    //
2159
    if get_zeppelin and GetGold() > 300 and GetWood() > 100 then
2160
        call Trace("purchase zep\n") //xxx
2161
        call PurchaseZeppelin()
2162
        set get_zeppelin = false
2163
        set ready_for_zeppelin = false
2164
        return
2165
    endif
2166
    set ready_for_zeppelin = true
2167
2168
    // coordinate with allies
2169
    //
2170
    set allies = GetAllyCount(ai_player) > 0
2171
    if allies and MeleeDifficulty() != MELEE_NEWBIE then
2172
        set common = GetAllianceTarget()
2173
        if common != null then
2174
            call Trace("join ally force\n") //xxx
2175
            if GetMegaTarget() != null then
2176
                call AddSiege()
2177
            endif
2178
            call FormGroup(3,true)
2179
            call AttackMoveKillA(common)
2180
            call SetAllianceTarget(null)
2181
            return
2182
        endif
2183
    endif
2184
2185
    // take expansions as needed
2186
    //
2187
    if needs_exp then
2188
        call Trace("needs exp\n") //xxx
2189
        set creep = GetExpansionFoe()
2190
        if creep != null then
2191
            call Trace("attack exp\n") //xxx
2192
            call SetAllianceTarget(creep)
2193
            call FormGroup(3,true)
2194
            call AttackMoveKillA(creep)
2195
            call Sleep(20)
2196
            set take_exp = false
2197
            return
2198
        endif
2199
    endif
2200
2201
    // all-out attack if the player is weak
2202
    //
2203
    if MeleeDifficulty() != MELEE_NEWBIE then
2204
        set mega = GetMegaTarget()
2205
        if mega != null then
2206
            call Trace("MEGA TARGET!!!\n") //xxx
2207
            call AddSiege()
2208
            call FormGroup(3,true)
2209
            call AttackMoveKillA(mega)
2210
            return
2211
        endif
2212
    endif
2213
2214
    // deny player an expansion
2215
    //
2216
    set hall = GetEnemyExpansion()
2217
    set daytime = GetFloatGameState(GAME_STATE_TIME_OF_DAY)
2218
    set can_siege = has_siege and (air_units or (daytime>=4 and daytime<=12))
2219
2220
    if hall!=null and (can_siege or not IsTowered(hall)) then
2221
2222
        call Trace("test player town attack\n") //xxx
2223
2224
        if MeleeDifficulty() == MELEE_NEWBIE then
2225
            set minimum = 3
2226
        elseif allies and MeleeDifficulty() == MELEE_NORMAL then
2227
            set minimum = 1
2228
        else
2229
            set minimum = 0 // HARD, INSANE, and NORMAL with no allies
2230
        endif
2231
2232
        if exp_seen >= minimum then
2233
            call Trace("do player town attack\n") //xxx
2234
            set exp_seen = 0
2235
            call AddSiege()
2236
            call SetAllianceTarget(hall)
2237
            call FormGroup(3,true)
2238
            call AttackMoveKillA(hall)
2239
            return
2240
        endif
2241
2242
        set exp_seen = exp_seen + 1
2243
    endif
2244
2245
    // attack player's main base when siege is available
2246
    //
2247
    if can_siege then
2248
        call Trace("attack player's town\n") //xxx
2249
        call AddSiege()
2250
        call AnyPlayerAttack()
2251
        return
2252
    endif
2253
2254
    // extended, more specific method of determining creep levels
2255
    //
2256
    if min_creeps != -1 then
2257
        call TraceI("custom creep attack %d\n",max_creeps) //xxx
2258
        call CreepAttackEx()
2259
        return
2260
    endif
2261
2262
    // nothing better to do, so kill a creep camp
2263
    //
2264
    if major_ok then
2265
        call Trace("major creep attack\n") //xxx
2266
        call MajorCreepAttack()
2267
        return
2268
    endif
2269
2270
    call Trace("minor creep attack\n") //xxx
2271
    call MinorCreepAttack()
2272
endfunction
2273
2274
//============================================================================
2275
function GetZeppelin takes nothing returns nothing
2276
    if ready_for_zeppelin then
2277
        set get_zeppelin = true
2278
    endif
2279
endfunction
2280
2281
//============================================================================
2282
function FoodUsed takes nothing returns integer
2283
    return GetPlayerState(ai_player,PLAYER_STATE_RESOURCE_FOOD_USED)
2284
endfunction
2285
2286
//============================================================================
2287
function FoodCap takes nothing returns integer
2288
    return GetPlayerState(ai_player,PLAYER_STATE_RESOURCE_FOOD_CAP)
2289
endfunction
2290
2291
//============================================================================
2292
function FoodSpace takes nothing returns integer
2293
    return FoodCap() - FoodUsed()
2294
endfunction
2295
2296
//============================================================================
2297
function FoodAvail takes integer base returns integer
2298
    return GetFoodMade(racial_farm) * TownCount(racial_farm) + GetFoodMade(base) * TownCount(base)
2299
endfunction
2300
2301
//============================================================================
2302
function BuildAttackers takes nothing returns nothing
2303
    local integer index = 0
2304
    local integer unitid
2305
    local integer desire
2306
    local integer count
2307
2308
    loop
2309
        exitwhen index == harass_length
2310
2311
        set unitid = harass_units[index]
2312
        set desire = harass_qty[index] + IgnoredUnits(unitid)
2313
        set count  = TownCount(unitid)
2314
2315
        if count != desire then
2316
            if not StartUnit(desire,unitid,-1) then
2317
                return
2318
            endif
2319
        endif
2320
2321
        set index = index + 1
2322
    endloop
2323
endfunction
2324
2325
//============================================================================
2326
function BuildDefenders takes nothing returns nothing
2327
    local integer index = 0
2328
    local integer unitid
2329
    local integer qty
2330
    loop
2331
        exitwhen index == defense_length
2332
2333
        set unitid = defense_units[index]
2334
        set qty = defense_qty[index]
2335
2336
        call Conversions(qty,unitid)
2337
        call AddDefenders(qty,unitid)
2338
2339
        set index = index + 1
2340
    endloop
2341
endfunction
2342
2343
//============================================================================
2344
function CampaignBasicsA takes nothing returns nothing
2345
    local integer food_each = GetFoodMade(racial_farm)
2346
    local integer on_wood
2347
2348
    call ClearHarvestAI()
2349
2350
    if CaptainInCombat(false) then
2351
        set on_wood = 0
2352
    else
2353
        set on_wood = campaign_wood_peons
2354
    endif
2355
2356
    call HarvestGold(0,campaign_gold_peons)
2357
    call HarvestWood(0,on_wood)
2358
2359
    if harvest_town1 then
2360
        call HarvestGold(1,campaign_gold_peons)
2361
        call HarvestWood(1,on_wood)
2362
    endif
2363
2364
    if harvest_town2 then
2365
        call HarvestGold(2,campaign_gold_peons)
2366
        call HarvestWood(2,on_wood)
2367
    endif
2368
2369
    if harvest_town3 then
2370
        call HarvestGold(3,campaign_gold_peons)
2371
        call HarvestWood(3,on_wood)
2372
    endif
2373
2374
    if do_campaign_farms and FoodUsed()+food_each-1 > food_each*(TownCount(racial_farm)+1) then
2375
        call StartUnit(TownCount(racial_farm)+1,racial_farm,-1)
2376
    endif
2377
2378
    if build_campaign_attackers then
2379
        call BuildAttackers()
2380
    endif
2381
2382
    if not CaptainInCombat(false) then
2383
        call BuildDefenders()
2384
    endif
2385
2386
    call FillGuardPosts()
2387
    call ReturnGuardPosts()
2388
endfunction
2389
2390
//============================================================================
2391
function CampaignBasics takes nothing returns nothing
2392
    call Sleep(1)
2393
    call CampaignBasicsA()
2394
    call StaggerSleep(1,5)
2395
    loop
2396
        call CampaignBasicsA()
2397
        call Sleep(campaign_basics_speed)
2398
    endloop
2399
endfunction
2400
2401
//============================================================================
2402
function CampaignAI takes integer farms, code heroes returns nothing
2403
    if GetGameDifficulty() == MAP_DIFFICULTY_EASY then
2404
        set difficulty = EASY
2405
2406
        call SetTargetHeroes(false)
2407
        call SetUnitsFlee(false)
2408
2409
    elseif GetGameDifficulty() == MAP_DIFFICULTY_NORMAL then
2410
        set difficulty = NORMAL
2411
2412
        call SetTargetHeroes(false)
2413
        call SetUnitsFlee(false)
2414
2415
    elseif GetGameDifficulty() == MAP_DIFFICULTY_HARD then
2416
        set difficulty = HARD
2417
2418
        call SetPeonsRepair(true)
2419
    else
2420
        set difficulty = INSANE
2421
    endif
2422
2423
    call InitAI()
2424
    call InitBuildArray()
2425
    call InitAssaultGroup()
2426
    call CreateCaptains()
2427
2428
    call SetNewHeroes(false)
2429
    if heroes != null then
2430
        call SetHeroLevels(heroes)
2431
    endif
2432
2433
    call SetHeroesFlee(false)
2434
    call SetGroupsFlee(false)
2435
    call SetSlowChopping(true)
2436
    call GroupTimedLife(false)
2437
    call SetCampaignAI()
2438
    call Sleep(0.1)
2439
2440
    set racial_farm = farms
2441
    call StartThread(function CampaignBasics)
2442
    call StartBuildLoop()
2443
endfunction
2444
2445
//============================================================================
2446
function UnsummonAll takes nothing returns nothing
2447
    local unit bldg
2448
    loop
2449
        set bldg = GetBuilding(ai_player)
2450
        exitwhen bldg==null
2451
        call Unsummon(bldg)
2452
        call Sleep(2)
2453
    endloop
2454
endfunction
2455
2456
//============================================================================
2457
//  SkillArrays
2458
//============================================================================
2459
function SkillArrays takes nothing returns integer
2460
    local integer level = GetHeroLevelAI()
2461
2462
    if level > max_hero_level then
2463
        set max_hero_level = level
2464
    endif
2465
2466
    if GetHeroId() == hero_id then
2467
        return skills1[level]
2468
    elseif GetHeroId() == hero_id2 then
2469
        return skills2[level]
2470
    else
2471
        return skills3[level]
2472
    endif
2473
endfunction
2474
2475
//--------------------------------------------------------------------------------------------------
2476
//  SetSkillArray
2477
//--------------------------------------------------------------------------------------------------
2478
function SetSkillArray takes integer index, integer id returns nothing
2479
    local integer i = 1
2480
2481
    if index == 1 then
2482
        if hero_id != id then
2483
            return
2484
        endif
2485
        loop
2486
            set skills1[i] = skill[i]
2487
            exitwhen i == 10
2488
            set i = i + 1
2489
        endloop
2490
    elseif index == 2 then
2491
        if hero_id2 != id then
2492
            return
2493
        endif
2494
        loop
2495
            set skills2[i] = skill[i]
2496
            exitwhen i == 10
2497
            set i = i + 1
2498
        endloop
2499
    else
2500
        if hero_id3 != id then
2501
            return
2502
        endif
2503
        loop
2504
            set skills3[i] = skill[i]
2505
            exitwhen i == 10
2506
            set i = i + 1
2507
        endloop
2508
    endif
2509
endfunction
2510
2511
//============================================================================
2512
//  AwaitMeleeHeroes
2513
//============================================================================
2514
function AwaitMeleeHeroes takes nothing returns nothing
2515
    if GetUnitCountDone(hero_id2) > 0 then
2516
        set two_heroes = true
2517
    endif
2518
    loop
2519
        exitwhen GetUnitCountDone(hero_id)>0 and (take_exp or (not two_heroes or GetUnitCountDone(hero_id2)>0))
2520
        call Sleep(1)
2521
    endloop
2522
endfunction
2523
2524
//============================================================================
2525
//  PickMeleeHero
2526
//============================================================================
2527
function PickMeleeHero takes race raceid returns integer
2528
    local integer first
2529
    local integer second
2530
    local integer third
2531
    local integer last
2532
    local integer array heroes
2533
2534
    //------------------------------------------------------------------------
2535
    if raceid == RACE_HUMAN then
2536
    //------------------------------------------------------------------------
2537
        set heroes[1] = ARCHMAGE
2538
        set heroes[2] = MTN_KING
2539
        set heroes[3] = PALADIN
2540
        set heroes[4] = BLOOD_MAGE
2541
2542
    //------------------------------------------------------------------------
2543
    elseif raceid == RACE_ORC then
2544
    //------------------------------------------------------------------------
2545
        set heroes[1] = BLADE_MASTER
2546
        set heroes[2] = FAR_SEER
2547
        set heroes[3] = TAUREN_CHIEF
2548
        set heroes[4] = SHADOW_HUNTER
2549
2550
    //------------------------------------------------------------------------
2551
    elseif raceid == RACE_NIGHTELF then
2552
    //------------------------------------------------------------------------
2553
        set heroes[1] = DEMON_HUNTER
2554
        set heroes[2] = KEEPER
2555
        set heroes[3] = MOON_BABE
2556
        set heroes[4] = WARDEN
2557
2558
    //------------------------------------------------------------------------
2559
    elseif raceid == RACE_UNDEAD then
2560
    //------------------------------------------------------------------------
2561
        set heroes[1] = DEATH_KNIGHT
2562
        set heroes[2] = DREAD_LORD
2563
        set heroes[3] = LICH
2564
        set heroes[4] = CRYPT_LORD
2565
    else
2566
        set hero_id = 0
2567
    endif
2568
2569
    if VersionCompatible(VERSION_FROZEN_THRONE) then
2570
        set last = 4
2571
    else
2572
        set last = 3
2573
    endif
2574
2575
    set first  = GetRandomInt(1,last)
2576
    set second = GetRandomInt(1,last-1)
2577
    set third  = GetRandomInt(1,last-2)
2578
2579
    set hero_id        = heroes[first]
2580
    set heroes[first]  = heroes[last]
2581
    set hero_id2       = heroes[second]
2582
    set heroes[second] = heroes[last-1]
2583
    set hero_id3       = heroes[third]
2584
2585
    return hero_id
2586
endfunction
2587