• 🏆 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!

[General] Attempting to make functioning AI

Status
Not open for further replies.
Level 6
Joined
Mar 31, 2012
Messages
169
War3 AI has a lot of crippling issues that I have to resolve if I'm going to make large scale singleplayer maps. The first major one is that it sometimes retreats after killing 5 units or 1 tower rather than continuing to attack like in other RTS games. I believe this could be related to CaptainGoHome() so one thought I had was to dig through common.ai and prevent that from ever being called unless I expressly do so in the aiscript, but in case this is an obviously foolhardy fix, or in case someone has already solved this and I simply don't know about it, I'm posting about it now before I investigate that solution.

The second main issue is the fact that the units often chase the captain unit and outright refuse to respond to being attacked, so one guard tower can shut down an entire attack force if the captain unit gets stuck inside its range. Given War3's poor pathfinding this is an inevitability regardless of map structure, and a problem that map developers shouldn't have to deal with. Would be nice to have some sort of alternative attack handling system that doesn't require a bunch of hackneyed triggers, but failing that sorcery, it'd be nice to see a less radical solution to this issue that just makes the AI aggressive without trying to do fancy blizzard stuff like "retreating" forever while one tower kills the whole wave.

The third (because 3) thing I'd like to ask about is a surefire way to make AI expand and tech, as my peers have had issues having these things occur consistently. If there are example scripts that will handle this, and also accept entirely custom techtrees and etc, that'd be really helpful. I would also like to find a way to make the AI actually play fair with resources but I'm not holding my breath for that, since they barely ever even harvest wood consistently, let alone spend the money they get.

If any more clarification on any of these THREE issues is needed, let me know.
 
Well, are you basing your AIs on melee AIs?

1. Because in Campaign AIs, you can set a bunch of options like:
JASS:
    call SetCampaignAI(  )
    call SetTargetHeroes( false )
    call SetPeonsRepair( true )
    call SetHeroesFlee( false )
    call SetHeroesBuyItems( true )
    call SetUnitsFlee( false )
    call SetGroupsFlee( false )
    call SetWatchMegaTargets( true )
    call SetIgnoreInjured( false )
    call SetHeroesTakeItems( true )
    call SetSlowChopping( true )
    call SetCaptainChanges( false )
    call SetSmartArtillery( true )
    call GroupTimedLife(true)
    call DoCampaignFarms(false)
You can for example call SetUnitsFlee( false ) and call SetGroupsFlee( false ). With these you can control many of the aspects of your AI.

2. Note that, as far as I know, there is no such thing as a captain unit. Captains are purely programming constructs. There are two captains: Attack Captain and Defense Captain. In campaign AIs, we usually suicide units. Having a retreating behaviour is more of a melee thing, which you can disable with options if you like. I am not sure if there is additional retreating behaviour programmed in common.ai on top of what the AI does naturally.

3. I have no experience in making the AI to expand, but there are a few natives that relate to that, such as:
JASS:
native GetExpansionFoe      takes nothing                               returns unit
native GetExpansionX        takes nothing                               returns integer
native GetExpansionY        takes nothing                               returns integer
You can check how they are used in common.ai.

Teching should be very easy. You just do something like this in your BuildPriorites:
JASS:
    call SetBuildUpgrEx(0, 1, 2, YG_STEEL_MELEE_WEAPONS)
    call SetBuildUpgrEx(0, 1, 2, YG_STEEL_ARMOR)
    call SetBuildUpgrEx(0, 1, 2, YG_STEEL_RANGED_WEAPONS)
    call SetBuildUpgrEx(0, 1, 2, YG_WARLOCK_ADEPT_TRAINING)
    call SetBuildUpgrEx(0, 1, 1, YG_IMPROVED_BOWS)
    call SetBuildUpgrEx(0, 1, 1, YG_MARKSMANSHIP)
    call SetBuildUpgrEx(0, 0, 1, YG_POISONED_ARROWS)
    call SetBuildUpgrEx(0, 0, 1, YG_FURY_SLASH)
 
Level 12
Joined
Jun 15, 2016
Messages
472
Expending a bit on @Tommi Gustafsson 's answer, which is very much correct:

0. Campaign AI and melee AI behave differently. You should specify what kind of AI you want, and learn existing scripts accordingly. Also, here is a link to the common.ai file from version 1.6, afaik it hadn't changed at all in the last 15 years. Lastly, if your problems are with campaign AI you should read up on that here.

