From 964ec268990d00a22b51180ffbed60765b8b0d76 Mon Sep 17 00:00:00 2001 From: SMUnlimited Date: Sun, 26 Nov 2023 18:14:19 +0000 Subject: [PATCH] Fix #189 and refactoring The non AMAI common code had been incorrectly modified when it should not have. Moved the official AI scripts to its own file. --- common.eai | 1693 +------------------------------------------ common_original.eai | 1690 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1692 insertions(+), 1691 deletions(-) create mode 100644 common_original.eai diff --git a/common.eai b/common.eai index 6f8f8d17f..a1cd3b521 100644 --- a/common.eai +++ b/common.eai @@ -12929,1697 +12929,8 @@ endfunction //_________________________________________________________________________________________________________________________________________________ -//_________________________________________________________________________________________________________________________________________________ - -//============================================================================ -// Standard common.ai V1.18 by Blizzard Entertainment (Implementation by Strategy Master) -//============================================================================ - -//============================================================================ -function InitAI takes nothing returns nothing - set ai_player = Player(GetAiPlayer()) - set sleep_seconds = 0 - call InitAiUnits() - call InitArrays() - call StopGathering() -endfunction - -//============================================================================ -function StandardAI takes code heroes, code peons, code attacks returns nothing - - local boolean isNewbie = (MeleeDifficulty() == MELEE_NEWBIE) - - call InitAI() - - call SetMeleeAI() - - call SetDefendPlayer(true) - call SetGroupsFlee(not isNewbie) - call SetHeroesBuyItems(not isNewbie) - call SetHeroesFlee(true) - call SetHeroesTakeItems(true) - call SetIgnoreInjured(true) - call SetPeonsRepair(true) - call SetSmartArtillery(not isNewbie) - call SetTargetHeroes(not isNewbie) - call SetUnitsFlee(not isNewbie) - call SetWatchMegaTargets(true) - - call CreateCaptains() - - call SetHeroLevels(heroes) - - call Sleep(0.1) - call StartThread(peons) - call StartThread(attacks) -endfunction - -//============================================================================ -// Utility Functions -//============================================================================ - -function SetZepNextWave takes nothing returns nothing - set zep_next_wave = true -endfunction - -function SuicideSleep takes integer seconds returns nothing - set sleep_seconds = sleep_seconds - seconds - loop - exitwhen seconds <= 0 - exitwhen allow_signal_abort and CommandsWaiting() != 0 - - if seconds >= 5 then - call Sleep(5) - set seconds = seconds - 5 - else - call Sleep(seconds) - set seconds = 0 - endif - endloop -endfunction - -//============================================================================ -function WaitForSignal takes nothing returns integer - local integer cmd - local boolean display = false //xxx - loop - exitwhen CommandsWaiting() != 0 - - //xxx - call Trace("waiting for a signal to begin AI script...\n") - set display = true - call Sleep(2) - exitwhen CommandsWaiting() != 0 - call Sleep(2) - exitwhen CommandsWaiting() != 0 - call Sleep(2) - exitwhen CommandsWaiting() != 0 - call Sleep(2) - exitwhen CommandsWaiting() != 0 - call Sleep(2) - //xxx - - endloop - - //xxx - if display then - call Trace("signal received, beginning AI script\n") - endif - //xxx - - set cmd = GetLastCommand() - call PopLastCommand() - return cmd -endfunction - -//============================================================================ -function SetWoodPeons takes integer count returns nothing - set campaign_wood_peons = count -endfunction - -//============================================================================ -function SetGoldPeons takes integer count returns nothing - set campaign_gold_peons = count -endfunction - -//============================================================================ -function SetHarvestLumber takes boolean harvest returns nothing - if harvest then - set campaign_wood_peons = 3 - else - set campaign_wood_peons = 0 - endif -endfunction - -//============================================================================ -function SetFormGroupTimeouts takes boolean state returns nothing - set form_group_timeouts = state -endfunction - -//============================================================================ -function DoCampaignFarms takes boolean state returns nothing - set do_campaign_farms = state -endfunction - -//============================================================================ -function GetMinorCreep takes nothing returns unit - return GetCreepCamp(0,9,false) -endfunction - -//============================================================================ -function GetMajorCreep takes nothing returns unit - return GetCreepCamp(10,100,allow_air_creeps) -endfunction - -//============================================================================ -function InitBuildArray takes nothing returns nothing - set build_length = 0 -endfunction - -//============================================================================ -function InitMeleeGroup takes nothing returns nothing - call InitAssaultGroup() - call RemoveInjuries() - call RemoveSiege() -endfunction - -//============================================================================ -function PrepFullSuicide takes nothing returns nothing - call InitAssaultGroup() - call InitDefenseGroup() - set campaign_gold_peons = 0 - set campaign_wood_peons = 0 -endfunction - -//============================================================================ -function SetReplacements takes integer easy, integer med, integer hard returns nothing - if difficulty == EASY then - call SetReplacementCount(easy) - elseif difficulty == NORMAL then - call SetReplacementCount(med) - else - call SetReplacementCount(hard) - endif -endfunction - -//============================================================================ -function StartTownBuilder takes code func returns nothing - call StartThread(func) -endfunction - -//============================================================================ -function SetBuildAll takes integer t, integer qty, integer unitid, integer town returns nothing - if qty > 0 then - set build_qty[build_length] = qty - set build_type[build_length] = t - set build_item[build_length] = unitid - set build_town[build_length] = town - set build_length = build_length + 1 - endif -endfunction - -//============================================================================ -function SetBuildUnit takes integer qty, integer unitid returns nothing - call SetBuildAll(BUILD_UNIT,qty,unitid,-1) -endfunction - -//============================================================================ -function SetBuildNext takes integer qty, integer unitid returns nothing - local integer has = GetUnitCount(unitid) - if has >= qty then - return - endif - call SetBuildAll(BUILD_UNIT,GetUnitCountDone(unitid)+1,unitid,-1) -endfunction - -//============================================================================ -function SetBuildUnitEx takes integer easy, integer med, integer hard, integer unitid returns nothing - if difficulty == EASY then - call SetBuildAll(BUILD_UNIT,easy,unitid,-1) - elseif difficulty == NORMAL then - call SetBuildAll(BUILD_UNIT,med,unitid,-1) - else - call SetBuildAll(BUILD_UNIT,hard,unitid,-1) - endif -endfunction - -//============================================================================ -function SecondaryTown takes integer town, integer qty, integer unitid returns nothing - call SetBuildAll(BUILD_UNIT,qty,unitid,town) -endfunction - -//============================================================================ -function SecTown takes integer town, integer qty, integer unitid returns nothing - call SetBuildAll(BUILD_UNIT,qty,unitid,town) -endfunction - -//============================================================================ -function SetBuildUpgr takes integer qty, integer unitid returns nothing - if MeleeDifficulty() != MELEE_NEWBIE or qty == 1 then - call SetBuildAll(BUILD_UPGRADE,qty,unitid,-1) - endif -endfunction - -//============================================================================ -function SetBuildUpgrEx takes integer easy, integer med, integer hard, integer unitid returns nothing - if difficulty == EASY then - call SetBuildAll(BUILD_UPGRADE,easy,unitid,-1) - elseif difficulty == NORMAL then - call SetBuildAll(BUILD_UPGRADE,med,unitid,-1) - else - call SetBuildAll(BUILD_UPGRADE,hard,unitid,-1) - endif -endfunction - -//============================================================================ -function SetBuildExpa takes integer qty, integer unitid returns nothing - call SetBuildAll(BUILD_EXPAND,qty,unitid,-1) -endfunction - -//============================================================================ -function StartUpgrade takes integer level, integer upgid returns boolean - local integer gold_cost - local integer wood_cost - - if GetUpgradeLevel(upgid) >= level then - return true - endif - - set gold_cost = GetUpgradeGoldCost(upgid) - if total_gold < gold_cost then - return false - endif - - set wood_cost = GetUpgradeWoodCost(upgid) - if total_wood < wood_cost then - return false - endif - - return SetUpgrade(upgid) -endfunction - -//============================================================================ -function BuildFactory takes integer unitid returns nothing - if GetGold() > 1000 and GetWood() > 500 then - call SetBuildUnit( 2, unitid ) - else - call SetBuildUnit( 1, unitid ) - endif -endfunction - -//============================================================================ -function GuardSecondary takes integer townid, integer qty, integer unitid returns nothing - if TownHasHall(townid) and TownHasMine(townid) then - call SecondaryTown( townid, qty, unitid ) - endif -endfunction - -//============================================================================ -function BasicExpansion takes boolean build_it, integer unitid returns nothing - if build_it and HallsCompleted(unitid) then - call SetBuildExpa( TownCount(unitid)+1, unitid ) - endif -endfunction - -//============================================================================ -function UpgradeAll takes integer baseid, integer newid returns nothing - call SetBuildUnit( TownCountDone(baseid), newid ) -endfunction - -//============================================================================ -// FoodPool -//============================================================================ -function FoodPool takes integer food, boolean weak, integer id1, integer use1, boolean strong, integer id2, integer use2 returns nothing - if strong then - call SetBuildUnit( (food - use1 * TownCount(id1)) / use2, id2 ) - elseif weak then - call SetBuildUnit( (food - use2 * TownCount(id2)) / use1, id1 ) - endif -endfunction - -//============================================================================ -// MeleeTownHall -//============================================================================ -function MeleeTownHall takes integer townid, integer unitid returns nothing - if TownHasMine(townid) and not TownHasHall(townid) then - call SecondaryTown ( townid, 1, unitid ) - endif -endfunction - -//============================================================================ -function WaitForUnits takes integer unitid, integer qty returns nothing - loop - exitwhen TownCountDone(unitid) == qty - call Sleep(2) - endloop -endfunction - -//============================================================================ -function StartUnit takes integer ask_qty, integer unitid, integer town returns boolean - local integer have_qty - local integer need_qty - local integer afford_gold - local integer afford_wood - local integer afford_qty - local integer gold_cost - local integer wood_cost - - //------------------------------------------------------------------------ - // if we have all we're asking for then make nothing - // - if town == -1 then - set have_qty = TownCount(unitid) - else - set have_qty = TownCountTown(unitid,town) - endif - - if have_qty >= ask_qty then - return true - endif - set need_qty = ask_qty - have_qty - - //------------------------------------------------------------------------ - // limit the qty we're requesting to the amount of resources available - // - set gold_cost = GetUnitGoldCost(unitid) - set wood_cost = GetUnitWoodCost(unitid) - - if gold_cost == 0 then - set afford_gold = need_qty - else - set afford_gold = total_gold / gold_cost - endif - if afford_gold < need_qty then - set afford_qty = afford_gold - else - set afford_qty = need_qty - endif - - if wood_cost == 0 then - set afford_wood = need_qty - else - set afford_wood = total_wood / wood_cost - endif - if afford_wood < afford_qty then - set afford_qty = afford_wood - endif - - // if we're waiting on gold/wood; pause build orders - if afford_qty < 1 then - return false - endif - - //------------------------------------------------------------------------ - // whether we make right now what we're requesting or not, assume we will - // and deduct the cost of the units from our fake gold total right away - // - set total_gold = total_gold - gold_cost * need_qty - set total_wood = total_wood - wood_cost * need_qty - - if total_gold < 0 then - set total_gold = 0 - endif - if total_wood < 0 then - set total_wood = 0 - endif - - //------------------------------------------------------------------------ - // give the AI a chance to make the units (it may not be able to right now - // but that doesn't stop us from trying other units after this as long - // as we have enough money to make this AND the needed, unbuilt ones) - // - return SetProduce(afford_qty,unitid,town) -endfunction - -//============================================================================ -function WaitForTown takes integer towns, integer townid returns nothing - local integer i = 0 - loop - call Sleep(10) - exitwhen TownCount(townid) >= towns - set i = i + 1 - exitwhen i == GetBJMaxPlayers() - endloop -endfunction - -//============================================================================ -function StartExpansion takes integer qty, integer hall returns boolean - local integer count - local integer town - local unit peon = null - local integer gold_cost - local boolean b = true - - set count = TownCount(hall) - if count >= qty then - return true - endif - - set town = GetNextExpansion() - if town == -1 then - return true - endif - - set take_exp = true - - set gold_cost = GetUnitGoldCost(hall) - if gold_cost > total_gold then - return false - endif - set total_gold = total_gold - gold_cost - - if GetExpansionFoe() != null then - return true - endif - - set peon = GetExpansionPeon() - if peon != null then - set b = SetExpansion(peon,hall) - set peon = null - return b - endif - return true -endfunction - -//============================================================================ -function OneBuildLoop takes nothing returns nothing - local integer index = 0 - local integer qty - local integer id - local integer tp - - set total_gold = GetGold() - gold_buffer - set total_wood = GetWood() - - loop - exitwhen index == build_length - - set qty = build_qty [index] - set id = build_item[index] - set tp = build_type[index] - - //-------------------------------------------------------------------- - if tp == BUILD_UNIT then - if not StartUnit(qty,id,build_town[index]) then - return - endif - - //-------------------------------------------------------------------- - elseif tp == BUILD_UPGRADE then - call StartUpgrade(qty,id) - - //-------------------------------------------------------------------- - else // tp == BUILD_EXPAND - if not StartExpansion(qty,id) then - return - endif - endif - - set index = index + 1 - endloop -endfunction - -//============================================================================ -function BuildLoop takes nothing returns nothing - call OneBuildLoop() - call StaggerSleep(1,2) - loop - call OneBuildLoop() - call Sleep(2) - endloop -endfunction - -//============================================================================ -function StartBuildLoop takes nothing returns nothing - call StartThread(function BuildLoop) -endfunction - -//============================================================================ -function SetInitialWave takes integer seconds returns nothing - set sleep_seconds = seconds -endfunction - -//============================================================================ -function AddSleepSeconds takes integer seconds returns nothing - set sleep_seconds = sleep_seconds + seconds -endfunction - -//============================================================================ -function SleepForever takes nothing returns nothing - call Trace("going to sleep forever\n") //xxx - loop - call Sleep(100) - endloop -endfunction - -//============================================================================ -function PlayGame takes nothing returns nothing - call StartBuildLoop() - call SleepForever() -endfunction - -//============================================================================ -function ConvertNeeds takes integer unitid returns nothing - if GetUnitCount(unitid) < 1 then - call StartUnit(1,unitid,-1) - endif -endfunction - -//============================================================================ -function Conversions takes integer desire, integer unitid returns nothing - - if GetUnitCount(unitid) >= desire then - return - endif - - #INCLUDETABLE <$VER$\UnitConversions.txt> #EFR - if unitid == %1 then - call ConvertNeeds(%2) - call ConvertNeeds(%3) - call MergeUnits(desire,%2,%3,%1) - endif - #ENDINCLUDE - - #INCLUDETABLE <$VER$\UnitEquivalence.txt> #EFR #COND "%2" eq "BUILT_FROM" - if unitid == %1 then - call ConvertNeeds(%3) - call ConvertUnits(desire, %3) - endif - #ENDINCLUDE - -endfunction - -//============================================================================ -function SetAssaultGroup takes integer qty, integer max, integer unitid returns nothing - call Conversions(max,unitid) - - if qty <= 0 and TownCountDone(unitid) == 0 then - return - endif - set harass_qty[harass_length] = qty - set harass_max[harass_length] = max - set harass_units[harass_length] = unitid - set harass_length = harass_length + 1 -endfunction - -//============================================================================ -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 - local integer i1 = 1 - local integer i2 = 1 - local integer i3 = 1 - local integer q1 - local integer q2 - local integer q3 - - if difficulty == EASY then - set q1 = e1 - set q2 = e2 - set q3 = e3 - elseif difficulty == NORMAL then - set q1 = m1 - set q2 = m2 - set q3 = m3 - else // difficulty == HARD - set q1 = h1 - set q2 = h2 - set q3 = h3 - endif - - loop - exitwhen q1<=0 and q2<=0 and q3<=0 - - if q1 > 0 then - call SetAssaultGroup(i1,i1,u1) - set q1 = q1 - 1 - set i1 = i1 + 1 - endif - - if q2 > 0 then - call SetAssaultGroup(i2,i2,u2) - set q2 = q2 - 1 - set i2 = i2 + 1 - endif - - if q3 > 0 then - call SetAssaultGroup(i3,i3,u3) - set q3 = q3 - 1 - set i3 = i3 + 1 - endif - endloop -endfunction - -//============================================================================ -function SetMeleeGroup takes integer unitid returns nothing - if unitid == hero_id then - call SetAssaultGroup(1,9,unitid) - else - call SetAssaultGroup((TownCountDone(unitid)*3)/4,20,unitid) - endif -endfunction - -//============================================================================ -function CampaignDefender takes integer level, integer qty, integer unitid returns nothing - if qty > 0 and difficulty >= level then - set defense_qty[defense_length] = qty - set defense_units[defense_length] = unitid - set defense_length = defense_length + 1 - call Conversions(qty,unitid) - call SetBuildUnit(qty,unitid) - endif -endfunction - -//============================================================================ -function CampaignDefenderEx takes integer easy, integer med, integer hard, integer unitid returns nothing - if difficulty == EASY then - call CampaignDefender(EASY,easy,unitid) - elseif difficulty == NORMAL then - call CampaignDefender(NORMAL,med,unitid) - else - call CampaignDefender(HARD,hard,unitid) - endif -endfunction - -//============================================================================ -function CampaignAttacker takes integer level, integer qty, integer unitid returns nothing - if qty > 0 and difficulty >= level then - call SetAssaultGroup(qty,qty,unitid) - endif -endfunction - -//============================================================================ -function CampaignAttackerEx takes integer easy, integer med, integer hard, integer unitid returns nothing - if difficulty == EASY then - call CampaignAttacker(EASY,easy,unitid) - elseif difficulty == NORMAL then - call CampaignAttacker(NORMAL,med,unitid) - else - call CampaignAttacker(HARD,hard,unitid) - endif -endfunction - -//============================================================================ -function FormGroup takes integer seconds, boolean testReady returns nothing - local integer index - local integer count - local integer unitid - local integer desire - local integer readyPercent - - // normally test for CaptainReadiness() of 50% - if testReady == true then - set readyPercent = 50 - call Trace("forming group, requiring healthy guys\n") //xxx - else - set readyPercent = 0 - call Trace("forming group, unit health not important\n") //xxx - endif - - call Trace("trying to gather forces\n") //xxx - - loop - call SuicideSleep(seconds) - call InitAssault() - - set index = 0 - loop - exitwhen index == harass_length - - set unitid = harass_units[index] - set desire = harass_max[index] - set count = TownCountDone(unitid) - - call Conversions(desire,unitid) - - if count >= desire then - call AddAssault(desire,unitid) - else - set desire = harass_qty[index] - - if count < desire then - call AddAssault(desire,unitid) - else - call AddAssault(count,unitid) - endif - endif - - set index = index + 1 - endloop - - //xxx - if form_group_timeouts and (sleep_seconds < -60) then - call Trace("exit form group -- timeout\n") - elseif CaptainInCombat(true) then - call Trace("exit form group -- can't form while already in combat\n") - elseif CaptainIsFull() and CaptainReadiness() >= readyPercent then - call Trace("exit form group -- ready\n") - endif - //xxx - - // time out and send group anyway if time has already expired - exitwhen form_group_timeouts and (sleep_seconds < -60) - exitwhen CaptainInCombat(true) - exitwhen CaptainIsFull() and CaptainReadiness() >= readyPercent - endloop -endfunction - -//============================================================================ -function WavePrepare takes integer unitid returns integer - return GetUnitBuildTime(unitid) -endfunction - -//============================================================================ -function PrepTime takes nothing returns integer - local integer unitid - local integer missing - local integer prep - local integer count - local integer largest = 30 - local integer index = 0 - - loop - exitwhen index == harass_length - - set unitid = harass_units[index] - set missing = harass_qty[index] + IgnoredUnits(old_id[unitid]) - TownCount(unitid) - set prep = WavePrepare(unitid) * missing - - if prep > largest then - set largest = prep - endif - - set index = index + 1 - endloop - call TraceI("next wave will require around %d seconds to build and gather\n",largest) //xxx - - return largest -endfunction - -//============================================================================ -function PrepSuicideOnPlayer takes integer seconds returns boolean - local integer wave_prep = PrepTime() - local integer save_length - - set save_length = harass_length - set harass_length = 0 - - call AddSleepSeconds(seconds) - if sleep_seconds-wave_prep > 0 then - call TraceI("going to sleep for %d seconds before gathering next attack wave\n",sleep_seconds-wave_prep) //xxx - call SuicideSleep(sleep_seconds-wave_prep) - endif - - call Trace("preparing suicide attack wave\n") //xxx - - set harass_length = save_length - if harass_length < 1 then - call Trace("ERROR - no units specificed, exiting early\n") //xxx - return false - endif - - return true -endfunction - -//============================================================================ -function SleepUntilAtGoal takes nothing returns nothing - loop - exitwhen CaptainRetreating() - exitwhen CaptainAtGoal() // reached goal - exitwhen CaptainIsHome() // failed to path and returned home - exitwhen CaptainIsEmpty() // all units died - call SuicideSleep(3) - endloop -endfunction - -//============================================================================ -function SleepInCombat takes nothing returns nothing - local integer count = 0 - debug call Trace("SleepInCombat\n") - loop - loop - exitwhen not CaptainInCombat(true) // goal is cleared - exitwhen CaptainIsEmpty() // duh - call SuicideSleep(1) - endloop - - set count = count + 1 - exitwhen count >= 8 - - //xxx this is what it should have been; do this for next patch? - //call SuicideSleep(1) - endloop - debug call Trace("exit SleepInCombat\n") -endfunction - -//============================================================================ -function AttackMoveXYA takes integer x, integer y returns nothing - - if zep_next_wave then - call LoadZepWave(x,y) - set zep_next_wave = false - endif - - call AttackMoveXY(x,y) - call SleepUntilAtGoal() - call SleepInCombat() -endfunction - -//============================================================================ -function SuicideOnPlayerWave takes nothing returns nothing - call Trace("waiting for attack wave to enter combat\n") //xxx - loop - //xxx - if allow_signal_abort and CommandsWaiting() != 0 then - call Trace("ABORT -- attack wave override\n") - endif - - if CaptainInCombat(true) then - call Trace("done - captain has entered combat\n") - endif - - if CaptainIsEmpty() then - call Trace("done - all units are dead\n") - endif - - if sleep_seconds < -300 then - call Trace("done - timeout, took too long to reach engage the enemy\n") - endif - //xxx - - exitwhen allow_signal_abort and CommandsWaiting() != 0 - - exitwhen CaptainInCombat(true) - exitwhen CaptainIsEmpty() - call SuicideSleep(10) - exitwhen sleep_seconds < -300 - endloop - - call Trace("waiting for attack wave to die\n") //xxx - loop - //xxx - if allow_signal_abort and CommandsWaiting() != 0 then - call Trace("ABORT - attack wave override\n") - endif - - if CaptainIsEmpty() then - call Trace("done - all units are dead\n") - endif - - if sleep_seconds < -300 then - call Trace("done - timeout, took too long to reach engage the enemy\n") - endif - //xxx - - exitwhen allow_signal_abort and CommandsWaiting() != 0 - - exitwhen CaptainIsEmpty() - call SuicideSleep(10) - exitwhen sleep_seconds < -300 - endloop -endfunction - -//-------------------------------------------------------------------------------------------------- -function CommonSuicideOnPlayer takes boolean standard, boolean bldgs, integer seconds, player p, integer x, integer y returns nothing - local integer save_peons - - if not PrepSuicideOnPlayer(seconds) then - return - endif - - set save_peons = campaign_wood_peons - set campaign_wood_peons = 0 - - loop - //xxx - if allow_signal_abort and CommandsWaiting() != 0 then - call Trace("ABORT -- attack wave override\n") - endif - //xxx - - exitwhen allow_signal_abort and CommandsWaiting() != 0 - - loop - exitwhen allow_signal_abort and CommandsWaiting() != 0 - - call FormGroup(5,true) - exitwhen sleep_seconds <= 0 - call TraceI("waiting %d seconds before suicide\n",sleep_seconds) //xxx - endloop - - if standard then - if bldgs then - exitwhen SuicidePlayer(p,sleep_seconds >= -60) - else - exitwhen SuicidePlayerUnits(p,sleep_seconds >= -60) - endif - else - call AttackMoveXYA(x,y) - endif - - call TraceI("waiting %d seconds before timeout\n",60+sleep_seconds) //xxx - call SuicideSleep(5) - endloop - - set campaign_wood_peons = save_peons - set harass_length = 0 - - call SuicideOnPlayerWave() -endfunction - -//-------------------------------------------------------------------------------------------------- -function SuicideOnPlayer takes integer seconds, player p returns nothing - call CommonSuicideOnPlayer(true,true,seconds,p,0,0) -endfunction - -//-------------------------------------------------------------------------------------------------- -function SuicideOnUnits takes integer seconds, player p returns nothing - call CommonSuicideOnPlayer(true,false,seconds,p,0,0) -endfunction - -//-------------------------------------------------------------------------------------------------- -function SuicideOnPoint takes integer seconds, player p, integer x, integer y returns nothing - call CommonSuicideOnPlayer(false,false,seconds,p,x,y) -endfunction - -//============================================================================ -function SuicideUntilSignal takes integer seconds, player p returns nothing - local integer save - local integer wave_prep = PrepTime() - - loop - call AddSleepSeconds(seconds) - if sleep_seconds-wave_prep > 0 then - call SuicideSleep(sleep_seconds-wave_prep) - endif - - set save = campaign_wood_peons - set campaign_wood_peons = 0 - loop - loop - call FormGroup(5, true) - exitwhen sleep_seconds <= 0 - exitwhen CommandsWaiting() != 0 - endloop - exitwhen SuicidePlayer(p,sleep_seconds >= -60) - exitwhen CommandsWaiting() != 0 - call SuicideSleep(3) - endloop - set campaign_wood_peons = save - - loop - exitwhen CaptainIsEmpty() - exitwhen CommandsWaiting() != 0 - call SuicideSleep(5) - endloop - exitwhen CommandsWaiting() != 0 - endloop -endfunction - -//-------------------------------------------------------------------------------------------------- -function SuicideOnce takes integer easy, integer med, integer hard, integer unitid returns nothing - if difficulty == EASY then - call SuicideUnit(easy,unitid) - elseif difficulty == NORMAL then - call SuicideUnit(med,unitid) - else - call SuicideUnit(hard,unitid) - endif -endfunction - -//-------------------------------------------------------------------------------------------------- -function SuicideUnitA takes integer unitid returns nothing - if unitid != 0 then - call SuicideUnit(1,unitid) - endif - call Sleep(0.1) -endfunction - -//-------------------------------------------------------------------------------------------------- -function SuicideUnitB takes integer unitid, integer playerid returns nothing - if unitid != 0 then - call SuicideUnitEx(1,unitid,playerid) - endif - call Sleep(0.1) -endfunction - -//-------------------------------------------------------------------------------------------------- -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 - call Trace("MASS SUICIDE - this script is now technically done\n") //xxx - - call PrepFullSuicide() - loop - call SuicideUnitA(u1) - call SuicideUnitA(u2) - call SuicideUnitA(u3) - call SuicideUnitA(u4) - call SuicideUnitA(u5) - call SuicideUnitA(u6) - call SuicideUnitA(u7) - call SuicideUnitA(u8) - call SuicideUnitA(u9) - call SuicideUnitA(uA) - endloop -endfunction - -//-------------------------------------------------------------------------------------------------- -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 - call Trace("MASS SUICIDE - this script is now technically done\n") //xxx - - call PrepFullSuicide() - loop - call SuicideUnitB(u1,playerid) - call SuicideUnitB(u2,playerid) - call SuicideUnitB(u3,playerid) - call SuicideUnitB(u4,playerid) - call SuicideUnitB(u5,playerid) - call SuicideUnitB(u6,playerid) - call SuicideUnitB(u7,playerid) - call SuicideUnitB(u8,playerid) - call SuicideUnitB(u9,playerid) - call SuicideUnitB(uA,playerid) - endloop -endfunction - -//-------------------------------------------------------------------------------------------------- -function SuicideOnPlayerEx takes integer easy, integer med, integer hard, player p returns nothing - if difficulty == EASY then - call SuicideOnPlayer(easy,p) - elseif difficulty == NORMAL then - call SuicideOnPlayer(med,p) - else - call SuicideOnPlayer(hard,p) - endif -endfunction - -//-------------------------------------------------------------------------------------------------- -function SuicideOnUnitsEx takes integer easy, integer med, integer hard, player p returns nothing - if difficulty == EASY then - call SuicideOnUnits(easy,p) - elseif difficulty == NORMAL then - call SuicideOnUnits(med,p) - else - call SuicideOnUnits(hard,p) - endif -endfunction - -//-------------------------------------------------------------------------------------------------- -function SuicideOnPointEx takes integer easy, integer med, integer hard, player p, integer x, integer y returns nothing - if difficulty == EASY then - call SuicideOnPoint(easy,p,x,y) - elseif difficulty == NORMAL then - call SuicideOnPoint(med,p,x,y) - else - call SuicideOnPoint(hard,p,x,y) - endif -endfunction - -//============================================================================ -function ForeverSuicideOnPlayer takes integer seconds, player p returns nothing - local integer length = harass_length - loop - exitwhen allow_signal_abort and CommandsWaiting() != 0 - call SuicideOnPlayer(seconds,p) - set harass_length = length - endloop -endfunction - -//============================================================================ -function CommonSleepUntilTargetDead takes unit target, boolean reform returns nothing - loop - exitwhen CaptainRetreating() - exitwhen CaptainReadinessHP() <= 40 - - exitwhen not UnitAlive(target) - exitwhen UnitInvis(target) and not IsUnitDetected(target,ai_player) - - if not TownThreatened() then - call AttackMoveKill(target) - endif - - call SuicideSleep(3) - - if reform and sleep_seconds < -40 then - if CaptainInCombat(true) then - set sleep_seconds = sleep_seconds + 5 - else - set sleep_seconds = 0 - call FormGroup(1,false) - endif - endif - endloop -endfunction - -//============================================================================ -function SleepUntilTargetDead takes unit target returns nothing - call CommonSleepUntilTargetDead(target,false) -endfunction - -//============================================================================ -function ReformUntilTargetDead takes unit target returns nothing - debug call Trace("ReformUntilTargetDead\n") - call CommonSleepUntilTargetDead(target,true) -endfunction - -//============================================================================ -function AttackMoveKillA takes unit target returns nothing - if target == null then - call SuicideSleep(3) - return - endif - - debug call Trace("AttackMoveKillA\n") - call AttackMoveKill(target) - call ReformUntilTargetDead(target) - call SleepInCombat() -endfunction - -//============================================================================ -function MinorCreepAttack takes nothing returns nothing - local unit target = GetMinorCreep() - call SetAllianceTarget(target) - call FormGroup(3, true) - call AttackMoveKillA(target) - set target = null -endfunction - -//============================================================================ -function MajorCreepAttack takes nothing returns nothing - local unit target = GetMajorCreep() - call SetAllianceTarget(target) - call FormGroup(3,true) - call AttackMoveKillA(target) - set target = null -endfunction - -//============================================================================ -function CreepAttackEx takes nothing returns nothing - local unit target = GetCreepCamp(min_creeps,max_creeps,allow_air_creeps) - call SetAllianceTarget(target) - call FormGroup(3,true) - call AttackMoveKillA(target) - set target = null -endfunction - -//============================================================================ -function AnyPlayerAttack takes nothing returns nothing - local unit hall = GetEnemyExpansion() - - if hall == null then - call StartGetEnemyBase() - loop - exitwhen not WaitGetEnemyBase() - call SuicideSleep(1) - endloop - set hall = GetEnemyBase() - endif - - call SetAllianceTarget(hall) - call FormGroup(3,true) - call AttackMoveKillA(hall) - set hall = null -endfunction - -//============================================================================ -function ExpansionAttack takes nothing returns nothing - local unit creep = GetExpansionFoe() - local integer x - - call FormGroup(3, true) - if creep == null then - set x = GetExpansionX() - if x != -1 then - call AttackMoveXYA(x,GetExpansionY()) - endif - else - call AttackMoveKillA(creep) - endif - set creep = null -endfunction - -//============================================================================ -// AddSiege -//============================================================================ -function AddSiege takes nothing returns nothing - - #INCLUDETABLE <$VER$\StandardUnits.txt> #EFR #COND "%4" =~ /\bsiege\b/ - call SetAssaultGroup( 0, 9, %1 ) - #ENDINCLUDE - -endfunction - -//=========================================================================== -// GetAllyCount -//============================================================================ -function GetAllyCount takes player whichPlayer returns integer - local integer playerIndex = 0 - local integer count = 0 - local player indexPlayer - - loop - set indexPlayer = Player(playerIndex) - if whichPlayer != indexPlayer then - if GetPlayerAlliance(whichPlayer,indexPlayer,ALLIANCE_PASSIVE) then - if GetPlayerAlliance(indexPlayer,whichPlayer,ALLIANCE_PASSIVE) then - if GetPlayerStructureCount(indexPlayer,true) > 0 then - set count = count + 1 - endif - endif - endif - endif - set playerIndex = playerIndex + 1 - exitwhen playerIndex == GetBJMaxPlayers() - endloop - set indexPlayer = null - return count -endfunction - -//============================================================================ -// SingleMeleeAttack -//============================================================================ -function SingleMeleeAttack takes boolean needs_exp, boolean has_siege, boolean major_ok, boolean air_units returns nothing - local boolean can_siege - local real daytime - local unit hall - local unit mega - local unit creep - local unit common - local integer minexp - local boolean allies - - call Trace("===SingleMeleeAttack===\n") //xxx - - if TownThreatened() then - call Trace("sleep 2, town threatened\n") //xxx - call Sleep(2) - return - endif - - // purchase zeppelins - // - if get_zeppelin and GetGold() > 300 and GetWood() > 100 then - call Trace("purchase zep\n") //xxx - call PurchaseZeppelin() - set get_zeppelin = false - set ready_for_zeppelin = false - return - endif - set ready_for_zeppelin = true - - // coordinate with allies - // - set allies = GetAllyCount(ai_player) > 0 - if allies and MeleeDifficulty() != MELEE_NEWBIE then - set common = GetAllianceTarget() - if common != null then - call Trace("join ally force\n") //xxx - if GetMegaTarget() != null then - call AddSiege() - endif - call FormGroup(3,true) - call AttackMoveKillA(common) - call SetAllianceTarget(null) - set common = null - return - endif - endif - - // take expansions as needed - // - if needs_exp then - call Trace("needs exp\n") //xxx - set creep = GetExpansionFoe() - if creep != null then - call Trace("attack exp\n") //xxx - call SetAllianceTarget(creep) - call FormGroup(3,true) - call AttackMoveKillA(creep) - call Sleep(20) - set take_exp = false - set creep = null - return - endif - endif - - // all-out attack if the player is weak - // - if MeleeDifficulty() != MELEE_NEWBIE then - set mega = GetMegaTarget() - if mega != null then - call Trace("MEGA TARGET!!!\n") //xxx - call AddSiege() - call FormGroup(3,true) - call AttackMoveKillA(mega) - set mega = null - return - endif - endif - - // deny player an expansion - // - set hall = GetEnemyExpansion() - set daytime = GetFloatGameState(GAME_STATE_TIME_OF_DAY) - set can_siege = has_siege and (air_units or (daytime>=4 and daytime<=12)) - - if hall!=null and (can_siege or not IsTowered(hall)) then - - call Trace("test player town attack\n") //xxx - - if MeleeDifficulty() == MELEE_NEWBIE then - set minexp = 3 - elseif allies and MeleeDifficulty() == MELEE_NORMAL then - set minexp = 1 - else - set minexp = 0 // HARD, INSANE, and NORMAL with no allies - endif - - if exp_seen >= minexp then - call Trace("do player town attack\n") //xxx - set exp_seen = 0 - call AddSiege() - call SetAllianceTarget(hall) - call FormGroup(3,true) - call AttackMoveKillA(hall) - set hall = null - return - endif - set hall = null - set exp_seen = exp_seen + 1 - endif - - // attack player's main base when siege is available - // - if can_siege then - call Trace("attack player's town\n") //xxx - call AddSiege() - call AnyPlayerAttack() - return - endif - - // extended, more specific method of determining creep levels - // - if min_creeps != -1 then - call TraceI("custom creep attack %d\n",max_creeps) //xxx - call CreepAttackEx() - return - endif - - // nothing better to do, so kill a creep camp - // - if major_ok then - call Trace("major creep attack\n") //xxx - call MajorCreepAttack() - return - endif - - call Trace("minor creep attack\n") //xxx - call MinorCreepAttack() -endfunction - -//============================================================================ -function GetZeppelin takes nothing returns nothing - if ready_for_zeppelin then - set get_zeppelin = true - endif -endfunction - -//============================================================================ -function BuildAttackers takes nothing returns nothing - local integer index = 0 - local integer unitid - local integer desire - local integer count - - loop - exitwhen index == harass_length - - set unitid = harass_units[index] - set desire = harass_qty[index] + IgnoredUnits(unitid) - set count = TownCount(unitid) - - if count != desire then - if not StartUnit(desire,unitid,-1) then - return - endif - endif - - set index = index + 1 - endloop -endfunction - -//============================================================================ -function BuildDefenders takes nothing returns nothing - local integer index = 0 - local integer unitid - local integer qty - loop - exitwhen index == defense_length - - set unitid = defense_units[index] - set qty = defense_qty[index] - - call Conversions(qty,unitid) - call AddDefenders(qty,unitid) - - set index = index + 1 - endloop -endfunction - -//============================================================================ -function CampaignBasicsA takes nothing returns nothing - local integer food_each = GetFoodMade(racial_farm) - local integer on_wood - - call ClearHarvestAI() - - if CaptainInCombat(false) then - set on_wood = 0 - else - set on_wood = campaign_wood_peons - endif - - call HarvestGold(0,campaign_gold_peons) - call HarvestWood(0,on_wood) - - if harvest_town1 then - call HarvestGold(1,campaign_gold_peons) - call HarvestWood(1,on_wood) - endif - - if harvest_town2 then - call HarvestGold(2,campaign_gold_peons) - call HarvestWood(2,on_wood) - endif - - if harvest_town3 then - call HarvestGold(3,campaign_gold_peons) - call HarvestWood(3,on_wood) - endif - - if do_campaign_farms and FoodUsed()+food_each-1 > food_each*(TownCount(racial_farm)+1) then - call StartUnit(TownCount(racial_farm)+1,racial_farm,-1) - endif - - if build_campaign_attackers then - call BuildAttackers() - endif - - if not CaptainInCombat(false) then - call BuildDefenders() - endif - - call FillGuardPosts() - call ReturnGuardPosts() -endfunction - -//============================================================================ -function CampaignBasics takes nothing returns nothing - call Sleep(1) - call CampaignBasicsA() - call StaggerSleep(1,5) - loop - call CampaignBasicsA() - call Sleep(campaign_basics_speed) - endloop -endfunction - -//============================================================================ -function CampaignAI takes integer farms, code heroes returns nothing - if GetGameDifficulty() == MAP_DIFFICULTY_EASY then - set difficulty = EASY - - call SetTargetHeroes(false) - call SetUnitsFlee(false) - - elseif GetGameDifficulty() == MAP_DIFFICULTY_NORMAL then - set difficulty = NORMAL - - call SetTargetHeroes(false) - call SetUnitsFlee(false) - - elseif GetGameDifficulty() == MAP_DIFFICULTY_HARD then - set difficulty = HARD - - call SetPeonsRepair(true) - else - set difficulty = INSANE - endif - - call InitAI() - call InitBuildArray() - call InitAssaultGroup() - call CreateCaptains() - - call SetNewHeroes(false) - if heroes != null then - call SetHeroLevels(heroes) - endif - - call SetHeroesFlee(false) - call SetGroupsFlee(false) - call SetSlowChopping(true) - call GroupTimedLife(false) - call SetCampaignAI() - call Sleep(0.1) - - set racial_farm = farms - call StartThread(function CampaignBasics) - call StartBuildLoop() -endfunction - -//============================================================================ -function UnsummonAll takes nothing returns nothing - local unit bldg - loop - set bldg = GetBuilding(ai_player) - exitwhen bldg==null - call Unsummon(bldg) - call Sleep(2) - endloop -endfunction - -//============================================================================ -// SkillArrays -//============================================================================ -function SkillArrays takes nothing returns integer - local integer level = GetHeroLevelAI() - if level > max_hero_level then - set max_hero_level = level - endif - - if GetHeroId() == hero_id then - return skills1[level] - elseif GetHeroId() == hero_id2 then - return skills2[level] - else - return skills3[level] - endif -endfunction - -//-------------------------------------------------------------------------------------------------- -// SetSkillArray -//-------------------------------------------------------------------------------------------------- -function SetSkillArray takes integer index, integer id returns nothing - local integer i = 1 - - if index == 1 then - if hero_id != id then - return - endif - loop - set skills1[i] = skill[i] - exitwhen i == 10 - set i = i + 1 - endloop - elseif index == 2 then - if hero_id2 != id then - return - endif - loop - set skills2[i] = skill[i] - exitwhen i == 10 - set i = i + 1 - endloop - else - if hero_id3 != id then - return - endif - loop - set skills3[i] = skill[i] - exitwhen i == 10 - set i = i + 1 - endloop - endif -endfunction - -//============================================================================ -// AwaitMeleeHeroes -//============================================================================ -function AwaitMeleeHeroes takes nothing returns nothing - if GetUnitCountDone(hero_id2) > 0 then - set two_heroes = true - endif - loop - exitwhen GetUnitCountDone(hero_id)>0 and (take_exp or (not two_heroes or GetUnitCountDone(hero_id2)>0)) - call Sleep(1) - endloop -endfunction - -//============================================================================ -// PickMeleeHero -//============================================================================ -function PickMeleeHero takes race raceid returns integer - local integer first - local integer second - local integer third - local integer last - local integer array heroes - local integer i -#INCLUDETABLE <$VER$\GlobalSettings.txt> #EFR #COND '%1' eq 'ver_neutral_hero_number' - set %1 = %2 -#ENDINCLUDE - call InitAiUnits() // This function makes all unit ids go back to there originals - set i = ver_neutral_hero_number - //------------------------------------------------------------------------ - if raceid == RACE_HUMAN then - //------------------------------------------------------------------------ - - #INCLUDETABLE <$VER$\Races.txt> #COND '%1' eq 'HUMAN' - #INCLUDETABLE <$VER$\%1\Heroes.txt> #EFR - set heroes[#EVAL{%row}] = %1 - #ENDINCLUDE - #ENDINCLUDE - - //------------------------------------------------------------------------ - elseif raceid == RACE_ORC then - //------------------------------------------------------------------------ - #INCLUDETABLE <$VER$\Races.txt> #COND '%1' eq 'ORC' - #INCLUDETABLE <$VER$\%1\Heroes.txt> #EFR - set heroes[#EVAL{%row}] = %1 - #ENDINCLUDE - #ENDINCLUDE - - //------------------------------------------------------------------------ - elseif raceid == RACE_NIGHTELF then - //------------------------------------------------------------------------ - #INCLUDETABLE <$VER$\Races.txt> #COND '%1' eq 'ELF' - #INCLUDETABLE <$VER$\%1\Heroes.txt> #EFR - set heroes[#EVAL{%row}] = %1 - #ENDINCLUDE - #ENDINCLUDE - - //------------------------------------------------------------------------ - elseif raceid == RACE_UNDEAD then - //------------------------------------------------------------------------ - #INCLUDETABLE <$VER$\Races.txt> #COND '%1' eq 'UNDEAD' - #INCLUDETABLE <$VER$\%1\Heroes.txt> #EFR - set heroes[#EVAL{%row}] = %1 - #ENDINCLUDE - #ENDINCLUDE - - else - set hero_id = 0 - endif - - //if VersionCompatible(VERSION_FROZEN_THRONE) then - set last = race_hero_number + i - //else - // set last = race_hero_number - //endif - - set first = GetRandomInt(i+1,last) - set second = GetRandomInt(i+1,last-1) - if VersionCompatible(VERSION_FROZEN_THRONE) then - set third = GetRandomInt(i+1,last-2) - else - set third = i+1 - endif - set hero_id = heroes[first] - set heroes[first] = heroes[last] - set hero_id2 = heroes[second] - set heroes[second] = heroes[last-1] - set hero_id3 = heroes[third] - - return hero_id -endfunction +//AMAI VS AI Support +#INCLUDESCRIPT //function main takes nothing returns nothing diff --git a/common_original.eai b/common_original.eai new file mode 100644 index 000000000..cd8e108d5 --- /dev/null +++ b/common_original.eai @@ -0,0 +1,1690 @@ + +//============================================================================ +// Standard common.ai V1.18 by Blizzard Entertainment (Implementation by Strategy Master) +//============================================================================ + +//============================================================================ +function InitAI takes nothing returns nothing + set ai_player = Player(GetAiPlayer()) + set sleep_seconds = 0 + call InitAiUnits() + call InitArrays() + call StopGathering() +endfunction + +//============================================================================ +function StandardAI takes code heroes, code peons, code attacks returns nothing + + local boolean isNewbie = (MeleeDifficulty() == MELEE_NEWBIE) + + call InitAI() + + call SetMeleeAI() + + call SetDefendPlayer(true) + call SetGroupsFlee(not isNewbie) + call SetHeroesBuyItems(not isNewbie) + call SetHeroesFlee(true) + call SetHeroesTakeItems(true) + call SetIgnoreInjured(true) + call SetPeonsRepair(true) + call SetSmartArtillery(not isNewbie) + call SetTargetHeroes(not isNewbie) + call SetUnitsFlee(not isNewbie) + call SetWatchMegaTargets(true) + + call CreateCaptains() + + call SetHeroLevels(heroes) + + call Sleep(0.1) + call StartThread(peons) + call StartThread(attacks) +endfunction + +//============================================================================ +// Utility Functions +//============================================================================ + +function SetZepNextWave takes nothing returns nothing + set zep_next_wave = true +endfunction + +function SuicideSleep takes integer seconds returns nothing + set sleep_seconds = sleep_seconds - seconds + loop + exitwhen seconds <= 0 + exitwhen allow_signal_abort and CommandsWaiting() != 0 + + if seconds >= 5 then + call Sleep(5) + set seconds = seconds - 5 + else + call Sleep(seconds) + set seconds = 0 + endif + endloop +endfunction + +//============================================================================ +function WaitForSignal takes nothing returns integer + local integer cmd + local boolean display = false //xxx + loop + exitwhen CommandsWaiting() != 0 + + //xxx + call Trace("waiting for a signal to begin AI script...\n") + set display = true + call Sleep(2) + exitwhen CommandsWaiting() != 0 + call Sleep(2) + exitwhen CommandsWaiting() != 0 + call Sleep(2) + exitwhen CommandsWaiting() != 0 + call Sleep(2) + exitwhen CommandsWaiting() != 0 + call Sleep(2) + //xxx + + endloop + + //xxx + if display then + call Trace("signal received, beginning AI script\n") + endif + //xxx + + set cmd = GetLastCommand() + call PopLastCommand() + return cmd +endfunction + +//============================================================================ +function SetWoodPeons takes integer count returns nothing + set campaign_wood_peons = count +endfunction + +//============================================================================ +function SetGoldPeons takes integer count returns nothing + set campaign_gold_peons = count +endfunction + +//============================================================================ +function SetHarvestLumber takes boolean harvest returns nothing + if harvest then + set campaign_wood_peons = 3 + else + set campaign_wood_peons = 0 + endif +endfunction + +//============================================================================ +function SetFormGroupTimeouts takes boolean state returns nothing + set form_group_timeouts = state +endfunction + +//============================================================================ +function DoCampaignFarms takes boolean state returns nothing + set do_campaign_farms = state +endfunction + +//============================================================================ +function GetMinorCreep takes nothing returns unit + return GetCreepCamp(0,9,false) +endfunction + +//============================================================================ +function GetMajorCreep takes nothing returns unit + return GetCreepCamp(10,100,allow_air_creeps) +endfunction + +//============================================================================ +function InitBuildArray takes nothing returns nothing + set build_length = 0 +endfunction + +//============================================================================ +function InitMeleeGroup takes nothing returns nothing + call InitAssaultGroup() + call RemoveInjuries() + call RemoveSiege() +endfunction + +//============================================================================ +function PrepFullSuicide takes nothing returns nothing + call InitAssaultGroup() + call InitDefenseGroup() + set campaign_gold_peons = 0 + set campaign_wood_peons = 0 +endfunction + +//============================================================================ +function SetReplacements takes integer easy, integer med, integer hard returns nothing + if difficulty == EASY then + call SetReplacementCount(easy) + elseif difficulty == NORMAL then + call SetReplacementCount(med) + else + call SetReplacementCount(hard) + endif +endfunction + +//============================================================================ +function StartTownBuilder takes code func returns nothing + call StartThread(func) +endfunction + +//============================================================================ +function SetBuildAll takes integer t, integer qty, integer unitid, integer town returns nothing + if qty > 0 then + set build_qty[build_length] = qty + set build_type[build_length] = t + set build_item[build_length] = unitid + set build_town[build_length] = town + set build_length = build_length + 1 + endif +endfunction + +//============================================================================ +function SetBuildUnit takes integer qty, integer unitid returns nothing + call SetBuildAll(BUILD_UNIT,qty,unitid,-1) +endfunction + +//============================================================================ +function SetBuildNext takes integer qty, integer unitid returns nothing + local integer has = GetUnitCount(unitid) + if has >= qty then + return + endif + call SetBuildAll(BUILD_UNIT,GetUnitCountDone(unitid)+1,unitid,-1) +endfunction + +//============================================================================ +function SetBuildUnitEx takes integer easy, integer med, integer hard, integer unitid returns nothing + if difficulty == EASY then + call SetBuildAll(BUILD_UNIT,easy,unitid,-1) + elseif difficulty == NORMAL then + call SetBuildAll(BUILD_UNIT,med,unitid,-1) + else + call SetBuildAll(BUILD_UNIT,hard,unitid,-1) + endif +endfunction + +//============================================================================ +function SecondaryTown takes integer town, integer qty, integer unitid returns nothing + call SetBuildAll(BUILD_UNIT,qty,unitid,town) +endfunction + +//============================================================================ +function SecTown takes integer town, integer qty, integer unitid returns nothing + call SetBuildAll(BUILD_UNIT,qty,unitid,town) +endfunction + +//============================================================================ +function SetBuildUpgr takes integer qty, integer unitid returns nothing + if MeleeDifficulty() != MELEE_NEWBIE or qty == 1 then + call SetBuildAll(BUILD_UPGRADE,qty,unitid,-1) + endif +endfunction + +//============================================================================ +function SetBuildUpgrEx takes integer easy, integer med, integer hard, integer unitid returns nothing + if difficulty == EASY then + call SetBuildAll(BUILD_UPGRADE,easy,unitid,-1) + elseif difficulty == NORMAL then + call SetBuildAll(BUILD_UPGRADE,med,unitid,-1) + else + call SetBuildAll(BUILD_UPGRADE,hard,unitid,-1) + endif +endfunction + +//============================================================================ +function SetBuildExpa takes integer qty, integer unitid returns nothing + call SetBuildAll(BUILD_EXPAND,qty,unitid,-1) +endfunction + +//============================================================================ +function StartUpgrade takes integer level, integer upgid returns boolean + local integer gold_cost + local integer wood_cost + + if GetUpgradeLevel(upgid) >= level then + return true + endif + + set gold_cost = GetUpgradeGoldCost(upgid) + if total_gold < gold_cost then + return false + endif + + set wood_cost = GetUpgradeWoodCost(upgid) + if total_wood < wood_cost then + return false + endif + + return SetUpgrade(upgid) +endfunction + +//============================================================================ +function BuildFactory takes integer unitid returns nothing + if GetGold() > 1000 and GetWood() > 500 then + call SetBuildUnit( 2, unitid ) + else + call SetBuildUnit( 1, unitid ) + endif +endfunction + +//============================================================================ +function GuardSecondary takes integer townid, integer qty, integer unitid returns nothing + if TownHasHall(townid) and TownHasMine(townid) then + call SecondaryTown( townid, qty, unitid ) + endif +endfunction + +//============================================================================ +function BasicExpansion takes boolean build_it, integer unitid returns nothing + if build_it and HallsCompleted(unitid) then + call SetBuildExpa( TownCount(unitid)+1, unitid ) + endif +endfunction + +//============================================================================ +function UpgradeAll takes integer baseid, integer newid returns nothing + call SetBuildUnit( TownCountDone(baseid), newid ) +endfunction + +//============================================================================ +// FoodPool +//============================================================================ +function FoodPool takes integer food, boolean weak, integer id1, integer use1, boolean strong, integer id2, integer use2 returns nothing + if strong then + call SetBuildUnit( (food - use1 * TownCount(id1)) / use2, id2 ) + elseif weak then + call SetBuildUnit( (food - use2 * TownCount(id2)) / use1, id1 ) + endif +endfunction + +//============================================================================ +// MeleeTownHall +//============================================================================ +function MeleeTownHall takes integer townid, integer unitid returns nothing + if TownHasMine(townid) and not TownHasHall(townid) then + call SecondaryTown ( townid, 1, unitid ) + endif +endfunction + +//============================================================================ +function WaitForUnits takes integer unitid, integer qty returns nothing + loop + exitwhen TownCountDone(unitid) == qty + call Sleep(2) + endloop +endfunction + +//============================================================================ +function StartUnit takes integer ask_qty, integer unitid, integer town returns boolean + local integer have_qty + local integer need_qty + local integer afford_gold + local integer afford_wood + local integer afford_qty + local integer gold_cost + local integer wood_cost + + //------------------------------------------------------------------------ + // if we have all we're asking for then make nothing + // + if town == -1 then + set have_qty = TownCount(unitid) + else + set have_qty = TownCountTown(unitid,town) + endif + + if have_qty >= ask_qty then + return true + endif + set need_qty = ask_qty - have_qty + + //------------------------------------------------------------------------ + // limit the qty we're requesting to the amount of resources available + // + set gold_cost = GetUnitGoldCost(unitid) + set wood_cost = GetUnitWoodCost(unitid) + + if gold_cost == 0 then + set afford_gold = need_qty + else + set afford_gold = total_gold / gold_cost + endif + if afford_gold < need_qty then + set afford_qty = afford_gold + else + set afford_qty = need_qty + endif + + if wood_cost == 0 then + set afford_wood = need_qty + else + set afford_wood = total_wood / wood_cost + endif + if afford_wood < afford_qty then + set afford_qty = afford_wood + endif + + // if we're waiting on gold/wood; pause build orders + if afford_qty < 1 then + return false + endif + + //------------------------------------------------------------------------ + // whether we make right now what we're requesting or not, assume we will + // and deduct the cost of the units from our fake gold total right away + // + set total_gold = total_gold - gold_cost * need_qty + set total_wood = total_wood - wood_cost * need_qty + + if total_gold < 0 then + set total_gold = 0 + endif + if total_wood < 0 then + set total_wood = 0 + endif + + //------------------------------------------------------------------------ + // give the AI a chance to make the units (it may not be able to right now + // but that doesn't stop us from trying other units after this as long + // as we have enough money to make this AND the needed, unbuilt ones) + // + return SetProduce(afford_qty,unitid,town) +endfunction + +//============================================================================ +function WaitForTown takes integer towns, integer townid returns nothing + local integer i = 0 + loop + call Sleep(10) + exitwhen TownCount(townid) >= towns + set i = i + 1 + exitwhen i == GetBJMaxPlayers() + endloop +endfunction + +//============================================================================ +function StartExpansion takes integer qty, integer hall returns boolean + local integer count + local integer town + local unit peon = null + local integer gold_cost + local boolean b = true + + set count = TownCount(hall) + if count >= qty then + return true + endif + + set town = GetNextExpansion() + if town == -1 then + return true + endif + + set take_exp = true + + set gold_cost = GetUnitGoldCost(hall) + if gold_cost > total_gold then + return false + endif + set total_gold = total_gold - gold_cost + + if GetExpansionFoe() != null then + return true + endif + + set peon = GetExpansionPeon() + if peon != null then + set b = SetExpansion(peon,hall) + set peon = null + return b + endif + return true +endfunction + +//============================================================================ +function OneBuildLoop takes nothing returns nothing + local integer index = 0 + local integer qty + local integer id + local integer tp + + set total_gold = GetGold() - gold_buffer + set total_wood = GetWood() + + loop + exitwhen index == build_length + + set qty = build_qty [index] + set id = build_item[index] + set tp = build_type[index] + + //-------------------------------------------------------------------- + if tp == BUILD_UNIT then + if not StartUnit(qty,id,build_town[index]) then + return + endif + + //-------------------------------------------------------------------- + elseif tp == BUILD_UPGRADE then + call StartUpgrade(qty,id) + + //-------------------------------------------------------------------- + else // tp == BUILD_EXPAND + if not StartExpansion(qty,id) then + return + endif + endif + + set index = index + 1 + endloop +endfunction + +//============================================================================ +function BuildLoop takes nothing returns nothing + call OneBuildLoop() + call StaggerSleep(1,2) + loop + call OneBuildLoop() + call Sleep(2) + endloop +endfunction + +//============================================================================ +function StartBuildLoop takes nothing returns nothing + call StartThread(function BuildLoop) +endfunction + +//============================================================================ +function SetInitialWave takes integer seconds returns nothing + set sleep_seconds = seconds +endfunction + +//============================================================================ +function AddSleepSeconds takes integer seconds returns nothing + set sleep_seconds = sleep_seconds + seconds +endfunction + +//============================================================================ +function SleepForever takes nothing returns nothing + call Trace("going to sleep forever\n") //xxx + loop + call Sleep(100) + endloop +endfunction + +//============================================================================ +function PlayGame takes nothing returns nothing + call StartBuildLoop() + call SleepForever() +endfunction + +//============================================================================ +function ConvertNeeds takes integer unitid returns nothing + if GetUnitCount(unitid) < 1 then + call StartUnit(1,unitid,-1) + endif +endfunction + +//============================================================================ +function Conversions takes integer desire, integer unitid returns nothing + + if GetUnitCount(unitid) >= desire then + return + endif + + #INCLUDETABLE <$VER$\UnitConversions.txt> #EFR + if unitid == %1 then + call ConvertNeeds(%2) + call ConvertNeeds(%3) + call MergeUnits(desire,%2,%3,%1) + endif + #ENDINCLUDE + + #INCLUDETABLE <$VER$\UnitEquivalence.txt> #EFR #COND "%2" eq "BUILT_FROM" + if unitid == %1 then + call ConvertNeeds(%3) + call ConvertUnits(desire, %3) + endif + #ENDINCLUDE + +endfunction + +//============================================================================ +function SetAssaultGroup takes integer qty, integer max, integer unitid returns nothing + call Conversions(max,unitid) + + if qty <= 0 and TownCountDone(unitid) == 0 then + return + endif + set harass_qty[harass_length] = qty + set harass_max[harass_length] = max + set harass_units[harass_length] = unitid + set harass_length = harass_length + 1 +endfunction + +//============================================================================ +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 + local integer i1 = 1 + local integer i2 = 1 + local integer i3 = 1 + local integer q1 + local integer q2 + local integer q3 + + if difficulty == EASY then + set q1 = e1 + set q2 = e2 + set q3 = e3 + elseif difficulty == NORMAL then + set q1 = m1 + set q2 = m2 + set q3 = m3 + else // difficulty == HARD + set q1 = h1 + set q2 = h2 + set q3 = h3 + endif + + loop + exitwhen q1<=0 and q2<=0 and q3<=0 + + if q1 > 0 then + call SetAssaultGroup(i1,i1,u1) + set q1 = q1 - 1 + set i1 = i1 + 1 + endif + + if q2 > 0 then + call SetAssaultGroup(i2,i2,u2) + set q2 = q2 - 1 + set i2 = i2 + 1 + endif + + if q3 > 0 then + call SetAssaultGroup(i3,i3,u3) + set q3 = q3 - 1 + set i3 = i3 + 1 + endif + endloop +endfunction + +//============================================================================ +function SetMeleeGroup takes integer unitid returns nothing + if unitid == hero_id then + call SetAssaultGroup(1,9,unitid) + else + call SetAssaultGroup((TownCountDone(unitid)*3)/4,20,unitid) + endif +endfunction + +//============================================================================ +function CampaignDefender takes integer level, integer qty, integer unitid returns nothing + if qty > 0 and difficulty >= level then + set defense_qty[defense_length] = qty + set defense_units[defense_length] = unitid + set defense_length = defense_length + 1 + call Conversions(qty,unitid) + call SetBuildUnit(qty,unitid) + endif +endfunction + +//============================================================================ +function CampaignDefenderEx takes integer easy, integer med, integer hard, integer unitid returns nothing + if difficulty == EASY then + call CampaignDefender(EASY,easy,unitid) + elseif difficulty == NORMAL then + call CampaignDefender(NORMAL,med,unitid) + else + call CampaignDefender(HARD,hard,unitid) + endif +endfunction + +//============================================================================ +function CampaignAttacker takes integer level, integer qty, integer unitid returns nothing + if qty > 0 and difficulty >= level then + call SetAssaultGroup(qty,qty,unitid) + endif +endfunction + +//============================================================================ +function CampaignAttackerEx takes integer easy, integer med, integer hard, integer unitid returns nothing + if difficulty == EASY then + call CampaignAttacker(EASY,easy,unitid) + elseif difficulty == NORMAL then + call CampaignAttacker(NORMAL,med,unitid) + else + call CampaignAttacker(HARD,hard,unitid) + endif +endfunction + +//============================================================================ +function FormGroup takes integer seconds, boolean testReady returns nothing + local integer index + local integer count + local integer unitid + local integer desire + local integer readyPercent + + // normally test for CaptainReadiness() of 50% + if testReady == true then + set readyPercent = 50 + call Trace("forming group, requiring healthy guys\n") //xxx + else + set readyPercent = 0 + call Trace("forming group, unit health not important\n") //xxx + endif + + call Trace("trying to gather forces\n") //xxx + + loop + call SuicideSleep(seconds) + call InitAssault() + + set index = 0 + loop + exitwhen index == harass_length + + set unitid = harass_units[index] + set desire = harass_max[index] + set count = TownCountDone(unitid) + + call Conversions(desire,unitid) + + if count >= desire then + call AddAssault(desire,unitid) + else + set desire = harass_qty[index] + + if count < desire then + call AddAssault(desire,unitid) + else + call AddAssault(count,unitid) + endif + endif + + set index = index + 1 + endloop + + //xxx + if form_group_timeouts and (sleep_seconds < -60) then + call Trace("exit form group -- timeout\n") + elseif CaptainInCombat(true) then + call Trace("exit form group -- can't form while already in combat\n") + elseif CaptainIsFull() and CaptainReadiness() >= readyPercent then + call Trace("exit form group -- ready\n") + endif + //xxx + + // time out and send group anyway if time has already expired + exitwhen form_group_timeouts and (sleep_seconds < -60) + exitwhen CaptainInCombat(true) + exitwhen CaptainIsFull() and CaptainReadiness() >= readyPercent + endloop +endfunction + +//============================================================================ +function WavePrepare takes integer unitid returns integer + return GetUnitBuildTime(unitid) +endfunction + +//============================================================================ +function PrepTime takes nothing returns integer + local integer unitid + local integer missing + local integer prep + local integer count + local integer largest = 30 + local integer index = 0 + + loop + exitwhen index == harass_length + + set unitid = harass_units[index] + set missing = harass_qty[index] + IgnoredUnits(unitid) - TownCount(unitid) + set prep = WavePrepare(unitid) * missing + + if prep > largest then + set largest = prep + endif + + set index = index + 1 + endloop + call TraceI("next wave will require around %d seconds to build and gather\n",largest) //xxx + + return largest +endfunction + +//============================================================================ +function PrepSuicideOnPlayer takes integer seconds returns boolean + local integer wave_prep = PrepTime() + local integer save_length + + set save_length = harass_length + set harass_length = 0 + + call AddSleepSeconds(seconds) + if sleep_seconds-wave_prep > 0 then + call TraceI("going to sleep for %d seconds before gathering next attack wave\n",sleep_seconds-wave_prep) //xxx + call SuicideSleep(sleep_seconds-wave_prep) + endif + + call Trace("preparing suicide attack wave\n") //xxx + + set harass_length = save_length + if harass_length < 1 then + call Trace("ERROR - no units specificed, exiting early\n") //xxx + return false + endif + + return true +endfunction + +//============================================================================ +function SleepUntilAtGoal takes nothing returns nothing + loop + exitwhen CaptainRetreating() + exitwhen CaptainAtGoal() // reached goal + exitwhen CaptainIsHome() // failed to path and returned home + exitwhen CaptainIsEmpty() // all units died + call SuicideSleep(3) + endloop +endfunction + +//============================================================================ +function SleepInCombat takes nothing returns nothing + local integer count = 0 + debug call Trace("SleepInCombat\n") + loop + loop + exitwhen not CaptainInCombat(true) // goal is cleared + exitwhen CaptainIsEmpty() // duh + call SuicideSleep(1) + endloop + + set count = count + 1 + exitwhen count >= 8 + + //xxx this is what it should have been; do this for next patch? + //call SuicideSleep(1) + endloop + debug call Trace("exit SleepInCombat\n") +endfunction + +//============================================================================ +function AttackMoveXYA takes integer x, integer y returns nothing + + if zep_next_wave then + call LoadZepWave(x,y) + set zep_next_wave = false + endif + + call AttackMoveXY(x,y) + call SleepUntilAtGoal() + call SleepInCombat() +endfunction + +//============================================================================ +function SuicideOnPlayerWave takes nothing returns nothing + call Trace("waiting for attack wave to enter combat\n") //xxx + loop + //xxx + if allow_signal_abort and CommandsWaiting() != 0 then + call Trace("ABORT -- attack wave override\n") + endif + + if CaptainInCombat(true) then + call Trace("done - captain has entered combat\n") + endif + + if CaptainIsEmpty() then + call Trace("done - all units are dead\n") + endif + + if sleep_seconds < -300 then + call Trace("done - timeout, took too long to reach engage the enemy\n") + endif + //xxx + + exitwhen allow_signal_abort and CommandsWaiting() != 0 + + exitwhen CaptainInCombat(true) + exitwhen CaptainIsEmpty() + call SuicideSleep(10) + exitwhen sleep_seconds < -300 + endloop + + call Trace("waiting for attack wave to die\n") //xxx + loop + //xxx + if allow_signal_abort and CommandsWaiting() != 0 then + call Trace("ABORT - attack wave override\n") + endif + + if CaptainIsEmpty() then + call Trace("done - all units are dead\n") + endif + + if sleep_seconds < -300 then + call Trace("done - timeout, took too long to reach engage the enemy\n") + endif + //xxx + + exitwhen allow_signal_abort and CommandsWaiting() != 0 + + exitwhen CaptainIsEmpty() + call SuicideSleep(10) + exitwhen sleep_seconds < -300 + endloop +endfunction + +//-------------------------------------------------------------------------------------------------- +function CommonSuicideOnPlayer takes boolean standard, boolean bldgs, integer seconds, player p, integer x, integer y returns nothing + local integer save_peons + + if not PrepSuicideOnPlayer(seconds) then + return + endif + + set save_peons = campaign_wood_peons + set campaign_wood_peons = 0 + + loop + //xxx + if allow_signal_abort and CommandsWaiting() != 0 then + call Trace("ABORT -- attack wave override\n") + endif + //xxx + + exitwhen allow_signal_abort and CommandsWaiting() != 0 + + loop + exitwhen allow_signal_abort and CommandsWaiting() != 0 + + call FormGroup(5,true) + exitwhen sleep_seconds <= 0 + call TraceI("waiting %d seconds before suicide\n",sleep_seconds) //xxx + endloop + + if standard then + if bldgs then + exitwhen SuicidePlayer(p,sleep_seconds >= -60) + else + exitwhen SuicidePlayerUnits(p,sleep_seconds >= -60) + endif + else + call AttackMoveXYA(x,y) + endif + + call TraceI("waiting %d seconds before timeout\n",60+sleep_seconds) //xxx + call SuicideSleep(5) + endloop + + set campaign_wood_peons = save_peons + set harass_length = 0 + + call SuicideOnPlayerWave() +endfunction + +//-------------------------------------------------------------------------------------------------- +function SuicideOnPlayer takes integer seconds, player p returns nothing + call CommonSuicideOnPlayer(true,true,seconds,p,0,0) +endfunction + +//-------------------------------------------------------------------------------------------------- +function SuicideOnUnits takes integer seconds, player p returns nothing + call CommonSuicideOnPlayer(true,false,seconds,p,0,0) +endfunction + +//-------------------------------------------------------------------------------------------------- +function SuicideOnPoint takes integer seconds, player p, integer x, integer y returns nothing + call CommonSuicideOnPlayer(false,false,seconds,p,x,y) +endfunction + +//============================================================================ +function SuicideUntilSignal takes integer seconds, player p returns nothing + local integer save + local integer wave_prep = PrepTime() + + loop + call AddSleepSeconds(seconds) + if sleep_seconds-wave_prep > 0 then + call SuicideSleep(sleep_seconds-wave_prep) + endif + + set save = campaign_wood_peons + set campaign_wood_peons = 0 + loop + loop + call FormGroup(5, true) + exitwhen sleep_seconds <= 0 + exitwhen CommandsWaiting() != 0 + endloop + exitwhen SuicidePlayer(p,sleep_seconds >= -60) + exitwhen CommandsWaiting() != 0 + call SuicideSleep(3) + endloop + set campaign_wood_peons = save + + loop + exitwhen CaptainIsEmpty() + exitwhen CommandsWaiting() != 0 + call SuicideSleep(5) + endloop + exitwhen CommandsWaiting() != 0 + endloop +endfunction + +//-------------------------------------------------------------------------------------------------- +function SuicideOnce takes integer easy, integer med, integer hard, integer unitid returns nothing + if difficulty == EASY then + call SuicideUnit(easy,unitid) + elseif difficulty == NORMAL then + call SuicideUnit(med,unitid) + else + call SuicideUnit(hard,unitid) + endif +endfunction + +//-------------------------------------------------------------------------------------------------- +function SuicideUnitA takes integer unitid returns nothing + if unitid != 0 then + call SuicideUnit(1,unitid) + endif + call Sleep(0.1) +endfunction + +//-------------------------------------------------------------------------------------------------- +function SuicideUnitB takes integer unitid, integer playerid returns nothing + if unitid != 0 then + call SuicideUnitEx(1,unitid,playerid) + endif + call Sleep(0.1) +endfunction + +//-------------------------------------------------------------------------------------------------- +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 + call Trace("MASS SUICIDE - this script is now technically done\n") //xxx + + call PrepFullSuicide() + loop + call SuicideUnitA(u1) + call SuicideUnitA(u2) + call SuicideUnitA(u3) + call SuicideUnitA(u4) + call SuicideUnitA(u5) + call SuicideUnitA(u6) + call SuicideUnitA(u7) + call SuicideUnitA(u8) + call SuicideUnitA(u9) + call SuicideUnitA(uA) + endloop +endfunction + +//-------------------------------------------------------------------------------------------------- +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 + call Trace("MASS SUICIDE - this script is now technically done\n") //xxx + + call PrepFullSuicide() + loop + call SuicideUnitB(u1,playerid) + call SuicideUnitB(u2,playerid) + call SuicideUnitB(u3,playerid) + call SuicideUnitB(u4,playerid) + call SuicideUnitB(u5,playerid) + call SuicideUnitB(u6,playerid) + call SuicideUnitB(u7,playerid) + call SuicideUnitB(u8,playerid) + call SuicideUnitB(u9,playerid) + call SuicideUnitB(uA,playerid) + endloop +endfunction + +//-------------------------------------------------------------------------------------------------- +function SuicideOnPlayerEx takes integer easy, integer med, integer hard, player p returns nothing + if difficulty == EASY then + call SuicideOnPlayer(easy,p) + elseif difficulty == NORMAL then + call SuicideOnPlayer(med,p) + else + call SuicideOnPlayer(hard,p) + endif +endfunction + +//-------------------------------------------------------------------------------------------------- +function SuicideOnUnitsEx takes integer easy, integer med, integer hard, player p returns nothing + if difficulty == EASY then + call SuicideOnUnits(easy,p) + elseif difficulty == NORMAL then + call SuicideOnUnits(med,p) + else + call SuicideOnUnits(hard,p) + endif +endfunction + +//-------------------------------------------------------------------------------------------------- +function SuicideOnPointEx takes integer easy, integer med, integer hard, player p, integer x, integer y returns nothing + if difficulty == EASY then + call SuicideOnPoint(easy,p,x,y) + elseif difficulty == NORMAL then + call SuicideOnPoint(med,p,x,y) + else + call SuicideOnPoint(hard,p,x,y) + endif +endfunction + +//============================================================================ +function ForeverSuicideOnPlayer takes integer seconds, player p returns nothing + local integer length = harass_length + loop + exitwhen allow_signal_abort and CommandsWaiting() != 0 + call SuicideOnPlayer(seconds,p) + set harass_length = length + endloop +endfunction + +//============================================================================ +function CommonSleepUntilTargetDead takes unit target, boolean reform returns nothing + loop + exitwhen CaptainRetreating() + exitwhen CaptainReadinessHP() <= 40 + + exitwhen not UnitAlive(target) + exitwhen UnitInvis(target) and not IsUnitDetected(target,ai_player) + + if not TownThreatened() then + call AttackMoveKill(target) + endif + + call SuicideSleep(3) + + if reform and sleep_seconds < -40 then + if CaptainInCombat(true) then + set sleep_seconds = sleep_seconds + 5 + else + set sleep_seconds = 0 + call FormGroup(1,false) + endif + endif + endloop +endfunction + +//============================================================================ +function SleepUntilTargetDead takes unit target returns nothing + call CommonSleepUntilTargetDead(target,false) +endfunction + +//============================================================================ +function ReformUntilTargetDead takes unit target returns nothing + debug call Trace("ReformUntilTargetDead\n") + call CommonSleepUntilTargetDead(target,true) +endfunction + +//============================================================================ +function AttackMoveKillA takes unit target returns nothing + if target == null then + call SuicideSleep(3) + return + endif + + debug call Trace("AttackMoveKillA\n") + call AttackMoveKill(target) + call ReformUntilTargetDead(target) + call SleepInCombat() +endfunction + +//============================================================================ +function MinorCreepAttack takes nothing returns nothing + local unit target = GetMinorCreep() + call SetAllianceTarget(target) + call FormGroup(3, true) + call AttackMoveKillA(target) + set target = null +endfunction + +//============================================================================ +function MajorCreepAttack takes nothing returns nothing + local unit target = GetMajorCreep() + call SetAllianceTarget(target) + call FormGroup(3,true) + call AttackMoveKillA(target) + set target = null +endfunction + +//============================================================================ +function CreepAttackEx takes nothing returns nothing + local unit target = GetCreepCamp(min_creeps,max_creeps,allow_air_creeps) + call SetAllianceTarget(target) + call FormGroup(3,true) + call AttackMoveKillA(target) + set target = null +endfunction + +//============================================================================ +function AnyPlayerAttack takes nothing returns nothing + local unit hall = GetEnemyExpansion() + + if hall == null then + call StartGetEnemyBase() + loop + exitwhen not WaitGetEnemyBase() + call SuicideSleep(1) + endloop + set hall = GetEnemyBase() + endif + + call SetAllianceTarget(hall) + call FormGroup(3,true) + call AttackMoveKillA(hall) + set hall = null +endfunction + +//============================================================================ +function ExpansionAttack takes nothing returns nothing + local unit creep = GetExpansionFoe() + local integer x + + call FormGroup(3, true) + if creep == null then + set x = GetExpansionX() + if x != -1 then + call AttackMoveXYA(x,GetExpansionY()) + endif + else + call AttackMoveKillA(creep) + endif + set creep = null +endfunction + +//============================================================================ +// AddSiege +//============================================================================ +function AddSiege takes nothing returns nothing + + #INCLUDETABLE <$VER$\StandardUnits.txt> #EFR #COND "%4" =~ /\bsiege\b/ + call SetAssaultGroup( 0, 9, %1 ) + #ENDINCLUDE + +endfunction + +//=========================================================================== +// GetAllyCount +//============================================================================ +function GetAllyCount takes player whichPlayer returns integer + local integer playerIndex = 0 + local integer count = 0 + local player indexPlayer + + loop + set indexPlayer = Player(playerIndex) + if whichPlayer != indexPlayer then + if GetPlayerAlliance(whichPlayer,indexPlayer,ALLIANCE_PASSIVE) then + if GetPlayerAlliance(indexPlayer,whichPlayer,ALLIANCE_PASSIVE) then + if GetPlayerStructureCount(indexPlayer,true) > 0 then + set count = count + 1 + endif + endif + endif + endif + set playerIndex = playerIndex + 1 + exitwhen playerIndex == GetBJMaxPlayers() + endloop + set indexPlayer = null + return count +endfunction + +//============================================================================ +// SingleMeleeAttack +//============================================================================ +function SingleMeleeAttack takes boolean needs_exp, boolean has_siege, boolean major_ok, boolean air_units returns nothing + local boolean can_siege + local real daytime + local unit hall + local unit mega + local unit creep + local unit common + local integer minexp + local boolean allies + + call Trace("===SingleMeleeAttack===\n") //xxx + + if TownThreatened() then + call Trace("sleep 2, town threatened\n") //xxx + call Sleep(2) + return + endif + + // purchase zeppelins + // + if get_zeppelin and GetGold() > 300 and GetWood() > 100 then + call Trace("purchase zep\n") //xxx + call PurchaseZeppelin() + set get_zeppelin = false + set ready_for_zeppelin = false + return + endif + set ready_for_zeppelin = true + + // coordinate with allies + // + set allies = GetAllyCount(ai_player) > 0 + if allies and MeleeDifficulty() != MELEE_NEWBIE then + set common = GetAllianceTarget() + if common != null then + call Trace("join ally force\n") //xxx + if GetMegaTarget() != null then + call AddSiege() + endif + call FormGroup(3,true) + call AttackMoveKillA(common) + call SetAllianceTarget(null) + set common = null + return + endif + endif + + // take expansions as needed + // + if needs_exp then + call Trace("needs exp\n") //xxx + set creep = GetExpansionFoe() + if creep != null then + call Trace("attack exp\n") //xxx + call SetAllianceTarget(creep) + call FormGroup(3,true) + call AttackMoveKillA(creep) + call Sleep(20) + set take_exp = false + set creep = null + return + endif + endif + + // all-out attack if the player is weak + // + if MeleeDifficulty() != MELEE_NEWBIE then + set mega = GetMegaTarget() + if mega != null then + call Trace("MEGA TARGET!!!\n") //xxx + call AddSiege() + call FormGroup(3,true) + call AttackMoveKillA(mega) + set mega = null + return + endif + endif + + // deny player an expansion + // + set hall = GetEnemyExpansion() + set daytime = GetFloatGameState(GAME_STATE_TIME_OF_DAY) + set can_siege = has_siege and (air_units or (daytime>=4 and daytime<=12)) + + if hall!=null and (can_siege or not IsTowered(hall)) then + + call Trace("test player town attack\n") //xxx + + if MeleeDifficulty() == MELEE_NEWBIE then + set minexp = 3 + elseif allies and MeleeDifficulty() == MELEE_NORMAL then + set minexp = 1 + else + set minexp = 0 // HARD, INSANE, and NORMAL with no allies + endif + + if exp_seen >= minexp then + call Trace("do player town attack\n") //xxx + set exp_seen = 0 + call AddSiege() + call SetAllianceTarget(hall) + call FormGroup(3,true) + call AttackMoveKillA(hall) + set hall = null + return + endif + set hall = null + set exp_seen = exp_seen + 1 + endif + + // attack player's main base when siege is available + // + if can_siege then + call Trace("attack player's town\n") //xxx + call AddSiege() + call AnyPlayerAttack() + return + endif + + // extended, more specific method of determining creep levels + // + if min_creeps != -1 then + call TraceI("custom creep attack %d\n",max_creeps) //xxx + call CreepAttackEx() + return + endif + + // nothing better to do, so kill a creep camp + // + if major_ok then + call Trace("major creep attack\n") //xxx + call MajorCreepAttack() + return + endif + + call Trace("minor creep attack\n") //xxx + call MinorCreepAttack() +endfunction + +//============================================================================ +function GetZeppelin takes nothing returns nothing + if ready_for_zeppelin then + set get_zeppelin = true + endif +endfunction + +//============================================================================ +function BuildAttackers takes nothing returns nothing + local integer index = 0 + local integer unitid + local integer desire + local integer count + + loop + exitwhen index == harass_length + + set unitid = harass_units[index] + set desire = harass_qty[index] + IgnoredUnits(unitid) + set count = TownCount(unitid) + + if count != desire then + if not StartUnit(desire,unitid,-1) then + return + endif + endif + + set index = index + 1 + endloop +endfunction + +//============================================================================ +function BuildDefenders takes nothing returns nothing + local integer index = 0 + local integer unitid + local integer qty + loop + exitwhen index == defense_length + + set unitid = defense_units[index] + set qty = defense_qty[index] + + call Conversions(qty,unitid) + call AddDefenders(qty,unitid) + + set index = index + 1 + endloop +endfunction + +//============================================================================ +function CampaignBasicsA takes nothing returns nothing + local integer food_each = GetFoodMade(racial_farm) + local integer on_wood + + call ClearHarvestAI() + + if CaptainInCombat(false) then + set on_wood = 0 + else + set on_wood = campaign_wood_peons + endif + + call HarvestGold(0,campaign_gold_peons) + call HarvestWood(0,on_wood) + + if harvest_town1 then + call HarvestGold(1,campaign_gold_peons) + call HarvestWood(1,on_wood) + endif + + if harvest_town2 then + call HarvestGold(2,campaign_gold_peons) + call HarvestWood(2,on_wood) + endif + + if harvest_town3 then + call HarvestGold(3,campaign_gold_peons) + call HarvestWood(3,on_wood) + endif + + if do_campaign_farms and FoodUsed()+food_each-1 > food_each*(TownCount(racial_farm)+1) then + call StartUnit(TownCount(racial_farm)+1,racial_farm,-1) + endif + + if build_campaign_attackers then + call BuildAttackers() + endif + + if not CaptainInCombat(false) then + call BuildDefenders() + endif + + call FillGuardPosts() + call ReturnGuardPosts() +endfunction + +//============================================================================ +function CampaignBasics takes nothing returns nothing + call Sleep(1) + call CampaignBasicsA() + call StaggerSleep(1,5) + loop + call CampaignBasicsA() + call Sleep(campaign_basics_speed) + endloop +endfunction + +//============================================================================ +function CampaignAI takes integer farms, code heroes returns nothing + if GetGameDifficulty() == MAP_DIFFICULTY_EASY then + set difficulty = EASY + + call SetTargetHeroes(false) + call SetUnitsFlee(false) + + elseif GetGameDifficulty() == MAP_DIFFICULTY_NORMAL then + set difficulty = NORMAL + + call SetTargetHeroes(false) + call SetUnitsFlee(false) + + elseif GetGameDifficulty() == MAP_DIFFICULTY_HARD then + set difficulty = HARD + + call SetPeonsRepair(true) + else + set difficulty = INSANE + endif + + call InitAI() + call InitBuildArray() + call InitAssaultGroup() + call CreateCaptains() + + call SetNewHeroes(false) + if heroes != null then + call SetHeroLevels(heroes) + endif + + call SetHeroesFlee(false) + call SetGroupsFlee(false) + call SetSlowChopping(true) + call GroupTimedLife(false) + call SetCampaignAI() + call Sleep(0.1) + + set racial_farm = farms + call StartThread(function CampaignBasics) + call StartBuildLoop() +endfunction + +//============================================================================ +function UnsummonAll takes nothing returns nothing + local unit bldg + loop + set bldg = GetBuilding(ai_player) + exitwhen bldg==null + call Unsummon(bldg) + call Sleep(2) + endloop +endfunction + +//============================================================================ +// SkillArrays +//============================================================================ +function SkillArrays takes nothing returns integer + local integer level = GetHeroLevelAI() + if level > max_hero_level then + set max_hero_level = level + endif + + if GetHeroId() == hero_id then + return skills1[level] + elseif GetHeroId() == hero_id2 then + return skills2[level] + else + return skills3[level] + endif +endfunction + +//-------------------------------------------------------------------------------------------------- +// SetSkillArray +//-------------------------------------------------------------------------------------------------- +function SetSkillArray takes integer index, integer id returns nothing + local integer i = 1 + + if index == 1 then + if hero_id != id then + return + endif + loop + set skills1[i] = skill[i] + exitwhen i == 10 + set i = i + 1 + endloop + elseif index == 2 then + if hero_id2 != id then + return + endif + loop + set skills2[i] = skill[i] + exitwhen i == 10 + set i = i + 1 + endloop + else + if hero_id3 != id then + return + endif + loop + set skills3[i] = skill[i] + exitwhen i == 10 + set i = i + 1 + endloop + endif +endfunction + +//============================================================================ +// AwaitMeleeHeroes +//============================================================================ +function AwaitMeleeHeroes takes nothing returns nothing + if GetUnitCountDone(hero_id2) > 0 then + set two_heroes = true + endif + loop + exitwhen GetUnitCountDone(hero_id)>0 and (take_exp or (not two_heroes or GetUnitCountDone(hero_id2)>0)) + call Sleep(1) + endloop +endfunction + +//============================================================================ +// PickMeleeHero +//============================================================================ +function PickMeleeHero takes race raceid returns integer + local integer first + local integer second + local integer third + local integer last + local integer array heroes + local integer i +#INCLUDETABLE <$VER$\GlobalSettings.txt> #EFR #COND '%1' eq 'ver_neutral_hero_number' + set %1 = %2 +#ENDINCLUDE + call InitAiUnits() // This function makes all unit ids go back to there originals + set i = ver_neutral_hero_number + //------------------------------------------------------------------------ + if raceid == RACE_HUMAN then + //------------------------------------------------------------------------ + + #INCLUDETABLE <$VER$\Races.txt> #COND '%1' eq 'HUMAN' + #INCLUDETABLE <$VER$\%1\Heroes.txt> #EFR + set heroes[#EVAL{%row}] = %1 + #ENDINCLUDE + #ENDINCLUDE + + //------------------------------------------------------------------------ + elseif raceid == RACE_ORC then + //------------------------------------------------------------------------ + #INCLUDETABLE <$VER$\Races.txt> #COND '%1' eq 'ORC' + #INCLUDETABLE <$VER$\%1\Heroes.txt> #EFR + set heroes[#EVAL{%row}] = %1 + #ENDINCLUDE + #ENDINCLUDE + + //------------------------------------------------------------------------ + elseif raceid == RACE_NIGHTELF then + //------------------------------------------------------------------------ + #INCLUDETABLE <$VER$\Races.txt> #COND '%1' eq 'ELF' + #INCLUDETABLE <$VER$\%1\Heroes.txt> #EFR + set heroes[#EVAL{%row}] = %1 + #ENDINCLUDE + #ENDINCLUDE + + //------------------------------------------------------------------------ + elseif raceid == RACE_UNDEAD then + //------------------------------------------------------------------------ + #INCLUDETABLE <$VER$\Races.txt> #COND '%1' eq 'UNDEAD' + #INCLUDETABLE <$VER$\%1\Heroes.txt> #EFR + set heroes[#EVAL{%row}] = %1 + #ENDINCLUDE + #ENDINCLUDE + + else + set hero_id = 0 + endif + + //if VersionCompatible(VERSION_FROZEN_THRONE) then + set last = race_hero_number + i + //else + // set last = race_hero_number + //endif + + set first = GetRandomInt(i+1,last) + set second = GetRandomInt(i+1,last-1) + if VersionCompatible(VERSION_FROZEN_THRONE) then + set third = GetRandomInt(i+1,last-2) + else + set third = i+1 + endif + set hero_id = heroes[first] + set heroes[first] = heroes[last] + set hero_id2 = heroes[second] + set heroes[second] = heroes[last-1] + set hero_id3 = heroes[third] + + return hero_id +endfunction \ No newline at end of file