• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

Turning melee ai into campaign ai

Level 4
Joined
Apr 14, 2021
Messages
63
The title is pretty straightforward. I took the melee human ai script and edited in high elven parts to adjust it for a custom map of mine. As far as my intuition goes, I'm in a dead end where I don't see a plausible solution, I'm not a programmer – the most I can do is set up peons, build sequences, attack sequences and then call it all in the main function. The idea of going through a very different programming style seems pretty arduous, at least to me. Really would appreciate it if anyone could check out my "work in progress" script and let me know what the script lacks, thanks.

If you're, by any chance, wondering what happens when I load the ai script, the peasants just go straight for the gold mine and play brain dead.
Also, does it matter if I send the AI command (0, 0) in the trigger editor if I don't put the WaitForSignal command in the script?

JASS:
//==================================================================================================
//  $Id: human.ai,v 1.15 2003/04/23 19:26:00 bfitch Exp $
//==================================================================================================
globals
    boolean basic_opening       = true

    boolean b_hero_done        = false
    boolean b_knights_ok        = false

    integer c_altar_done        = 0
    integer c_castle_done       = 0
    integer c_food_made         = 0
    integer c_food_used         = 0
    integer c_footman_done      = 0
    integer c_gold              = 0
    integer c_gold_owned        = 0
    integer c_hall              = 0
    integer c_hall_done         = 0
    integer c_hawk_done         = 0
    integer c_hero_done         = 0
    integer c_house             = 0
    integer c_house_done        = 0
    integer c_keep_done         = 0
    integer c_knight_done       = 0
    integer c_mill_done         = 0
    integer c_mines             = 0
    integer c_peasant_done      = 0
    integer c_priest_done       = 0
    integer c_archer_done       = 0
    integer c_sanctum_done      = 0
    integer c_smith_done        = 0
    integer c_sorceress_done    = 0
    integer c_skyfury           = 0
    integer c_skyfury_done      = 0
    integer c_earthfury         = 0
    integer c_earthfury_done    = 0
    integer c_zep               = 0
endglobals

//--------------------------------------------------------------------------------------------------
//  set_skills
//--------------------------------------------------------------------------------------------------
function set_skills takes nothing returns nothing

    set skill[ 1] = FLAMESTRIKE
    set skill[ 2] = BANISH
    set skill[ 3] = SIPHON_MANA
    set skill[ 4] = FLAMESTRIKE
    set skill[ 5] = SIPHON_MANA
    set skill[ 6] = SUMMON_PHOENIX
    set skill[ 7] = FLAMESTRIKE
    set skill[ 8] = SIPHON_MANA
    set skill[ 9] = BANISH
    set skill[10] = BANISH

    call SetSkillArray(1, 'Hkal')
    call SetSkillArray(2, 'Hkal')
    call SetSkillArray(3, 'Hkal')

endfunction

//--------------------------------------------------------------------------------------------------
//  setup_force
//--------------------------------------------------------------------------------------------------
function setup_force takes nothing returns nothing
    call AwaitMeleeHeroes()
    call InitMeleeGroup()

    call SetMeleeGroup( hero_id             )
    call SetMeleeGroup( 'hhes'              )
    call SetMeleeGroup( KNIGHT              )
    call SetMeleeGroup( 'nhea'              )
    call SetMeleeGroup( PRIEST              )
    call SetMeleeGroup( SORCERESS           )
    call SetMeleeGroup( 'nws1'              )

    call SetInitialWave(10)
endfunction

//--------------------------------------------------------------------------------------------------
//  force_level
//--------------------------------------------------------------------------------------------------
function force_level takes nothing returns integer
    local integer level = 4 // basic hero
    set level = level + 2 * (c_footman_done + c_priest_done + c_sorceress_done)
    set level = level + 3 * (c_archer_done + c_hawk_done)
    set level = level + 5 * (c_hero_done + c_knight_done)
    set level = level + 6 *  c_hero_done
    return level
endfunction

//--------------------------------------------------------------------------------------------------
//  attack_sequence
//--------------------------------------------------------------------------------------------------
function attack_sequence takes nothing returns nothing
    local boolean needs_exp
    local boolean air_units
    local integer level

    loop
        exitwhen c_hero_done > 0 and c_footman_done >= 2
        call Sleep(2)
    endloop

    if MeleeDifficulty() == MELEE_NEWBIE then
        call Sleep(240)
    endif

    call StaggerSleep(0,2)
    loop
        loop
            exitwhen not CaptainRetreating()
            call Sleep(2)
        endloop

        call setup_force()

        set level = force_level()
        set max_creeps = level * 4 / 5
        set min_creeps = max_creeps - 10
        if min_creeps < 0 then
            set min_creeps = 0
        endif

        set needs_exp        = take_exp and (level >= 9 or c_gold_owned < 2000)
        set air_units        = c_hawk_done > 0
        set allow_air_creeps = (c_archer_done + c_hawk_done) >= 3

        call SingleMeleeAttack(needs_exp,false,air_units)

        if MeleeDifficulty() == MELEE_NEWBIE then
            call Sleep(60)
        endif
    endloop
endfunction

//--------------------------------------------------------------------------------------------------
//  init_vars
//--------------------------------------------------------------------------------------------------
function init_vars takes nothing returns nothing

    set c_altar_done        = GetUnitCountDone(HUMAN_ALTAR)
    set c_castle_done       = TownCountDone(CASTLE)
    set c_food_made         = c_hall * GetFoodMade(TOWN_HALL) + c_house * GetFoodMade(ELF_FARM)
    set c_food_used         = FoodUsed()
    set c_footman_done      = GetUnitCountDone('hhes')
    set c_gold              = GetGold()
    set c_gold_owned        = GetGoldOwned()
    set c_hall              = TownCount(TOWN_HALL)
    set c_hall_done         = TownCountDone(TOWN_HALL)
    set c_hawk_done         = GetUnitCountDone('nws1')
    set c_hero_done         = GetUnitCountDone(hero_id)
    set c_house             = GetUnitCount(ELF_FARM)
    set c_house_done        = GetUnitCountDone(ELF_FARM)
    set c_keep_done         = TownCountDone(KEEP)
    set c_knight_done       = GetUnitCountDone(KNIGHT)
    set c_mill_done         = GetUnitCountDone(LUMBER_MILL)
    set c_mines             = GetMinesOwned()
    set c_peasant_done      = GetUnitCountDone(PEASANT)
    set c_priest_done       = GetUnitCountDone(PRIEST)
    set c_archer_done     = GetUnitCountDone('nhea')
    set c_sanctum_done      = GetUnitCountDone(SANCTUM)
    set c_smith_done        = GetUnitCountDone(BLACKSMITH)
    set c_sorceress_done    = GetUnitCountDone(SORCERESS)
    set c_skyfury           = TownCount(HIGH_SKY)
    set c_skyfury_done      = TownCountDone(HIGH_SKY)
    set c_earthfury         = TownCount(HIGH_EARTH)
    set c_earthfury_done    = TownCountDone(HIGH_EARTH)
    set c_zep               = GetUnitCount(ZEPPELIN)

    set b_hero_done        = GetUnitCountDone(hero_id) >= 1
    set b_knights_ok        = c_castle_done>=1 and c_mill_done>=1 and c_smith_done>=1

    if basic_opening and (b_hero_done or (MeleeDifficulty() == MELEE_NEWBIE and c_castle_done >= 1)) then
        set basic_opening = false
    endif
endfunction

//--------------------------------------------------------------------------------------------------
//  set_vars
//--------------------------------------------------------------------------------------------------
function set_vars takes nothing returns nothing
    loop
        call init_vars()
        call Sleep(1)
    endloop
endfunction

