Count abilities

Level 7
Joined
Mar 16, 2014
Messages
163
I have a custom skills game where units can learn hundreds of different potential skills.

I need to be able to count how many abilities a unit has without manually coding out a check of if it has every single ability in the game one by one with conditions of "If level of ability for unit greater than 0." I could theoretically do it that way but it's a very painful and inefficient process.

Is there any alternative system for this to check how many abilities a unit has?

Edit: My slow computer double posted the thread. Sorry!
 
Level 41
Joined
Feb 27, 2007
Messages
5,240
There is no good solution. The best you can get is to loop native BlzGetUnitAbilityByIndex takes unit whichUnit, integer index returns ability until it returns null (it returns an ability agent, not an integer). As explained by Nichilus here, this function will return a lot of 'extra' abilities that likely aren't what you're looking for, and the index ordering can be a little weird:
  • While the list includes some abilities by default, any new ability is pushed to the start of the list, to index 0
  • Abilities on this list include abilities like 'Attack' and 'Move', learned hero abilities, non hero abilities but also buffs
    • For example, in a fresh new map the list of abilities for Paladin will look like this:
      Code:
      0 = Inventory
      1 = Attack
      ...
    • and after the Paladin learns Devotion Aura the list looks like this:
      Code:
      0 = Devotion Aura buff (BHad)
      1 = Devotion Aura ability (AHad)
      2 = Inventory
      3 = Attack
      ...
  • Same thing happens if you add unit ability to the hero midgame
    • for example to give hero Evasion via buff, you would have dummy buff + give the hero a hidden Evasion ability for the duration of the buff
There is a stupid simple solution which is to give every relevant ability that you would like to 'show up' in a search a custom rawcode within a specific range (for example A100 .. A300), then loop over only those rawcodes sequentially querying the level of each ability.
 
Level 7
Joined
Mar 16, 2014
Messages
163
There is no good solution. The best you can get is to loop native BlzGetUnitAbilityByIndex takes unit whichUnit, integer index returns ability until it returns null (it returns an ability agent, not an integer). As explained by Nichilus here, this function will return a lot of 'extra' abilities that likely aren't what you're looking for, and the index ordering can be a little weird:

There is a stupid simple solution which is to give every relevant ability that you would like to 'show up' in a search a custom rawcode within a specific range (for example A100 .. A300), then loop over only those rawcodes sequentially querying the level of each ability.
Can you give an example code of how I'd loop through checking if unit X has all abilities with certain raw codes?
 

Uncle

Warcraft Moderator
Level 69
Joined
Aug 10, 2018
Messages
7,195
That might be unnecessary though. Don't you have a trigger that runs when a unit gains a new skill? Just increase the "counter" when that happens:
  • Events
    • -- A unit gets a new skill --
  • Conditions
  • Actions
    • Set Variable CV = (Custom value of unit getting new skill)
    • Set Variable SkillCount[CV] = SkillCount[CV] + 1
This method for tracking data is called Unit Indexing.

If you're learning the skill from a Hero Skill menu then you simply use the "Learn skill" event and check if the (Learned skill level) is equal to 1.

Then don't forget to subtract 1 from SkillCount[] if you lose a skill (if that's even possible in your map).
 
Last edited:
Level 7
Joined
Mar 16, 2014
Messages
163
Literally just increment an integer....
JASS:
set i = 'A100'
loop
  set L = GetUnitAbilityLevel(u,i)
  if L > 0 then
    //the unit had this ability
  endif
  set i = i+1
  exitwhen i >= 'A300'
endloop

Wasn't sure you could put that in an integer is why I was confused, thanks.
From searching there seems to be no way to manually set an ability's raw code, though.

That might be unnecessary though. Don't you have a trigger that runs when a unit gains a new skill? Just increase this "counter" at that time using indexing:
  • Events
    • -- A unit gets a new skill --
  • Conditions
  • Actions
    • Set Variable CV = (Custom value of unit getting new skill)
    • Set Variable SkillCount[CV] = SkillCount[CV] + 1
If you're learning the skill from a Hero Skill menu then you simply use the "Learn skill" event and check if the (Learned skill level) is equal to 1.

Then don't forget to subtract 1 from SkillCount[] if you lose a skill (if that's even possible in your map).
This would work and is a very good idea, the issue is that the units start with abilities immediately on them and start with different amounts of abilities.
 

Uncle

Warcraft Moderator
Level 69
Joined
Aug 10, 2018
Messages
7,195
Wasn't sure you could put that in an integer is why I was confused, thanks.
From searching there seems to be no way to manually set an ability's raw code, though.


This would work and is a very good idea, the issue is that the units start with abilities immediately on them and start with different amounts of abilities.
How about creating a database for all of your units? Or maybe just the heroes depending on how your map works:
  • Events
    • Map initialization
  • Conditions
  • Actions
    • Hashtable - Create a hashtable
    • Set Variable DB_Hashtable = (Last created hashtable)
    • Set Variable DB_Unit_Type = Paladin
    • Set Variable DB_Ability_Count = 5
    • Trigger - Run Add UnitType To Database (ignoring conditions)
    • Set Variable DB_Unit_Type = Blademaster
    • Set Variable DB_Ability_Count = 3
    • Trigger - Run Add UnitType To Database (ignoring conditions)
    • Set Variable DB_Unit_Type = Warden
    • Set Variable DB_Ability_Count = 10
    • Trigger - Run Add UnitType To Database (ignoring conditions)
You can store any custom data about them, essentially extending what the Object Editor can keep track of.

The Add UnitType To Database trigger would Save this data into our new Hashtable using DB_Unit_Type as the Parent key (but converted into an Integer) and using different Child keys starting at 0 for what you want to store. So DB_Ability_Count could be Saved at Child key 0, then if you had another Variable that you wanted to store it could be saved at Child key 1, etc:
  • Add UnitType To Database
    • Events
    • Conditions
    • Actions
      • Custom script: set udg_DB_Id = udg_DB_Unit_Type
      • Hashtable - Save DB_Ability_Count as 0 of DB_Id in DB_Hashtable
The end result would allow you to get this data from any Unit at any time - assuming that it has been added to the Database:
  • Events
    • Unit - A unit Enters playable map area
  • Conditions
    • ((Triggering unit) is a Hero) Equal to True
  • Actions
    • Set Variable TempUnit = (Entering unit)
    • Custom script: set udg_DB_Id = GetUnitTypeId(udg_TempUnit)
    • Set Variable CV = (Custom value of TempUnit)
    • Set Variable SkillCount[CV] = Load 0 of DB_ID from DB_Hashtable
So if the Paladin entered the map then this trigger would use it's Unit-Type id to Load the value 5 from the Hashtable (our saved ability count). You then use Unit Indexing to keep track of this value on an individual basis -> SkillCount[CV]. DB_Id is an Integer variable.

This can be extremely useful for making more advanced systems in your map. For example, maybe each Hero has a new 4th attribute, this would be a great place to set it's default starting value and increase per level.
 
Last edited:
Level 41
Joined
Feb 27, 2007
Messages
5,240
there seems to be no way to manually set an ability's raw code
Copy the ability, paste it. You can choose the code when you paste the ability. Remove the original version of the ability and change every:
  • Unit-type's ability list
  • Item-type's ability list
  • Trigger E/C/A
that refers to the original ability to now reference the new one. Immediately after deleting the original version each of these fields will look like it still refers to a valid ability, but double clicking on that field will show it's not actually in the list/action/whatever. If you are using a out-of-date World Edit where this isn't possible, that's your own damn fault. Reforged is not required to update your installation; that is still fully free.
 
Top