[General] Save / Clone learned abilitys to same unit type (hero)

Level 2
Joined
Feb 8, 2025
Messages
10
Hey everyone,


I'm working on a Warcraft III custom map and need help figuring out if it's possible to remember which ability a hero has learned, including its level, and then learn the same ability (at the same level) to an identical hero unit type that gets sent to the battlefield. Essentially, your own hero is just chilling in the base (like in direct strike). I already figured out how to carry on the level and items of the hero to this battlefield hero version, but abilities learned by the hero in base seem to be impossible to move / save in any way.

I tried using "unit learns ability" and then checked if its possible to save the learned ability to a variable, but that seems not to be an option.



Does anyone know a good way to achieve this? Would this require Hashtable storage or JASS, or is there a more straightforward way? Any guidance or examples would be greatly appreciated!


Thanks!

Edit:

I tried to play around with hashtables and even that does not seem to be an option? I just cant seem to store the data of a learned ability (or abilitys that a unit has) in to a variable or hashtable.

Why there is almost every other trigger in the GUI but this one seems to be forgotten or thought that it's not important?
 
Last edited:
Level 30
Joined
Aug 29, 2012
Messages
1,382
Sure you can, no need for hashtables either

  • Learn
    • Events
      • Unit - A unit Learns a skill
    • Conditions
    • Actions
      • // ABILITY 1 //
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Learned Hero Skill) Equal to Human Archmage - Blizzard
        • Then - Actions
          • Set VariableSet HeroAbility[1] = Blizzard
          • Set VariableSet AbilityLevel[1] = (Level of HeroAbility[1] for (Triggering unit))
        • Else - Actions
      • // ABILITY 2 //
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Learned Hero Skill) Equal to Summon Water Elemental
        • Then - Actions
          • Set VariableSet HeroAbility[2] = Summon Water Elemental
          • Set VariableSet AbilityLevel[2] = (Level of HeroAbility[2] for (Triggering unit))
        • Else - Actions
      • // ABILITY 3 //
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Learned Hero Skill) Equal to Brilliance Aura
        • Then - Actions
          • Set VariableSet HeroAbility[3] = Summon Brilliance Aura
          • Set VariableSet AbilityLevel[3] = (Level of HeroAbility[3] for (Triggering unit))
        • Else - Actions
  • // ETC //
HeroAbility needs to be an Ability Code variable, not an Ability variable
 

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,866
Here's a little system that I meant to upload earlier but got sidetracked. It's effectively what Chaosium posted but more automated.

The main appeal is that it can pair two units together so that whenever the "source" unit updates it's skills those changes apply to the "target" unit automatically. So in Direct Strike terms, the Source would be your building back home and the Target would be the hero that spawns in and fights. This pairing is only one way by default, so the Target cannot update the Source.

The only thing it appears to be missing is managing Tome of Retraining (unlearning skills). Also, there's a memory leak when you remove a unit from the game that was using the system (leaks said unit) but that may never occur and is very minor.
 

Attachments

  • SkillTracker1.w3m
    23.6 KB · Views: 5
Last edited:
Level 45
Joined
Feb 27, 2007
Messages
5,578
If you want to identically duplicate a unit, the most direct way to do that is to save it in the GameCache and then restore the unit somewhere on the map. This should copy literally everything including current HP/MP values and held items. Depending on what you've done this could break some custom spells that rely on enter-map or learn events.
 
Level 2
Joined
Feb 8, 2025
Messages
10
Sure you can, no need for hashtables either

  • Learn
    • Events
      • Unit - A unit Learns a skill
    • Conditions
    • Actions
      • // ABILITY 1 //
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Learned Hero Skill) Equal to Human Archmage - Blizzard
        • Then - Actions
          • Set VariableSet HeroAbility[1] = Blizzard
          • Set VariableSet AbilityLevel[1] = (Level of HeroAbility[1] for (Triggering unit))
        • Else - Actions
      • // ABILITY 2 //
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Learned Hero Skill) Equal to Summon Water Elemental
        • Then - Actions
          • Set VariableSet HeroAbility[2] = Summon Water Elemental
          • Set VariableSet AbilityLevel[2] = (Level of HeroAbility[2] for (Triggering unit))
        • Else - Actions
      • // ABILITY 3 //
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Learned Hero Skill) Equal to Brilliance Aura
        • Then - Actions
          • Set VariableSet HeroAbility[3] = Summon Brilliance Aura
          • Set VariableSet AbilityLevel[3] = (Level of HeroAbility[3] for (Triggering unit))
        • Else - Actions
  • // ETC //