1. There are two possible reasons for an enemy attack group to "flee": either it's actually fleeing (in that case tommi's answer should fix this), or they have received a different instruction (I will focus on that). You should first see that your problem is not with fleeing, then see the suggestions here.

That second option shouldn't actually happen in a campaign AI. the function used for campaign attacks is SuicideOnPlayerEx, and looking at the common.ai you can see that an attack wave ends in the function SuicideOnPlayerWave only when: all attacking units are dead, all possible targets are dead, it took too long to find a target (or a special case when receiving a manual command). If we're talking about a campaign AI, I'd say the last option - taking too long to find a target - is your culprit. We'll take a slightly more detailed look at SuicideOnPlayerWave:

JASS:
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

Consider 2 things: 1) the attack ends once sleep_seconds < -300. 2) the function SuicideSleep(X) lowers the variable sleep_seconds by X. With that considered, if an attack wave takes a lot of time to reach a target, and the next target is not close enough, the condition sleep_seconds < -300 might be true, and the wave terminates.

The melee AI has a more comlicated control flow, but whatever can cause it to change target (again, this is not fleeing as what tommi suggested) can be seen here:

JASS:
function CommonSleepUntilTargetDead takes unit target, boolean reform returns nothing
    loop
        exitwhen CaptainRetreating() // You can actually see here that CaptainRetreating is something you can't control with the AI.
                                                // Also, I believe the function SetGroupsFlee is what makes CaptainRetreating evaluate to true.
        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

Things like low total HP, not finding the target unit, having a town threatened, etc. can all cause your captain to shift targets.

2. I think the problem is your attackers are chasing a unit with a higher priority than, say, a tower. The tower plucks your units off one at a time while they are tripping over one another due to bad pathing. In that case, this is going to be difficult to solve. Truth is, the AI is not developed enough to be this reactive, but there is a possible solution (even if it is not that good):

As tommi wrote, the AI has two "middlemen" for handling units: the attack captain and the defense captain, where the attack captain goes - attacking units follow (and the same goes for the defense captain). Attacking in the AI boils to a few optional "attack natives":

JASS:
native AttackMoveKill       takes unit target                           returns nothing
native AttackMoveXY         takes integer x, integer y                  returns nothing
native SuicidePlayer        takes player id, boolean check_full         returns boolean
native SuicidePlayerUnits   takes player id, boolean check_full         returns boolean

Like tommi said, campaign attack mostly use the native SuicidePlayer - attacking any unit of the player with no discrimination, going partially by target priority set by the object editor for every unit (I think, still not tested). What you can try to do, is to get the location of some of your units (more on how later*), and check for any impeding enemy units or towers surrounding them during an attack (you can do that the same as normal JASS: GroupEnumUnitsInRange or something). If you find a tower, you can force your units to attack it using the native AttackMoveKill. The same answer should work with melee AI, which uses all of the attack natives above for different attacks.

* You can actually use some JASS functions in the AI script, for example calling CreateUnit from an AI script works with no problems. You can try to get a variable to hold some of your units then get their location (special units and heroes should be easy enough to find).

3. Expansion are not very understandable in existing scripts, and I never really tried to understand how they work, so can't help much with that. I can direct you to the common.ai, as well as blizzards melee AI script (Human AI script attached), and @Michael Peppers 's custom AI, which supposedly supports custom techtrees.
 
Level 6
Joined
Mar 31, 2012
Messages
169
Thanks for the detailed replies. I'll try to clear up any confusion now, since I wasn't very clear about my exact intentions in the OP.

What I want is to use war3 as a platform for actual RTS gameplay. Virtually none of the campaign missions accomplish this and the base game is incredibly slow. I've already created a new game state that cuts down unit hp by 60-75%, reduces scale by 20-33%, reduces collision by 33-50%, greatly increases turn rate (virtually removing it), removes heroes, increases attack speed by 33%, and removes passive regeneration. Eventually I will rework every race, item, and spell, most likely removing many of the abilities and making them reward positioning and precision rather than long, prolonged battles. Though this isn't relevant to the technical questions of the AI at face value, I hope this will more clearly spell out my intentions.

In SCBW, I am able to tell AI to expand anywhere I please, and the attacks are much more consistent and never retreat unless the AI's bases are in danger (and even then you can turn this flag off). The AI is actually so much more consistent that you can have it start out with 50 ore and never feed it money, and if it's written well enough it can perform exceptionally well. I don't see a way to make the AI in war3 hold a candle to BW's currently, which is why I'm asking these questions as part of risk assessment for investing time into a war3 project.