//--------------------------------------------------------------------------------------------------
//  do_upgrades
//--------------------------------------------------------------------------------------------------
function do_upgrades takes nothing returns nothing

    if c_keep_done >= 1 then

        call SetBuildUpgr( 1, UPG_WOOD )

        if c_castle_done >= 1 then
            call SetBuildUpgr( 2, UPG_WOOD )
        endif

        if b_knights_ok then
            call SetBuildUpgr( 1, UPG_BREEDING )
        endif
        if c_sanctum_done >= 1 then
            if c_priest_done >= 1 then
                call SetBuildUpgr( 1, UPG_PRAYING )
            endif
            if c_sorceress_done >= 1 then
                call SetBuildUpgr( 1, UPG_SORCERY )
            endif
        endif
        if c_castle_done >= 1 then

            call SetBuildUpgr( 2, UPG_WOOD )

            if c_sanctum_done >= 1 then
                if c_priest_done >= 1 then
                    call SetBuildUpgr( 2, UPG_PRAYING )
                endif
                if c_sorceress_done >= 1 then
                    call SetBuildUpgr( 2, UPG_SORCERY )
                endif
            endif
        endif
    endif

    call SetBuildUpgr( 1, UPG_DEFEND )

    if c_smith_done >= 1 then
        call SetBuildUpgr( 1, UPG_ARMOR     )
        call SetBuildUpgr( 1, UPG_MELEE     )
        call SetBuildUpgr( 1, UPG_MOON_ARMOR)
        call SetBuildUpgr( 1, UPG_STR_MOON  )

        if c_keep_done >= 1 then
            call SetBuildUpgr( 2, UPG_ARMOR     )
            call SetBuildUpgr( 2, UPG_MELEE     )
            call SetBuildUpgr( 2, UPG_MOON_ARMOR)
            call SetBuildUpgr( 2, UPG_STR_MOON  )

            if c_castle_done >= 1 then
                call SetBuildUpgr( 3, UPG_ARMOR     )
                call SetBuildUpgr( 3, UPG_MELEE     )
                call SetBuildUpgr( 3, UPG_MOON_ARMOR)
                call SetBuildUpgr( 3, UPG_STR_MOON  )
            endif
        endif
    endif

    if c_archer_done >= 1 and c_keep_done >= 1 then
        call SetBuildUpgr( 1, UPG_BOWS )
        if c_castle_done >= 1 then
            call SetBuildUpgr( 1, UPG_MARKSMAN )
        endif
    endif

    if c_mill_done >= 1 then
        call SetBuildUpgr( 1, UPG_MASONRY )
        if c_keep_done >= 1 then
            call SetBuildUpgr( 2, UPG_MASONRY )
        endif
    endif

endfunction

//--------------------------------------------------------------------------------------------------
//  build_sequence
//--------------------------------------------------------------------------------------------------
function build_sequence takes nothing returns nothing
    local integer peasants

    call InitBuildArray()

    if basic_opening then

        call MeleeTownHall( 0, TOWN_HALL )
        call MeleeTownHall( 1, TOWN_HALL )

        call SetBuildUnit(  6, PEASANT      )
        call SetBuildUnit(  1, HUMAN_ALTAR  )
        call SetBuildUnit(  7, PEASANT      )
        call SetBuildUnit(  1, HOUSE        )
        call SetBuildUnit(  1, BARRACKS     )
        call SetBuildUnit(  9, PEASANT      )
        call SetBuildUnit(  2, ELF_FARM     )
        call SetBuildUnit(  1, hero_id      )
        call SetBuildUnit( 11, PEASANT      )
        call SetBuildUnit(  1, 'hhes'       )
        call SetBuildUnit(  3, ELF_FARM     )
        call SetBuildUnit( 12, PEASANT      )
        call SetBuildUnit(  2, 'hhes'       )
        call SetBuildUnit( 13, PEASANT      )
        call SetBuildUnit(  3, 'hhes'       )
        call SetBuildUnit( 14, PEASANT      )
        call SetBuildUnit(  4, ELF_FARM     )
        call SetBuildUnit( 15, PEASANT      )
        call SetBuildUnit(  4, 'hhes'       )
        call SetBuildUnit( 16, PEASANT      )
        call SetBuildUnit(  5, 'hhes'       )
        call SetBuildUnit(  1, BLACKSMITH   )
        call SetBuildUnit(  6, 'hhes'       )
        call SetBuildUnit(  5, ELF_FARM     )
        call SetBuildUnit(  8, 'hhes'       )
        call SetBuildUnit(  6, ELF_FARM     )
        call SetBuildUnit(  2, 'nhea'       )
        call SetBuildUnit(  7, ELF_FARM     )
        call SetBuildUnit(  3, 'nhea'       )
        call SetBuildUnit(  1, ARCANE_VAULT )

        call BasicExpansion( c_mines < 2, TOWN_HALL )

        call SetBuildUnit(  4, 'nhea'       )
        call SetBuildUnit(  1, LUMBER_MILL  )

        if MeleeDifficulty() != MELEE_NEWBIE then
            call GuardSecondary( 1, 2, HIGH_SKY  )
            if c_mill_done >= 1 then
                call GuardSecondary( 1, 2, HIGH_EARTH  )
            endif
        endif

        call SetBuildUnit(  1, KEEP         )
        call SetBuildUpgr(  1, UPG_DEFEND   )
        call SetBuildUpgr(  1, UPG_ARMOR    )
        call SetBuildUnit(  7, ELF_FARM     )
        call SetBuildUpgr(  1, UPG_MELEE    )

        if c_keep_done < 1 then
            return
        endif

        call SetBuildUnit(  1, CASTLE       )

        call GuardSecondary( 0, 2, HIGH_EARTH  )
        if c_earthfury_done >= 3 then
            call GuardSecondary( 0, 1, HIGH_SKY  )
        endif

        call SetBuildUpgr(  1, UPG_STR_MOON )
        call SetBuildUnit(  1, SANCTUM      )
        call SetBuildUpgr(  1, UPG_WOOD     )
        call SetBuildUpgr(  2, UPG_ARMOR    )
        call SetBuildUpgr(  2, UPG_WOOD     )
        return
    endif

    // need a peasant or nothing will get built
    //
    if c_hall_done >= 1 then
        set peasants = 6 - GetWood() / 200
        if peasants < 3 then
            set peasants = 3
        endif
        if c_mines < 2 then
            set peasants = peasants + 5
        else
            set peasants = peasants + 10
        endif
        if peasants > 15 then
            set peasants = 15
        endif
        call SetBuildNext( peasants, PEASANT )
    endif

    // need a hall or we can't resource and make more peasants
    //
    if c_hall < 1 and c_peasant_done >= 1 then
        call MeleeTownHall( 0, TOWN_HALL )
        call MeleeTownHall( 1, TOWN_HALL )
        call MeleeTownHall( 2, TOWN_HALL )
    endif

    if c_gold > 500 and GetWood() < 100 then
        call SetBuildNext( 20, PEASANT )
    endif

    // if we have low gold in our mines then we need to expand
    //
    if c_gold_owned < 2000 then
        call BasicExpansion( c_mines < 2, TOWN_HALL )
        if MeleeDifficulty() != MELEE_NEWBIE then
            call GuardSecondary( 2, 2, HIGH_SKY  )
            if c_earthfury >= 2 then
                call GuardSecondary( 2, 2, HIGH_EARTH  )
            endif
        endif
    endif

    // get enough burrows to handle current food demand
    //
    if c_food_used + 5 >= c_food_made then
        call SetBuildUnit(  c_house_done + 1, ELF_FARM )
    endif

    // always rebuild heroes for defense
    //
    if c_altar_done >= 1 then
        if b_hero_done and MeleeDifficulty() != MELEE_NEWBIE then
                if c_castle_done >= 1 then
                    call SetBuildUnit( 1, hero_id )
                endif
            else
        call SetBuildUnit( 1, HUMAN_ALTAR )
    endif

    // minimum melee defense
    //
    call SetBuildUnit( 1, ELF_HIGH_BARRACKS )
    if b_knights_ok then
        call SetBuildUnit( 2, KNIGHT        )
    else
        call SetBuildUnit( 4, 'hhes'        )
    endif

    // minimum ranged/air defense
    //
        call SetBuildUnit( 3, 'nws1'    )
    else
        call SetBuildUnit( 1, BLACKSMITH )
        if c_smith_done >= 1 or c_gold < 1000 then
            call SetBuildUnit( 4, 'nhea'   )
        endif
    endif

    // siege attackers
    //
    call SetBuildUnit( 1, KEEP      )

    call SetBuildUnit( c_earthfury_done - c_skyfury_done, HIGH_EARTH )
    
    // if we have a lot of gold then advance the tech tree
    //
    if c_gold > 1000 then
        call SetBuildUnit( 1, ARCANE_VAULT  )
        call SetBuildUnit( 1, BLACKSMITH    )
        call SetBuildUnit( 1, LUMBER_MILL   )
        call SetBuildUnit( 1, SANCTUM       )
        call SetBuildUnit( 1, CASTLE        )

        call do_upgrades()

        if c_gold > 2000 then
            call BuildFactory( ELF_HIGH_BARRACKS       )
            call BuildFactory( SANCTUM                 )
        endif

    elseif c_food_used >= UPKEEP_TIER1 then
        call do_upgrades()
    endif

    call BasicExpansion( c_mines < 2, TOWN_HALL )

    if c_food_used >= UPKEEP_TIER2-10 and c_gold < 2000 then
        return
    endif

    // full up with more troops in general
    //
    if b_knights_ok then
        call SetBuildNext( 4, KNIGHT )
    endif

    if c_sanctum_done >= 1 then
        call SetBuildNext( 2, PRIEST        )
        call SetBuildNext( 1, SORCERESS     )

        if c_aviary_done >= 1 then
            call SetBuildNext( 2, 'nws1' )
        endif

        call SetBuildNext( 2, SORCERESS     )
    endif

    if c_gold_owned < 10000 then
        call BasicExpansion( c_mines < 3, TOWN_HALL )
    endif

    if c_food_used >= 60 and c_zep < 3 then
        call GetZeppelin()
    endif
