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

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...

Moderator

M

Moderator

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 the other stuff you typically want to use FirstOfGroup loops instead.

Your GetAngleDifference function gets the smallest angle between two angles? I wonder if it is more efficient than this:

JASS:
        set ang = RAbsBJ(ang - ang2)
        if ang > 180 then
            set ang = R2I(ang) / 360 * 360 + 360 - ang
        endif

I don't see a problem using a local text tag instead of "bj_lastCreatedTextTag", because, keep in mind that JASS is an interpreted language, longer names take longer to process, and that the optimizer will not compress bj_ global names.

You end up with a lot of duplicates of code by using Anitarf's functions interfaces. While I am not aware of any alternatives to fitness functions, http://www.hiveworkshop.com/forums/jass-resources-412/system-spell-struct-204774/ by Nestharus poops all over SpellEvent by Anitarf.

I'm considering approving this and since I could not find glitches I will approve it with an initial rating of 3/5.
 
Great system!

JASS:
    private interface AIInterface
        method loopActions      takes nothing returns nothing defaults nothing  // Determines the periodic behavior of the hero. Defined by default.
        method assistAlly       takes nothing returns boolean defaults false      // Actions to take when supporting allies. Needs to return true if a supportive action was taken. Has higher priority than attacking enemies
        method assaultEnemy     takes nothing returns nothing defaults nothing  // Actions to take when attacking enemies. Defined by default.
        method runActions       takes nothing returns boolean defaults false    // Actions to take when running to (RUN_X, RUN_Y). Needs to return true if an action was taken.
        method safeActions      takes nothing returns nothing defaults nothing  // Actions to take while at (RUN_X, RUN_Y)
    endinterface

struct HeroAI extends AIInterface

JASS:
        group units
        group allies
        group enemies

ZOMG

You don't have to use an interface, module interfaces are cooler :p (Cleaner, faster, and they don't create shitcode for teh lulz)

Since you don't need the interface, you can make that struct extend an array.

Also, instead of a group, you can use a linked list of units (LinkedListModule by Dirac and UnitIndexer so you don't only store 32-bytes of data instead of storing ~3072-bytes.) (By this, I mean you should store the Unit Ids.)

GroupUtils

Or, LinkedListModule and UnitIndexer because dynamic groups are too old school now :p

JASS:
        method operator isChanneling takes nothing returns boolean
            local integer o = GetUnitCurrentOrder(.hero)
            return o == 852664 or /* Healing spray
                */ o == 852183 or /* Starfall
                */ o == 852593 or /* Stampede
                */ o == 852488 or /* Flamestrike
                */ o == 852089 or /* Blizzard
                */ o == 852238 // Rain of Fire
        endmethod

This method should be in a textmacro somewhere at the top of the script so that it's easier for the user to configure it.

private function interface RegisterHeroAIFunc takes unit h returns nothing

This duplicates a lot of code :/
You could make the user pass code arguments to the functions instead and if you need to store them, convert them to boolexprs with the function Filter(code)
It's a lot cooler ^_^



There are many more things that could be improved, but I'm really tired at the moment.
I want to give this a 5/5, but I can't do that yet ;)
 
Level 14
Joined
Nov 18, 2007
Messages
1,084
Thanks for the feedback! ^_^

@Magtheridon96
If I used a module interface instead, would the user still be able to call on the AI's actions from a hero without knowing what kind of AI the hero has?

I'll look into using linked lists but it looks like it might complicate things on the user's end.

For the function interface: If I switched to using boolexprs, I would need a trigger to evaluate it and a global variable to store the unit, right?
 
Last edited:
For the function interface: If I switched to using boolexprs, I would need a trigger to evaluate it and a global variable to store the unit, right?

For the unit, yes.
For the trigger, nah, you can add "FireCode" as a requirement (Jass section)
But, I wouldn't recommend doing that just yet cause I just did a ninja-update and found a major bug in it :eek:
I'll tell you when it's safe to use it :p

edit
FireCode has been updated.

Now that I think about it, a LinkedList wouldn't make much of a difference.
It would just add tons of shitcode to your library.
Use those groups, it's ok.
 
Last edited:
Level 14
Joined
Nov 18, 2007
Messages
1,084
First, you need to make sure that you have implemented all the required libraries. So basically all the triggers only under the "Needed Libraries" needs to be copied into your map.
Then copy the trigger named HeroAI into your map.
Now, to run the AI for a hero, you need some custom script.
  • Custom script: call RunHeroAI(YourUnit)
Right now, I'm still updating the system so I'd advise you to wait before implementing this.
 
Level 7
Joined
Sep 2, 2011
Messages
349
Alrighty. Great work on this. I'm really planning on using this after it is finished. Do also make a documentation for noobs (like me) on how to uhm use it properly. Since, I really lack in jass in anyway.
 
JASS:
    struct Learnset    
        private TableArray info
        
        method operator [] takes integer key returns Table
            return info[key - 1]
        endmethod
        
        static method create takes nothing returns thistype
            local thistype this = thistype.allocate()
            set .info = TableArray[MAX_SKILL_LVL]
            return this
        endmethod
    endstruct

Well, you aren't destroying any of the instances, so the optimal solution here would be this:

JASS:
    struct LearnSet extends array
        // This integer does all the allocation for you ;)
        private static integer stack = 1
        // 3-D Array, FUCK YEAH!
        private static TableArray array info
        
        method operator [] takes integer key returns Table
            return info[this][key - 1]
        endmethod
        
        static method create takes nothing returns thistype
            local thistype this = stack
            set stack = stack + 1
            set info[this] = TableArray[MAX_SKILL_LVL]
            return this
        endmethod
    endstruct

This way, you're producing much less compiled code, making the script more light-weight :)
I broke compatibility though :p
I want it to follow Jass convention ;)