Well, are you basing your AIs on melee AIs?
I'm using campaign class. As I understand, it's like BW, where certain functions are precluded depending on the class of script.

Teching should be very easy. You just do something like this in your BuildPriorites:
Are there any tools for debugging when these don't work? And if I wanted to tell them to tech up to a certain structure (e.g. Great Hall -> Stronghold), but they don't, how would I troubleshoot something like this? Assuming I've already confirmed that the function fires with a debug message, and the AI has the tech requirements and resources necessary, but simply won't "click the button" upon receiving instruction.

Things like low total HP, not finding the target unit, having a town threatened, etc. can all cause your captain to shift targets.
Yes, brood war has something vaguely similar to the attack timeout you mentioned, except that's the max number of seconds it can wait before forcing the attack to commence. Here it seems this is paradoxically reversed, and of course in service to a design philosophy entirely polar to mine, making it both incredibly unhelpful and infuriating. Is there a way to prevent this from occurring, either by speeding up the attack selection to consistently select targets well before the 300 seconds mark, or by removing the upper limit entirely?

going partially by target priority set by the object editor for every unit (I think, still not tested).
If this is actually relevant to the AI targeting, I can just reduce the score of towers, but that may jeopardize the positioning of siege weapons, which I don't want. Being able to feed every unit type its own preferences for target selection would be better than what blizzard does where AI just suicide onto towers and siege weapons. I suppose I can partially resolve this issue with my gameplay overhaul anyways, since units will be less sluggish and more responsive from the get go. We'll see where that leaves me.

Regarding your potential fix: I would like to stay away from really complex and inorganic (psuedo)trigger systems where possible, but I also recognize that there's no way to modify the game's innate functions as almost no reverse engineering has been made public in the war3 community. Until an engineer with a messiah complex decides to grace us with their presence, I assume this will not change, as most people have either settled for the half implemented systems that are possible, or moved on to greener pastures. I'll look further into what you described if I'm still running into the suicidal wave issue after more dev time.

It's very unfortunate that expansions seem entirely undocumented and untested. I thought about pulling some from the melee AI but in my experience with BW, melee functions don't mix well with campaign script classes. I'll read up on the references provided by both of you and see if I can come to any more helpful conclusions in that regard. Thanks again for your time and assistance.
 
Level 23
Joined
Jul 26, 2008
Messages
1,317
War3 AI has a lot of crippling issues that I have to resolve if I'm going to make large scale singleplayer maps. The first major one is that it sometimes retreats after killing 5 units or 1 tower rather than continuing to attack like in other RTS games. I believe this could be related to CaptainGoHome() so one thought I had was to dig through common.ai and prevent that from ever being called unless I expressly do so in the aiscript, but in case this is an obviously foolhardy fix, or in case someone has already solved this and I simply don't know about it, I'm posting about it now before I investigate that solution.
Some methods you can use to somewhat circumvent this issue:
1)Remove all delays between attack waves, and have the number of production buildings be the "delay" that determines the time between waves, so if your army attacks 1 unit and retreats, it will automatically go and attack as soon as it has returned to base.
2)Have all main buildings have a long range, low damage attack, so if an enemy wave tries to kill 1 outlying tower, it will be auto provoked to fight.
3)Use terraining to make sure there is no such outlying building/tower.

The third (because 3) thing I'd like to ask about is a surefire way to make AI expand and tech, as my peers have had issues having these things occur consistently. If there are example scripts that will handle this, and also accept entirely custom techtrees and etc, that'd be really helpful. I would also like to find a way to make the AI actually play fair with resources but I'm not holding my breath for that, since they barely ever even harvest wood consistently, let alone spend the money they get.
I have never heard of campaign AI expanding. Your best best would be to research the AI for the maps ROC NE05 (Cenarius map, but this is a bad choice since NE forces taking over bases might not be real expansion, just triggering) or FT UD08 (Illidan v Arthas map, probably the best choice for research since to my knowledge Illidan "expands" whenever he takes/retakes an obelisk).
 