HeroAbility needs to be an Ability Code variable, not an Ability variable
So the only option I have is to do this for all the skills and different heros I have going on? A Massive trigger list? :/

Ill see if I can work with that uncle provided, if I can impliment it to my system somehow... Cheers for help guys! this opened some options for me.

Here's a little system that I meant to upload earlier but got sidetracked. It's effectively what Chaosium posted but more automated.

The main appeal is that it can pair two units together so that whenever the "source" unit updates it's skills those changes apply to the "target" unit automatically. So in Direct Strike terms, the Source would be your building back home and the Target would be the hero that spawns in and fights. This pairing is only one way by default, so the Target cannot update the Source.

The only thing it appears to be missing is managing Tome of Retraining (unlearning skills). Also, there's a memory leak when you remove a unit from the game that was using the system (leaks said unit) but that may never occur and is very minor.

This is something I am looking for.

How do I initialize the skill data if I dont have heros on the map at game time 0.0? or do I create every unit once at 0.0, initialize them, then remove all the units so they are not displayed anywhere? this way they stay on the tracker? or can I do this when the hero is created?
 

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,866
You need to manually register heroes as they come into play. This is done on an individual basis.

Here's a Desert Strike themed example:
  • Events
    • Unit - A unit Finishes construction
  • Conditions
    • (Unit-type of (Triggering unit)) Equal to Paladin (Building)
  • Actions
    • Set Variable MyBuilding = (Triggering unit)
    • Set Variable SkillTracker_Skills[1] = Holy Light
    • Custom script: call Skill_Tracker_Add_New_Range( udg_MyBuilding, 1 )
    • -------- --------
    • Unit - Create 1 Paladin (Hero)...
    • Set Variable MyHero = (Last created unit)
    • Custom script: call Skill_Tracker_Copy( udg_MyBuilding, udg_MyHero, true )
    • Unit - Hide MyHero
Now the building and the hero are paired together, and any time the building learns a skill the hero will as well. You'd then want to set references between the Hero and the Building, which can be done using a Unit Indexer or Hashtable, so that you can Unhide the Hero when it comes time to move it onto the "battlefield" and Hide it again whenever necessary. Alternatively, you can create a brand new Hero on the fly and Copy() the data again, but that seems like bad design since Heroes can be revived and reused.
 
Last edited:
Level 2
Joined
Feb 8, 2025
Messages
10
You need to manually register heroes as they come into play. This is done on an individual basis.

Here's a Desert Strike themed example:
  • Events
    • Unit - A unit Finishes construction
  • Conditions
    • (Unit-type of (Triggering unit)) Equal to Paladin (Building)
  • Actions
    • Set Variable MyBuilding = (Triggering unit)
    • Set Variable SkillTracker_Skills[1] = Holy Light
    • Custom script: call Skill_Tracker_Add_New_Range( udg_MyBuilding, 1 )
    • -------- --------
    • Unit - Create 1 Paladin (Hero)...
    • Set Variable MyHero = (Last created unit)
    • Custom script: call Skill_Tracker_Copy( udg_MyBuilding, udg_MyHero, true )
    • Unit - Hide MyHero
