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

Hero AI v4.3.4

  • Like
Reactions: RakEnRoL
Description
This system provides a simple computer AI for arena-type maps. Basic actions for the AI include learning skills, picking up items, buying items, and running away. The default AI can be customized further by the user for specific heroes.

There are also four optional add-ons intended to make coding the AI easier.
One is the priority library that allows the AI to choose targets based on more factors.
The second is the threat library, which allows the AI to perceive threat. This will factor in the AI's decision to run away.
The third is the event response library, intended to allow the AI to react to specific events.
The last is an independent library from Hero AI and allows the AI to have a handicap or advantage based on its difficulty.
Requires JNGP and the most recent JassHelper.

The code is quite long and better seen in the test-map with the example AIs.

v4.3.4
  • Removed FireCode which has been graveyarded. Magtheridon96 is still credited for the logic of evaluating a boolexpr.
  • Removed GetHeroAIIndex, which should have been pretty useless
  • Clarified parts of the documentation
v4.3.3
  • Added a curItem method operator to retrieve the item the hero is trying to buy.
v4.3.2
  • The methods canBuyItem and buyItem are now accessible.
v4.3.1
  • Now properly accounts for neutral units with a NEUTRAL_PLAYER constant.
  • Optionally supports IsUnitChanneling
v4.3.0
  • GroupUtils is now optional.
  • weightPriority is now a method instead of being static.
  • Added a weightThreat method to HeroAIThreat.
  • Removed some dead code.
v4.2.0
  • Custom AI are now able to define a shop unit for the AI to go to by setting .shop or calling .canShop().
  • The AI state variable is now readonly.
  • SELL_ITEM_RANGE is now public.
v4.1.0
  • Learnset can now account for morphing heroes.
  • Learnset now supports multiple skills per level.
v4.0.0
  • Separated learnset and itemset-related configuration from HeroAI into their own triggers for organization. They are still part of the core system.
  • Added AIPlayerDifficultySettings. This library is independent of HeroAI and allows the user to handicap or give an advantages to computer players based on their difficulty setting.
  • The system now requires GetClosestWidget.
  • Added a new function, RegisterHeroAISkill, to allow the user to define the learnset for a hero in its AI struct
  • Changes IsSafeUnit to take the hero's owner instead.
  • SetupItemTypes was renamed to SetupDefaultItemBuild.
  • Buying items now supports lumber.
  • Itemset syntax has been changed. The system now requires registration of items to find out its gold and lumber cost. Items can also consider shop ids so that the AI will run to them.
  • Itemsets function a bit differently. They can hold up to MAX_ITEMSET_SIZE items and will be used to tell how the AI should upgrade its hero's items.
  • Heroes will refund items when they try to improve their item build.
  • HeroAIStruct now has a utility method operator to refer to the amount of lumber the owner has. Both this and gold can now be directly set to affect the owner's resouces.
  • runAway has been deprecated in favor of a state member. This will be used to tell what kind of condition the hero is in.
v3.1.0
  • Changed RegisterHeroAI so that it won't be inlined.
  • Changed behavior of the AI to attack enemies or assist allies if the hero is at the safe spot and safeActions is not defined.
  • Now allows the user to customize the threat threshold factor for running away. THRESHOLD_RUN_FACTOR is used for the default and is based on percent life.
  • Minor code improvements
  • [Test-Map] Updated FireCode
v3.0.0
  • Allowed threat and priority to support specific unit configuration
  • AI can now consider threat to run away
  • Includes a THRESHOLD_RUN_FACTOR in HeroAIThreat so that heroes won't easily run away
  • Allowed AI to find a place to run to instead of always running to static coordinates
  • Added an on acquire event to HeroAIEventResponse
  • Fixed USE_ON_ATTACKED
  • Renamed moveAround to move
  • Renamed FOUNTAIN_RNG to SAFETY_RANGE
  • Renamed needHeal to runAway
  • Improved Learnset to fully reflect that only one instance is created
  • General code improvements
