Warcraft 3 AI Fix (Use Hero Spells)

Status
Not open for further replies.
Level 3
Joined
Apr 1, 2019
Messages
48
I was not sure where to post this in order to make people easily find this, because I saw a couple of guys in WC3 seeking for this.

However since one of the latest patches, the AI in Warcraft 3 cannot choose Hero spells for their heroes.
In any melee or custom map, it fails the standard AI script and somehow they don't know how to learn a hero spell.
However, if the spell is learnt, they can use it like in the old days.

That was really annoying when I wanted to practice agaisnt AI or similiar occasions.

So I did a kind of "fix".
I did some GUI and jass and it doesn't look very nice, but I made it work and you can easily adjust the settings. I made some triggers which make the AI heroes learn spells via trigger. The order in which they learn them can be adjusted, if you like to do it. I just did write it very fast, so ... no thoughts about the order.

How to use it:
- I attached a trigger file to this post ('AI fix triggers.zip').
- There are 2 files in it you must have both of them in the same directory!
- Just download it, open the map you wanna play with AI in the World Editor. Copy that map or save it with different name to not override it.
- Then go to the "Trigger"-Section in the World Editor (it is the 'a'-Symbol).
- Then: File -> Import Triggers -> Choose the .wtg file (but make sure the other file is in same directory).
- Then go to "Scenario -> Map Options" and on the bottom of this new window is an option called "Game Data Set". Change it to "Melee (Latest Patch)" because otherwise the editor will most likely save your map in a very old WC3 version.
- Save map and play (or adjust the order of the spell learning in the trigger section).

This will make a melee map marked as "non melee", because it has triggers. Anyway I did nothing else but make the computer-controlled heroes learn their spells, so they can use it.

It would be nice to mention me if you use it.

I also attached the "emerald gardens" (normal WC3 TFT map) in which I imported the AI fix, so you can see how it should look like.
 

Attachments

  • AI fix triggers.zip
    2.6 KB · Views: 537
  • (12)emeraldgardens AI fix.w3x
    318.2 KB · Views: 310
Level 3
Joined
Apr 1, 2019
Messages
48
How does this even make sense since they both should be using the same AI files...
Good question, here is what I think about it:
The AI in classic is broken since a few patches. That might be around the time they had the first versions of the Closed Beta for Reforged.
So what I think is, that they plan to make the AI a bit harder in Reforged and as soon as both games can be played together, the AI in Classic will be the same as in Reforged and therefore updated.

I think this, or something similiar, is the reason why the AI in classic cannot learn hero spells but the reforged AI can do it.
However, you can test it if you don't believe me, the AI in classic still cannot learn hero spells without my script.
AI in Reforged can do.

EDIT:
You may have realized that Reforged is running on another patch than classic, yet.
It is not the same game yet, but it will be.
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,285
The AI in classic is broken since a few patches. That might be around the time they had the first versions of the Closed Beta for Reforged.
So what I think is, that they plan to make the AI a bit harder in Reforged and as soon as both games can be played together, the AI in Classic will be the same as in Reforged and therefore updated.
Except the classic AI should already be the same as reforged? The AI is working in 1.32 beta and switching to classic graphics should only change what assets are loaded, and not what AI file is loaded...

However, you can test it if you don't believe me, the AI in classic still cannot learn hero spells without my script.
AI in Reforged can do.
Without the beta I cannot test 1.32 with classic graphics if the AI is broken.
You may have realized that Reforged is running on another patch than classic, yet.
It is not the same game yet, but it will be.
Reforged runs on the same patches as classic. Just the patch containing Reforged, 1.32, is only being released next month. As I mentioned already...
I think this AI bug is fixed for 1.32.
Since people say the AI in the reforged beta (1.32) is working. I do not see why playing with classic graphics should suddenly make the game select a different, broken AI file. Especially seeing how reforged and classic graphics are meant to be cross compatible when playing melee.
 
Level 3
Joined
Apr 1, 2019
Messages
48
They are meant to be cross compatible but they are not yet!

Classic and Reforged are 2 different games right now.
Classic will get a big update (as soon as it gets integrated in the blizzard batlenet launcher ) and then I think the AI problem will be solved too.