Now the building and the hero are paired together, and any time the building learns a skill the hero will as well. You'd then want to set references between the Hero and the Building, which can be done using a Unit Indexer or Hashtable, so that you can Unhide the Hero when it comes time to move it onto the "battlefield" and Hide it again whenever necessary. Alternatively, you can create a brand new Hero on the fly and Copy() the data again, but that seems like bad design since Heroes can be revived and reused.
Alright I got it working somewhat for my system. it does copy the initial first ability or two I have teached the hero in base, but when the unit dies on the battlefield and then is re-created and resent every X interval (Timer based waves of units), then this newly created hero does not have the freshly leveled abilities anymore, only the first abilities it had like 4 waves ago. Everytime this unit is created I call the skill_tracker_copy from the base hero, is this correct or am I doing something wrong?

Edit:

also note worthy stuff: There is only 1 hero per player alive on the battlefield. Only when the hero dies there is a boolean check that its actually dead and only then it creates +1 unit to attack again. These units are CPU controlled by player 13.

This system seems to break when the unit is already fightning, and you level up a skill in base. The ability does get updated, but once the unit dies and is sent again to battlefield EVERYTHING seems to reset as if it was totally different unit than whats in the array.

I save this trained hero in a unit array so once a hero unit is created its saved to heroarray[#] (number for player).

I also have a CPU copy for this hero that is saved in CPUheroarray[#] (basically just a sets itself from heroarray[same #]
  • spawn hero p1
    • Events
      • Time - wavetimer expires
    • Conditions
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • heroalive[1] Equal to True
          • CPUheroalive[1] Equal to False
        • Then - Actions
          • Wait 1.00 seconds
          • Set VariableSet red_spawnpoint = (Random point in redteam send <gen>)
          • Unit - Create 1 (Unit-type of CPUheroarray[1]) for Player 13 (Maroon) at red_spawnpoint facing Default building facing degrees
          • Custom script: call Skill_Tracker_Copy(udg_heroarray[1],GetLastCreatedUnit(), true)
          • Set VariableSet CPUheroalive[1] = True
          • -------- abilitys --------
          • -------- visual assurance --------
          • Unit - Change color of (Last created unit) to (Color of Player 1 (Red))
          • Hero - Set Name of (Last created unit) to (Proper name of heroarray[1])
          • Unit Group - Add (Last created unit) to p1hero_set
          • -------- move stats --------
          • Hero - Set (Last created unit) Hero-level to (Hero level of heroarray[1]), Hide level-up graphics
          • Hero - Create (Item-type of (Item carried by heroarray[1] in slot 1)) and give it to (Last created unit)
          • Hero - Create (Item-type of (Item carried by heroarray[1] in slot 2)) and give it to (Last created unit)
          • Hero - Create (Item-type of (Item carried by heroarray[1] in slot 3)) and give it to (Last created unit)
          • Hero - Create (Item-type of (Item carried by heroarray[1] in slot 4)) and give it to (Last created unit)
          • Hero - Create (Item-type of (Item carried by heroarray[1] in slot 5)) and give it to (Last created unit)
          • Hero - Create (Item-type of (Item carried by heroarray[1] in slot 6)) and give it to (Last created unit)
          • Hero - Modify Strength of (Last created unit): Set to (Strength of heroarray[1] (Exclude bonuses)).
          • Hero - Modify Agility of (Last created unit): Set to (Agility of heroarray[1] (Exclude bonuses)).
          • Hero - Modify Intelligence of (Last created unit): Set to (Intelligence of heroarray[1] (Exclude bonuses)).
          • Hero - Modify Intelligence of (Last created unit): Set to (Intelligence of heroarray[1] (Exclude bonuses)).
          • -------- action after spawning --------
          • Set VariableSet p1heroattack = (Random point in center move right <gen>)
          • Unit - Order (Last created unit) to Attack-Move To p1heroattack
        • Else - Actions
      • Custom script: call RemoveLocation(udg_p1heroattack)
      • Custom script: call RemoveLocation(udg_red_spawnpoint)
Dont worry about the "Unit Group - Add (Last created unit) to p1hero_set" its later cleared in a different trigger (dying event).

Also other small leaks but am first trying to work out this prototype.

here is what I tried to use as a test unit.

  • ST Setup
    • Events
      • Unit - A unit Finishes training a unit
    • Conditions
      • (Owner of (Triggering unit)) Equal to Player 1 (Red)
      • (Unit-type of (Trained unit)) Equal to Paladin
    • Actions
      • Wait 0.50 seconds
      • -------- Initialize the skill data for hero --------
      • -------- --------
      • Set VariableSet SkillTracker_Skills[1] = Holy Light
      • Set VariableSet SkillTracker_Skills[2] = Divine Shield
      • Set VariableSet SkillTracker_Skills[3] = Devotion Aura
      • Set VariableSet SkillTracker_Skills[4] = Resurrection
      • -------- --------
      • Custom script: call Skill_Tracker_New_Range( udg_heroarray[1], 4 )
      • -------- --------


Edit 2:

I noticed the system breaks somewhere between leveling abilitys and making a new unit. When I level up the abilitys and both units are alive its working fine, but if I level up the abilitys on the base hero when the battlefield hero is dead and waiting to be created it just completely breaks and it spawns as a LVL 1 hero with the player 13 color, even the player color change action or hero proper name action wont happen. Whats going on?

Edit 3:

Somehow it only does this with paladin learning holy light... This is so confusing and me not knowing JASS that much makes it so hard...

edit 4:

Going down the bug splattering spree, leveling up any 2 levels to any skills breaks the CPU hero.
Any skill works for the first leveled up skill and it gets carried to the created hero fine. the moment I add any more skills to the base standing hero it totally bricks the CPU hero.

I am so lost why this is happening.
 
Last edited:

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,866
I answered these questions in my last post, it works on individual units.

Every time you do this:
  • Unit - Create 1 (Unit-type of CPUheroarray[1]) for Player 13 (Maroon) at red_spawnpoint facing Default building facing degrees
You're creating a brand new "individual" unit. This new unit has no idea about anything related to the "previous" unit that was once doing it's job.
That's why I suggested reviving/hiding/unhiding/moving the hero instead of recreating it. That'll allow you to preserve everything about it.


Also, careful with using Waits like this, and you're referencing a Variable that doesn't appear to be Set yet:
  • ST Setup
    • Events
      • Unit - A unit Finishes training a unit
    • Conditions
      • (Owner of (Triggering unit)) Equal to Player 1 (Red)
      • (Unit-type of (Trained unit)) Equal to Paladin
    • Actions
      • Wait 0.50 seconds
      • -------- Initialize the skill data for hero --------
      • -------- --------
      • Set VariableSet SkillTracker_Skills[1] = Holy Light
      • Set VariableSet SkillTracker_Skills[2] = Divine Shield
      • Set VariableSet SkillTracker_Skills[3] = Devotion Aura
      • Set VariableSet SkillTracker_Skills[4] = Resurrection
      • -------- --------
      • Custom script: call Skill_Tracker_New_Range( udg_heroarray[1], 4 )
      • -------- --------
^ Who is heroarray[1]? Are you sure it's even set yet? Why is there a Wait? What does that even do besides mess things up?

A quick breakdown of the system functions:

Skill_Tracker_New_Range() = This registers a new unit with the given SkillTracker_Skills between indexes [1] and [X]. In your case you should only run this once per BUILDING.

Skill_Tracker_Copy() = This takes an existing registered unit, so your building from before, and registers another new unit using the existing unit's data. So in your case your new HERO would get a copy and paste of the BUILDING's data. If you set the boolean to true then the new unit will also be paired to the existing unit. This pairing means that the new unit will automatically update when you run the Skill_Tracker_Update() function on the existing unit. So whenever you run Skill_Tracker_Update() on the BUILDING, the HERO will update as well. This relationship only works one way with the "source" unit being in control.

Skill_Tracker_Update() = This takes an existing registered unit, so your building, and it takes a Skill and it's current Level. It then uses that provided information to update the unit's skill data inside of the system. If the building is paired to a hero then the hero will also update at the same time automatically. In other words, whenever your building learns a skill you run would run this function providing this skill/level, and then the Hero (if any) will update as well, trying to learn that skill up to the correct level.


Some caveats that come to mind (I may edit this with more later):

The hero has to spend skill points in it's hero skill menu in order to learn and increase the level of an ability. There's a chance that the hero will be stunned or dead and cannot actually execute the order to level up a skill. For example, your Hero gets hit by Storm Bolt and is stunned for 5 seconds. During that time you order the Building paired with that Hero to learn Holy Light. A stunned Hero cannot take any actions so it ignores the "automatic learn order" and fails to learn Holy Light and you end up in a broken/buggy situation. I may be able to fix this but I had originally assumed it wouldn't be a problem.
 
Last edited:
Level 2
Joined
Feb 8, 2025
Messages
10
I answered these questions in my last post, it works on individual units.

Every time you do this:
  • Unit - Create 1 (Unit-type of CPUheroarray[1]) for Player 13 (Maroon) at red_spawnpoint facing Default building facing degrees
You're creating a brand new "individual" unit. This new unit has no idea about anything related to the "previous" unit that was once doing it's job.
That's why I suggested reviving/hiding/unhiding/moving the hero instead of recreating it. That'll allow you to preserve everything about it.


Also, careful with using Waits like this, and you're referencing a Variable that doesn't appear to be Set yet:
  • ST Setup
    • Events
      • Unit - A unit Finishes training a unit
    • Conditions
      • (Owner of (Triggering unit)) Equal to Player 1 (Red)
      • (Unit-type of (Trained unit)) Equal to Paladin
    • Actions
      • Wait 0.50 seconds
      • -------- Initialize the skill data for hero --------
      • -------- --------
      • Set VariableSet SkillTracker_Skills[1] = Holy Light
      • Set VariableSet SkillTracker_Skills[2] = Divine Shield
      • Set VariableSet SkillTracker_Skills[3] = Devotion Aura
      • Set VariableSet SkillTracker_Skills[4] = Resurrection
      • -------- --------
      • Custom script: call Skill_Tracker_New_Range( udg_heroarray[1], 4 )
      • -------- --------
^ Who is heroarray[1]? Are you sure it's even set yet? Why is there a Wait? What does that even do besides mess things up?

A quick breakdown of the system functions:

Skill_Tracker_New_Range() = This registers a new unit with the given SkillTracker_Skills between indexes [1] and [X]. In your case you should only run this once per BUILDING.

Skill_Tracker_Copy() = This takes an existing registered unit, so your building from before, and registers another new unit using the existing unit's data. So in your case your new HERO would get a copy and paste of the BUILDING's data. If you set the boolean to true then the new unit will also be paired to the existing unit. This pairing means that the new unit will automatically update when you run the Skill_Tracker_Update() function on the existing unit. So whenever you run Skill_Tracker_Update() on the BUILDING, the HERO will update as well. This relationship only works one way with the "source" unit being in control.

Skill_Tracker_Update() = This takes an existing registered unit, so your building, and it takes a Skill and it's current Level. It then uses that provided information to update the unit's skill data inside of the system. If the building is paired to a hero then the hero will also update at the same time automatically. In other words, whenever your building learns a skill you run would run this function providing this skill/level, and then the Hero (if any) will update as well, trying to learn that skill up to the correct level.


Some caveats that come to mind (I may edit this with more later):

The hero has to spend skill points in it's hero skill menu in order to learn and increase the level of an ability. There's a chance that the hero will be stunned or dead and cannot actually execute the order to level up a skill. For example, your Hero gets hit by Storm Bolt and is stunned for 5 seconds. During that time you order the Building paired with that Hero to learn Holy Light. A stunned Hero cannot take any actions so it ignores the "automatic learn order" and fails to learn Holy Light and you end up in a broken/buggy situation. I may be able to fix this but I had originally assumed it wouldn't be a problem.

"You're creating a brand new "individual" unit. This new unit has no idea about anything related to the "previous" unit that was once doing it's job."
You're right, but the idea is not to have the newly created unit mimic the one that was just in the field, I want it to follow what the hero in base is doing.
That's why I update the newly created hero everytime and clone the units data/stats/items from the hero in base.

Thanks for clarifying this whole setup. There must be something wrong on this thing still tho. The hero works fine with 1 ability learned what ever one it is, but once it has 2 or more abilities learned or even if its a same ability but at level 2, the whole unit creation trigger just goes out the window.

I even disabled update once the unit was spawned and already on the move so there was no possibility it was dead / stunned / what ever yet.

why does it break the whole trigger tho? I cant find a reason for that. it stops all the actions under the spawn location instant move action.


Edit: I moved the update below everything... now it works... what..
 
Last edited:

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,866
I updated the system to be a bit more automated. It should avoid the "hero was disabled and couldn't learn skill" issue that I mentioned before. I also automated the Update() function to run without needing you to do it yourself. In other words, it will automatically sync learned skills if you've created a pairing between two units (it's still a one-way relationship, the source reflects changes to the target). All of these changes likely fix the other issues that you were experiencing, but I can't confirm because I didn't experience them myself.

The demo portion of the map is a more fleshed out "Desert Strike" example that shows the concepts I described before. You'll see that the Building and Hero are now paired together through Array variables. The Hero is not recreated because that's unnecessary, we want to preserve changes throughout the game by reusing it. I also show how you can share Items between the Building/Hero, as well as take advantage of Arrays to make most triggers work in a generic way for everyone. You rarely need to create a unique trigger for each Player, Arrays can solve that problem.

One change that may throw you errors, I renamed Skill_Tracker_New_Range() to Skill_Tracker_Add().
  • Custom script: call Skill_Tracker_Add( udg_DemoUnit, 4 )
^ Same exact concept as before, just a new function name.

Edit: Also, Skill_Tracker_Update() now only takes a unit. It's optional and exists just in case you need to "force" an update (it's usually automated):
  • Custom script: call Skill_Tracker_Update( udg_DemoUnit )
 