v2.0.0
  • Switched to a module interface
  • AI can no longer be destroyed
  • Corrected priority library
  • Added an optional add-on, HeroAIEventResponses
  • Uses FireCode instead of the function interface
  • isChanneling now has a text macro to provide easier configuration
  • Restructured some code
  • Renamed MAX_ITEM_INVENTORY to MAX_INVENTORY_SIZE
v1.0.0
Released


Please give credit if you use this system in your map.

Credits:
  • Magtheridon96 for IsUnitChanneling and RegisterPlayerUnitEvent. His feedback was also valuable in improving the system.
  • Vexorian for TimerUtils
  • Rising_Dusk for GroupUtils
  • Bribe for NewTable
  • Anitarf for PruneGroup, FitnessFunc, and SpellEvent (used only in test-map)
  • Spinnaker for Get Closest Widget
  • jim7777 for good feedback and suggestions
  • DarnYak for EotA which inspired the Assassin AI in the test-map

Any feedback or suggestions to improve this system would be greatly appreciated.

Keywords:
computer, AI, artificial, intelligence, arena, hero
Contents

HeroAI (Map)

Reviews
16th Jan 2012 Bribe: This is a great template/building block and I'm thinking to recommend it. GroupFunctionality is a mostly terrible resource. Half of it was already done in Blizzard.j, the GroupRemoveUnitTimed thing is pretty good though. For...
Level 10
Joined
May 27, 2009
Messages
494
Yeah, for now, i'm still using the custom AI with varying techniques depending on the difficulty

anyways go! haha

EDIT:
Can you give me a sample code to make the AI stop if it has a specific ability/buff?
But before doing so, the AI will first check the threat, if it needs to stop if the threat is too high or just keep on moving until the threat became high then stop (if the ability/buff is still present)

oh and i'm having another problem
the AI stops doing orders (or simply stops at one point) randomly when stunned consecutively..i don't know if this is a wc3 engine bug or just the triggers aren't working properly.

EDIT 2:
Uhm please add some documentation about the Shop.. sheez i'm still looking up with the defaultloopactions hahaha
full of fail struct members lol
Please at least, make .shop public D: You can't apply shop via Custom AI. So sad
 
Last edited:
Level 14
Joined
Nov 18, 2007
Messages
1,084
Can you give me a sample code to make the AI stop if it has a specific ability/buff?
But before doing so, the AI will first check the threat, if it needs to stop if the threat is too high or just keep on moving until the threat became high then stop (if the ability/buff is still present)
What do you mean by stop? Like stop attacking and run away?
the AI stops doing orders (or simply stops at one point) randomly when stunned consecutively..i don't know if this is a wc3 engine bug or just the triggers aren't working properly.
This sounds problematic, but I don't know what should cause the AI to be like this since the code doesn't do anything with the hero being stunned. A test map might be nice.
full of fail struct members lol
?
Please at least, make .shop public D: You can't apply shop via Custom AI. So sad
Yeah, I didn't really add any documentation about that because I thought shopping should just be handled internally by the system.
What is the situation in which you would want to set the custom AI's .shop? How would you want this to act, ex would you want it so that when you set .shop directly, the hero stops doing whatever it's doing and starts running to that unit?
 
Level 10
Joined
May 27, 2009
Messages
494
something like the one included in the defaultLoopActions
unfortunately, the code will run LoopActions of the CustomAI and since i can't use .shop, it wouldn't go to any shop

or perhaps a method for letting the hero go to the shop.
And maybe, let it work if its current order is the move method or just idle


hmm lemme work on the test map

