//===========================================================================
// Calculate the modulus/remainder of (dividend) divided by (divisor).
// Examples: 18 mod 5 = 3. 15 mod 5 = 0. -8 mod 5 = 2.
//
function ModuloInteger takes integer dividend, integer divisor returns integer
local integer modulus = dividend - (dividend / divisor) * divisor
// If the dividend was negative, the above modulus calculation will
// be negative, but within (-divisor..0). We can add (divisor) to
// shift this result into the desired range of (0..divisor).
if (modulus < 0) then
set modulus = modulus + divisor
endif
return modulus
endfunction
function ChooseHeroSkill takes nothing returns integer
local integer curHero = GetHeroId()
local integer level = GetHeroLevelAI()
local integer mod = ModuloInteger(level, 4)
local boolean skillUlti = ModuloInteger(level, 6) == 0 and level / 6 <= 9
// Paladin
if (curHero == 'Hpal') then
if (skillUlti) then
return 'AHre' // resurrection
elseif (mod == 0) then
return 'AHhb'
elseif (mod == 1) then
return 'AHds'
elseif (mod == 2) then
return 'AHad'
endif
// Arch mage
elseif (curHero == 'Hamg') then
if (skillUlti) then
return 'AHmt' // mass teleport
elseif (mod == 0) then
return 'AHbz'
elseif (mod == 1) then
return 'AHab'
elseif (mod == 2) then
return 'AHwe'
endif
// Mountain King
elseif (curHero == 'Hmkg') then
if (skillUlti) then
return 'AHav' // avatar
elseif (mod == 0) then
return 'AHtc'
elseif (mod == 1) then
return 'AHtb'
elseif (mod == 2) then
return 'AHbh'
endif
// Blood Mage
elseif (curHero == 'Hblm') then
if (skillUlti) then
return 'AHpx' // phoenix
elseif (mod == 0) then
return 'AHfs'
elseif (mod == 1) then
return 'AHbn'
elseif (mod == 2) then
return 'AHdr'
endif
// TODO Add all hero types!
endif
return 'Aamk'
endfunction
function ConfigureAI takes nothing returns nothing
call SetTargetHeroes( true )
call SetUnitsFlee( true )
call SetHeroesFlee( true )
call SetPeonsRepair( true )
call SetHeroesBuyItems( true )
call SetHeroesTakeItems( true )
endfunction
function BuildingStrategy takes nothing returns nothing
// **********************************
// * Building Strategy *
// **********************************
// Tier 1 Buildings
call SetReplacements( 1, 2, 3 )
call SetBuildUnit( 1, TOWN_HALL )
call SetBuildUnit( 10, PEASANT )
call SetBuildUnit( 4, 'n00E' ) // Human Citizen (Male)
call SetBuildUnit( 3, HOUSE )
call SetBuildUnit( 3, 'h00R' ) // Human Housing
call SetBuildUnit( 2, BARRACKS )
call SetBuildUnit( 1, HUMAN_ALTAR )
call SetBuildUnit( 1, LUMBER_MILL )
call SetBuildUnit( 1, BLACKSMITH )
call SetBuildUnit( 1, ARCANE_VAULT )
call CampaignDefenderEx( 2, 2, 3, FOOTMAN )
call CampaignDefenderEx( 1, 1, 1, RIFLEMAN )
// Tier 2 buildings
call SetBuildUnit( 1, KEEP )
call SetBuildUnit( 1, BLACKSMITH )
call SetBuildUnit( 1, ARCANE_SANCTUM )
call SetBuildUnit( 4, HOUSE )
call SetBuildUnit( 5, PEASANT )
call SetBuildUnit( 4, 'n00F' ) // Human Citizen (Female)
call SetBuildUnit( 4, WATCH_TOWER )
// Tier 3 buildings
call SetBuildUnit( 1, CASTLE )
call SetBuildUnit( 1, AVIARY )
call SetBuildUnit( 5, HOUSE )
call SetBuildUnit( 2, ARCANE_TOWER )
call SetBuildUnit( 2, GUARD_TOWER )
call SetBuildUnit( 4, 'n00E' ) // Human Citizen (Male)
call SetBuildUnit( 20, PEASANT )
call SetBuildUnit( 5, 'h00R' ) // Human Housing
// **********************************
// * End Building Strategy *
// **********************************
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 )
else
// If no target was found, sleep a bit before trying again
call Sleep( 20 )
endif
endfunction
function AttackWaves takes nothing returns nothing
//*** WAVE 1 ***
call InitAssaultGroup()
call CampaignAttackerEx( 2, 3, 3, FOOTMAN )
call CampaignAttackerEx( 0, 1, 2, RIFLEMAN )
call Sleep( M3 ) // Waits 3 minutes before attacking
call LaunchAttack()
//*** WAVE 1 ***
call InitAssaultGroup()
call CampaignAttackerEx( 2, 3, 3, FOOTMAN )
call CampaignAttackerEx( 0, 1, 2, RIFLEMAN )
call LaunchAttack()
//*** WAVE 2 *** Between 2 or 3 minutes after Wave 1
call InitAssaultGroup()
call CampaignAttackerEx( 3, 4, 4, FOOTMAN )
call CampaignAttackerEx( 1, 2, 3, RIFLEMAN )
call LaunchAttack()
//*** WAVE 3 *** Between 2 or 3 minutes after Wave 2
call InitAssaultGroup()
call CampaignAttackerEx( 3, 4, 4, FOOTMAN )
call CampaignAttackerEx( 1, 2, 3, RIFLEMAN )
call CampaignAttackerEx( 1, 2, 3, KNIGHT )
call LaunchAttack()
//*** WAVE 4 *** Between 2 or 3 minutes after Wave 3
call InitAssaultGroup()
call CampaignAttackerEx( 3, 4, 4, FOOTMAN )
call CampaignAttackerEx( 1, 2, 3, RIFLEMAN )
call CampaignAttackerEx( 1, 2, 3, KNIGHT )
call CampaignAttackerEx( 1, 2, 3, MORTAR )
call LaunchAttack()
//*** WAVE 5 *** Between 2 or 3 minutes after Wave 4
call InitAssaultGroup()
call CampaignAttackerEx( 3, 4, 4, FOOTMAN )
call CampaignAttackerEx( 1, 2, 3, RIFLEMAN )
call CampaignAttackerEx( 1, 2, 3, KNIGHT )
call CampaignAttackerEx( 1, 2, 3, MORTAR )
call CampaignAttackerEx( 2, 2, 3, PRIEST )
call LaunchAttack()
//*** WAVE 6 *** Between 2 or 3 minutes after Wave 5
call InitAssaultGroup()
call CampaignAttackerEx( 3, 4, 4, FOOTMAN )
call CampaignAttackerEx( 1, 2, 3, RIFLEMAN )
call CampaignAttackerEx( 1, 2, 3, KNIGHT )
call CampaignAttackerEx( 1, 2, 3, MORTAR )
call CampaignAttackerEx( 2, 2, 3, PRIEST )
call LaunchAttack()
//*** WAVE 7 *** Between 2 or 3 minutes after Wave 6
call InitAssaultGroup()
call CampaignAttackerEx( 3, 4, 4, FOOTMAN )
call CampaignAttackerEx( 1, 2, 3, RIFLEMAN )
call CampaignAttackerEx( 1, 2, 3, KNIGHT )
call CampaignAttackerEx( 1, 2, 3, MORTAR )
call CampaignAttackerEx( 2, 2, 3, PRIEST )
call CampaignAttackerEx( 2, 2, 3, SORCERESS )
call LaunchAttack()
//*** WAVE 8 *** Between 2 or 3 minutes after Wave 7
call InitAssaultGroup()
call CampaignAttackerEx( 3, 4, 4, FOOTMAN )
call CampaignAttackerEx( 1, 2, 3, RIFLEMAN )
call CampaignAttackerEx( 1, 2, 3, KNIGHT )
call CampaignAttackerEx( 1, 2, 3, MORTAR )
call CampaignAttackerEx( 2, 2, 3, PRIEST )
call CampaignAttackerEx( 2, 2, 3, SORCERESS )
call CampaignAttackerEx( 2, 2, 3, SPELL_BREAKER )
call LaunchAttack()
//*** WAVE 9 *** Between 2 or 3 minutes after Wave 8
call InitAssaultGroup()
call CampaignAttackerEx( 3, 4, 4, FOOTMAN )
call CampaignAttackerEx( 1, 2, 3, RIFLEMAN )
call CampaignAttackerEx( 1, 2, 3, KNIGHT )
call CampaignAttackerEx( 1, 2, 3, MORTAR )
call CampaignAttackerEx( 2, 2, 3, PRIEST )
call CampaignAttackerEx( 2, 2, 3, SORCERESS )
call CampaignAttackerEx( 2, 2, 3, SPELL_BREAKER )
call CampaignAttackerEx( 2, 2, 3, GRYPHON )
call LaunchAttack()
//*** WAVE 10 *** Between 2 or 3 minutes after Wave 9
call InitAssaultGroup()
call CampaignAttackerEx( 3, 4, 4, FOOTMAN )
call CampaignAttackerEx( 1, 2, 3, RIFLEMAN )
call CampaignAttackerEx( 1, 2, 3, KNIGHT )
call CampaignAttackerEx( 1, 2, 3, MORTAR )
call CampaignAttackerEx( 2, 2, 3, PRIEST )
call CampaignAttackerEx( 2, 2, 3, SORCERESS )
call CampaignAttackerEx( 2, 2, 3, SPELL_BREAKER )
call CampaignAttackerEx( 2, 2, 3, GRYPHON )
call CampaignAttackerEx( 2, 2, 3, TANK )
call LaunchAttack()
loop //Init the infinite attack loop
//*** WAVE 11 *** Between 2 or 3 minutes after Wave 10
call InitAssaultGroup()
call CampaignAttackerEx( 20, 30, 40, FOOTMAN )
call CampaignAttackerEx( 10, 20, 30, RIFLEMAN )
call CampaignAttackerEx( 10, 20, 30, KNIGHT )
call CampaignAttackerEx( 10, 20, 30, MORTAR )
call CampaignAttackerEx( 10, 20, 30, PRIEST )
call CampaignAttackerEx( 10, 20, 30, SORCERESS )
call CampaignAttackerEx( 10, 20, 30, SPELL_BREAKER )
call CampaignAttackerEx( 10, 20, 30, GRYPHON )
call CampaignAttackerEx( 10, 20, 30, TANK )
call LaunchAttack()
endloop
endfunction
function main takes nothing returns nothing
call CampaignAI( HOUSE, function ChooseHeroSkill )
call ConfigureAI( )
call BuildingStrategy( )
call AttackWaves( )
endfunction