Attachments

  • SkillTracker2.w3m
    30.3 KB · Views: 3
Last edited:
Level 2
Joined
Feb 8, 2025
Messages
10
I updated the system to be a bit more automated. It should avoid the "hero was disabled and couldn't learn skill" issue that I mentioned before. I also automated the Update() function to run without needing you to do it yourself. In other words, it will automatically sync learned skills if you've created a pairing between two units (it's still a one-way relationship, the source reflects changes to the target). All of these changes likely fix the other issues that you were experiencing, but I can't confirm because I didn't experience them myself.

The demo portion of the map is a more fleshed out "Desert Strike" example that shows the concepts I described before. You'll see that the Building and Hero are now paired together through Array variables. The Hero is not recreated because that's unnecessary, we want to preserve changes throughout the game by reusing it. I also show how you can share Items between the Building/Hero, as well as take advantage of Arrays to make most triggers work in a generic way for everyone. You rarely need to create a unique trigger for each Player, Arrays can solve that problem.

One change that may throw you errors, I renamed Skill_Tracker_New_Range() to Skill_Tracker_Add().
  • Custom script: call Skill_Tracker_Add( udg_DemoUnit, 4 )
^ Same exact concept as before, just a new function name.
Man you are so good at this. You work so fast aswell. Ill see what I can comee up with this and thanks again for helping out. Been trying this for 2 days my self and I just couldn't figure it out.