endfunction

//--------------------------------------------------------------------------------------------------
//  peon_assignment
//--------------------------------------------------------------------------------------------------
function peon_assignment takes nothing returns nothing
    local integer T
    loop
        call ClearHarvestAI()

        set T = TownWithMine()

        call HarvestGold(T,4)
        call HarvestWood(0,1)
        call HarvestGold(T,1)
        call HarvestWood(0,1)

        if c_hall_done > 1 and c_mines > 1 then
            call HarvestGold(T+1,5)
        endif

        call HarvestWood(0,15)

        call build_sequence()

        call Sleep(GetRandomInt(1,3))
    endloop
endfunction

//--------------------------------------------------------------------------------------------------
//    main
//--------------------------------------------------------------------------------------------------
function main takes nothing returns nothing
    call CampaignAI(ELF_FARM, null)
    call peon_assignment()
    call attack_sequence()
    call set_skills()
    call StartThread(function set_vars)
endfunction
 
What is the purpose of your script for the campaign mission? If you want just a basic attack and defence script like the AIs in the blizz campaign use then you'd be better taking those AIs and adapting them instead.

I've attached some of those scripts below. Let me know how these look to you and whether they make sense :)

EDIT: If the peasants are just mining gold then it means that there is an error in the script causing the whole thing to fail. This will usually be a syntax error such as missing variables, a typo etc.
 

Attachments

  • u03_light_blue.ai
    2.6 KB · Views: 3
  • u03_green.ai
    2.6 KB · Views: 3
  • u03_blue_reforged.ai
    4.2 KB · Views: 4
  • u03_blue.ai
    4.1 KB · Views: 3
Level 31
Joined
Aug 29, 2012
Messages
1,435
There are indeed errors in the script so it's all invalidated

1749150519685.png


For the 1st one, the variable is FLAME_STRIKE, that was close enough :p

SingleMeleeAttack takes 4 arguments (I think)
1749150651057.png


And you got an unknown variable
 
Level 4
Joined
Apr 14, 2021
Messages
63
What is the purpose of your script for the campaign mission? If you want just a basic attack and defence script like the AIs in the blizz campaign use then you'd be better taking those AIs and adapting them instead.
I'm testing out using a little more complex ai behavior as opposed to the plain campaign ai – I'm adjusting it for Key of the Three Moons campaign mission.
I'm hoping that if I can get it to work, then perhaps I could integrate it for the undead ai as well.

There are indeed errors in the script so it's all invalidated
I got it to work, the peasants no longer just head for the gold mine, but I just hit another dead end. I don't know if it's reforged's clunky mechanics or if I am just stupid, but the ai is still brain dead, I waited for a good 5 minutes to see if time is a factor, but it still does absolutely nothing.
Also, how did you get the debug information? It would probably save me a lot of trouble knowing where I went wrong.

JASS:
//==================================================================================================
//  $Id: human.ai,v 1.15 2003/04/23 19:26:00 bfitch Exp $
//==================================================================================================
globals
    boolean basic_opening       = true

    boolean b_hero_done        = false
    boolean b_knights_ok        = false

    integer c_altar_done        = 0
    integer c_castle_done       = 0
    integer c_food_made         = 0
    integer c_food_used         = 0
    integer c_footman_done      = 0
    integer c_gold              = 0
    integer c_gold_owned        = 0
    integer c_hall              = 0
    integer c_hall_done         = 0
    integer c_hawk_done         = 0
    integer c_hero_done         = 0
    integer c_house             = 0
    integer c_house_done        = 0
    integer c_keep_done         = 0
    integer c_knight_done       = 0
    integer c_mill_done         = 0
    integer c_mines             = 0
    integer c_peasant_done      = 0
    integer c_priest_done       = 0
    integer c_archer_done       = 0
    integer c_sanctum_done      = 0
    integer c_smith_done        = 0
    integer c_sorceress_done    = 0
    integer c_skyfury           = 0
    integer c_skyfury_done      = 0
    integer c_earthfury         = 0
    integer c_earthfury_done    = 0
    integer c_zep               = 0
endglobals

//--------------------------------------------------------------------------------------------------
//  set_skills
//--------------------------------------------------------------------------------------------------
function set_skills takes nothing returns nothing

    set skill[ 1] = FLAME_STRIKE
    set skill[ 2] = BANISH
    set skill[ 3] = SIPHON_MANA
    set skill[ 4] = FLAME_STRIKE
    set skill[ 5] = SIPHON_MANA
    set skill[ 6] = SUMMON_PHOENIX
    set skill[ 7] = FLAME_STRIKE
    set skill[ 8] = SIPHON_MANA
    set skill[ 9] = BANISH
    set skill[10] = BANISH

    call SetSkillArray(1, 'Hkal')
    call SetSkillArray(2, 'Hkal')
    call SetSkillArray(3, 'Hkal')

endfunction

//--------------------------------------------------------------------------------------------------
//  setup_force
//--------------------------------------------------------------------------------------------------
function setup_force takes nothing returns nothing
    call AwaitMeleeHeroes()
    call InitMeleeGroup()

    call SetMeleeGroup( hero_id             )
    call SetMeleeGroup( 'hhes'              )
    call SetMeleeGroup( KNIGHT              )
    call SetMeleeGroup( 'nhea'              )
    call SetMeleeGroup( PRIEST              )
    call SetMeleeGroup( SORCERESS           )
    call SetMeleeGroup( 'nws1'              )

    call SetInitialWave(10)
endfunction

//--------------------------------------------------------------------------------------------------
//  force_level
//--------------------------------------------------------------------------------------------------
function force_level takes nothing returns integer
    local integer level = 4 // basic hero
    set level = level + 2 * (c_footman_done + c_priest_done + c_sorceress_done)
    set level = level + 3 * (c_archer_done + c_hawk_done)
    set level = level + 5 * (c_hero_done + c_knight_done)
    set level = level + 6 *  c_hero_done
    return level
endfunction