Level 6
Joined
Mar 31, 2012
Messages
169
1)Remove all delays between attack waves, and have the number of production buildings be the "delay" that determines the time between waves, so if your army attacks 1 unit and retreats, it will automatically go and attack as soon as it has returned to base.
My maps will be quite large, so the travel time alone would make this insufficient.
2)Have all main buildings have a long range, low damage attack, so if an enemy wave tries to kill 1 outlying tower, it will be auto provoked to fight.
This seems really awkward and gimmicky, and could easily be gamed by players once they realized what was happening.
3)Use terraining to make sure there is no such outlying building/tower.
See above. If players or other AI build outposts, which happens all the time in larger scale maps, their AI opponents run the risk of retreating after the outpost is dead. Attentive players can game the system this way (I've done it plenty of times when streaming other people's content) and I don't want to prevent players from expanding in large scale maps, obviously, so this can't be the solution.

Good idea about the Illidan map. I'm looking through it now but it's hard to focus on understanding the script when I find comments like "bigger is harder".

edit:
Here's what I found in u08x07.ai
//==================================================================================================
// $Id: u08x07.ai,v 1.3.2.3 2003/05/12 19:54:27 mheiberg Exp $
//==================================================================================================
globals
constant integer SET_X = 1
constant integer SET_Y = 2
endglobals

//--------------------------------------------------------------------------------------------------
// get_coords
//--------------------------------------------------------------------------------------------------
function get_coords takes nothing returns nothing

local integer x = -1
local integer y = -1

local integer cmd
local integer data

loop
loop
exitwhen CommandsWaiting() > 0
call Sleep(0.1)
endloop
set cmd = GetLastCommand()
set data = GetLastData()
call PopLastCommand()

//------------------------------------------------------------------------------------------
if cmd == SET_X then
//------------------------------------------------------------------------------------------
set x = data

//------------------------------------------------------------------------------------------
elseif cmd == SET_Y then
//------------------------------------------------------------------------------------------
set y = data

endif
exitwhen x != -1 and y != -1
endloop

call ShiftTownSpot(R2I(GetStartLocationX(GetPlayerStartLocation(ai_player))), R2I(GetStartLocationY(GetPlayerStartLocation(ai_player))))
call SetCaptainHome(BOTH_CAPTAINS,x,y)
call TeleportCaptain(x,y)
endfunction

//--------------------------------------------------------------------------------------------------
// main
//--------------------------------------------------------------------------------------------------
function main takes nothing returns nothing

call CampaignAI(NAGA_CORAL,null)
call SetPeonsRepair(true)
call get_coords()

call SetBuildUnitEx( 1,1,1, NAGA_CORAL )
call SetBuildUnitEx( 1,1,2, NAGA_SPAWNING )
call SetBuildUnitEx( 1,1,1, NAGA_SHRINE )
call SetBuildUnitEx( 2,2,2, NAGA_CORAL )
call SetBuildUnitEx( 3,3,4, NAGA_GUARDIAN )

loop
exitwhen GetUnitCountDone(NAGA_CORAL) >= 1
call Sleep(1)
endloop

call CampaignDefenderEx( 1,1,2, NAGA_MYRMIDON )
call CampaignDefenderEx( 2,2,3, NAGA_SIREN )
call CampaignDefenderEx( 1,1,1, NAGA_SNAP_DRAGON )
call CampaignDefenderEx( 1,1,2, NAGA_TURTLE )
call CampaignDefenderEx( 1,1,1, NAGA_ROYAL )

call SetBuildUpgrEx( 1,1,1, UPG_SIREN )
call SetBuildUpgrEx( 1,1,1, UPG_NAGA_ENSNARE )
call SetBuildUpgrEx( 1,1,1, UPG_NAGA_ABOLISH )
call SetBuildUpgrEx( 2,2,2, UPG_SIREN )

call SleepForever()
endfunction
It seems the town sleeps until receiving new coordinates (presumably from map triggers) and then starts its build thread after its center and captain(s?) are moved. I'm not sure whether this AI is being run for the same player as the main Illidan town or if it's another blizzard hack where they have 6-7 AIs with the same team color. Maybe someone here knows more about this?

edit 2: looks like the triggers assign the ai town centers and the expansions are all different players. What a mess. Not going to be usable for me. I think I'm going to need to pull expansion logic from the melee AI. Maybe someone else has already done this, so I'll look at the previously linked examples for more info.
 
Last edited:
Level 23
Joined
Jul 26, 2008
Messages
1,317
My maps will be quite large
My personal experience with campaign AI in very large maps is that the AI will completely bug out, and they won't send any attack waves at all. I would suggest, before embarking on this potential project, is to make a random AI on a map and place the enemy team on the other side of the map. Then keep making the map bigger all the while testing each map version to see at what distance the AI just fails to send attack waves due to the massive distance between it and the closest enemy.
 