There are 2 different AIs right now.

AI in classic will not choose hero spells (since more than half a year)
AI in reforged chooses hero spells.

I tested it.

Further Discussion in the "Patches" Topic, but not here.
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,285
Classic and Reforged are 2 different games right now.
No they are not... Classic is just the default graphics for Warcraft III. Reforged graphics are behind a pay wall (licence check) and are being added in 1.32.
Classic will get a big update (as soon as it gets integrated in the blizzard batlenet launcher ) and then I think the AI problem will be solved too.
You mean 1.32, which is in beta test for anyone who pre-ordered Reforge?
There are 2 different AIs right now.
In 1.32 there should only be 1 AI, which is the AI from 1.31 with its bugs fixed. This AI should be used irrespective of what graphics you have Warcraft III set to. This is required since players running classic graphics have to be able to play melee containing AI players with players running reforged graphics.
 
Level 3
Joined
Apr 1, 2019
Messages
48
Again, this is not the thread to discuss this!
Where do you gain your information from? You are wrong! Did you play both? I do play both!

Reforged is on a whole other patch than Classic. Example: Necromancer 'Raise Dead' Ability, 'Cripple' Ability, etc.
Classic: First Cripple
Reforged: First Raise Dead


Additionally I want to stretch the fact, the only thing important for this thread is the following fact:


The AI in Reforged currently can learn and use hero abilities.
The AI in Classic WC3 currently cannot learn and use hero abilities.
That's why my script is currently for WC 3 classic, so the AI learns hero spells there.



If you wanna continue a non relevant discussion on the differences of Reforged, you are free to write me in private or in the official discussion topic!

Edit:
I added 2 screens in order to prove my statement.
 

Attachments

  • Warcraft 3 cripple classic.PNG
    Warcraft 3 cripple classic.PNG
    111.4 KB · Views: 384
  • Warcraft 3 cripple reforged.PNG
    Warcraft 3 cripple reforged.PNG
    112.8 KB · Views: 341
Last edited:

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,285
1.32 is exclusive to Reforged users. At the moment, the classic battle net still uses 1.31 patch which has the broken AI.
The beta test of 1.32 is exclusive to Reforged pre-orders. The patch itself will not be. Hence why I am asking for people running 1.32 beta with classic graphics (reforged graphics turned off) to confirm if the issue is fixed, since it should be.
 
Level 3
Joined
Apr 1, 2019
Messages
48
1.32 is exclusive to Reforged users. At the moment, the classic battle net still uses 1.31 patch which has the broken AI.
Again I need to stretch the fact:

The AI in Reforged currently can learn and use hero abilities.
The AI in Classic WC3 currently cannot learn and use hero abilities.
That's why my script is currently for WC 3 classic, so the AI learns hero spells there.
This is tested! Don't believe everything you read from other sites.

And all further Patch discussions are not meant to be here.
 
Level 2
Joined
May 21, 2012
Messages
4
By the way here is better and more compact fix for broken SetHeroLevels native (functions StandardAI and CampaignAI uses it).

JASS:
function SkillArraysFix takes nothing returns nothing
    local integer level = GetHeroLevelAI()
    local integer g_at = 0
    local integer g_size = 0
    local unit u = null
    local group g = CreateGroup()
    
    call GroupEnumUnitsOfPlayer(g, ai_player, null)
    set g_size = BlzGroupGetSize(g)
    loop
        exitwhen g_at >= g_size
        set u = BlzGroupUnitAt(g, g_at)
        
        if level > max_hero_level then
            set max_hero_level = level
        endif
        
        if GetHeroId() == hero_id then
            call SelectHeroSkill(u, skills1[level])
        elseif GetHeroId() == hero_id2 then
            call SelectHeroSkill(u, skills2[level])
        elseif GetHeroId() == hero_id3 then
            call SelectHeroSkill(u, skills3[level])
        endif
        
        set g_at = g_at + 1
    endloop
    call DestroyGroup(g)
    set g = null
    set u = null
endfunction