I really need to get familiar with this JASS thing, I'we coded in other languages before but I just couldn't get my self to learn another language lol
 

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,866
Man you are so good at this. You work so fast aswell. Ill see what I can comee up with this and thanks again for helping out. Been trying this for 2 days my self and I just couldn't figure it out.

I really need to get familiar with this JASS thing, I'we coded in other languages before but I just couldn't get my self to learn another language lol
You can switch your map's scripting language to Lua mode, that opens the door to programming languages like:
TypeScript, CSharp, and Lua of course, which is perfectly fine to use on it's own.
Lua was introduced in the pre-Reforged patch (1.31) and is basically a dream come true for anyone that wants a more modern programming experience.

Just understand that you're stuck using one language or the other, which means that you will lose out on the huge library of Jass systems that have been created over the years. But also know that Lua makes most of those systems obsolete and/or there's a Lua alternative that exists. Here's some great Lua authors to name a few: Bribe, Tasyen, Chopinski, Antares. Their resources often have Jass AND Lua versions.

But if you're still learning GUI and making mistakes there then I would probably stick with Jass for now.
 
Last edited:
Level 2
Joined
Feb 8, 2025
Messages
10
You can switch your map's scripting language to Lua mode, that opens the door to programming languages like:
TypeScript, CSharp, and Lua of course, which is perfectly fine to use on it's own.
Lua was introduced in the pre-Reforged patch (1.31) and is basically a dream come true for anyone that wants a more modern programming experience.

