//===========================================================================
//
// ElfAi
//
// Warcraft III AI script
// Generated by the Warcraft III World Editor
// Date: Tue Aug 12 10:18:27 2014
//
//===========================================================================
//***************************************************************************
//*
//* Global Variables
//*
//***************************************************************************
globals
integer D_WAR_ZEPPELIN = 'h00M'
integer D_VOIDWALKER = 'h007'
integer D_INFERNAL_MACHINE = 'o00P'
integer D_EFREETI = 'o00Q'
integer D_NETHER_DRAKE = 'n00F'
integer D_BLOODFIEND = 'n000'
integer D_OVERLORD = 'n001'
integer D_IMP = 'n00A'
integer D_BEHOLDER = 'n00E'
integer D_DOOMBRINGER = 'n00G'
integer D_DEMON_WORKER = 'n003'
integer D_HALL_OF_CHAOS = 'o00E'
integer D_HALL_OF_CORRUPTION = 'o00F'
integer D_HALL_OF_DOOM = 'o00G'
integer D_ALTAR_OF_CHAOS = 'o012'
integer D_SUMMONING_PORTAL = 'o00H'
integer D_DEMONIC_SHRINE = 'o011'
integer D_DEMON_GATE = 'o014'
integer D_SHRINE_OF_THE_DEATHWALKER = 'o013'
integer D_BLOOD_PIT = 'o00N'
integer D_DEMON_TOWER = 'n00O'
integer D_FUSION_CANNON = 'n00P'
integer D_IMMOLATOR = 'n00N'
integer D_SUCCUBUS_MISTRESS = 'E006'
integer D_CHAOS_GENERAL = 'O00T'
integer D_WARLOCK = 'U001'
integer MARK_OF_DOOM = 'A02T'
integer LIFE_DRAIN = 'A02U'
integer AURA_OF_SWIFTNESS = 'A003'
integer SEDUCTION = 'A024'
integer DEMONIC_LEAP = 'A04F'
integer CLEAVE = 'A04G'
integer INSPIRING_PRESENCE = 'A039'
integer ARMAGEDDON = 'A02B'
integer CHAOS_STRIKE = 'A006'
integer DARK_MINIONS = 'A008'
integer COUNTERSPELL = 'A043'
integer DIMENSIONAL_PORTAL = 'A03J'
integer UPG_CHAOS_ARMOR = 'R00W'
integer UPG_CORRUPTING_ATTACK = 'R00Z'
integer UPG_EFREETI = 'R011'
integer UPG_FATAL_WEEP = 'R012'
integer UPG_IMPROVED_WEAPONS = 'R00Y'
integer UPG_MANA_LEECH = 'R013'
integer UPG_PLASMA_GRENADES = 'R014'
integer UPG_REINFORCED_HIDES = 'R00X'
integer UPG_VOIDWALKER = 'R010'
integer attackWave = 1
integer nextDelay = 0
integer awGold = 0
integer awWood = 0
endglobals
//***************************************************************************
//*
//* Utility Functions
//*
//***************************************************************************
//===========================================================================
function CheckLastCommand takes boolean pop returns integer
local integer cmd = GetLastCommand()
if (pop) then
call PopLastCommand( )
endif
return cmd
endfunction
//===========================================================================
function CheckLastCommandData takes boolean pop returns integer
local integer data = GetLastData()
if (pop) then
call PopLastCommand( )
endif
return data
endfunction
//===========================================================================
function TotalFoodProduced takes nothing returns integer
return GetPlayerState(ai_player,PLAYER_STATE_RESOURCE_FOOD_CAP)
endfunction
//===========================================================================
function ExpansionNeeded takes nothing returns boolean
return take_exp
endfunction
//===========================================================================
function BuildExpansion takes integer hallID, integer mineID returns nothing
if (HallsCompleted(hallID)) then
call SetBuildExpa( TownCount(hallID) + 1, mineID )
endif
endfunction
//===========================================================================
function CurrentAttackWave takes nothing returns integer
return attackWave
endfunction
//===========================================================================
function ResetAttackUnits takes nothing returns nothing
set awGold = 0
set awWood = 0
call InitAssaultGroup( )
endfunction
//===========================================================================
function AddAttackUnit takes integer minQty, integer maxQty, integer unitID returns nothing
// Track attacking gold workers
if (unitID == D_DEMON_WORKER) then
set awGold = awGold + minQty
endif
// Track attacking wood workers
if (unitID == D_DEMON_WORKER) then
set awWood = awWood + minQty
endif
call SetAssaultGroup( minQty, maxQty, unitID )
endfunction
//***************************************************************************
//*
//* Basic Options
//*
//***************************************************************************
//===========================================================================
function InitOptions takes nothing returns nothing
call SetMeleeAI( )
call SetDefendPlayer( false )
call SetRandomPaths( false )
call SetTargetHeroes( true )
call SetPeonsRepair( true )
call SetHeroesFlee( true )
call SetHeroesBuyItems( true )
call SetUnitsFlee( true )
call SetGroupsFlee( false )
call SetWatchMegaTargets( false )
call SetIgnoreInjured( true )
call SetHeroesTakeItems( true )
call SetSlowChopping( false )
call SetCaptainChanges( false )
call SetSmartArtillery( true )
endfunction
//***************************************************************************
//*
//* Conditions
//*
//***************************************************************************
//===========================================================================
// Updates the values of all preset conditions
//===========================================================================
function UpdateConditions takes nothing returns nothing
endfunction
//***************************************************************************
//*
//* Heroes
//*
//***************************************************************************
//===========================================================================
// Stores hero ID and skills
//===========================================================================
function SetHero takes integer order, integer heroid returns nothing
if (order == 1) then
set hero_id = heroid
if (heroid == D_CHAOS_GENERAL) then
set skills1[ 1] = DEMONIC_LEAP
set skills1[ 2] = CLEAVE
set skills1[ 3] = INSPIRING_PRESENCE
set skills1[ 4] = DEMONIC_LEAP
set skills1[ 5] = CLEAVE
set skills1[ 6] = ARMAGEDDON
set skills1[ 7] = INSPIRING_PRESENCE
set skills1[ 8] = DEMONIC_LEAP
set skills1[ 9] = CLEAVE
set skills1[10] = INSPIRING_PRESENCE
elseif (heroid == D_WARLOCK) then
set skills1[ 1] = CHAOS_STRIKE
set skills1[ 2] = DARK_MINIONS
set skills1[ 3] = COUNTERSPELL
set skills1[ 4] = CHAOS_STRIKE
set skills1[ 5] = DARK_MINIONS
set skills1[ 6] = DIMENSIONAL_PORTAL
set skills1[ 7] = COUNTERSPELL
set skills1[ 8] = CHAOS_STRIKE
set skills1[ 9] = DARK_MINIONS
set skills1[10] = COUNTERSPELL
elseif (heroid == D_SUCCUBUS_MISTRESS) then
set skills1[ 1] = MARK_OF_DOOM
set skills1[ 2] = LIFE_DRAIN
set skills1[ 3] = AURA_OF_SWIFTNESS
set skills1[ 4] = MARK_OF_DOOM
set skills1[ 5] = LIFE_DRAIN
set skills1[ 6] = SEDUCTION
set skills1[ 7] = AURA_OF_SWIFTNESS
set skills1[ 8] = MARK_OF_DOOM
set skills1[ 9] = LIFE_DRAIN
set skills1[10] = AURA_OF_SWIFTNESS
endif
elseif (order == 2) then
set hero_id2 = heroid
if (heroid == D_CHAOS_GENERAL) then
set skills2[ 1] = DEMONIC_LEAP
set skills2[ 2] = CLEAVE
set skills2[ 3] = INSPIRING_PRESENCE
set skills2[ 4] = DEMONIC_LEAP
set skills2[ 5] = CLEAVE
set skills2[ 6] = ARMAGEDDON
set skills2[ 7] = INSPIRING_PRESENCE
set skills2[ 8] = DEMONIC_LEAP
set skills2[ 9] = CLEAVE
set skills2[10] = INSPIRING_PRESENCE
elseif (heroid == D_WARLOCK) then
set skills2[ 1] = CHAOS_STRIKE
set skills2[ 2] = DARK_MINIONS
set skills2[ 3] = COUNTERSPELL
set skills2[ 4] = CHAOS_STRIKE
set skills2[ 5] = DARK_MINIONS
set skills2[ 6] = DIMENSIONAL_PORTAL
set skills2[ 7] = COUNTERSPELL
set skills2[ 8] = CHAOS_STRIKE
set skills2[ 9] = DARK_MINIONS
set skills2[10] = COUNTERSPELL
elseif (heroid == D_SUCCUBUS_MISTRESS) then
set skills2[ 1] = MARK_OF_DOOM
set skills2[ 2] = LIFE_DRAIN
set skills2[ 3] = AURA_OF_SWIFTNESS
set skills2[ 4] = MARK_OF_DOOM
set skills2[ 5] = LIFE_DRAIN
set skills2[ 6] = SEDUCTION
set skills2[ 7] = AURA_OF_SWIFTNESS
set skills2[ 8] = MARK_OF_DOOM
set skills2[ 9] = LIFE_DRAIN
set skills2[10] = AURA_OF_SWIFTNESS
endif
elseif (order == 3) then
set hero_id3 = heroid
if (heroid == D_CHAOS_GENERAL) then
set skills3[ 1] = DEMONIC_LEAP
set skills3[ 2] = CLEAVE
set skills3[ 3] = INSPIRING_PRESENCE
set skills3[ 4] = DEMONIC_LEAP
set skills3[ 5] = CLEAVE
set skills3[ 6] = ARMAGEDDON
set skills3[ 7] = INSPIRING_PRESENCE
set skills3[ 8] = DEMONIC_LEAP
set skills3[ 9] = CLEAVE
set skills3[10] = INSPIRING_PRESENCE
elseif (heroid == D_WARLOCK) then
set skills3[ 1] = CHAOS_STRIKE
set skills3[ 2] = DARK_MINIONS
set skills3[ 3] = COUNTERSPELL
set skills3[ 4] = CHAOS_STRIKE
set skills3[ 5] = DARK_MINIONS
set skills3[ 6] = DIMENSIONAL_PORTAL
set skills3[ 7] = COUNTERSPELL
set skills3[ 8] = CHAOS_STRIKE
set skills3[ 9] = DARK_MINIONS
set skills3[10] = COUNTERSPELL
elseif (heroid == D_SUCCUBUS_MISTRESS) then
set skills3[ 1] = MARK_OF_DOOM
set skills3[ 2] = LIFE_DRAIN
set skills3[ 3] = AURA_OF_SWIFTNESS
set skills3[ 4] = MARK_OF_DOOM
set skills3[ 5] = LIFE_DRAIN
set skills3[ 6] = SEDUCTION
set skills3[ 7] = AURA_OF_SWIFTNESS
set skills3[ 8] = MARK_OF_DOOM
set skills3[ 9] = LIFE_DRAIN
set skills3[10] = AURA_OF_SWIFTNESS
endif
endif
endfunction
//===========================================================================
// Selects hero IDs for three possible heroes
//===========================================================================
function SelectHeroes takes nothing returns nothing
local integer roll = GetRandomInt(1,100)
call SetHero( 1, D_CHAOS_GENERAL )
call SetHero( 2, D_WARLOCK )
call SetHero( 3, D_SUCCUBUS_MISTRESS )
endfunction
//===========================================================================
// Returns the hero skill for the given hero and level
//===========================================================================
function ChooseHeroSkill takes nothing returns integer
local integer curHero = GetHeroId()
local integer level = GetHeroLevelAI()
if (level > max_hero_level) then
set max_hero_level = level
endif
if (curHero == hero_id) then
return skills1[level]
elseif (curHero == hero_id2) then
return skills2[level]
elseif (curHero == hero_id3) then
return skills3[level]
endif
return 0
endfunction
//***************************************************************************
//*
//* Building and Harvesting
//*
//***************************************************************************
function DoUpgrades takes nothing returns nothing
call SetBuildUpgr( 1, UPG_FATAL_WEEP )
call SetBuildUpgr( 1, UPG_MANA_LEECH )
call SetBuildUpgr( 1, UPG_PLASMA_GRENADES )
call SetBuildUpgr( 1, UPG_CHAOS_ARMOR )
call SetBuildUpgr( 1, UPG_CORRUPTING_ATTACK )
call SetBuildUpgr( 1, UPG_IMPROVED_WEAPONS )
call SetBuildUpgr( 1, UPG_REINFORCED_HIDES )
call SetBuildUpgr( 1, UPG_EFREETI )
call SetBuildUpgr( 1, UPG_VOIDWALKER )
call SetBuildUpgr( 2, UPG_CHAOS_ARMOR )
call SetBuildUpgr( 2, UPG_CORRUPTING_ATTACK )
call SetBuildUpgr( 2, UPG_IMPROVED_WEAPONS )
call SetBuildUpgr( 2, UPG_REINFORCED_HIDES )
call SetBuildUpgr( 2, UPG_EFREETI )
call SetBuildUpgr( 2, UPG_VOIDWALKER )
call SetBuildUpgr( 3, UPG_CHAOS_ARMOR )
call SetBuildUpgr( 3, UPG_CORRUPTING_ATTACK )
call SetBuildUpgr( 3, UPG_IMPROVED_WEAPONS )
call SetBuildUpgr( 3, UPG_REINFORCED_HIDES )
endfunction
//===========================================================================
// Specifies building priorities for workers
//===========================================================================
function BuildPriorities takes nothing returns nothing
local integer mine = TownWithMine()
call SetBuildAll( BUILD_UNIT, 1, D_HALL_OF_CHAOS, -1 )
call SetBuildAll( BUILD_UNIT, 6, D_DEMON_WORKER, -1 )
call SetBuildAll( BUILD_UNIT, 1, D_ALTAR_OF_CHAOS, -1 )
call SetBuildAll( BUILD_UNIT, 7, D_DEMON_WORKER, -1 )
call SetBuildAll( BUILD_UNIT, 1, D_SUMMONING_PORTAL, -1 )
call SetBuildAll( BUILD_UNIT, 9, D_DEMON_WORKER, -1 )
call SetBuildAll( BUILD_UNIT, 1, hero_id, -1 )
call SetBuildAll( BUILD_UNIT, 11, D_DEMON_WORKER, -1 )
call SetBuildAll( BUILD_UNIT, 1, D_IMP, -1 )
call SetBuildAll( BUILD_UNIT, 12, D_DEMON_WORKER, -1 )
call SetBuildAll( BUILD_UNIT, 2, D_IMP, -1 )
call SetBuildAll( BUILD_UNIT, 13, D_DEMON_WORKER, -1 )
call SetBuildAll( BUILD_UNIT, 15, D_DEMON_WORKER, -1 )
call SetBuildAll( BUILD_UNIT, 4, D_IMP, -1 )
call SetBuildAll( BUILD_UNIT, 1, D_DEMONIC_SHRINE, -1 )
call SetBuildAll( BUILD_UNIT, 4, D_BEHOLDER, -1 )
if GetGoldOwned() < 1000 then
call BuildExpansion( D_HALL_OF_CHAOS, D_HALL_OF_CHAOS )
endif
call SetBuildAll( BUILD_UNIT, 1, D_DEMON_TOWER, -1 )
call SetBuildAll( BUILD_UNIT, 1, D_FUSION_CANNON, -1 )
call SetBuildAll( BUILD_UNIT, 1, D_IMMOLATOR, -1 )
call DoUpgrades()
if MeleeDifficulty() > MELEE_NEWBIE then
call SetBuildAll( BUILD_UNIT, 2, D_DEMON_TOWER, -1 )
call SetBuildAll( BUILD_UNIT, 2, D_FUSION_CANNON, -1 )
if MeleeDifficulty() > MELEE_NORMAL then
call SetBuildAll( BUILD_UNIT, 3, D_DEMON_TOWER, -1 )
call SetBuildAll( BUILD_UNIT, 3, D_FUSION_CANNON, -1 )
call SetBuildAll( BUILD_UNIT, 2, D_IMMOLATOR, -1 )
endif
endif
call SetBuildAll( BUILD_UNIT, 1, D_HALL_OF_CORRUPTION, -1 )
call SetBuildAll( BUILD_UNIT, 1, hero_id2, -1 )
call SetBuildAll( BUILD_UNIT, 3, D_BLOODFIEND, -1 )
call SetBuildAll( BUILD_UNIT, 1, D_BLOOD_PIT, -1 )
call SetBuildAll( BUILD_UNIT, 2, D_INFERNAL_MACHINE, -1 )
call SetBuildAll( BUILD_UNIT, 1, D_SHRINE_OF_THE_DEATHWALKER, -1 )
call SetBuildAll( BUILD_UNIT, 2, D_VOIDWALKER, -1 )
call SetBuildAll( BUILD_UNIT, 1, D_EFREETI, -1 )
call SetBuildAll( BUILD_UNIT, 1, D_HALL_OF_DOOM, -1 )
call SetBuildAll( BUILD_UNIT, 1, hero_id3, -1 )
call SetBuildAll( BUILD_UNIT, 2, D_OVERLORD, -1 )
call SetBuildAll( BUILD_UNIT, 2, D_NETHER_DRAKE, -1 )
call SetBuildAll( BUILD_UNIT, 1, D_WAR_ZEPPELIN, -1 )
call SetBuildAll( BUILD_UNIT, 1, D_DEMON_GATE, -1 )
call SetBuildAll( BUILD_UNIT, 1, D_DOOMBRINGER, -1 )
if MeleeDifficulty() > MELEE_NEWBIE then
call SetBuildAll( BUILD_UNIT, 3, D_DEMON_TOWER, -1 )
call SetBuildAll( BUILD_UNIT, 3, D_FUSION_CANNON, -1 )
call SetBuildAll( BUILD_UNIT, 2, D_IMMOLATOR, -1 )
if MeleeDifficulty() > MELEE_NORMAL then
call SetBuildAll( BUILD_UNIT, 4, D_DEMON_TOWER, -1 )
call SetBuildAll( BUILD_UNIT, 4, D_FUSION_CANNON, -1 )
call SetBuildAll( BUILD_UNIT, 3, D_IMMOLATOR, -1 )
endif
endif
endfunction
//===========================================================================
// Specifies harvesting priorities for workers
//===========================================================================
function HarvestPriorities takes nothing returns nothing
local integer mine = TownWithMine()
local integer allGold = GetUnitCountDone(D_DEMON_WORKER)
local integer allWood = GetUnitCountDone(D_DEMON_WORKER)
local integer numWorkers
set numWorkers = 5
call HarvestGold( mine, numWorkers )
set numWorkers = 5
call HarvestWood( mine, numWorkers )
set numWorkers = 5
call HarvestGold( 1, numWorkers )
set numWorkers = allWood - awWood
if (numWorkers > 0) then
call HarvestWood( mine, numWorkers )
endif
endfunction
//===========================================================================
// Determines all building and harvesting assignments for workers
//===========================================================================
function WorkerAssignment takes nothing returns nothing
loop
call UpdateConditions( )
// Harvesting
call ClearHarvestAI( )
call HarvestPriorities( )
// Building
call InitBuildArray( )
call BuildPriorities( )
call Sleep( 2 )
endloop
endfunction
//***************************************************************************
//*
//* Attacking
//*
//***************************************************************************
//===========================================================================
// Returns true if the minimum forces for an attack exist
//===========================================================================
function HaveMinimumAttackers takes nothing returns boolean
local integer count
// Check for attack wave limit
//if (attackWave > 1) then
// return false
//endif
// First Hero Only
if ((GetUnitCountDone(hero_id) > 0) or (GetUnitCountDone(hero_id2) > 0) or (GetUnitCountDone(hero_id3) > 0)) and (GetUnitCountDone(D_IMP) > 2) and (GetUnitCountDone(D_BEHOLDER) > 2) then
return true
endif
return false
endfunction
//===========================================================================
// Assigns units to attack based on the given attack group
//===========================================================================
function PrepareAttackGroup takes integer groupID returns nothing
local integer all
// Attack Group #1: All Units
if (groupID == 1) then
set all = GetUnitCountDone( D_WAR_ZEPPELIN )
call AddAttackUnit( all, all, D_WAR_ZEPPELIN )
set all = GetUnitCountDone( hero_id )
call AddAttackUnit( all, all, hero_id )
set all = GetUnitCountDone( hero_id2 )
call AddAttackUnit( all, all, hero_id2 )
set all = GetUnitCountDone( hero_id3 )
call AddAttackUnit( all, all, hero_id3 )
set all = GetUnitCountDone( D_VOIDWALKER )
call AddAttackUnit( all, all, D_VOIDWALKER )
set all = GetUnitCountDone( D_INFERNAL_MACHINE )
call AddAttackUnit( all, all, D_INFERNAL_MACHINE )
set all = GetUnitCountDone( D_IMP )
set all = all - 2
if (all < 0) then
set all = 0
endif
call AddAttackUnit( all, all, D_IMP )
set all = GetUnitCountDone( D_EFREETI )
call AddAttackUnit( all, all, D_EFREETI )
set all = GetUnitCountDone( D_NETHER_DRAKE )
call AddAttackUnit( all, all, D_NETHER_DRAKE )
set all = GetUnitCountDone( D_BLOODFIEND )
call AddAttackUnit( all, all, D_BLOODFIEND )
set all = GetUnitCountDone( D_OVERLORD )
call AddAttackUnit( all, all, D_OVERLORD )
set all = GetUnitCountDone( D_DOOMBRINGER )
call AddAttackUnit( all, all, D_DOOMBRINGER )
set all = GetUnitCountDone( D_BEHOLDER )
set all = all - 2
if (all < 0) then
set all = 0
endif
call AddAttackUnit( all, all, D_BEHOLDER )
endif
endfunction
//===========================================================================
// Prepares an attack group based on the current attack wave
//===========================================================================
function PrepareForces takes nothing returns nothing
//if (attackWave == 1) then
call PrepareAttackGroup( 1 )
//endif
endfunction
//===========================================================================
// Sleep delays for each attack wave
//===========================================================================
function AttackWaveDelay takes integer inWave returns nothing
if (inWave < nextDelay) then
return
endif
if (inWave == 1) then
call Sleep( 0 )
endif
set nextDelay = inWave + 1
endfunction
//===========================================================================
// Advances attack wave counter
//===========================================================================
function AttackWaveUpdate takes nothing returns nothing
call AttackWaveDelay( attackWave )
set attackWave = attackWave + 1
if (attackWave > 1) then
set attackWave = 1
set nextDelay = attackWave + 1
endif
endfunction
//===========================================================================
// Basic attack functionality
//===========================================================================
function AttackTarget takes unit target, boolean addAlliance returns nothing
if (target == null) then
return
endif
if (addAlliance) then
call SetAllianceTarget( target )
endif
call FormGroup( 3, true )
call AttackMoveKillA( target )
if (not addAlliance) then
call SetAllianceTarget( null )
endif
endfunction
//===========================================================================
// Initiates an attack based on target priorities
//===========================================================================
function LaunchAttack takes nothing returns nothing
local unit target = null
local boolean setAlly = true
// Don't launch any attack while town is threatened
if (TownThreatened()) then
call Sleep( 2 )
return
endif
// Target Priority #1
if (target == null) then
set target = GetAllianceTarget()
if (target != null) then
set setAlly = false
endif
endif
// Target Priority #2
if (target == null) then
set target = GetExpansionFoe()
if (target != null) then
set take_exp = false
endif
endif
// Target Priority #3
if (target == null) then
set target = GetMegaTarget()
endif
// Target Priority #4
if (target == null) then
set target = GetEnemyExpansion()
endif
// Target Priority #5
if (target == null) then
set target = GetEnemyExpansion()
if (target == null) then
call StartGetEnemyBase( )
loop
exitwhen (not WaitGetEnemyBase())
call SuicideSleep( 1 )
endloop
set target = GetEnemyBase()
endif
endif
// Target Priority #6
if (target == null) then
set target = GetCreepCamp( 0, 9, false )
endif
// Target Priority #7
if (target == null) then
set target = GetCreepCamp( 10, 100, true )
endif
// Attack the target and increment attack wave
if (target != null) then
call AttackTarget( target, setAlly )
call AttackWaveUpdate( )
else
// If no target was found, sleep a bit before trying again
call Sleep( 20 )
endif
endfunction
//===========================================================================
// Determines all attacking assignments
//===========================================================================
function AttackAssignment takes nothing returns nothing
call StaggerSleep( 0, 2 )
if (attackWave == 1) then
call AttackWaveDelay( 0 )
endif
loop
loop
call UpdateConditions( )
exitwhen (HaveMinimumAttackers() and not CaptainRetreating())
call Sleep( 2 )
endloop
call RemoveInjuries( )
call ResetAttackUnits( )
call PrepareForces( )
call LaunchAttack( )
endloop
endfunction
//***************************************************************************
//*
//* Main Entry Point
//*
//***************************************************************************
//===========================================================================
function main takes nothing returns nothing
call InitAI( )
call InitOptions( )
call SelectHeroes( )
call CreateCaptains( )
call SetHeroLevels( function ChooseHeroSkill )
call Sleep( 0.1 )
call StartThread( function WorkerAssignment )
call StartThread( function AttackAssignment )
call PlayGame( )
endfunction