//--------------------------------------------------------------------------------------------------
//  attack_sequence
//--------------------------------------------------------------------------------------------------
function attack_sequence takes nothing returns nothing
    local boolean needs_exp
    local boolean has_siege
    local boolean air_units
    local integer level

    loop
        exitwhen c_hero_done > 0 and c_footman_done >= 2
        call Sleep(2)
    endloop

    if MeleeDifficulty() == MELEE_NEWBIE then
        call Sleep(240)
    endif

    call StaggerSleep(0,2)
    loop
        loop
            exitwhen not CaptainRetreating()
            call Sleep(2)
        endloop

        call setup_force()

        set level = force_level()
        set max_creeps = level * 4 / 5
        set min_creeps = max_creeps - 10
        if min_creeps < 0 then
            set min_creeps = 0
        endif

        set needs_exp        = take_exp and (level >= 9 or c_gold_owned < 2000)
        set has_siege        = level >= 40 or c_knight_done > 0
        set air_units        = c_hawk_done > 0
        set allow_air_creeps = (c_archer_done + c_hawk_done) >= 3

        call SingleMeleeAttack(needs_exp,has_siege,false,air_units)

        if MeleeDifficulty() == MELEE_NEWBIE then
            call Sleep(60)
        endif
    endloop
endfunction

//--------------------------------------------------------------------------------------------------
//  init_vars
//--------------------------------------------------------------------------------------------------
function init_vars takes nothing returns nothing

    set c_altar_done        = GetUnitCountDone(HUMAN_ALTAR)
    set c_castle_done       = TownCountDone(CASTLE)
    set c_food_made         = c_hall * GetFoodMade(TOWN_HALL) + c_house * GetFoodMade(ELF_FARM)
    set c_food_used         = FoodUsed()
    set c_footman_done      = GetUnitCountDone('hhes')
    set c_gold              = GetGold()
    set c_gold_owned        = GetGoldOwned()
    set c_hall              = TownCount(TOWN_HALL)
    set c_hall_done         = TownCountDone(TOWN_HALL)
    set c_hawk_done         = GetUnitCountDone('nws1')
    set c_hero_done         = GetUnitCountDone(hero_id)
    set c_house             = GetUnitCount(ELF_FARM)
    set c_house_done        = GetUnitCountDone(ELF_FARM)
    set c_keep_done         = TownCountDone(KEEP)
    set c_knight_done       = GetUnitCountDone(KNIGHT)
    set c_mill_done         = GetUnitCountDone(LUMBER_MILL)
    set c_mines             = GetMinesOwned()
    set c_peasant_done      = GetUnitCountDone(PEASANT)
    set c_priest_done       = GetUnitCountDone(PRIEST)
    set c_archer_done     = GetUnitCountDone('nhea')
    set c_sanctum_done      = GetUnitCountDone(SANCTUM)
    set c_smith_done        = GetUnitCountDone(BLACKSMITH)
    set c_sorceress_done    = GetUnitCountDone(SORCERESS)
    set c_skyfury           = TownCount(HIGH_SKY)
    set c_skyfury_done      = TownCountDone(HIGH_SKY)
    set c_earthfury         = TownCount(HIGH_EARTH)
    set c_earthfury_done    = TownCountDone(HIGH_EARTH)
    set c_zep               = GetUnitCount(ZEPPELIN)

    set b_hero_done        = GetUnitCountDone(hero_id) >= 1
    set b_knights_ok        = c_castle_done>=1 and c_mill_done>=1 and c_smith_done>=1

    if basic_opening and (b_hero_done or (MeleeDifficulty() == MELEE_NEWBIE and c_castle_done >= 1)) then
        set basic_opening = false
    endif
endfunction

//--------------------------------------------------------------------------------------------------
//  set_vars
//--------------------------------------------------------------------------------------------------
function set_vars takes nothing returns nothing
    loop
        call init_vars()
        call Sleep(1)
    endloop
endfunction

//--------------------------------------------------------------------------------------------------
//  do_upgrades
//--------------------------------------------------------------------------------------------------
function do_upgrades takes nothing returns nothing

    if c_keep_done >= 1 then

        call SetBuildUpgr( 1, UPG_WOOD )

        if c_castle_done >= 1 then
            call SetBuildUpgr( 2, UPG_WOOD )
        endif

        if b_knights_ok then
            call SetBuildUpgr( 1, UPG_BREEDING )
        endif
        if c_sanctum_done >= 1 then
            if c_priest_done >= 1 then
                call SetBuildUpgr( 1, UPG_PRAYING )
            endif
            if c_sorceress_done >= 1 then
                call SetBuildUpgr( 1, UPG_SORCERY )
            endif
        endif
        if c_castle_done >= 1 then

            call SetBuildUpgr( 2, UPG_WOOD )

            if c_sanctum_done >= 1 then
                if c_priest_done >= 1 then
                    call SetBuildUpgr( 2, UPG_PRAYING )
                endif
                if c_sorceress_done >= 1 then
                    call SetBuildUpgr( 2, UPG_SORCERY )
                endif
            endif
        endif
    endif

    call SetBuildUpgr( 1, UPG_DEFEND )

    if c_smith_done >= 1 then
        call SetBuildUpgr( 1, UPG_ARMOR     )
        call SetBuildUpgr( 1, UPG_MELEE     )
        call SetBuildUpgr( 1, UPG_MOON_ARMOR)
        call SetBuildUpgr( 1, UPG_STR_MOON  )

        if c_keep_done >= 1 then
            call SetBuildUpgr( 2, UPG_ARMOR     )
            call SetBuildUpgr( 2, UPG_MELEE     )
            call SetBuildUpgr( 2, UPG_MOON_ARMOR)
            call SetBuildUpgr( 2, UPG_STR_MOON  )

            if c_castle_done >= 1 then
                call SetBuildUpgr( 3, UPG_ARMOR     )
                call SetBuildUpgr( 3, UPG_MELEE     )
                call SetBuildUpgr( 3, UPG_MOON_ARMOR)
                call SetBuildUpgr( 3, UPG_STR_MOON  )
            endif
        endif
    endif

    if c_archer_done >= 1 and c_keep_done >= 1 then
        call SetBuildUpgr( 1, UPG_BOWS )
        if c_castle_done >= 1 then
            call SetBuildUpgr( 1, UPG_MARKSMAN )
        endif
    endif

    if c_mill_done >= 1 then
        call SetBuildUpgr( 1, UPG_MASONRY )
        if c_keep_done >= 1 then
            call SetBuildUpgr( 2, UPG_MASONRY )
        endif
    endif

endfunction