EDIT:
i made a Ward System for the AI to use some wards (or something like for observing unit purposes)
here take a look, you can use it if you want :D
JASS:
library WardsSystem uses HeroAI
    globals
        private constant integer ITEM_ID = 'I001'
        private constant real RADIUS = 800
        private hashtable ht = InitHashtable()
        private real array obsX[8194]
        private real array obsY[8194]
        private integer MAX_OBS = 0
    endglobals
    
    private function Filt takes nothing returns boolean
        return HaveSavedInteger(ht,GetUnitTypeId(GetFilterUnit()),0)
    endfunction
    
    function CheckWard takes unit hero, boolean move returns boolean
        local unit obs
        local real hx = GetUnitX(hero)
        local real hy = GetUnitY(hero)
        local boolean cast = false
        local integer i = 0
        local item it = GetItemOfTypeFromUnitBJ(hero,ITEM_ID)
        if null != it then
            loop
                exitwhen i >= MAX_OBS
                set obs = GetClosestUnitInRange(obsX[i],obsY[i],RADIUS,Filter(function Filt))
                if null == obs then
                    set cast = UnitUseItemPoint(hero,it,obsX[i],obsY[i])
                    set i = MAX_OBS + 1
                elseif move then //should the AI move around the map if the user want the hero to move?
                    call IssuePointOrder(hero,"attack",hx + GetRandomReal(-HeroAI_MOVE_DIST, HeroAI_MOVE_DIST), hy + GetRandomReal(-HeroAI_MOVE_DIST, HeroAI_MOVE_DIST))
                endif
                set i = i + 1
            endloop
        endif
        set it = null
        set obs = null
        return cast
    endfunction
    
    function RegisterWardPoints takes real x, real y returns nothing
        set obsX[MAX_OBS] = x
        set obsY[MAX_OBS] = y
        set MAX_OBS = MAX_OBS + 1
    endfunction
    
    private module M
        static method onInit takes nothing returns nothing
            call SaveInteger(ht,'o003',0,1)
            /*set obsX[MAX_OBS] = -601
            set obsY[MAX_OBS] = -1719
            set MAX_OBS = MAX_OBS + 1*/
        endmethod
    endmodule
    
    private struct S extends array
        implement M
    endstruct
endlibrary
Not yet in the mood of perfecting it but could be useful eh?
test map should be coming soon
just gonna finish the AI for a hero in my map

EDIT:
any shop update?.. i can't just remove the custom loopAction :/ very useful but doesn't have the shop epicness
 
Last edited:
Level 14
Joined
Nov 18, 2007
Messages
1,084
That sounds like an annoying bug that Blizzard would come up with, but I can't seem to reproduce it. Is it a specific part of the map bounds (like the bottom part of the map)?

This is what I'm testing it with:
JASS:
function Trig_Melee_Initialization_Actions takes nothing returns nothing
    // I change the sign of the numbers along with commenting them out to test various sides.
    local real x = GetUnitX(gg_unit_hpea_0000) +10000000 
    local real y = GetUnitY(gg_unit_hpea_0000) -10000000 
    call IssuePointOrder( gg_unit_hpea_0000, "attack", x, y)
endfunction

//===========================================================================
function InitTrig_Melee_Initialization takes nothing returns nothing
    set gg_trg_Melee_Initialization = CreateTrigger(  )
    call TriggerRegisterPlayerEventEndCinematic( gg_trg_Melee_Initialization, Player(0) )
    call TriggerAddAction( gg_trg_Melee_Initialization, function Trig_Melee_Initialization_Actions )
endfunction
 
Level 10
Joined
May 27, 2009
Messages
494
the system is having some kind of problems
dunno, but if all slots are filled with computers, there might come a time that either one or two of them aren't working anymore

and if you will play for a long time, there will be a chance for Warcraft III to automatically close or a chance to stop it from responding
 
Level 14
Joined
Nov 18, 2007
Messages
1,084
Hm, I can't think of any reason right now why the AI would act like this (unless it's actually related to the bug Mag posted about o_O).
I can't really say much without having a test-map since I've never really seen it act strange.

Is this just the general AI or is there custom AI involved?
Have you noticed any pattern for this occurring?
What's the general time it takes for WC3 to bug?
 