Are there any tools for debugging when these don't work? And if I wanted to tell them to tech up to a certain structure (e.g. Great Hall -> Stronghold), but they don't, how would I troubleshoot something like this? Assuming I've already confirmed that the function fires with a debug message, and the AI has the tech requirements and resources necessary, but simply won't "click the button" upon receiving instruction.
Well, your best bet is triggers.
1. You can make a trigger that gives all AI units to you and then you can check if the upgrade button actually works. Sometimes, it might have a strange tech requirement or something that prevents the AI from using it.
2. You can make a trigger which sends an AI command to the AI, which in turn makes the AI to print some debug data.
3. You can make a trigger that shows how much the AI has resources.

Well, you get the idea. But I have found the method 1 to be the best in testing custom units and races.
 
Level 6
Joined
Mar 31, 2012
Messages
169
Using Nowow's guide (and a lot of patience) I've been able to make my first AI. One of the first things I had to realize is how dissimilar Jass executes compared to ASM. I have very little experience with C++ so I wasn't used to defining functions before calling them and so on, which caused quite a few headaches earlier today.

I've run into occasional problems with the AI sending more than 5 peasants to the gold mine, which to me seems like there's some strange, undocumented native at work. I've rewritten common.ai to remove the defense captain wood methods in CampaignBasicsA, but I'm not sure if it's actually resolved or not, since the previous behavior was not consistent. I also may have imported common.ai incorrectly? The beginning of CampaignBasicsA looks like this now:
Code:
    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,campaign_wood_peons)

    if harvest_town1 then
        call HarvestGold(1,campaign_gold_peons)
        call HarvestWood(1,campaign_wood_peons)
    endif

    if harvest_town2 then
        call HarvestGold(2,campaign_gold_peons)
        call HarvestWood(2,campaign_wood_peons)
    endif

    if harvest_town3 then
        call HarvestGold(3,campaign_gold_peons)
        call HarvestWood(3,campaign_wood_peons)
And here's the script I wrote, for reference. https://pastebin.com/raw/Yiu5n1Kg

Biggest pain points currently are testing efficiently. I'd like some way to speed the game up, but I've heard that war3 doesn't perform well under these conditions. I'd at least like to let the game run while alt-tabbed, as currently it pauses when not in focus. Any fixes for these? I'm also looking for generic advice from those who're more experienced, maybe I'm doing something wrong with my structure that could be improved. I'll be looking through the melee expansion code soon to see if I can find out how to creep gold mines specifically before attempting to expand. Thanks again for the help.
 
Level 6
Joined
Mar 31, 2012
Messages
169
Remove as in through triggers, or deleting them from the map? Because the AI refuses to work at all if they don't start out with them, which may be something to do with my script I suppose. edit: yeah that was it, I've resolved the issue now. Main problem will be making the AI competitive with players if it can't start out with any peasants.
 
Last edited:
Level 6
Joined
Mar 31, 2012
Messages
169
In the instances where missions begin with cutscenes, I can start the build order early and have them train their first 5 workers. Main issue is they would probably start to harvest resources before the player was able to. I guess I can just set their gold mine contents and the AI player's stockpile to whatever I want after the cutscene though. Thanks for the heads up on that issue.

I'll post again when I have investigated expansions, as I'll undoubtedly need some help with those.
 
Level 12
Joined
Nov 3, 2013
Messages
989
If you're having trouble with units ignoring buildings, try changing the armor type on the structures from Fortified to any other (e.g. Heavy like Guard Towers etc.) (Edit: I just used a guard tower when testing, so units ignore buildings even if they don't have fortified armor) or perhaps changing their 'target as' to something other than 'structure' and maybe units will attack them...


As far as I know, the attack (target) priority works like this:


attacking units > units that aren't workers > attacking workers > workers > attacking buildings > buildings > units attacking a friendly unit (e.g. attacking your own units makes the AI ignore the unit that's attacking unless it's the only remaining target)


Being targeted as 'flying' and/or having a secondary attack with extra range that can only target ground/flying may also have an affect, but I don't really know how it works... (It's just that I've noticed that units that can attack flying units will sometimes ignore other units right in front of them, or change their target, to attack the flying units instead.)



Then there's some other things with the computer AI, like if you attack a hero unit, all nearby enemy units owned by that player (and any allied computer ai units) will all attack the unit that attacked the hero unit.

It's quite easy to test, just have a tower and some units, some enemy units and a hero.