Just understand that you're stuck using one language or the other, which means that you will lose out on the huge library of Jass systems that have been created over the years. But also know that Lua makes most of those systems obsolete and/or there's a Lua alternative that exists. Here's some great Lua authors to name a few: Bribe, Tasyen, Chopinski, Antares. Their resources often have Jass AND Lua versions.

But if you're still learning GUI and making mistakes there then I would probably stick with Jass for now.
Cheers!

Alright quick question... uh.. I got it working very nicely, added 2 different heros and it was all working fine for 1 player only. The moment I added CPU ally and shared control of its units and built a hero on there aswell, it just seemed to totally AGAIN mess everything up...

So basically if I test stuff solo everything is working as intented but the moment I introduce 2nd hero (even if its same) it just breaks?

I do
  • Set VariableSet PN = (Player number of (Owner of (Trained unit)))
  • Custom script: call Skill_Tracker_Add(udg_heroarray[udg_PN], 4)
when trained unit event happens.

So now that players themself set the PN integer they should not mix correct?

Also even if I make a same hero on both players for some reason now the blue hero abilities get leveled on red hero aswell in the batlefield lol.
 
Last edited:
Level 45
Joined
Feb 27, 2007
Messages
5,578
Pardon my stupidity and intentional ignorance because i haven't actually opened any of the downloads in this thread. I ask a simple question: wouldn't it be easier just to do something like this:
  • Events
    • Unit - A unit learns a skill
  • Conditions
  • Actions
    • Set KeyU = GetUnitIndex(GetTriggerUnit()) //with a unit indexer
    • Set KeyAbil = Key(SomeIntegerStringKeyConversionFuckeryThatGUICantDoDirectly(Learned hero skill))
    • Set KeyAC = Key("AbilityCount")
    • Set AC = (Load KeyAC of KeyU in AbilityHash)
    • Set LVL = ((Load KeyAbil of KeyU in AbilityHash) + 1)
    • Hashtable - Save LVL as KeyAbil of KeyU in AbilityHash
    • If (All conditions are true) then do (Then actions) else do (Else actions)
      • If - Conditions
        • LVL equal to 1 //this means it was a new ability learned
      • Then - Actions
        • Set AC = (AC + 1)
        • Hashtable - Save SomeMoreIntegerConversionFuckery(Learned hero skill) as AC of Abil in AbilityHash
      • Else - Actions