Level 10
Joined
May 27, 2009
Messages
494
There's a custom AI involved

For the pattern, some AI will first stop moving around after it is revived (unless an enemy comes near to it), then afterwards more and more AI will stop moving but not all of them. Then when there are a lots of AI fighting in one place, they'll just attack the one with the highest priority (i guess), dunno but after some time, warcraft 3 will just stop.

This thing usually happens if I play with 5+ AI Players
General time is random, but usually takes effect if you're already playing for at least 20 minutes
 
Level 14
Joined
Nov 18, 2007
Messages
1,084
So I just ran a test game at 5x speed for 12 minutes (~60 minutes of actual game time) with the test map and I didn't see anything wrong with the AI system. No heroes acted strangely or anything. I edited the test map to include a hero revival of 30 seconds so that the heroes wouldn't end up wandering around for the entire duration.

EDIT:
Small update to v4.3.1.
What I didn't mention in the changelog was that the test map now features hero revival and the Paladin AI's assistAlly method was corrected (ally had to be initialized as null or else the check failed.)
 
Last edited:
Level 2
Joined
Aug 13, 2011
Messages
10
Sorry! I'm a lazy guy.. I have a map with 24 Heroes, 4 skill / hero
So its gonna be 96 skills need to be added,

in function SetupLearnset I have been change a little bit

