• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[JASS] Campaign AI, weird issue with custom buildings order

Level 16
Joined
Apr 20, 2014
Messages
523
As far as I know, AI has issue with custom Town Hall and all. With classic buildings, if you order:
JASS:
call SetBuildUnit(1, TOWN_HALL)
call SetBuildUnit(1, KEEP)
call SetBuildUnit(1, CASTLE)
It will build a single Town Hall and then upgrade it until Castle.

But, if you do the same with custom buildings, it will build a custom Town Hall, then upgrade it to custom Keep AND build a new Town Hall, which it's not what we want.

So I myself tried to find a solution:

JASS:
    if (((GetUnitCount(KEEPD) == 0) and (GetUnitCount(CASTLED) == 0))) then
        call SetBuildUnit(1, TOWND)
    endif
    if (((GetUnitCount(TOWND) == 1) and (GetUnitCount(CASTLED) == 0))) then
        call SetBuildUnit(1, KEEPD)
    endif
    if (((GetUnitCount(TOWND) == 0) and (GetUnitCount(KEEPD) == 1))) then
        call SetBuildUnit(1, CASTLED)
    endif
(Note that it's custom units)

I tried to make something like: don't build a new town hall if you have one.

In fact, I thought it worked perfectly... but nope.
The function GetUnitCount seems to work only once: at the beginning of the map.


If you make the AI start with no buildings: Town Hall is builded but not upgraded
If you make the AI start with a Keep: Keep is upgraded to Castle and no new Town Hall is builded. But if it's destroyed, it's not builded again.
...
As you can see, the IF conditions are respected only at the launch.


So my great question is: is there a way to make the "GetUnitCount" being checked in real-time?
Or is there a total different solution?

Thanks.
 
Level 18
Joined
Mar 16, 2008
Messages
721
Try using build expansion instead of town hall?

JASS:
call BuildExpansion( TOWN_HALL, TOWN_HALL )

there's something different with town halls that i'm trying to figure out. i'm having a problem where once the AI's town hall gets destroyed, it won't rebuild. Maybe someone who understands AI expansions better could explain the correct way to have AIs expand. If you look in this guide, he has quite an intricate system regarding expansions. I'm considering implementing it to my script.


JASS:
constant integer BUILD_EXPAND       = 3

//============================================================================
function SetBuildExpa takes integer qty, integer unitid returns nothing
    call SetBuildAll(BUILD_EXPAND,qty,unitid,-1)
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 StartExpansion takes integer qty, integer hall returns boolean
    local integer count
    local integer town
    local unit    peon
    local integer gold_cost

    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
        return SetExpansion(peon,hall)
    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
 
Last edited:
Level 28
Joined
Feb 18, 2014
Messages
3,579
That happens because your custom buildings are not defined in common.ai file. The AI doesn't understand that your custom keep is an upgraded version of your custom hall, so it builds a new one instead.
JASS:
function TownCountEx takes integer unitid, boolean only_done, integer townid returns integer

    local integer have_qty = GetUnitCountEx(unitid,only_done,townid)

    if unitid == TOWN_HALL then
        set have_qty = have_qty + GetUnitCountEx(KEEP,false,townid) + GetUnitCountEx(CASTLE,false,townid)
    elseif unitid == KEEP then
        set have_qty = have_qty  + GetUnitCountEx(CASTLE,false,townid)

    elseif unitid == WATCH_TOWER then
        set have_qty = have_qty + GetUnitCountEx(GUARD_TOWER,false,townid) + GetUnitCountEx(CANNON_TOWER,false,townid) + GetUnitCountEx(ARCANE_TOWER,false,townid)

    elseif unitid == PEASANT then
        set have_qty = have_qty + GetUnitCountEx(MILITIA,false,townid)

    elseif unitid == GREAT_HALL then
        set have_qty = have_qty + GetUnitCountEx(STRONGHOLD,false,townid) + GetUnitCountEx(FORTRESS,false,townid)
    elseif unitid == STRONGHOLD then
        set have_qty = have_qty + GetUnitCountEx(FORTRESS,false,townid)

    elseif unitid == HEAD_HUNTER then
        set have_qty = have_qty + GetUnitCountEx(BERSERKER,false,townid)

    elseif unitid == SPIRIT_WALKER then
        set have_qty = have_qty + GetUnitCountEx(SPIRIT_WALKER_M,false,townid)
    elseif unitid == SPIRIT_WALKER_M then
        set have_qty = have_qty + GetUnitCountEx(SPIRIT_WALKER,only_done,townid)

    elseif unitid == NECROPOLIS_1 then
        set have_qty = have_qty + GetUnitCountEx(NECROPOLIS_2,false,townid) + GetUnitCountEx(NECROPOLIS_3,false,townid)
    elseif unitid == NECROPOLIS_2 then
        set have_qty = have_qty + GetUnitCountEx(NECROPOLIS_3,false,townid)

    elseif unitid == ZIGGURAT_1 then
        set have_qty = have_qty + GetUnitCountEx(ZIGGURAT_2,false,townid) + GetUnitCountEx(ZIGGURAT_FROST,false,townid)

    elseif unitid == GARGOYLE then
        set have_qty = have_qty + GetUnitCountEx(GARGOYLE_MORPH,false,townid)

    elseif unitid == TREE_LIFE then
        set have_qty = have_qty + GetUnitCountEx(TREE_AGES,false,townid) + GetUnitCountEx(TREE_ETERNITY,false,townid)
    elseif unitid == TREE_AGES then
        set have_qty = have_qty + GetUnitCountEx(TREE_ETERNITY,false,townid)

    elseif unitid == DRUID_TALON then
        set have_qty = have_qty + GetUnitCountEx(DRUID_TALON_M,false,townid)
    elseif unitid == DRUID_TALON_M then
        set have_qty = have_qty + GetUnitCountEx(DRUID_TALON,only_done,townid)

    elseif unitid == DRUID_CLAW then
        set have_qty = have_qty + GetUnitCountEx(DRUID_CLAW_M,false,townid)
    elseif unitid == DRUID_CLAW_M then
        set have_qty = have_qty + GetUnitCountEx(DRUID_CLAW,only_done,townid)

    elseif unitid == ILLIDAN then
        set have_qty = have_qty + GetUnitCountEx(ILLIDAN_DEMON,false,townid)

    endif
    return have_qty
endfunction
To fix this issue, you have to add a new condition for your custom building below one of the conditions above.
 
Level 18
Joined
Mar 16, 2008
Messages
721
you can probably do with GUI. Do you know how to make GUI conditions?

1691387300818.png
 
Level 6
Joined
Jun 7, 2016
Messages
30
Build an AI Script for Night Elves, i only altered the basic model, and it works fine. Then from the Night Elves AI Script as the base, i made for my New Custom Techtree and it always build several Town Halls,
How to make AI recognize my custom buildings is the upgraded version of the previous town hall with GUI?
 
Level 18
Joined
Mar 16, 2008
Messages
721
Use the arithmatic settings so it goes a + b + c = 0, zero or whatever number of expansions you want

1691391922910.png

right now you have a = 0, and, b = 0, and, c = 0 [EDIT: maybe this method won't be a problem???]

ok so how many bases do you want it to have?

so let's say you want two bases, which is a main plus one expansion.

so you will do

upgrade to t2 if (t2 + t3 = 0)
upgrade to t3 if (t3 = 0)
build expansion if (t1 + t2 + t3 < 3)

i think that would work right?
 
Last edited:
Level 18
Joined
Mar 16, 2008
Messages
721
Does anyone have an example JassAI for this? I'm quite stumped.
Here is a good one for Campaign AIs:

If you want a more melee AI then copy from the GUI AI Editor.
 
Level 16
Joined
Apr 20, 2014
Messages
523
Does anyone have an example JassAI for this? I'm quite stumped.
Here is my building order in my "player7.ai", TOWND, KEEPD and CASTLED being custom units:
1709750298741.png

Then we have common.ai file with this function:
1709750434418.png

where I added this at the end for my custom units:
1709750449328.png


This custom common.ai must be imported on your map aswell.

Was this your question?
 
Level 18
Joined
Mar 16, 2008
Messages
721
Yup. I figured it out after posting, but thanks regardless. Does anyone have a tutorial or something about making the AI play around with expansions?
There are little to no resources on this topic. My memory is a bit rusty but I've tried to consolidate some of my thoughts about AI expansions in this post:

I don't think any of these functions actually caused a crash rather it was related to a unit having no pathing, which can cause AI scripts to crash WC3.

I don't know if these work with a "campaign" AI. I use melee AI based on the GUI AI editor's template. My "insane king" script in kings and knights is a solid example of a AI that creeps, expands by only .ai script.
 
Top