And take your time on fixing those Interfaces (I know how hard it is to manage a module interface) :p

edit
And when you update the code, could you paste it outside of hidden tags?
The font size is horrible :(

edit
Another optimization:

JASS:
    struct ItemSet extends array
        private static integer stack = 0
        private static integer array items
        private static integer array costs
        private static integer array count = 0
        
        method itemId takes integer index returns integer
            return items[this * MAX_ITEM_INVENTORY + index]
        endmethod
        
        method cost takes integer index returns integer
            return costs[this * MAX_ITEM_INVENTORY + index]
        endmethod

        method operator total takes nothing returns integer
            return count[this]
        endmethod
        
        static method create takes nothing returns thistype
            set stack = stack + 1
            return stack
        endmethod
        
        method addItemId takes integer id, integer c returns nothing
            debug if count[this] < 6 then
                set items[this * MAX_ITEM_INVENTORY + count[this]] = id
                set costs[this * MAX_ITEM_INVENTORY + count[this]] = c
                set count[this] = count[this] + 1
            debug else
                debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "[ItemSet]Error: Max Items Capacity Reached. Aborting.")
            debug endif
        endmethod
    endstruct

That should do it.
It looks better, but I broke compatibility :p
It's ok since this resource is still new ;)
 
Last edited:
Nah, you can keep it as 1.0.0 since it's still new :p
My ModeManager system is already up to 6.0.0.0 =p
I broke backwards compatibility with long intervals of time xD