I have this trigger from the beginning so I decide to use "Loop" in the next Trigger.

  • Setup Units
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Set HEROES[1] = HeroArchMage
      • Set SKILL[1] = (Archmage) Crushing Wave
      • Set SKILL[2] = (Archmage) Frost Ball
      • Set SKILL[3] = (Archmage) Brilliance Aura
      • Set SKILL[4] = (Archmage) Blizzard
      • Set HEROES[2] = HeroPaladin
      • Set SKILL[5] = (Paladin) SuperHammer
      • Set SKILL[6] = (Paladin) Mirror Image
      • Set SKILL[7] = (Paladin) Devotion Aura
      • Set SKILL[8] = (Paladin) Storm of the Dead
      • Set HEROES[3] = HeroMountainKing
      • Set SKILL[9] = (Mountain King) Thunder Clap
      • Set SKILL[10] = (Mountain King) Storm Bolt
      • Set SKILL[11] = (Mountain King) Bash
      • Set SKILL[12] = (Mountain King) Avatar
      • Set HEROES[4] = BloodMage2
      • Set SKILL[13] = (Blood Mage) Flame Strike
      • Set SKILL[14] = (Blood Mage) Phoenix
      • Set SKILL[15] = (Blood Mage) Banish
      • Set SKILL[16] = (Blood Mage) Super Lightning
      • Set HEROES[5] = HeroBlademaster
      • Set SKILL[17] = (Blade Master) Pháp kiem
      • Set SKILL[18] = (Blade Master) Mirror Image
      • Set SKILL[19] = [Blade Master] Critical Aura
      • Set SKILL[20] = [BladeMaster] Bladestorm
      • Set HEROES[6] = HeroFarseer
      • Set SKILL[21] = [Far Seer] Chain Lightning
      • Set SKILL[22] = [Far Seer] Feral Spirit
      • Set SKILL[23] = [Far Seer] Avoid
      • Set SKILL[24] = [Far Seer] Sleep
      • Set HEROES[7] = HeroTaurenChieftain
      • Set SKILL[25] = [Tauren Chieftain] Shockwave
      • Set SKILL[26] = [Tauren Chieftain] War Stomp
      • Set SKILL[27] = [Tauren Chieftain] Endurance Aura
      • Set SKILL[28] = [Tauren Chieftain] Reincarnation
      • Set HEROES[8] = ShadowHunter
      • Set SKILL[29] = [ShadowHunter] Healing Ward (Witch Doctor)
      • Set SKILL[30] = [Shadow Hunter] Voodoo Spirits
      • Set SKILL[31] = [Shadow Hunter] Hex
      • Set SKILL[32] = [Shadow Hunter] Big Bad Voodoo
      • Set HEROES[9] = HeroDeathKnight
      • Set SKILL[33] = [Death Knight] Circle of Death
      • Set SKILL[34] = [Death Knight] Death Stomp
      • Set SKILL[35] = [Death Knight] Unholy Aura
      • Set SKILL[36] = [Death Knight] Animate Dead
      • Set HEROES[10] = LichVersion2
      • Set SKILL[37] = [Lich] Frost Nova
      • Set SKILL[38] = [Lich] Frost Attack
      • Set SKILL[39] = [Lich] Frost Armor (Autocast)
      • Set SKILL[40] = [Lich] Hand of Frost
      • Set HEROES[11] = HeroDreadLord
      • Set SKILL[41] = [Dreadlord] Carrion Swarm
      • Set SKILL[42] = [Dreadlord] Sleep
      • Set SKILL[43] = [Dreadlord] Vampiric Aura
      • Set SKILL[44] = [Dreadlord] RockFireFall
      • Set HEROES[12] = HeroCryptLord
      • Set SKILL[45] = [Crypt Lord] Impale
      • Set SKILL[46] = [Crypt Lord] Carrion Beetles
      • Set SKILL[47] = [Crypt Lord] Spiked Carapace
      • Set SKILL[48] = [Crypt Lord] Locust Swarm
      • Set HEROES[13] = KeeperoftheGrove
      • Set SKILL[49] = [Keeper of the Grove] Feral Spirit
      • Set SKILL[50] = [Keeper of the Grove] Hidden
      • Set SKILL[51] = [Keeper of the Grove] Thorns Aura
      • Set SKILL[52] = [Keeper of the Grove] Circle Spirit
      • Set HEROES[14] = PriestessOfTheMoon
      • Set SKILL[53] = [Priestess of the Moon] Starfall
      • Set SKILL[54] = [Priestess of the Moon] Searing Arrows
      • Set SKILL[55] = [Priestess of the Moon] Trueshot Aura
      • Set SKILL[56] = [Priestess of the Moon] Spirit of Moon
      • Set HEROES[15] = Warden2
      • Set SKILL[57] = [Warden] Fan of Knives
      • Set SKILL[58] = [Warden] Shadow Strike
      • Set SKILL[59] = [Warden] Blink
      • Set SKILL[60] = [Warden] Poison Bolt
      • Set HEROES[16] = EvilIllidan
      • Set SKILL[61] = [Demon Hunter] KiemKhi
      • Set SKILL[62] = [Demon Hunter] Immolation
      • Set SKILL[63] = [Demon Hunter] Evasion
      • Set SKILL[64] = [Demon Hunter] Metamorphosis
      • Set HEROES[17] = FelGuardBlue
      • Set SKILL[65] = [FelGuardBlue] Storm Bolt
      • Set SKILL[66] = [FelGuardBlue] Mana Burn
      • Set SKILL[67] = [FelGuardBlue] Cleaving Attack
      • Set SKILL[68] = [FelGuardBlue] Mirror Image
      • Set HEROES[18] = HeroAlchemist
      • Set SKILL[69] = [Alchemist] Chemical Rage
      • Set SKILL[70] = [Alchemist] Acid Bomb
      • Set SKILL[71] = [Alchemist] Healing Spray
      • Set SKILL[72] = [Alchemist] Transmute
      • Set HEROES[19] = HeroTinker
      • Set SKILL[73] = [Tinker] Cluster Rockets
      • Set SKILL[74] = [Tinker] Pocket Factory
      • Set SKILL[75] = [Tinker] Machine Crazy
      • Set SKILL[76] = [Tinker] Robo-Goblin
      • Set HEROES[20] = Kiljaedin
      • Set SKILL[77] = [Warlock] Fast & Furious
      • Set SKILL[78] = [Warlock] Breath of Fire
      • Set SKILL[79] = [Warlock] Charm
      • Set SKILL[80] = [Warlock] Rain of Fire
      • Set HEROES[21] = Arthas
      • Set SKILL[81] = [Arthas] Swords
      • Set SKILL[82] = [Arthas] Forked Lightning
      • Set SKILL[83] = [Arthas] Holy Light Aura
      • Set SKILL[84] = [Arthas] Electrical Attack
      • Set HEROES[22] = BansheeRanger
      • Set SKILL[85] = [BansheeRanger] Poison Arrow
      • Set SKILL[86] = [BansheeRanger] Black Arrow
      • Set SKILL[87] = [BansheeRanger] Silence
      • Set SKILL[88] = [BansheeRanger] Charm
      • Set HEROES[23] = HeroAvatarOfFlame
      • Set SKILL[89] = [AvatarOfFlame] Summon Lava Spawn
      • Set SKILL[90] = [AvatarOfFlame] Soul Burn
      • Set SKILL[91] = [AvatarOfFlame] Incinerate
      • Set SKILL[92] = [AvatarOfFlame] Volcano
      • Set HEROES[24] = Thrall
      • Set SKILL[93] = [Thrall] Lightning Shield
      • Set SKILL[94] = [Thrall] Storm Bolt
      • Set SKILL[95] = [Thrall] Spell Shield
      • Set SKILL[96] = [Thrall] Chain Lightning