Where do I put this?
You either import files into a map with Scripts/===AI FILES===.ai or if you have local files enabled drop them in Scripts folder (or create one if you don't have one).
 
Level 2
Joined
May 21, 2012
Messages
4
Well yeah, since I think SetHeroLevels(code) native always checks if any units has any unused skill points either by events or its own internal timer and the code function (SkillArraysFix) just reacts immediately to any unspent points. Much better than having a custom function on the timer.
 
Level 3
Joined
Nov 8, 2021
Messages
11
Well yeah, since I think SetHeroLevels(code) native always checks if any units has any unused skill points either by events or its own internal timer and the code function (SkillArraysFix) just reacts immediately to any unspent points. Much better than having a custom function on the timer.

@kizonrus would you be able to explain the fix please? what has changed exactly?

I am trying to fix ai in my custom map with custom heroes.
My ChooseHeroSkill looks like this:
JASS:
function ChooseHeroSkill takes nothing returns integer
    local integer curHero = GetHeroId()
    local integer level = GetHeroLevelAI()
    local integer skill_index = Get2DSkillIndex(hero_index, 4 - (level + 2) % 4) // picks skills 4,3,2,1 depending on a level

    if (level > max_hero_level) then
        set max_hero_level = level
    endif
    call DisplayTimedTextToPlayer(Player(0),0,0,10,"Start picking skills")
    call DisplayTimedTextToPlayer(Player(0),0,0,10,"AI picks skill hero_id: " + Int2Str(hero_index) + "; level: " + Int2Str(level))
    if (curHero == hero_id) then
        if (level < 6) then
            set skill_index = Get2DSkillIndex(hero_index, 1 + (level - 1) % 3) // picks skills 1,2,3 depending on a level
        endif
        call DisplayTimedTextToPlayer(Player(0),0,0,10,"AI picks skill_id: " + Int2Str(skill_index) + ", which is " + AbilityId2String(heroes_abilities[skill_index]))
        return heroes_abilities[skill_index]
    endif
    call DisplayTimedTextToPlayer(Player(0),0,0,10,"Oh no! AI didn't pick skill")
    return 0
endfunction
hero_index is an integer in array of hero ids
heroes_abilities is an array of hero ability ids (1.5d array, thats what Get2DSkillIndex() is for)
Int2Str is a custom implementation of I2S but for ai scripts
 
Level 2
Joined
May 21, 2012
Messages
4
@kizonrus would you be able to explain the fix please? what has changed exactly?

I am trying to fix ai in my custom map with custom heroes.
My ChooseHeroSkill looks like this:
JASS:
function ChooseHeroSkill takes nothing returns integer
    local integer curHero = GetHeroId()
    local integer level = GetHeroLevelAI()
    local integer skill_index = Get2DSkillIndex(hero_index, 4 - (level + 2) % 4) // picks skills 4,3,2,1 depending on a level

    if (level > max_hero_level) then
        set max_hero_level = level
    endif
    call DisplayTimedTextToPlayer(Player(0),0,0,10,"Start picking skills")
    call DisplayTimedTextToPlayer(Player(0),0,0,10,"AI picks skill hero_id: " + Int2Str(hero_index) + "; level: " + Int2Str(level))
    if (curHero == hero_id) then
        if (level < 6) then
            set skill_index = Get2DSkillIndex(hero_index, 1 + (level - 1) % 3) // picks skills 1,2,3 depending on a level
        endif
        call DisplayTimedTextToPlayer(Player(0),0,0,10,"AI picks skill_id: " + Int2Str(skill_index) + ", which is " + AbilityId2String(heroes_abilities[skill_index]))
        return heroes_abilities[skill_index]
    endif
    call DisplayTimedTextToPlayer(Player(0),0,0,10,"Oh no! AI didn't pick skill")
    return 0
endfunction
hero_index is an integer in array of hero ids
heroes_abilities is an array of hero ability ids (1.5d array, thats what Get2DSkillIndex() is for)
Int2Str is a custom implementation of I2S but for ai scripts
You are suppose to manually force hero unit to spend its point with SelectHeroSkill function.
mb this example will explain it better.
JASS:
function AIHeroLevelUpFunction takes nothing returns integer
    local integer g_at = 0
    local integer g_size = 0
    local unit u = null
    local group g = CreateGroup()
    local integer HeroLevel = GetHeroLevelAI()
    local integer HeroId = GetHeroId()
    local integer HeroSkill = 0
    local integer array HeroSkillA
    
    //Check which hero type leveled up
    if HeroId == PALADIN then
        set HeroSkillA[1] = HOLY_BOLT
        set HeroSkillA[2] = DIVINE_SHIELD
        set HeroSkillA[3] = HOLY_BOLT
        set HeroSkillA[4] = DEVOTION_AURA
        set HeroSkillA[5] = HOLY_BOLT
        set HeroSkillA[6] = RESURRECTION
        set HeroSkillA[7] = DIVINE_SHIELD
        set HeroSkillA[8] = DEVOTION_AURA
        set HeroSkillA[9] = DEVOTION_AURA
        set HeroSkillA[10] = DIVINE_SHIELD
    elseif HeroId == ARCHMAGE then
        set HeroSkillA[1] = WATER_ELEMENTAL
        set HeroSkillA[2] = BRILLIANCE_AURA
        set HeroSkillA[3] = WATER_ELEMENTAL
        set HeroSkillA[4] = BRILLIANCE_AURA
        set HeroSkillA[5] = WATER_ELEMENTAL
        set HeroSkillA[6] = BRILLIANCE_AURA
        set HeroSkillA[7] = MASS_TELEPORT
        set HeroSkillA[8] = BLIZZARD
        set HeroSkillA[9] = BLIZZARD
        set HeroSkillA[10] = BLIZZARD
    endif
    
    //Cycle through all units of our ai
    call GroupEnumUnitsOfPlayer(g, ai_player, null)
    set g_size = BlzGroupGetSize(g)
    loop
        exitwhen g_at >= g_size
        set u = BlzGroupUnitAt(g, g_at)
        
        //Is not actually used anywhere so you can just delete this
        if HeroLevel > max_hero_level then
            set max_hero_level = HeroLevel
        endif
        //
        
        //Spend our dude's point on a skill
        set HeroSkill = HeroSkillA[HeroLevel]
        if HeroSkill > 0 then
            call SelectHeroSkill(u, HeroSkill)
        endif
        
        set g_at = g_at + 1
    endloop
    call DestroyGroup(g)
    set g = null
    set u = null
    
    //Just in case but you can safely set it to 0 or remove it and set function's type to nothing
    return HeroSkill
endfunction

function main takes nothing returns nothing
    //If you are using standard melee ai functions
    call StandardAI(function AIHeroLevelUpFunction, function YOUR_PEON_FUNCTION, function YOUR_ATTACK_FUNCTION)
    
    //If you are using standard campaign ai functions
    call CampaignAI(HOUSE, function AIHeroLevelUpFunction)

    //Or you can simply use this function if you don't use either (those 2 above call this function)
    call SetHeroLevels(function AIHeroLevelUpFunction)
    
    //Your other functions
endfunction
 
Level 3
Joined
Nov 8, 2021
Messages
11
You are suppose to manually force hero unit to spend its point with SelectHeroSkill function.
mb this example will explain it better.
JASS:
function AIHeroLevelUpFunction takes nothing returns integer
    local integer g_at = 0
    local integer g_size = 0
    local unit u = null
    local group g = CreateGroup()
    local integer HeroLevel = GetHeroLevelAI()
    local integer HeroId = GetHeroId()
    local integer HeroSkill = 0
    local integer array HeroSkillA
   
    //Check which hero type leveled up
    if HeroId == PALADIN then
        set HeroSkillA[1] = HOLY_BOLT
        set HeroSkillA[2] = DIVINE_SHIELD
        set HeroSkillA[3] = HOLY_BOLT
        set HeroSkillA[4] = DEVOTION_AURA
        set HeroSkillA[5] = HOLY_BOLT
        set HeroSkillA[6] = RESURRECTION
        set HeroSkillA[7] = DIVINE_SHIELD
        set HeroSkillA[8] = DEVOTION_AURA
        set HeroSkillA[9] = DEVOTION_AURA
        set HeroSkillA[10] = DIVINE_SHIELD
    elseif HeroId == ARCHMAGE then
        set HeroSkillA[1] = WATER_ELEMENTAL
        set HeroSkillA[2] = BRILLIANCE_AURA
        set HeroSkillA[3] = WATER_ELEMENTAL
        set HeroSkillA[4] = BRILLIANCE_AURA
        set HeroSkillA[5] = WATER_ELEMENTAL
        set HeroSkillA[6] = BRILLIANCE_AURA
        set HeroSkillA[7] = MASS_TELEPORT
        set HeroSkillA[8] = BLIZZARD
        set HeroSkillA[9] = BLIZZARD
        set HeroSkillA[10] = BLIZZARD
    endif
   
    //Cycle through all units of our ai
    call GroupEnumUnitsOfPlayer(g, ai_player, null)
    set g_size = BlzGroupGetSize(g)
    loop
        exitwhen g_at >= g_size
        set u = BlzGroupUnitAt(g, g_at)
       
        //Is not actually used anywhere so you can just delete this
        if HeroLevel > max_hero_level then
            set max_hero_level = HeroLevel
        endif
        //
       
        //Spend our dude's point on a skill
        set HeroSkill = HeroSkillA[HeroLevel]
        if HeroSkill > 0 then
            call SelectHeroSkill(u, HeroSkill)
        endif
       
        set g_at = g_at + 1
    endloop
    call DestroyGroup(g)
    set g = null
    set u = null
   
    //Just in case but you can safely set it to 0 or remove it and set function's type to nothing
    return HeroSkill
endfunction

function main takes nothing returns nothing
    //If you are using standard melee ai functions
    call StandardAI(function AIHeroLevelUpFunction, function YOUR_PEON_FUNCTION, function YOUR_ATTACK_FUNCTION)
   
    //If you are using standard campaign ai functions
    call CampaignAI(HOUSE, function AIHeroLevelUpFunction)

    //Or you can simply use this function if you don't use either (those 2 above call this function)
    call SetHeroLevels(function AIHeroLevelUpFunction)
   
    //Your other functions
endfunction
Ok makes sense! I’ve done it through a unit gains level trigger. I guess it is easier to maintain an array of abilities in triggers anyway.
 
Level 2
Joined
Aug 10, 2021
Messages
7
I was not sure where to post this in order to make people easily find this, because I saw a couple of guys in WC3 seeking for this.

However since one of the latest patches, the AI in Warcraft 3 cannot choose Hero spells for their heroes.
In any melee or custom map, it fails the standard AI script and somehow they don't know how to learn a hero spell.
However, if the spell is learnt, they can use it like in the old days.

That was really annoying when I wanted to practice agaisnt AI or similiar occasions.

So I did a kind of "fix".
I did some GUI and jass and it doesn't look very nice, but I made it work and you can easily adjust the settings. I made some triggers which make the AI heroes learn spells via trigger. The order in which they learn them can be adjusted, if you like to do it. I just did write it very fast, so ... no thoughts about the order.

How to use it:
  • I attached a trigger file to this post ('AI fix triggers.zip').
  • There are 2 files in it you must have both of them in the same directory!
  • Just download it, open the map you wanna play with AI in the World Editor. Copy that map or save it with different name to not override it.
  • Then go to the "Trigger"-Section in the World Editor (it is the 'a'-Symbol).
  • Then: File -> Import Triggers -> Choose the .wtg file (but make sure the other file is in same directory).
  • Then go to "Scenario -> Map Options" and on the bottom of this new window is an option called "Game Data Set". Change it to "Melee (Latest Patch)" because otherwise the editor will most likely save your map in a very old WC3 version.
  • Save map and play (or adjust the order of the spell learning in the trigger section).

This will make a melee map marked as "non melee", because it has triggers. Anyway I did nothing else but make the computer-controlled heroes learn their spells, so they can use it.

It would be nice to mention me if you use it.

I also attached the "emerald gardens" (normal WC3 TFT map) in which I imported the AI fix, so you can see how it should look like.
I found a minor mistake in your trigger. Searing Arrows' ID is 'AHfa', not 'AEfa'. When I watched my replay I noticed that the PoTM bot didn't choose some skills then I check the trigger and found out that.
 
Status
Not open for further replies.
Top