//--------------------------------------------------------------------------------------------------
//  build_sequence
//--------------------------------------------------------------------------------------------------
function build_sequence takes nothing returns nothing
    local integer peasants

    call InitBuildArray()

    if basic_opening then

        call MeleeTownHall( 0, TOWN_HALL )
        call MeleeTownHall( 1, TOWN_HALL )

        call SetBuildUnit(  6, PEASANT      )
        call SetBuildUnit(  1, HUMAN_ALTAR  )
        call SetBuildUnit(  7, PEASANT      )
        call SetBuildUnit(  1, HOUSE        )
        call SetBuildUnit(  1, BARRACKS     )
        call SetBuildUnit(  9, PEASANT      )
        call SetBuildUnit(  2, ELF_FARM     )
        call SetBuildUnit(  1, hero_id      )
        call SetBuildUnit( 11, PEASANT      )
        call SetBuildUnit(  1, 'hhes'       )
        call SetBuildUnit(  3, ELF_FARM     )
        call SetBuildUnit( 12, PEASANT      )
        call SetBuildUnit(  2, 'hhes'       )
        call SetBuildUnit( 13, PEASANT      )
        call SetBuildUnit(  3, 'hhes'       )
        call SetBuildUnit( 14, PEASANT      )
        call SetBuildUnit(  4, ELF_FARM     )
        call SetBuildUnit( 15, PEASANT      )
        call SetBuildUnit(  4, 'hhes'       )
        call SetBuildUnit( 16, PEASANT      )
        call SetBuildUnit(  5, 'hhes'       )
        call SetBuildUnit(  1, BLACKSMITH   )
        call SetBuildUnit(  6, 'hhes'       )
        call SetBuildUnit(  5, ELF_FARM     )
        call SetBuildUnit(  8, 'hhes'       )
        call SetBuildUnit(  6, ELF_FARM     )
        call SetBuildUnit(  2, 'nhea'       )
        call SetBuildUnit(  7, ELF_FARM     )
        call SetBuildUnit(  3, 'nhea'       )
        call SetBuildUnit(  1, ARCANE_VAULT )

        call BasicExpansion( c_mines < 2, TOWN_HALL )

        call SetBuildUnit(  4, 'nhea'       )
        call SetBuildUnit(  1, LUMBER_MILL  )

        if MeleeDifficulty() != MELEE_NEWBIE then
            call GuardSecondary( 1, 2, HIGH_SKY  )
            if c_mill_done >= 1 then
                call GuardSecondary( 1, 2, HIGH_EARTH  )
            endif
        endif

        call SetBuildUnit(  1, KEEP         )
        call SetBuildUpgr(  1, UPG_DEFEND   )
        call SetBuildUpgr(  1, UPG_ARMOR    )
        call SetBuildUnit(  7, ELF_FARM     )
        call SetBuildUpgr(  1, UPG_MELEE    )

        if c_keep_done < 1 then
            return
        endif

        call SetBuildUnit(  1, CASTLE       )

        call GuardSecondary( 0, 2, HIGH_EARTH  )
        if c_earthfury_done >= 3 then
            call GuardSecondary( 0, 1, HIGH_SKY  )
        endif

        call SetBuildUpgr(  1, UPG_STR_MOON )
        call SetBuildUnit(  1, SANCTUM      )
        call SetBuildUpgr(  1, UPG_WOOD     )
        call SetBuildUpgr(  2, UPG_ARMOR    )
        call SetBuildUpgr(  2, UPG_WOOD     )
        return
    endif

    // need a peasant or nothing will get built
    //
    if c_hall_done >= 1 then
        set peasants = 6 - GetWood() / 200
        if peasants < 3 then
            set peasants = 3
        endif
        if c_mines < 2 then
            set peasants = peasants + 5
        else
            set peasants = peasants + 10
        endif
        if peasants > 15 then
            set peasants = 15
        endif
        call SetBuildNext( peasants, PEASANT )
    endif

    // need a hall or we can't resource and make more peasants
    //
    if c_hall < 1 and c_peasant_done >= 1 then
        call MeleeTownHall( 0, TOWN_HALL )
        call MeleeTownHall( 1, TOWN_HALL )
        call MeleeTownHall( 2, TOWN_HALL )
    endif

    if c_gold > 500 and GetWood() < 100 then
        call SetBuildNext( 20, PEASANT )
    endif

    // if we have low gold in our mines then we need to expand
    //
    if c_gold_owned < 2000 then
        call BasicExpansion( c_mines < 2, TOWN_HALL )
        if MeleeDifficulty() != MELEE_NEWBIE then
            call GuardSecondary( 2, 2, HIGH_SKY  )
            if c_earthfury >= 2 then
                call GuardSecondary( 2, 2, HIGH_EARTH  )
            endif
        endif
    endif

    // get enough burrows to handle current food demand
    //
    if c_food_used + 5 >= c_food_made then
        call SetBuildUnit(  c_house_done + 1, ELF_FARM )
    endif

    // always rebuild heroes for defense
    //
    if c_altar_done >= 1 then
        if b_hero_done and MeleeDifficulty() != MELEE_NEWBIE then
                if c_castle_done >= 1 then
                    call SetBuildUnit( 1, hero_id )
                endif
            else
        call SetBuildUnit( 1, HUMAN_ALTAR )
    endif

    // minimum melee defense
    //
    call SetBuildUnit( 1, ELF_HIGH_BARRACKS )
    if b_knights_ok then
        call SetBuildUnit( 2, KNIGHT        )
    else
        call SetBuildUnit( 4, 'hhes'        )
    endif

    // minimum ranged/air defense
    //
        call SetBuildUnit( 3, 'nws1'    )
    else
        call SetBuildUnit( 1, BLACKSMITH )
        if c_smith_done >= 1 or c_gold < 1000 then
            call SetBuildUnit( 4, 'nhea'   )
        endif
    endif

    // siege attackers
    //
    call SetBuildUnit( 1, KEEP      )

    call SetBuildUnit( c_earthfury_done - c_skyfury_done, HIGH_EARTH )
    
    // if we have a lot of gold then advance the tech tree
    //
    if c_gold > 1000 then
        call SetBuildUnit( 1, ARCANE_VAULT  )
        call SetBuildUnit( 1, BLACKSMITH    )
        call SetBuildUnit( 1, LUMBER_MILL   )
        call SetBuildUnit( 1, SANCTUM       )
        call SetBuildUnit( 1, CASTLE        )

        call do_upgrades()

        if c_gold > 2000 then
            call BuildFactory( ELF_HIGH_BARRACKS       )
            call BuildFactory( SANCTUM                 )
        endif

    elseif c_food_used >= UPKEEP_TIER1 then
        call do_upgrades()
    endif

    call BasicExpansion( c_mines < 2, TOWN_HALL )

    if c_food_used >= UPKEEP_TIER2-10 and c_gold < 2000 then
        return
    endif

    // full up with more troops in general
    //
    if b_knights_ok then
        call SetBuildNext( 4, KNIGHT )
    endif

    if c_sanctum_done >= 1 then
        call SetBuildNext( 2, PRIEST        )
        call SetBuildNext( 1, SORCERESS     )

        call SetBuildNext( 2, 'nws1' )

        call SetBuildNext( 2, SORCERESS     )
    endif

    if c_gold_owned < 10000 then
        call BasicExpansion( c_mines < 3, TOWN_HALL )
    endif

    if c_food_used >= 60 and c_zep < 3 then
        call GetZeppelin()
    endif
endfunction

//--------------------------------------------------------------------------------------------------
//  peon_assignment
//--------------------------------------------------------------------------------------------------
function peon_assignment takes nothing returns nothing
    local integer T
    loop
        call ClearHarvestAI()

        set T = TownWithMine()

        call HarvestGold(T,4)
        call HarvestWood(0,1)
        call HarvestGold(T,1)
        call HarvestWood(0,1)

        if c_hall_done > 1 and c_mines > 1 then
            call HarvestGold(T+1,5)
        endif

        call HarvestWood(0,15)

        call build_sequence()

        call Sleep(GetRandomInt(1,3))
    endloop
endfunction

//--------------------------------------------------------------------------------------------------
//    main
//--------------------------------------------------------------------------------------------------
function main takes nothing returns nothing
    call CampaignAI(ELF_FARM, null)
    call peon_assignment()
    call attack_sequence()
    call set_skills()
    call StartThread(function set_vars)
endfunction
 
Level 4
Joined
Apr 14, 2021
Messages
63
Haha, all is fine. Even if I ultimately fail in getting this to work, I wouldn't sweat it as this is also beyond me, I'm just tinkering around to see if I can at least "upgrade" it, if anything. Thank you for the syntax thing, too.
 
I'm testing out using a little more complex ai behavior as opposed to the plain campaign ai – I'm adjusting it for Key of the Three Moons campaign mission.
I'm hoping that if I can get it to work, then perhaps I could integrate it for the undead ai as well.
Complex in what way? Imo starting from a melee AI and trying to convert it is not the best way to go. Instead you would be better taking one of the Campaign AIs and adding whatever more complex behaviour you want to it. Melee and Key of the Three Moons are quite different in how they work so I don't think a melee AI is the way to go.
 
Level 4
Joined
Apr 14, 2021
Messages
63
Been doing that for a long while, actually. But if you mean for me to insert functions manually, then that could be a problem since I don't really possess adequate programming skills in order to manage. Sure, I can understand it, but apply it – not so much. That's why it's easier for me to try to adjust and integrate the existing content.

Taking a look at the n07_rainbow.ai script for the final night elf mission, there is a bunch of code that I can partially understand, but not comprehend it to the point where I can point out the rules of calling each function, line of code and whatnot, especially when it's a campaign script.

I just thought that taking out unnecessary bits from a melee ai script and throwing in bits that I require would save me some trouble. Albeit, I don't get where the line is drawn between melee ai and campaign ai, in terms of what code is reserved for melee and what for campaign, if there's a thing like that.
 
I see, well that's exactly my point the campaign AIs are simpler, so it will be easier to transfer over or implement or integrate any added functionality that you need that we can help with. The melee AI script is not designed for campaign missions.