JASS:
//==========================================================================================
// This is separated from the main system of HeroAI to provide better organization.
// It covers how the AI will learn skills.
//
// When MULTIPLE_SKILLS_PER_LVL is true, you can register as many as MAX_SKILL_PER_LVL spells
// to one level for a hero in case you want your hero to learn multiple skills at one level.
//##########################################################################################
// Function API:
//
//	* RegisterHeroAISkill takes integer unitTypeId, integer level, integer spellId *
//		Registers the spell that a hero of unitTypeId should learn at level.
//		This is provided as an alternative way of setting up skills in a custom AI and is 
//      recommended to do so then registering skills here.
//==========================================================================================

// Please don't call this textmacro.
//! textmacro HeroAILearnset

    globals
        private constant integer	MAX_SKILL_LVL 		    = 140 	// The level at which the hero learns all of its skills
        private constant boolean    HAVE_MORPH_HEROES       = true  // Set to true if you have heroes that can morph
        private constant boolean    MULTIPLE_SKILLS_PER_LVL = true  // Set to true if you want learnsets to register more than one skill per level
        private constant integer    MAX_SKILL_PER_LVL       = 2     // The max number of skills a hero can learn every level. Only configure this if you have MULTIPLE_SKILLS_PER_LVL set to true. 
    endglobals    
    
	// The following allow better ease of configuration
    private keyword Learnset
    static if HAVE_MORPH_HEROES then
    private keyword MorphHeroType
    endif
    globals
        private Learnset LearnsetInfo
    endglobals
    
    // Configures how the heroes learn skills by unit-type id.
    // You need to override this function with your own heroes and their skills.
    
    // You should also set up any morphing heroes to their normal unit-type id so
    // that you won't need to copy a learnset again.
    private function SetupLearnset takes nothing returns nothing
        local integer A //tuc la Level , khi no len toi level A thi no hoc skill o duoi
        local integer const = 36
        local integer B
        local integer n
        local integer IdSpell
        local integer IdHero
    	// Learnset Syntax:
    	// set LearnsetInfo[LEVEL OF HERO][HERO UNIT-TYPE ID] = SKILL ID
  
      //Danh cho skill binh thuong cua 24 Hero. 24x3 = 72 skill thuong`
      // Voi skill dac biet có 24 skill