That would automatically attach all learned abilities to every unit that learns anything. In order to know what skills a unit has learned you read child index AC from hash, then read child indices 1..AC which are the actual ability rawcodes (so you can add them), and then read child <the rawcode> for the level. Have to flush the hashtable on unit death and accounting for any abilities added manually through the editor or via trigger or leveled up by trigger is left as an exercise for the reader. ;)

Maybe that's what Uncle is doing, but it seems considerably simpler than precaching everything.
 

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,866
So now that players themself set the PN integer they should not mix correct?
Assuming PN is being Set properly then they'll each have their own [index] in the Array. [1] = Red, [2] = Blue, [3] = Teal, etc.
So yes, this avoids the mixing (overwriting) of data. Note that it only works for 1 Hero per Player, but I believe you said that was your intention.
Also even if I make a same hero on both players for some reason now the blue hero abilities get leveled on red hero aswell in the batlefield lol.
I'd have to see your entire trigger(s) and not just the snippets to know where you went wrong.

You can see in the demo map that it works fine for P1 and P2, both can have their own Hero.
 
Last edited:

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,866
Pardon my stupidity and intentional ignorance because i haven't actually opened any of the downloads in this thread. I ask a simple question: wouldn't it be easier just to do something like this:
  • Events
    • Unit - A unit learns a skill
  • Conditions
  • Actions
    • Set KeyU = GetUnitIndex(GetTriggerUnit()) //with a unit indexer
    • Set KeyAbil = Key(SomeIntegerStringKeyConversionFuckeryThatGUICantDoDirectly(Learned hero skill))
    • Set KeyAC = Key("AbilityCount")
    • Set AC = (Load KeyAC of KeyU in AbilityHash)
    • Set LVL = ((Load KeyAbil of KeyU in AbilityHash) + 1)
    • Hashtable - Save LVL as KeyAbil of KeyU in AbilityHash
    • If (All conditions are true) then do (Then actions) else do (Else actions)
      • If - Conditions
        • LVL equal to 1 //this means it was a new ability learned
      • Then - Actions
        • Set AC = (AC + 1)
        • Hashtable - Save SomeMoreIntegerConversionFuckery(Learned hero skill) as AC of Abil in AbilityHash
      • Else - Actions