In terms of code being reserved there isn't any but there will probably be some behavioural differences since they are written for two different purposes. Again, if you tell us what you want the AI to do it will be easier for us to help and show you how to achieve what you want :)
 
Level 4
Joined
Apr 14, 2021
Messages
63
Well, for starters, I think a build sequence, economy building (peasant assignments, expansions, etc), defense maintenance and attack waves are a must. I'm not looking for a handout, I simply want to understand which codes or functions would benefit my script, especially since common.ai doesn't really offer explanations, though, I believe functions are not bound to the existing ones.

I can get around the build sequence and maaybe the economy building, from the edited script I sent above, you could take a look and perhaps tell me if it's good enough or if it needs refining. But as far the attack sequence and the defense goes, I'm literally at a loss lol, given how I want the ai to be volatile with it's troop management and strike missions – basically give it more of a randomized feeling.
 
Ok that's fair enough,

Those campaign AIs are probably the better way to go in terms of build sequence, economy building etc apart from the expansion part, you want your campaign AI to expand? Defence maintenance is easy enough you use SetBuildUnitEx for all the pre-placed units and it will replace them when they're killed.

In terms of randomising attacks there's a few ways to do it but you'll want a separate function to do that. How much you split it into other functions is up to you but you'll basically want to set a bunch of integer variables to random integers between 2 numbers and then call those as CampaignAttackerEx with those randomised variables inputed. You can also use SetRandomPaths(true) to make them take random routes towards their enemy.
 
Level 4
Joined
Apr 14, 2021
Messages
63
Sure, I could try and make that work, would I put them as constant integers or just plain simple integers? And in what case would I need a boolean?

Onto the juicy part – how would I create the separate function, do I call it in the main function simply by using the "call" command, and most of all, what would I need to put in it? Same question for "SetRandomPaths(true)", do I call it in the separate function or the main one?
 
JASS:
//============================================================================
//  Stromgarde 04 -- Purple player -- AI Script
//============================================================================
globals
    player Proudmoore = PlayerEx(11) //player 11 Dark Green
    player User = PlayerEx(1) //player 1 Red
    player Ironforge = PlayerEx(9) //Player 9 Grey
   
    constant integer Ghoul = 'ugho'
    constant integer Acolyte = 'uaco'
    constant integer Zombie = 'nzom'
    constant integer Mutant = 'ndmu'
    constant integer Fiend = 'ucry'
    constant integer Necro = 'unec'
    constant integer Necrolyte = 'n60A'
    constant integer SkeleA = 'nska'
    constant integer Wagon = 'umtw'
    constant integer Abomination = 'uabo'
    constant integer Banshee = 'uban'
    constant integer Statue = 'uobs'
    constant integer Wraith = 'n61O'
    constant integer Gargoyle = 'ugar'
    constant integer Golem = 'nfgl'
    constant integer Wight = 'n60G'
    constant integer Wyrm = 'ufro'
    constant integer Eruptor = 'uple'
    constant integer DeathKnight = 'Udea'
    constant integer Rogue = 'O60M'
    constant integer Lich = 'Ulic'
    constant integer HARD_WAVE_DUR      = 90 // seconds
    constant integer NORMAL_WAVE_DUR    = 100 // seconds
    constant integer EASY_WAVE_DUR      = 120 // seconds
    constant integer CMD_SET_X1         = 1
    constant integer CMD_SET_Y1         = 2
    constant integer CMD_SET_X2         = 3
    constant integer CMD_SET_Y2         = 4
    constant integer CMD_SET_X3         = 5
    constant integer CMD_SET_Y3         = 6
    constant integer KulTiras_Dead      = 7
    constant integer Ironforge_Dead     = 8
    constant integer FinalWave          = 9
 
    player Target1                      = PlayerEx(11) //Player 11 Dark Green
    player Target2                      = PlayerEx(1)  //Player 1 Red
    player Target3                      = PlayerEx(9) //Player 9 Grey
    integer stage_x1                    = 0
    integer stage_y1                    = 0
    integer stage_x2                    = 0
    integer stage_y2                    = 0
    integer stage_x3                    = 0
    integer stage_y3                    = 0
    boolean KulTirasDead                = false
    boolean IronforgeDead               = false
    //All unit build times set to 2 seconds in map
    //Hero revive rate set to 300%
endglobals
//============================================================================
//  get_commands
//============================================================================
function get_commands takes nothing returns nothing
    local integer cmd
    local integer data
  
    loop
        loop
            exitwhen CommandsWaiting() != 0
            call Sleep(1)
        endloop
        set cmd  = GetLastCommand()
        set data = GetLastData()
        call PopLastCommand()
       
        if cmd == CMD_SET_X1 then
            set stage_x1 = data
        elseif cmd == CMD_SET_Y1 then
            set stage_y1 = data
        elseif cmd == CMD_SET_X2 then
            set stage_x2 = data
        elseif cmd == CMD_SET_Y2 then
            set stage_y2 = data
        elseif cmd == CMD_SET_X3 then
            set stage_x3 = data
        elseif cmd == CMD_SET_Y3 then
            set stage_y3 = data
        elseif cmd == KulTiras_Dead then
            set KulTirasDead = true
            set Target1 = PlayerEx(1)
            set stage_x1 = stage_x2
            set stage_y1 = stage_y2
        elseif cmd == Ironforge_Dead then
            set IronforgeDead = true
            set Target3 = PlayerEx(1)
        elseif cmd == FinalWave then
        else
        endif
    endloop
endfunction
//============================================================================
//  pit_stop
//============================================================================
function pit_stop takes integer easy, integer normal, integer hard returns nothing
    if difficulty == HARD then
        call Sleep(hard)
    elseif difficulty == NORMAL then
        call Sleep(normal)
    else
        call Sleep(easy)
    endif
endfunction
//============================================================================
//  meat_love
//============================================================================
function meat_love takes nothing returns nothing
    local integer towerCount
    local integer triggerCount
    local integer wagons
    local integer i
    // Count Human towers
    set towerCount = GetPlayerUnitTypeCount(User, 'h00O') + GetPlayerUnitTypeCount(User, 'h00P') + GetPlayerUnitTypeCount(User, 'h602')
    // Set trigger count based on difficulty
    if difficulty == HARD then
        set triggerCount = 4
    elseif difficulty == NORMAL then
        set triggerCount = 6
    else
        set triggerCount = 8
    endif
    if towerCount > triggerCount then
        set wagons = (towerCount - triggerCount) / 2
        if wagons > 12 then
            set wagons = 12
        endif
        set i = 0
        loop
            exitwhen i >= wagons
            call CampaignAttackerEx(1, 1, 1, Wagon)
            set i = i + 1
        endloop
    endif