The AI will completely ignore the tower until you attack the hero, if you stop attacking the hero the units will all immediately switch target to your other units. You can keep changing between targeting the hero and regular units to make the AI run back and forth constantly switching between trying to attack the units and the tower...



Then there's the hard coded call for help range (only applies to computer AI players & neutral hostile), so long as you attack a unit within something like 900+ unit range, any computer AI unit will try to attack you regardless of what the call for help range is or their unit acquisition etc.


And the computer AI always focuses low health units, so long as you move a unit with low health within attack range of a computer AI owned unit, the AI will attack that unit, if you leave the attack range the AI will continue attacking any other nearby units instead, if there are any.




All of this happens so long as the player slot is 'computer ai' or it's the neutral hostile player.

But if it's an unused player slot (e.g. simply left open/closed, or a player who left), then none or at least few of the behavior described above applies.

So now that I think about it, maybe it would work to simply run a custom ai script for an empty player slot instead of 'computer ai'...
 
Level 6
Joined
Mar 31, 2012
Messages
169
As far as I know, the attack (target) priority works like this:
They also seem to prioritize siege units (not sure if this is a flag) and workers that are repairing or building, both of which often get their entire army killed as they bumrush a distant or out-of-reach target. I'd like to turn off that behavior at least, but I don't know anything about it beyond that it exists.

So now that I think about it, maybe it would work to simply run a custom ai script for an empty player slot instead of 'computer ai'...
I'd likely have to write a shitload of functions, essentially porting a lot of data from common.ai, since presumably the computer player has some connection to it. Has this been tested or documented anywhere?
 
Level 12
Joined
Nov 3, 2013
Messages
989
Oh right, you can also give ai - ignore guard position a try.

  • AI - Ignore (Picked unit)'s guard position
At least it stops making the AI focus any unit that attacks a hero unit. (Just tested it.) And if I remember correctly it also fixes the hard coded call for help range. Maybe more...
 
Level 6
Joined
Mar 31, 2012
Messages
169
This sounds suspiciously related to SetReplacements, which I'd like to be able to use. I'll need to do some testing related to that.

The hero issue at least is moot since they don't exist in my project, but good to know all the same. Thanks for the info.
 
Level 12
Joined
Jun 15, 2016
Messages
472
Is there a list of all the jass functions that work within aiscript?

Not exactly. There are 3 JASS files compiled to each map: common.j, common.ai and blizzard.j, in that order. And the order is important, as you can only use functions in common.j and common.ai, but can't use the function in blizzard.j. That is not such a big loss considering all native JASS functions are in common.j, and blizzard.j contains compound functions. So, for example you can't use BJDebugMsg in an AI script, but you can use the underlying native DisplayTextToPlayer to create your own debug function etc.

However, this is as inconsistent as any other thing about the AI. For example, using type conversion natives like I2S will crash the map, making debugging a slightly bigger chore. AFAIK there isn't a document of which natives crash the AI, so tread carefully.

You can add this to the top of every map (or simply to your common.ai) to replace BJDebugMsg and some type conversion natives:

JASS:
//-------------------------------------------------------------------------------------------------
// DEBUG FUNCTIONS
//-------------------------------------------------------------------------------------------------

function B2S takes boolean b returns string
    if b then
        return "true"
    else
        return "false"
    endif
endfunction

function Dig2Str takes integer i returns string
    if i == 1 then
        return "1"
    elseif i == 2 then
        return "2"
    elseif i == 3 then
        return "3"
    elseif i == 4 then
        return "4"
    elseif i == 5 then
        return "5"
    elseif i == 6 then
        return "6"
    elseif i == 7 then
        return "7"
    elseif i == 8 then
        return "8"
    elseif i == 9 then
        return "9"
    else
        return "0"
    endif
endfunction

// Courtesy of AIAndy and Tommi. See source:
// http://www.hiveworkshop.com/threads/two-custom-campaign-ais-examples.8939/
function Int2Str takes integer ic returns string
    local string s = ""
    local integer i = ic
    local integer ialt = 0
    local boolean neg = false

    if i == 0 then
      return "0"
    endif
    if i < 0 then
      set neg = true
      set i = (-1)*i
    endif
    loop
      exitwhen i == 0
      set ialt = i
      set i = i / 10
      set s = Dig2Str( ialt - 10*i ) + s
    endloop
    if neg then
      set s = "-"+s
    endif
    return s
endfunction

function Msg takes string m returns nothing
   call DisplayTextToPlayer(user, 0, 0, m)
endfunction
 
Status
Not open for further replies.
Top