That would automatically attach all learned abilities to every unit that learns anything. In order to know what skills a unit has learned you read child index AC from hash, then read child indices 1..AC which are the actual ability rawcodes (so you can add them), and then read child <the rawcode> for the level. Have to flush the hashtable on unit death and accounting for any abilities added manually through the editor or via trigger or leveled up by trigger is left as an exercise for the reader. ;)

Maybe that's what Uncle is doing, but it seems considerably simpler than precaching everything.
I'm not sure if that'd be easier for the average GUI user, but yeah, I see what you're saying. The Key could even be a Unit-Type Id.

But the setup I use has some nice perks to it. Knowing all of the skills ahead of time allows you to do things like "call LearnSkill(3)", which could make a Hero level up it's "3rd skill". That'd be doable before it has learned anything. I realize that's an "off-topic feature" in regards to what OP wanted, but feature requests like that might come up. (tldr: I ain't changing it! Lol)
 
Last edited:
Level 2
Joined
Feb 8, 2025
Messages
10
Assuming PN is being Set properly then they'll each have their own [index] in the Array. [1] = Red, [2] = Blue, [3] = Teal, etc.
So yes, this avoids the mixing (overwriting) of data. Note that it only works for 1 Hero per Player, but I believe you said that was your intention.

I'd have to see your entire trigger(s) and not just the snippets to know where you went wrong.

You can see in the demo map that it works fine for P1 and P2, both can have their own Hero.
Oh just to mention, I am still using the old jass script since the new one you sent does not work. it gives me a error when trying to save:

"Too many arguments passed to function skill_tracker_update"


//===========================================================================
// Trigger: ST Learn Skill
//===========================================================================
function Trig_ST_Learn_Skill_Actions takes nothing returns nothing
// Update the learned skill.
call Skill_Tracker_Update(GetTriggerUnit() , GetLearnedSkill() , GetLearnedSkillLevel())
endfunction
and the line is
  • call Skill_Tracker_Update(GetTriggerUnit() , GetLearnedSkill() , GetLearnedSkillLevel())
Could this 2nd demo map version fix this hero issue am having with player 1 and 2 or whats up.


EDIT:

I just now was thinking about it, but does it matter that I do all this heroarray setting and moving in another trigger, should it be all in the same? I believe that could be mixing something up as its all happening at the same time...


After testing and fixing my triggers and actually puttin this whole HeroArray[PN] set at the same hero trained trigger seemed to fix this for now (for same hero type etc) ill test it on different heros now on 3 players.


Alright it's working fine now for all 3 heroes. This was all propably just cause of my stupidity in the end. Sorting the triggers and combining them seemed to be the best fix.
 
Last edited:
Top