endfunction
//============================================================================
//  main
//============================================================================
function main takes nothing returns nothing
    call CampaignAI('uzig',null) //Ziggurat
    call GroupTimedLife(true)
    call SetPeonsRepair(true)
    call SetSlowChopping(true)
    call SetRandomPaths(false)
    set campaign_wood_peons = 2
    set campaign_gold_peons = 5
    //Building Strategy
    //Tier 1
    call SetBuildUnitEx(5,5,5,Acolyte) //Acolytes
    call SetBuildUnitEx(3,3,3,'usep') //Crypt
    call SetBuildUnitEx(1,1,1,'ugrv') //Graveyard
    call SetBuildUnitEx(8,8,8,'uzg1') //Spirit Tower
    call SetBuildUnitEx(1,1,1,'uzg2') //Nerubian Tower
    call SetBuildUnitEx(12,12,12,'ntt1') //Death Tower
    call SetBuildUnitEx(1,1,1,'uaod') //Altar
    call SetBuildUnitEx(1,1,1,'ugol') //Haunted Gold Mine
    call SetBuildUnitEx(1,1,1,'utom') //Tomb of Relics
    //Tier 2
    call SetBuildUnitEx(3,3,3,'uslh') //Slaughterhouse
    call SetBuildUnitEx(2,2,2,'utod') //Temple of the Damned
    call SetBuildUnitEx(1,1,1,'usap') //Sacrifical Pit
    //Tier 3
    call SetBuildUnitEx(1,1,1,'unp2') //Black Citadel
    call SetBuildUnitEx(1,2,2,'ubon') //Boneyard
    //Defender Units
    call CampaignDefenderEx(1,1,1,Wight)
    call CampaignDefenderEx(1,1,1,Golem)
    call CampaignDefenderEx(2,2,2,Wyrm)
   
    call StartThread(function get_commands)
    //Attack Waves
    //Wave 1 //Basic Wave 1
    call SetCaptainHome(ATTACK_CAPTAIN,stage_x1,stage_y1)
    call InitAssaultGroup()
    call CampaignAttackerEx(5,6,10,Ghoul)
    call CampaignAttackerEx(4,4,6,Fiend)
    call SuicideOnPlayerEx(80,80,80,Target1)    //M1 20s All Difficulties (Tested on hard and launched at 2:45)
     
    //Wave 2 //Basic Wave 2
    call SetCaptainHome(ATTACK_CAPTAIN,stage_x2,stage_y2)
    call InitAssaultGroup()
    call CampaignAttackerEx(6,8,12,Ghoul)
    call CampaignAttackerEx(4,6,8,SkeleA)
    call CampaignAttackerEx(0,0,1,Wagon)
    call meat_love()
    call SuicideOnPlayerEx(EASY_WAVE_DUR,NORMAL_WAVE_DUR,HARD_WAVE_DUR,Target2)    //E:M5 N:M4 40s H:M4.5 (Tested on hard and launched at 4:25)
    //Wave 3 //Basic Wave 3
    call SetCaptainHome(ATTACK_CAPTAIN,stage_x3,stage_y3)
    call InitAssaultGroup()
    call CampaignAttackerEx(6,8,12,Ghoul)
    call CampaignAttackerEx(4,5,7,Fiend)
    call CampaignAttackerEx(0,0,1,Wagon)
    call meat_love()
    call SuicideOnPlayerEx(EASY_WAVE_DUR,NORMAL_WAVE_DUR,HARD_WAVE_DUR,Target3)    ////E:M7 N:M6 10s H:M6 (Tested on hard and launched at 6:25)
    //
    //Wave 4 //Banshee Wave
    call SetCaptainHome(ATTACK_CAPTAIN,stage_x1,stage_y1)
    call InitAssaultGroup()
    call CampaignAttackerEx(1,2,3,Abomination)
    call CampaignAttackerEx(6,8,10,Banshee)
    call CampaignAttackerEx(0,0,1,Wagon)
    call CampaignAttackerEx(1,1,1,Lich)
    call meat_love()
    call SuicideOnPlayerEx(120,120,120,Target1)    //E:M9 N:M8 10s H:M8
    //Wave 5 //Wight
    call SetCaptainHome(ATTACK_CAPTAIN,stage_x2,stage_y2)
    call InitAssaultGroup()
    call CampaignAttackerEx(2,2,3,Wight)
    call CampaignAttackerEx(3,4,5,Eruptor)
    call CampaignAttackerEx(3,4,5,Ghoul)
    call CampaignAttackerEx(0,0,1,Wagon)
    call CampaignAttackerEx(1,1,1,DeathKnight)
    call meat_love()
    call SuicideOnPlayerEx(EASY_WAVE_DUR,NORMAL_WAVE_DUR,HARD_WAVE_DUR,Target2)    //E:M11 N:M9 50s H:M9.5
    //Wave 6 //Casters
    call SetCaptainHome(ATTACK_CAPTAIN,stage_x3,stage_y3)
    call InitAssaultGroup()
    call CampaignAttackerEx(3,3,4,Abomination)
    call CampaignAttackerEx(3,3,4,Necrolyte)
    call CampaignAttackerEx(3,4,5,Necro)
    call CampaignAttackerEx(3,4,5,Wraith)
    call CampaignAttackerEx(1,1,1,Rogue)
    call SuicideOnPlayerEx(EASY_WAVE_DUR,NORMAL_WAVE_DUR,HARD_WAVE_DUR,Target3)    //E:M13 N:M11 30s H:M11
    //
    //Wave 7 //Anti Air
    call SetCaptainHome(ATTACK_CAPTAIN,stage_x1,stage_y1)
    call InitAssaultGroup()
    call CampaignAttackerEx(1,2,3,Wight)
    call CampaignAttackerEx(2,2,3,Fiend)
    call CampaignAttackerEx(3,4,5,SkeleA)
    call CampaignAttackerEx(5,7,9,Gargoyle)
    call CampaignAttackerEx(1,1,1,Lich)
    call meat_love()
    call SuicideOnPlayerEx(60,60,60,Target1)    //E:M14 N:M12 30s H:M12
    //Wave 8 //Siege Wave
    call SetCaptainHome(ATTACK_CAPTAIN,stage_x2,stage_y2)
    call InitAssaultGroup()
    call CampaignAttackerEx(1,1,1,Golem)
    call CampaignAttackerEx(3,5,6,Abomination)
    call CampaignAttackerEx(2,2,3,Wyrm)
    call CampaignAttackerEx(4,5,7,Wagon)
    call CampaignAttackerEx(1,1,1,DeathKnight)
    call SuicideOnPlayerEx(EASY_WAVE_DUR,NORMAL_WAVE_DUR,HARD_WAVE_DUR,Target2)    //E:M16 M:M14 10s H:M13.5
    //Wave 9 //WightGolem Wave
    call SetCaptainHome(ATTACK_CAPTAIN,stage_x3,stage_y3)
    call InitAssaultGroup()
    call CampaignAttackerEx(5,6,8,Golem)
    call CampaignAttackerEx(1,2,3,Wight)
    call CampaignAttackerEx(1,1,1,Rogue)
    call meat_love()
    call SuicideOnPlayerEx(EASY_WAVE_DUR,NORMAL_WAVE_DUR,HARD_WAVE_DUR,Target3)    //E:M18 M:M15 50s H:M15
    //
    //Wave 10 //Plague Wave
    call SetCaptainHome(ATTACK_CAPTAIN,stage_x1,stage_y1)
    call InitAssaultGroup()
    call CampaignAttackerEx(4,4,6,Ghoul)
    call CampaignAttackerEx(2,3,4,Eruptor)
    call CampaignAttackerEx(3,5,7,Abomination)
    call CampaignAttackerEx(1,1,2,Wagon)
    call CampaignAttackerEx(3,3,4,Necro)
    call meat_love()
    call SuicideOnPlayerEx(120,120,120,Target1)    //M2
    //Wave 11 //Skeleton Wave
    call SetCaptainHome(ATTACK_CAPTAIN,stage_x2,stage_y2)
    call InitAssaultGroup()
    call CampaignAttackerEx(3,4,6,Necrolyte)
    call CampaignAttackerEx(4,4,6,Abomination)
    call CampaignAttackerEx(1,1,2,Wagon)
    call CampaignAttackerEx(5,6,8,Necro)
    call meat_love()
    call SuicideOnPlayerEx(EASY_WAVE_DUR,NORMAL_WAVE_DUR,HARD_WAVE_DUR,Target2)    //M2
    //Wave 12 //F_U Wave 1
    call SetCaptainHome(ATTACK_CAPTAIN,stage_x3,stage_y3)
    call InitAssaultGroup()
    call CampaignAttackerEx(2,2,3,Wight)
    call CampaignAttackerEx(4,5,6,Eruptor)
    call CampaignAttackerEx(1,1,2,Wagon)
    call CampaignAttackerEx(2,2,3,Necro)
    call CampaignAttackerEx(2,2,3,Banshee)
    call CampaignAttackerEx(2,2,3,Wyrm)
    call SuicideOnPlayerEx(EASY_WAVE_DUR,NORMAL_WAVE_DUR,HARD_WAVE_DUR,Target3)    //M2
    //
    //Wave 13 //F_U Wave 2
    call SetCaptainHome(ATTACK_CAPTAIN,stage_x1,stage_y1)
    call InitAssaultGroup()
    call CampaignAttackerEx(2,2,3,Golem)
    call CampaignAttackerEx(3,4,5,Abomination)
    call CampaignAttackerEx(1,1,2,Wagon)
    call CampaignAttackerEx(2,2,3,Necrolyte)
    call CampaignAttackerEx(2,2,3,Wraith)
    call CampaignAttackerEx(5,6,7,SkeleA)
    call SuicideOnPlayerEx(120,120,120,Target1)    //M2
    //Wave 14 //F_U Wave 3
    call SetCaptainHome(ATTACK_CAPTAIN,stage_x2,stage_y2)
    call InitAssaultGroup()
    call CampaignAttackerEx(2,2,3,Golem)
    call CampaignAttackerEx(3,3,4,Wight)
    call CampaignAttackerEx(2,2,3,Wagon)
    call CampaignAttackerEx(2,2,3,Wraith)
    call CampaignAttackerEx(2,3,4,Eruptor)
    call CampaignAttackerEx(3,3,4,Banshee)
    call CampaignAttackerEx(2,2,3,Wyrm)
    call SuicideOnPlayerEx(EASY_WAVE_DUR,NORMAL_WAVE_DUR,HARD_WAVE_DUR,Target2)    //M2
    //Wave 15 //Casters
    call SetCaptainHome(ATTACK_CAPTAIN,stage_x3,stage_y3)
    call InitAssaultGroup()
    call CampaignAttackerEx(3,3,4,Abomination)
    call CampaignAttackerEx(3,3,4,Necrolyte)
    call CampaignAttackerEx(3,4,5,Necro)
    call CampaignAttackerEx(3,4,5,Wraith)
    call CampaignAttackerEx(1,1,1,Rogue)
    call meat_love()
    call SuicideOnPlayerEx(EASY_WAVE_DUR,NORMAL_WAVE_DUR,HARD_WAVE_DUR,Target3)    //E:M13 N:M11 30s H:M11
    //
    //Wave 16 //Plague Wave
    call SetCaptainHome(ATTACK_CAPTAIN,stage_x1,stage_y1)
    call InitAssaultGroup()
    call CampaignAttackerEx(4,4,6,Ghoul)
    call CampaignAttackerEx(2,3,4,Eruptor)
    call CampaignAttackerEx(3,5,7,Abomination)
    call CampaignAttackerEx(1,1,2,Wagon)
    call CampaignAttackerEx(3,3,4,Necro)
    call meat_love()
    call SuicideOnPlayerEx(120,120,120,Target1)    //M2
    //Wave 17 //Banshee Wave
    call SetCaptainHome(ATTACK_CAPTAIN,stage_x1,stage_y1)
    call InitAssaultGroup()
    call CampaignAttackerEx(2,3,4,Abomination)
    call CampaignAttackerEx(8,10,12,Banshee)
    call CampaignAttackerEx(0,0,1,Wagon)
    call CampaignAttackerEx(1,1,1,Lich)
    call meat_love()
    call SuicideOnPlayerEx(EASY_WAVE_DUR,NORMAL_WAVE_DUR,HARD_WAVE_DUR,Target2)    //M2
    //Wave 18 //F_U Wave 3
    call SetCaptainHome(ATTACK_CAPTAIN,stage_x2,stage_y2)
    call InitAssaultGroup()
    call CampaignAttackerEx(2,2,3,Golem)
    call CampaignAttackerEx(3,3,4,Wight)
    call CampaignAttackerEx(2,2,3,Wagon)
    call CampaignAttackerEx(2,2,3,Wraith)
    call CampaignAttackerEx(2,3,4,Eruptor)
    call CampaignAttackerEx(3,3,4,Necrolyte)
    call CampaignAttackerEx(2,2,3,Wyrm)
    call SuicideOnPlayerEx(EASY_WAVE_DUR,NORMAL_WAVE_DUR,HARD_WAVE_DUR,Target2)    //M2
      
    loop
        //Wave 12 //F_U Wave 1
        call SetCaptainHome(ATTACK_CAPTAIN,stage_x1,stage_y1)
        call InitAssaultGroup()
        call CampaignAttackerEx(2,2,3,Wight)
        call CampaignAttackerEx(4,5,6,Eruptor)
        call CampaignAttackerEx(1,1,2,Wagon)
        call CampaignAttackerEx(2,2,3,Necro)
        call CampaignAttackerEx(2,2,3,Banshee)
        call CampaignAttackerEx(2,2,3,Wyrm)
        call meat_love()
        call SuicideOnPlayerEx(EASY_WAVE_DUR,NORMAL_WAVE_DUR,HARD_WAVE_DUR,Target3)    //M2
        //Wave 13 //F_U Wave 2
        call SetCaptainHome(ATTACK_CAPTAIN,stage_x2,stage_y2)
        call InitAssaultGroup()
        call CampaignAttackerEx(2,2,3,Golem)
        call CampaignAttackerEx(3,4,5,Abomination)
        call CampaignAttackerEx(1,1,2,Wagon)
        call CampaignAttackerEx(2,2,3,Necro)
        call CampaignAttackerEx(2,2,3,Banshee)
        call CampaignAttackerEx(5,6,7,SkeleA)
        call meat_love()
        call SuicideOnPlayerEx(EASY_WAVE_DUR,NORMAL_WAVE_DUR,HARD_WAVE_DUR,Target1)    //M2
        //Wave 14 //F_U Wave 3
        call SetCaptainHome(ATTACK_CAPTAIN,stage_x3,stage_y3)
        call InitAssaultGroup()
        call CampaignAttackerEx(2,2,3,Golem)
        call CampaignAttackerEx(3,3,4,Wight)
        call CampaignAttackerEx(2,2,3,Wagon)
        call CampaignAttackerEx(2,2,3,Necro)
        call CampaignAttackerEx(3,4,5,Eruptor)
        call CampaignAttackerEx(3,3,4,Banshee)
        call CampaignAttackerEx(2,2,3,Wyrm)
        call meat_love()
        call SuicideOnPlayerEx(EASY_WAVE_DUR,NORMAL_WAVE_DUR,HARD_WAVE_DUR,Target2)    //M2
    endloop