set n = 1
    loop
        exitwhen n>24
        set B = 1
        loop
            exitwhen B>4
                if B!=4 then //Neu B = 4 tuc la nam trong khoang skill dac biet thi set qua 1 ve^' khác.
                        loop // o tren nay la hàm dành cho các skill binh thuong
                            set A = B
                                exitwhen A>(const+B)
                                    set IdSpell = udg_SKILL[B+3*n+(n-4)]
                                    set IdHero = udg_HEROES[n]
                                    set LearnsetInfo[A][IdHero] = IdSpell
                             set   A = A+4
                        endloop
                    else // o phia duoi nay la ham` danh` cho cac skill dac biet.
                        loop
                            set A = B+2
                                exitwhen A>(const+B)
                                   
                                    set IdSpell = udg_SKILL[B+3*n+(n-4)]
                                    set IdHero = udg_HEROES[n]
                                    set LearnsetInfo[A][IdHero] = IdSpell

                               set A = A+8
                        endloop
                endif
            set B=B+1    
        endloop
        set n=n+1
    endloop
        // Sau khi co hàm trên thì phai set skill theo thu tu. 
        //1 2 3 skill thuong, 4 skill dac biet. Cu nhu vay sap xep dung vi tri.
        
        //phia duoi nay` la ban goc. neu xem lai thi` duoi nay` la mau~ day

        set MorphHeroType['N009'] = 'N00B'    
        set MorphHeroType['N008'] = 'N00A'    
        set MorphHeroType['E007'] = 'E00B' 
    endfunction