I usually wait 3 days after the first upload before I go to 2.0.0.0 when breaking backwards compatibility (I don't want to fall in the same trap I did while developing ModeManager)
 
public constant real DEFAULT_PERIOD = 1.7 // The period in which the hero AI will do actions. A very low period can cause strain.

While this makes sense in general coding, it makes more sense to use events for wc3.


public constant real MOVE_DIST = 1000. // The random amount of distance the hero will move
This should probably be different depending on the unit

public constant integer MAX_INVENTORY_SIZE = 6 // The number of items the hero can hold
This is dependent upon unit and possible custom inventories

public constant real FOUNTAIN_RNG = 500. // The range the hero should be in of the fountain.
Should probably be changed to aura and it depends on the aura >.>. This value shouldn't exist... it should go until the unit has the aura on them.

private constant integer MAX_SKILL_LVL = 10 // The level at which the hero learns all of its skills
This is just plain silly as it can be dynamically calculated

return .percentLife <= .35 or (.percentLife <= .55 and .mana / GetUnitState(.hero, UNIT_STATE_MAX_MANA) <= .3) or (.maxLife < 700 and .life <= 250.)
Naive approach. This should depend on the number of enemy units, the number of ally units, the state of the ally units vs the enemy units, and depend on if there is a healer in range or not, in which case the AI should use the healer to heal the hero or w/e.

return .percentLife >= .85 and .mana / GetUnitState(.hero, UNIT_STATE_MAX_MANA) >= .65
Same issue. The return to points should be any point under play control that provides a means of healing.

JASS:
            return o == 852664 or /* Healing spray
                 */ o == 852183 or /* Starfall
                 */ o == 852593 or /* Stampede
                 */ o == 852488 or /* Flamestrike
                 */ o == 852089 or /* Blizzard
                 */ o == 852238 // Rain of Fire
Very bad approach. You can easily detect whether a unit is currently channeling or not. Make a seperate resource with an IsUnitChanneling function.

JASS:
    private function SetupItemTypes takes nothing returns nothing
        call DefaultItemBuild.addItemId('gcel', 100)
        call DefaultItemBuild.addItemId('bspd', 150) 
        call DefaultItemBuild.addItemId('rlif', 200)        
        call DefaultItemBuild.addItemId('prvt', 350)
        call DefaultItemBuild.addItemId('rwiz', 400)
        call DefaultItemBuild.addItemId('pmna', 500)
    endfunction
This seems stupid. It should be dependent on the hero and the state of the player and team.

JASS:
    private function SetupLearnset takes nothing returns nothing
        // Syntax:
        // set LearnsetInfo[LEVEL OF HERO][HERO UNIT-TYPE ID] = SKILL ID
        
        // Paladin
        set LearnsetInfo[1]['Hpal'] = 'AHhb' // Holy Light
        set LearnsetInfo[3]['Hpal'] = 'AHhb'
        set LearnsetInfo[5]['Hpal'] = 'AHhb'
        set LearnsetInfo[2]['Hpal'] = 'AHds' // Divine Shield
        set LearnsetInfo[4]['Hpal'] = 'AHds'
        set LearnsetInfo[7]['Hpal'] = 'AHds'
        set LearnsetInfo[8]['Hpal'] = 'AHad' // Devotion Aura
        set LearnsetInfo[9]['Hpal'] = 'AHad'
        set LearnsetInfo[10]['Hpal'] = 'AHad'
        set LearnsetInfo[6]['Hpal'] = 'AHre' // Resurrection
        
        // Blood Mage
        set LearnsetInfo[1]['Hblm'] = 'AHfs' // Flame Strike
        set LearnsetInfo[3]['Hblm'] = 'AHfs'
        set LearnsetInfo[5]['Hblm'] = 'AHfs'
        
        // Assassin
        set LearnsetInfo[1]['E000'] = 'A001' // Backstab
        set LearnsetInfo[3]['E000'] = 'A001'
        set LearnsetInfo[5]['E000'] = 'A001'
        set LearnsetInfo[7]['E000'] = 'A001'
    endfunction
This should depend on the current state of the game >.>. Obviously, if you are fighting undead heroes, you are going to want to go for Holy Light before anything else. If you have a large army and are fighting regular units, devotion aura. If you are fighting heroes regularly Divine Shield.

struct Itemset
This needs to provide a way to interface with a custom inventory

and (IsUnitAlly(u, temp.owner) or IsUnitEnemy(u, temp.owner))
That == true..

private method buyItems takes nothing returns nothing
Hero should buy items straight from the shop, so the set player state thing is silly as is the unit add item by id..

method defaultLoopActions takes nothing returns nothing
Instead of this, a goal needs to be defined for the hero. From there, the AI can follow actions leading to that goal.

method update takes nothing returns nothing
This is rather silly as it should just be tied in with events...

Threats should depend on hero weaknesses and strengths... if a hero is weak vs a specific unit, then obviously that hero should go for that unit first.

USE_ON_ATTACKED
Should use acquisition range rather than on attack




Overall, I wouldn't recommend anyone to use this resource quite yet. It requires a lot of work and a lot of rewriting. Try again ^)^. Also keep in mind that AI actions are largely dependent on the unit and the game that the unit is in as well as the state of the game. This makes general AI pretty much impossible to do, which is why I personally haven't done one. You could sort of get away with unique AI scripts for specific units, but you'd still have to customize them to a specific game (perhaps like a core goal script that effects all of the units).

All in all, I think AI has 3 parts: core AI script that all AI uses, unit specific script, and team specific scripts. You sort of have the core AI, although it isn't that great, as well as minimal support for unit specific (again not that great). This is why I said that you should probably just rewrite the whole thing ; ).
 
Level 7
Joined
Sep 2, 2011
Messages
349
@Nestharus

How about make your own AI. I know you can do it. As an experienced user like you can get the job done. I am looking forward for a great AI system.
 
Level 14
Joined
Nov 18, 2007
Messages
1,084
@Nestharus
JASS:
public constant real DEFAULT_PERIOD = 1.7 // The period in which the hero AI will do actions. A very low period can cause strain.
While this makes sense in general coding, it makes more sense to use events for wc3.
In what way would events help at all?
JASS:
public constant real MOVE_DIST = 1000. // The random amount of distance the hero will move
This should probably be different depending on the unit
I'm not convinced on this, though I could easily change the system to allow this. How is moving a random distance important enough for a specific unit type?
Should probably be changed to aura and it depends on the aura >.>. This value shouldn't exist... it should go until the unit has the aura on them.
I'm not aware of fountain healing giving a buff.
JASS:
private constant integer MAX_SKILL_LVL = 10 // The level at which the hero learns all of its skills
This is just plain silly as it can be dynamically calculated
The main purpose is to provide a size for the struct Learnset.
Naive approach. This should depend on the number of enemy units, the number of ally units, the state of the ally units vs the enemy units, and depend on if there is a healer in range or not, in which case the AI should use the healer to heal the hero or w/e.
This is a nice suggestion since I could have optionally used the threat library to complement it.
The return to points should be any point under play control that provides a means of healing.
I'll get to work on making a filter for safe point checks.
Make a seperate resource with an IsUnitChanneling function.
That seems more heavy weight than simply checking the unit's order, but I guess it could be done. It's not my top priority though.
It should be dependent on the hero and the state of the player and team.
The Paladin AI shows an example of how a custom inventory can be defined. The latter is really map-specific.
This should depend on the current state of the game >.>. Obviously, if you are fighting undead heroes, you are going to want to go for Holy Light before anything else. If you have a large army and are fighting regular units, devotion aura. If you are fighting heroes regularly Divine Shield.
This becomes too map-specific for something that was intended to be general.
This needs to provide a way to interface with a custom inventory
I can't support a custom inventory system unless I know which ones people use or how they make one.
That == true..
I don't see any.
Hero should buy items straight from the shop, so the set player state thing is silly as is the unit add item by id..
Either way, checking the player state is still required if you wanted the AI to buy items on triggers alone. The system only mimics buying items though since the AI never directly goes to a shop.
JASS:
method update takes nothing returns nothing
This is rather silly as it should just be tied in with events...
I don't understand what you mean.
Threats should depend on hero weaknesses and strengths... if a hero is weak vs a specific unit, then obviously that hero should go for that unit first.
This is a nice idea but I'm not sure if I'll implement this.
Should use acquisition range rather than on attack
I'll add that event.

Overall, thanks for your feedback. I felt, however, that you expected too much out of this system. My main goal was to create a basic AI that could be considered a template for unit specific ones. Something like team AI was never my intention because it becomes too map-specific and more of a hassle to configure.
 
Level 14
Joined
Nov 18, 2007
Messages
1,084
Updated to v3.0.0.
Main points (More detailed changelog in first post):

  • Backwards compatibility was broken by allowing heroes to choose a unit to run to instead of having the static coordinates RUN_X, RUN_Y. Some values and methods were also renamed.
  • Method interfaces were added to the priority and threat library to allow more specific configuration for a specific AI.
  • The AI can now factor in threat when deciding to run away. To help with this, a THRESHOLD_RUN_FACTOR is added in the threat library so that heroes won't run away so easily.
  • An on acquire event was added to the event response library.
 
Level 10
Joined
May 27, 2009
Messages
495
perhaps registering codes then firing it up when needed? then the condition will be up to the user or something like that

i guess gonna still understand the Event Response..
still staring at the test map :O

EDIT:
i just saved the test map

and viola!

wtgmdy.jpg



please fix your function.. it is returning nothing :))
the RegisterAI function in the HeroAI library
 