endfunction

Here's an example of a campaign AI I'm currently working on that uses functions for different things. So as we can see we have the "main" function where everything gets done and is what runs. You'll also see at the start of main where things like SetRandomPaths gets called these are all things that won't change so they're set at the start, slow chopping too so the AI never runs out of resources. You'll see the function meat_love I define earlier which adds extra Meat Wagons depending upon how many towers the player builds, it gets called within the set-up for every attack wave.

So yeah all functions have to be called using "call functionname" and variables are set using "set VariableName = __". You would want them as plain integers or maybe local integers. Constant integers are... constant and so cannot be changed. For the random int you'll want to use:

native GetRandomInt takes integer lowBound, integer highBound returns integer

So for example we could do:
function Random_Swordsmen takes nothing returns nothing
local integer Number

set Number = GetRandomInt(0,4)
call CampaignAttacker(NORMAL,Number, HIGH_ELF_SWORDSMAN)

endfunction

Then in main when you're prepping your attack waves you would do

call InitAssaultGroup()
call Random_Swordsmen()
call SuicideOnPlayer(M1,Player)

And it will send between 0 and 4 swordsmen to attack the player. Now the syntax might not be exactly correct here but it should give you a general idea :)

EDIT: JASS Manual: API Browser - common.j


These are online versions of the common.ai and common.j file in Wc3 that shows all the JASS functions you can use and how they work. They do go down and down until they will reach functions that are hardcoded and hidden under the hood but they should still help.
 
Level 4
Joined
Apr 14, 2021
Messages
63
Going through the script you provided and thinking a little about the example you gave, funnily enough, I understand it, though, not everything.

I'll try adjusting my code further in the morning and I'll get back to you.

In the meantime, what exactly is common.j? It obviously goes in correlation with common.ai, but common.ai is filled with things I am aware of, unlike common.j
 
Common.j is pretty much every JASS function you will use, so when you're triggering what those GUI actions, events etc actually are, under the hood are these JASS functions in common.j. By contrast, common.ai is all the functions relating to AI scripts.
 
Top