//==========================================================================================
// END OF USER CONFIGURATION
//==========================================================================================

    private function MakeAILearnSkills takes nothing returns nothing
        local unit u = GetTriggerUnit() 
        local integer typeId = GetUnitTypeId(u)
        static if MULTIPLE_SKILLS_PER_LVL then
        
        local integer i = 0
        
        endif
        if heroesAI.has(GetHandleId(u)) and GetHeroSkillPoints(u) > 0 then
            static if HAVE_MORPH_HEROES then
            
            if MorphHeroType.has(typeId) then
                set typeId = MorphHeroType[typeId]
            endif
            
            endif
            
            static if MULTIPLE_SKILLS_PER_LVL then
            
            loop
                exitwhen i == LearnsetInfo[GetUnitLevel(u)].skillNum(typeId)
                call SelectHeroSkill(u, LearnsetInfo[GetUnitLevel(u)].getSkill(typeId, i))
                set i = i + 1
            endloop
            
            else
            
            call SelectHeroSkill(u, LearnsetInfo[GetUnitLevel(u)][typeId])
            
            endif
        endif
        set u = null
    endfunction
    
    static if HAVE_MORPH_HEROES then
    
    private module MorphSuperHack
        static method onInit takes nothing returns nothing
            set thistype.info = Table.create()
        endmethod
    endmodule
    
    struct MorphHeroType extends array
        private static Table info
        
        static method operator [] takes integer morphedTypeId returns integer
            return info[morphedTypeId]
        endmethod
        
        static method operator []= takes integer morphedTypeId, integer originalTypeId returns nothing
            set info[morphedTypeId] = originalTypeId
        endmethod
        
        static method has takes integer morphedTypeId returns boolean
            return info.has(morphedTypeId)
        endmethod
        
        implement MorphSuperHack
    endstruct
    
    endif
    
    
    static if MULTIPLE_SKILLS_PER_LVL then
    
    private module RawIdIndexerInit
        static method onInit takes nothing returns nothing
            set thistype.info = Table.create()
        endmethod
    endmodule
    
    private struct RawIdIndexer
        static Table info
        static integer count = -1 // Zero-based indexing due to array storage
        
        implement RawIdIndexerInit
    endstruct
    
    private function RawId2Index takes integer rawId returns integer
        if RawIdIndexer.info.has(rawId) then
            return RawIdIndexer.info[rawId]
        endif
        set RawIdIndexer.count = RawIdIndexer.count + 1
        set RawIdIndexer.info[rawId] = RawIdIndexer.count
        return RawIdIndexer.count
    endfunction
    
    struct SkillArray extends array
        private static integer array skills     // Stores the skills based on hero raw id (indexed) and level it should be learned
        private static integer array skillNums  // Number of skills for a particular level
        
        // "this" refers to the level (zero-based) that the skill will be learned at
        
        method operator []= takes integer r, integer s returns nothing 
            local integer index
            set r = RawId2Index(r)
            set index = this + r * MAX_SKILL_LVL
            
            static if DEBUG_MODE then
            
            if index + skillNums[index] > 8190 then
                call BJDebugMsg("[Hero AI Learnset] Error: Index is too high, try lowering MAX_SKILL_PER_LVL?")
                return
            endif
            
            endif
            
            if skillNums[index] < MAX_SKILL_PER_LVL then                
                set skills[index + skillNums[index]] = s
                set skillNums[index] = skillNums[index] + 1
            debug else
                debug call BJDebugMsg("[Hero AI Learnset] Error: Exceeding the registration of skills to level " + I2S(this + 1))
            endif
        endmethod
        
        method getSkill takes integer r, integer whichOne returns integer
            return skills[(this + RawId2Index(r) * MAX_SKILL_LVL) + whichOne]
        endmethod
        
        method skillNum takes integer r returns integer
            return skillNums[this + RawId2Index(r) * MAX_SKILL_LVL]
        endmethod
    endstruct
    
    endif    
    
    private module M
        static method onInit takes nothing returns nothing            
            set LearnsetInfo = thistype.create()
            call RegisterPlayerUnitEvent(EVENT_PLAYER_HERO_LEVEL, function MakeAILearnSkills)
            call SetupLearnset()
        endmethod
    endmodule
    
    // Wrapper to make things look better and cheat the zero-indexed Table.
    // Only one instance will be created and used.
    struct Learnset extends array  
    
        static if MULTIPLE_SKILLS_PER_LVL then
        
        method operator [] takes integer lvl returns SkillArray
            static if DEBUG_MODE then
            
            if lvl > MAX_SKILL_LVL then
                call BJDebugMsg("[Hero AI Learnset] Error: Level of " + I2S(lvl) + " is higher than MAX_SKILL_LVL")
                return 0
            endif
            
            endif
            
            return lvl - 1
        endmethod
        
        else
        
        private static TableArray info
        
        method operator [] takes integer lvl returns Table
            static if DEBUG_MODE then
            
            if lvl > MAX_SKILL_LVL then
                call BJDebugMsg("[Hero AI Learnset] Error: Level of " + I2S(lvl) + " is higher than MAX_SKILL_LVL")
                return 0
            endif
            
            endif

            return info[lvl - 1]
        endmethod
        
        endif  
        
        static method create takes nothing returns thistype
            static if not MULTIPLE_SKILLS_PER_LVL then
            
            set info = TableArray[MAX_SKILL_LVL]
            
            endif
            return 1
        endmethod
        
        implement M
    endstruct
    
    function RegisterHeroAISkill takes integer unitTypeId, integer level, integer spellId returns nothing
    	set LearnsetInfo[level][unitTypeId] = spellId
    endfunction
    
//! endtextmacro

The problem, The code inside loop doesn't work.. I don't know how to fix it :D.. Of Course I can save the map without syntax error.. but when I play game, the Hero can't learn skill by themself. So somebody plz help me to figure out the problem? Thanks a lot.
 
Last edited:
Level 3
Joined
Jun 3, 2013
Messages
34
I think I'm going to have to raise the version number up to 2.0.0 already. XD

Thanks again for the feedback! I really appreciate it. ^_^

This is for Hero Arena AI System... Could it be also for AoS map types or would you be making a AoS type AI System?
Anyway.. I really like this +rep :goblin_good_job:
 

Deleted member 219079

D

Deleted member 219079

Is there a way I could remove a hero from the system?

Edit: as it seems you're inactive, i assume i ain't getting an answer... fuck, I spent the whole day trying to make a workaround for this, ended up screwing my map's code >.> well, back to fixing... ffs
 
Last edited by a moderator:
Top