Last edited:
Level 10
Joined
May 27, 2009
Messages
495
ohhh yes :D

hmm is it possible to write the Hero Skills setup in a respective custom AI? like how you enabled overwriting default item builds?
the library might get long..... but i think this can be optional or it will work like how does item builds setup work, difference is, there's no overwriting part or it can be a support for a skill like Attribute Bonus so you wouldn't write attribute bonus for each hero

EDIT:
i tried using up the test map ai but unfortunately, the Paladain's runActions method isn't working.. the Cast part with the priority one... i can't let it work :/ the firstofgroup always returns null...
but i just used (copied) the same code... and edit the setup part with hero skills, but it always returns null.. i removed the modPriority method
 
Last edited:
Level 14
Joined
Nov 18, 2007
Messages
1,084
hmm is it possible to write the Hero Skills setup in a respective custom AI?
That's a good suggestion. I'll probably do it with some kind of function API.

How did you define runActions?
Note that it must return a boolean if the Paladin was actually ordered to do something.
Ex:
JASS:
        method runActions takes nothing returns boolean 
            debug call BJDebugMsg("The Paladin runs away!")
            return false // He's only yelling at us through debug messages so return false
        endmethod
 
Level 10
Joined
May 27, 2009
Messages
495
oh no no no no.. my fault

it is assaultEnemy method
the one which will cast Holy bolt, but in my case, i changed it to impale but it isn't casting the skill

EDIT:
nvm managed to fix it just condition problems :D

EDIT 2:
i think the AI should go to a respective shop when buying or having items, it's kinda weird when they're walking then suddenly they have instant items.

Like renewing the API to something like
call DefaultItemBuild.addItemId('ITEM_ID', 'BUILDING_ID', GOLD_COST)
so the AI must go to the building first or at least near the building, well at least the building id can be the id when the unit is pre-placed on the map or detect if any valid bldg ids in the map?
 
Last edited:
Level 14
Joined
Nov 18, 2007
Messages
1,084
i think the AI should go to a respective shop when buying or having items, it's kinda weird when they're walking then suddenly they have instant items.
Yeah, I'm still thinking of a good way to do this. Would it make sense for the AI to attempt to walk towards the item shop when it has enough gold to purchase something, but if it encounters enemies, it'll start attacking and forget about buying things, unless it's really close to the shop?

Ah, I'm probably going to break backwards compatibility again and move the version up to v4.0.0 when I update the item-related issue.


Somewhat unrelated, but I'm thinking of separating the learnset and itemset related things from HeroAI into two other libraries that get required by HeroAI. Any opinions on this?
 
Level 10
Joined
May 27, 2009
Messages
495
I guess you may use either the region or the id of the shop since some shop (like in my map) is wandering around and some are just buildings

the action will AI do when he encounters an enemy when attempting to buy or go to a shop will be up to the user.. OR if it is safe to go to the shop when no enemies are nearby OR any safeCondition given by the user
in short just provide an API for that kind of method

for the libraries, its up to you :D

EDIT:
oh wait i can't use IsUnitVisible(u,.owner) in the EnemyFilter method (the one in paladin's test AI)
undeclared variable this

hmm.. not possible to use .owner in other methods? or any help ?? :D
 
Level 14
Joined
Nov 18, 2007
Messages
1,084
oh wait i can't use IsUnitVisible(u,.owner) in the EnemyFilter method (the one in paladin's test AI)
undeclared variable this
Just do this:
JASS:
IsUnitVisible(u, temp.owner)
temp is a static member provided by the HeroAIStruct module to help with group enumerations. It basically stores the struct instance and is set automatically by the method update (update gets called periodically so you should almost never have to call it).
 
Level 14
Joined
Nov 18, 2007
Messages
1,084
Updated to v4.0.0
Main Points:

  • System is separated into three parts to provide better organization.
  • GetClosestWidget is now required.
  • Itemsets are now done a bit differently along with item registration. Itemsets can now have up to MAX_ITEMSET_SIZE items. The AI can improve their item build and refund bought items.
  • Items now support a lumber cost.
  • Heroes can now go to shops to buy items instead of buying them instantly. If you don't want this feature, set up the item to have a shop type id of 0.
  • runAway has been replaced with a state member.
  • An independent library was added that can give a handicap or advantage to a computer player based on their difficulty.
 
Level 14
Joined
Nov 18, 2007
Messages
1,084
I haven't actually changed learnset at all besides moving it and adding that function. :p
I'm not exactly sure about Engineering Upgrade. I'm guessing that you should be able to make it work as long as you make the learnset choose the correct upgraded ability after an Engineering Upgrade ability has been learned.

EDIT: Yes you do need to do it like that unfortunately. :\

EDIT 2: I just realized that I should make a note for the user to copy the learnset for a hero that can morph in case it levels up while morphed. Or do something so that it won't be such a pain.
 
Last edited:
Level 10
Joined
May 27, 2009
Messages
495
I can't make Engineering upgrade to work (the hero won't learn the abilities applied/changed)
just going to edit some stuffs.. lets see what will happen >:D

EDIT:
Can you have a new way of setting up the Skills?

so it wouldn't overwrite each other since the easiest yet inefficient way of fixing is learning both of the abilities at the same time, but unfortunately, The system learn setup will just overwrite with each other D:
 
Level 14
Joined
Nov 18, 2007
Messages
1,084
Here's an example of what the Tinker's learnset looks like in the new test map version (4.0.1) that I will probably upload tomorrow:
JASS:
        // Tinker
        // Engineering Upgrade makes this a bit messy.
        // You will have to make sure that the other 3 abilities he learn
        // are correctly set to the upgraded ones from Engineering Upgrade.
        set LearnsetInfo[1]['Ntin'] = 'ANcs' // Cluster Rockets
        set LearnsetInfo[4]['Ntin'] = 'ANc1' // EU upgraded to level 1 at this point
        set LearnsetInfo[8]['Ntin'] = 'ANc2' // EU upgraded to level 2 at this point
        
        set LearnsetInfo[2]['Ntin'] = 'ANsy' // Pocket Factory
        set LearnsetInfo[5]['Ntin'] = 'ANs1' // EU upgraded to level 1 at this point
        set LearnsetInfo[10]['Ntin'] = 'ANs3' // EU upgraded to level 3 at this point
        
        set LearnsetInfo[3]['Ntin'] = 'ANeg' // Engineering Upgrade
        set LearnsetInfo[7]['Ntin'] = 'ANeg' 
        set LearnsetInfo[9]['Ntin'] = 'ANeg' 
        
        set LearnsetInfo[6]['Ntin'] = 'ANg1' // Robo-Goblin (EU upgraded to level 1 at this point)
Yeah it's really ugly. :\

EDIT:
Can you have a new way of setting up the Skills?

so it wouldn't overwrite each other since the easiest yet inefficient way of fixing is learning both of the abilities at the same time, but unfortunately, The system learn setup will just overwrite with each other
I'm not really sure what you mean.
 
Level 10
Joined
May 27, 2009
Messages
495
urgg so i need still to skip 1 level?

the hero is in max level, but the hero doesn't have the EU ability but instead will be added via trigger / item..

that's my problem since there's no exact level when to add the EU ability... and the worst thing is the hero will wonder to learn the non-EU or the EU enhanced ability D: and there's no skipping of levels... since the Eu isn't a skill of that hero

Perhaps having a boolean in the API?? that should be one of the best option since using a code like this:
JASS:
call RegisterHeroAISkill(UNIT_ID,16,ABILITY_ID)
call RegisterHeroAISkill(UNIT_ID,16,UPGRADED_ID)
will just let the hero learn the UPGRADED_ID even though he doesn't have the EU ability.. that will result into failure right? 'cause the ABILITY_ID setup will be overwritten by UPGRADED_ID according to your code
Perhaps avoid overwriting of skills? 'cause in that code, the ai will check 2 possible skills at that level which is 16 but the other one can only be learned if the hero has EU which i said earlier that it will be acquired/given via triggers or such

i hope you can understand me

but the shortest point is
disallow overwriting of skills >:D
'cause the hero might be able to learn two skills at one level (like learning ability 1 and ability 2 at level 4) something like that.. since the current learn set doesn't allow that
 
Level 14
Joined
Nov 18, 2007
Messages
1,084
Updated to v4.1.0
Main points:

  • Learnset supports an easy way for a hero that has a different unit-type id from another hero type (ex: a morphed hero) and should share the same learnset.
  • Learnset can now support multiple skills learned per level. If you don't want this feature, you should set MULTIPLE_SKILLS_PER_LVL to false in the HeroAILearnset trigger.
  • Static if abuse has increased greatly


@jim7777: If the case you describe is only for one hero, you should probably just code a custom learning trigger for it specifically since it would be more efficient than using MULTIPLE_SKILLS_PER_LVL.
 
Level 10
Joined
May 27, 2009
Messages
495
ahh yes great multiple skills per lvl

oh well... my suggestion isn't for one hero only, almost every hero in my map. LOL

the awkward moment i'm looking for the code.. I just saw paste bin
LOL

EDIT
great >:D

the last thing is, perhaps add a struct member / variable which will get the AI's current difficulty, so I wouldn't be calling the native so often
(for easier coding LOL)
 
Level 14
Joined
Nov 18, 2007
Messages
1,084
Yeah, I switched to Pastebin because updating the code here was a hassle and it stretched the screen a lot.

the last thing is, perhaps add a struct member / variable which will get the AI's current difficulty, so I wouldn't be calling the native so often
(for easier coding LOL)
Come on, it's not that hard to do it the native way. :p
If I ever do add that member, I'm probably going to do it with another update.
 
Top