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

Help request for goal: Units with various modificable fields.

Status
Not open for further replies.
Level 3
Joined
Sep 25, 2021
Messages
30
Summary:

On a map with hundreds of units, i need that every unit has more than 10 customizable values, other than life or mana.

Objective:

Melones warcraft.jpeg


Suposse that i want to make a map about growing units that are watermelons.

Every watermelon has its own ripeness, an own harshness, an own humidity, sweetness, seediness, chillness, and 10 other fields.
These are "characteristics".

Their characteristics change, for example:
When someone throws water on a watermelon, this watermelon gets its humidity value increased.
When some watermelons roll near a sugar field, these watermelons have their sweetness increased.

But every watermelon has its own, not all of them have the same humidity or and sweetness, or ripeness.

I do not care if the characteristics are not visible, i just need to have the value of each watermelon stored somewhere.

Problems to face:

Units do not have a personal indicator of sweetness or ripeness, in place they come with indicators of life, mana, others.

The watermelon characteristics that i invented are not 2 or 4, they are more than 20.

Trials:

I tried to pretend the life to be their ripeness, mana simulate the humidity, turn value to be the saltness, and others.
There are not abundant fields for that.
This leads to too much memorizing.

Request of solution:

Should i use arrays or hash tables to save and store how ripe each watermelon is, or how much humidity every watermelon has, etc.?

Could you do this without making, for example, an ability for ripeness and changing its level to indicate how ripe it is, or making an ability for humidity to know and obtain the watermelon's humidity?

Greetings:

Thank you.
 
Last edited:
Level 25
Joined
Sep 26, 2009
Messages
2,378
Best way would be to use a hash table - the unit itself is the key and subkeys are your characteristics - ripeness, sweetness, etc.
For example this could be part of your map initialization trigger
  • Unit Group - Pick every unit in (Units in (Playable map area) matching ((Unit-type of (Matching unit)) Equal to Watermelon)) and do (Actions)
    • Loop - Actions
      • Hashtable - Save 0.00 as (Key Sweetness.) of (Key (Picked unit).) in WatermelonValues.
      • Hashtable - Save 100.00 as (Key Moisture.) of (Key (Picked unit).) in WatermelonValues.

I would not do this via ability, since abilities are complex structures not meant to be used this way and not meant to have too many level (i.e. 1000 levels for sweetness). They would scale badly.

I am not sure how/if you want to visualize all characteristics, but there are options like showing a custom bars (for example via floating text) or if the player is owner of the watermelon, you could create a single passive ability and change it's extended tooltip to reflect the current values in the hashtable.
That way, the owning player would just mouse over the passive ability to see how the watermelon is doing
 
Level 3
Joined
Sep 25, 2021
Messages
30
Best way would be to use a hash table - the unit itself is the key and subkeys are your characteristics - ripeness, sweetness, etc.
For example this could be part of your map initialization trigger
  • Unit Group - Pick every unit in (Units in (Playable map area) matching ((Unit-type of (Matching unit)) Equal to Watermelon)) and do (Actions)
    • Loop - Actions
      • Hashtable - Save 0.00 as (Key Sweetness.) of (Key (Picked unit).) in WatermelonValues.
      • Hashtable - Save 100.00 as (Key Moisture.) of (Key (Picked unit).) in WatermelonValues.

I would not do this via ability, since abilities are complex structures not meant to be used this way and not meant to have too many level (i.e. 1000 levels for sweetness). They would scale badly.

I am not sure how/if you want to visualize all characteristics, but there are options like showing a custom bars (for example via floating text) or if the player is owner of the watermelon, you could create a single passive ability and change it's extended tooltip to reflect the current values in the hashtable.
That way, the owning player would just mouse over the passive ability to see how the watermelon is doing
This is very helpful.
I will present you around 10 questions next.

Regarding storing:

If you do not want to paste a tutorial of a hash table, i would like to learn what "save (x number) as" means.
How do you obtain and modify the values of a characteristic of a key/watermelon, or are the values uneditable after you put on the table?

I did not emphasize that watermelons can born on the map, not all exist beforehand, so i would need a way to store them on the Almighty Table Of Characteristics everytime that they enter the map.

Regarding displaying:

Would not giving them too many floating texts cause lags or leaks?
How or what command do you write on a text, to obtain and display on a part of it, a string (real or integer) which is the value of a characteristic of a key/unit?
I do not have much experience with floaty texts.
Can you paste a way to make multiple floating bars using floating texts?
I would like it too if they shown numbers instead of bars.
The characteristics are a lot, but it is useful if i want to display 2 or 3 important score of characteristics.

Currently, only the owner being able to view how their watermelons are doing is fine.

How or what code should i put on the tooltip of an ability to display the value of a characteristic of the watermelon?

Thanks for the response.
 
Level 3
Joined
Sep 25, 2021
Messages
30
Custom UI can display this stuff as well if you're comfortable with Jass/Lua. Check out Tasyen's tutorials on the matter.
I am more concerned to store the values, to be able to get the triggers to recognize them, and to edit them through functions, than to display the values to the players. I may find about custom ui after i do the storing part first. Thanks for that info.
 
Level 3
Joined
Sep 25, 2021
Messages
30
I am more concerned to store the values, to be able to get the triggers to recognize them, and to edit them through functions, than to display the values to the players. I may find about custom ui after i do the storing part first. Thanks for that info.
It is intended to be shown, but i want to resolve the system first, to keep an order.
I am about to learn jass on these days, yet, i am very comfortable with gui.
 
Level 25
Joined
Sep 26, 2009
Messages
2,378
If you do not want to paste a tutorial of a hash table, i would like to learn what "save (x number) as" means.

You can think of hashtables as two dimensional arrays. The action
  • Hashtable - Save <value> as <ChildKey> of <ParentKey> in Hashtable.
would be an equivalent to a two-dimensional array:
Code:
TwoDimensionalArray[ParentKey][ChildKey] = value
You access values of first array via ParentKey. What is stored under index ParentKey is actually another array. You access/set values in the second array via ChildKey.

In my example, I had the ParentKey as "Key (Picked unit)" - this returns the unit's HandleID - a unique identifier amongst all objects (handles) in the game. This way I am sure that only the specific unit can access its own data in the hashtable and no other unit will overwrite them.
You are not limited to only handle IDs - you can use an integer, or in my case, create a key from string (in my example, that's the "Key sweetness").
Do note that string keys are case-sensitive, so "Sweetness" (capital S) and "sweetness" are two different keys.

Another thing to note: I wrote that you can think of hashtables as two-dimensional arrays, but they are not exactly the same (e.g. hashtable can save multiple data types, while array can save only single data type, ...).
If you want a tutorial, you can check this: A Complete Beginners Guide to Hashtables

How do you obtain and modify the values of a characteristic of a key/watermelon, or are the values uneditable after you put on the table?
The "Hashtable - Save ..." actions set values in hashtables. If you use the same pair of ParentKey and ChildKey, you will overwrite existing values (if any) in the hashtable. So this way you can update your watermelon characteristics.
When you are setting a value to a variable, you have the option to "Hashtable - Load ...", which will read the value from the hashtable, provided you use the correct pair of ParentKey and ChildKey.
  • Hashtable - Save 0.00 as (Key Sweetness.) of (Key (Picked unit).) in WatermelonValues. //sets value
  • Set VariableSet sweetness = (Load (Key Sweetness.) of (Key (Picked unit).) from WatermelonValues.) //gets value

I did not emphasize that watermelons can born on the map, not all exist beforehand, so i would need a way to store them on the Almighty Table Of Characteristics everytime that they enter the map.
This is one of the annoying things about hashtables - if you cannot refer to your unit via event responses like (Triggering unit), (Last created unit), (Picked unit), etc., then you will have to use a custom script to get the handleID of your unit.
  • Set VariableSet UnitVar = Paladin 0000 <gen>
  • Custom script: set udg_HandleIdVar = GetHandleId(udg_UnitVar)
  • Hashtable - Save 0.00 as (Key Sweetness.) of HandleIdVar in WatermelonValues.
  • UnitVar is a variable of type "unit"
  • HandleIdVar is a variable of type "int"
  • When referring to global variables (created via GUI) in custom script, you have to prefix them with "udg_"

Would not giving them too many floating texts cause lags or leaks?
How or what command do you write on a text, to obtain and display on a part of it, a string (real or integer) which is the value of a characteristic of a key/unit?
I do not have much experience with floaty texts.
Can you paste a way to make multiple floating bars using floating texts?
I would like it too if they shown numbers instead of bars.
The characteristics are a lot, but it is useful if i want to display 2 or 3 important score of characteristics.
Floating texts are pretty lightweight and they don't leak if you dispose of them properly. I don't think many floating texts would lag your game
But from user experience, 10+ characteristics is too much to display, considering you have ~100 watermelons in the game - even if you do it via floating text or UI widgets as Uncle pointed out, all you would see in your map would be clusters or floating texts/widgets, hiding the game beneath them.

The loading bar via floating texts basically uses 10 dot '.' characters and changes their color to represent the value. E.g. 30% would be displayed as 3 blue dots and 7 black dots: "oooooooooo". You could also do a linear interpolation between blue and black to show values between... e.g. 35% could be "oooooooooo"
I think there were also progress/loading bars as special effects in the resource section on this site - similar to the floating texts, you would manipulate the special effect to show your progress.
In both cases, you are limited by the "display granularity" of the bar
  • the floating text has 10 dots, so you can display states by 10%. The linear interpolation may somewhat help
  • special effects are limited by how many "frames" the animation has. If the bar has only 20 frames to display progress bar going from empty to full, then your granularity is 5%
Both of those are way too small numbers, considering your sweetness has max value 1000.
Or do it via the UI frames that Uncle wrote about - but that will require jass or lua knowledge.
Edit: OR consider using something else - change the units color, size to determine ripeness and sweetness, add some watery effect to show moisture, etc.

Currently, only the owner being able to view how their watermelons are doing is fine.

How or what code should i put on the tooltip of an ability to display the value of a characteristic of the watermelon?
If you want to do it via an ability, then you will need to base the ability off an aura-type ability (e.g. devotion aura) - for some reason I am unable to change tooltips of passive abilities (like evasion, critical strike, etc.).
In your aura-type ability, just change the "Stats - Area of Effect" to some low value like 10.0 and change "Stats - Targets allowed" to "None". This way nobody will benefit from the aura.

What you want is to update values only of units that are selected (since you cannot mouse-over the ability of units you did not select).
The following will fire when player selects a unit. It will load its values from hashtable, build the tooltip text and update the tooltip of its "Stats" ability:
  • Untitled Trigger 002
    • Events
      • Player - Player 1 (Red) Selects a unit
    • Conditions
      • (Unit-type of (Triggering unit)) Equal to Watermelon
    • Actions
      • -------- load values --------
      • Set VariableSet sweetness = (Load (Key Sweetness.) of (Key (Triggering unit).) from WatermelonValues.)
      • Set VariableSet ripeness = (Load (Key Ripeness.) of (Key (Triggering unit).) from WatermelonValues.)
      • Set VariableSet moisture = (Load (Key Moisture.) of (Key (Triggering unit).) from WatermelonValues.)
      • -------- create tooltip --------
      • Set VariableSet Tooltip = (Sweetness: + (String(sweetness)))
      • Set VariableSet Tooltip = (Tooltip + (|nRipeness: + (String(ripeness))))
      • Set VariableSet Tooltip = (Tooltip + (|nMoisture: + (String(moisture))))
      • -------- update tooltip --------
      • Ability - Set Ability: (Unit: (Triggering unit)'s Ability with Ability Code: Stats )'s String Level Field: Tooltip - Normal - Extended ('aub1') of Level: 0 to Tooltip
      • Unit - Increase level of Stats for (Triggering unit)
      • Unit - Decrease level of Stats for (Triggering unit)

Or you can periodically get player's current unit selection, check if any watermelons are selected and update their values:
  • Untitled Trigger 003
    • Events
      • Time - Every 1.00 seconds of game time
    • Conditions
    • Actions
      • Custom script: set bj_wantDestroyGroup = true
      • Unit Group - Pick every unit in (Units currently selected by Player 1 (Red)) and do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Unit-type of (Picked unit)) Equal to Watermelon
            • Then - Actions
              • -------- update tooltip --------
            • Else - Actions
 
Last edited:

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,534
To add to what Nichilus said, you could also update the Ability tooltip whenever these stats are changed.

So a system could be thrown together to make it easy for yourself which would have multiple functions:
AddSweetness(amount)
AddRipeness(amount)
AddMoisture(amount)

When you call these functions you simply supply how much you want to adjust a given stat. Then these functions will do the Hashtable math for you and save the new value. Finally, there would be another function: UpdateStats()

This function would update the tooltip for the modified unit. So you would call it after adding your stats. For subtracting stats, simply supply a negative amount. You'll probably need to do some math to make sure that a value doesn't go below 0 or 1 so a unit doesn't end up with negative stats.

A Jass example (or hybrid GUI I guess):
  • Actions:
  • Set Variable ModifyTarget = Your unit
  • Custom script: call AddSweetness(10)
  • Custom script: call UpdateStats()
The Jass functions would reference ModifyTarget in their calculations.

A GUI example:
  • Actions:
  • Set Variable ModifyTarget = Your unit
  • Set Variable ModifyAmount = 10
  • Trigger - Run AddSweetness (ignoring conditions)
  • Trigger - Run UpdateStats (ignoring conditions)
The triggers that you run would reference ModifyTarget and ModifyAmount in their calculations.

I like designing systems like these because they're more Event based (Action -> Reaction), it makes sense to only update something that has actually changed. Plus this design can help with performance since you aren't doing unnecessary calculations all of the time. On top of that, it can make your life a lot easier when designing triggers in the future since you no longer have to touch the Hashtable stuff once the system is in place. A good system hides all of the complicated stuff behind the scenes and gives the user an easy to use interface to work with.
 
Last edited:
Level 3
Joined
Sep 25, 2021
Messages
30
Thanks Nich and Uncle for your applications in responses.
I respond early to stay present, but unfortunately, i have to get a space and mental state to do all of the testing.
i will come with new uncertainment and questions many days later on, so as one excuse to not get the thread closed.
I do not know if you get pinged for a message that is not parent quoted, such as this. I know that the moderation of text will deliver this text later too.
I will get my hands on the map after i get free time to do the sit.

A proximate map "x" is not centered on fruits, but watermelons are round (punny) subject objects and a good analogy of the relation of the units and system.
The map may have added a sort of memory of credits, it may be just a text, or to go about a phisical immersion, a mossy, old pillar dug on earth, messaged by with the user names that helped aspects on development.
 
Level 3
Joined
Sep 25, 2021
Messages
30
You can think of hashtables as two dimensional arrays. The action
  • Hashtable - Save <value> as <ChildKey> of <ParentKey> in Hashtable.
would be an equivalent to a two-dimensional array:
Code:
TwoDimensionalArray[ParentKey][ChildKey] = value
You access values of first array via ParentKey. What is stored under index ParentKey is actually another array. You access/set values in the second array via ChildKey.

In my example, I had the ParentKey as "Key (Picked unit)" - this returns the unit's HandleID - a unique identifier amongst all objects (handles) in the game. This way I am sure that only the specific unit can access its own data in the hashtable and no other unit will overwrite them.
You are not limited to only handle IDs - you can use an integer, or in my case, create a key from string (in my example, that's the "Key sweetness").
Do note that string keys are case-sensitive, so "Sweetness" (capital S) and "sweetness" are two different keys.

Another thing to note: I wrote that you can think of hashtables as two-dimensional arrays, but they are not exactly the same (e.g. hashtable can save multiple data types, while array can save only single data type, ...).
If you want a tutorial, you can check this: A Complete Beginners Guide to Hashtables


The "Hashtable - Save ..." actions set values in hashtables. If you use the same pair of ParentKey and ChildKey, you will overwrite existing values (if any) in the hashtable. So this way you can update your watermelon characteristics.
When you are setting a value to a variable, you have the option to "Hashtable - Load ...", which will read the value from the hashtable, provided you use the correct pair of ParentKey and ChildKey.
  • Hashtable - Save 0.00 as (Key Sweetness.) of (Key (Picked unit).) in WatermelonValues. //sets value
  • Set VariableSet sweetness = (Load (Key Sweetness.) of (Key (Picked unit).) from WatermelonValues.) //gets value


This is one of the annoying things about hashtables - if you cannot refer to your unit via event responses like (Triggering unit), (Last created unit), (Picked unit), etc., then you will have to use a custom script to get the handleID of your unit.
  • Set VariableSet UnitVar = Paladin 0000 <gen>
  • Custom script: set udg_HandleIdVar = GetHandleId(udg_UnitVar)
  • Hashtable - Save 0.00 as (Key Sweetness.) of HandleIdVar in WatermelonValues.
  • UnitVar is a variable of type "unit"
  • HandleIdVar is a variable of type "int"
  • When referring to global variables (created via GUI) in custom script, you have to prefix them with "udg_"


Floating texts are pretty lightweight and they don't leak if you dispose of them properly. I don't think many floating texts would lag your game
But from user experience, 10+ characteristics is too much to display, considering you have ~100 watermelons in the game - even if you do it via floating text or UI widgets as Uncle pointed out, all you would see in your map would be clusters or floating texts/widgets, hiding the game beneath them.

The loading bar via floating texts basically uses 10 dot '.' characters and changes their color to represent the value. E.g. 30% would be displayed as 3 blue dots and 7 black dots: "oooooooooo". You could also do a linear interpolation between blue and black to show values between... e.g. 35% could be "oooooooooo"
I think there were also progress/loading bars as special effects in the resource section on this site - similar to the floating texts, you would manipulate the special effect to show your progress.
In both cases, you are limited by the "display granularity" of the bar
  • the floating text has 10 dots, so you can display states by 10%. The linear interpolation may somewhat help
  • special effects are limited by how many "frames" the animation has. If the bar has only 20 frames to display progress bar going from empty to full, then your granularity is 5%
Both of those are way too small numbers, considering your sweetness has max value 1000.
Or do it via the UI frames that Uncle wrote about - but that will require jass or lua knowledge.
Edit: OR consider using something else - change the units color, size to determine ripeness and sweetness, add some watery effect to show moisture, etc.


If you want to do it via an ability, then you will need to base the ability off an aura-type ability (e.g. devotion aura) - for some reason I am unable to change tooltips of passive abilities (like evasion, critical strike, etc.).
In your aura-type ability, just change the "Stats - Area of Effect" to some low value like 10.0 and change "Stats - Targets allowed" to "None". This way nobody will benefit from the aura.

What you want is to update values only of units that are selected (since you cannot mouse-over the ability of units you did not select).
The following will fire when player selects a unit. It will load its values from hashtable, build the tooltip text and update the tooltip of its "Stats" ability:
  • Untitled Trigger 002
    • Events
      • Player - Player 1 (Red) Selects a unit
    • Conditions
      • (Unit-type of (Triggering unit)) Equal to Watermelon
    • Actions
      • -------- load values --------
      • Set VariableSet sweetness = (Load (Key Sweetness.) of (Key (Triggering unit).) from WatermelonValues.)
      • Set VariableSet ripeness = (Load (Key Ripeness.) of (Key (Triggering unit).) from WatermelonValues.)
      • Set VariableSet moisture = (Load (Key Moisture.) of (Key (Triggering unit).) from WatermelonValues.)
      • -------- create tooltip --------
      • Set VariableSet Tooltip = (Sweetness: + (String(sweetness)))
      • Set VariableSet Tooltip = (Tooltip + (|nRipeness: + (String(ripeness))))
      • Set VariableSet Tooltip = (Tooltip + (|nMoisture: + (String(moisture))))
      • -------- update tooltip --------
      • Ability - Set Ability: (Unit: (Triggering unit)'s Ability with Ability Code: Stats )'s String Level Field: Tooltip - Normal - Extended ('aub1') of Level: 0 to Tooltip
      • Unit - Increase level of Stats for (Triggering unit)
      • Unit - Decrease level of Stats for (Triggering unit)

Or you can periodically get player's current unit selection, check if any watermelons are selected and update their values:
  • Untitled Trigger 003
    • Events
      • Time - Every 1.00 seconds of game time
    • Conditions
    • Actions
      • Custom script: set bj_wantDestroyGroup = true
      • Unit Group - Pick every unit in (Units currently selected by Player 1 (Red)) and do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Unit-type of (Picked unit)) Equal to Watermelon
            • Then - Actions
              • -------- update tooltip --------
            • Else - Actions

To add to what Nichilus said, you could also update the Ability tooltip whenever these stats are changed.

So a system could be thrown together to make it easy for yourself which would have multiple functions:
AddSweetness(amount)
AddRipeness(amount)
AddMoisture(amount)

When you call these functions you simply supply how much you want to adjust a given stat. Then these functions will do the Hashtable math for you and save the new value. Finally, there would be another function: UpdateStats()

This function would update the tooltip for the modified unit. So you would call it after adding your stats. For subtracting stats, simply supply a negative amount. You'll probably need to do some math to make sure that a value doesn't go below 0 or 1 so a unit doesn't end up with negative stats.

A Jass example (or hybrid GUI I guess):
  • Actions:
  • Set Variable ModifyTarget = Your unit
  • Custom script: call AddSweetness(10)
  • Custom script: call UpdateStats()
The Jass functions would reference ModifyTarget in their calculations.

A GUI example:
  • Actions:
  • Set Variable ModifyTarget = Your unit
  • Set Variable ModifyAmount = 10
  • Trigger - Run AddSweetness (ignoring conditions)
  • Trigger - Run UpdateStats (ignoring conditions)
The triggers that you run would reference ModifyTarget and ModifyAmount in their calculations.

I like designing systems like these because they're more Event based (Action -> Reaction), it makes sense to only update something that has actually changed. Plus this design can help with performance since you aren't doing unnecessary calculations all of the time. On top of that, it can make your life a lot easier when designing triggers in the future since you no longer have to touch the Hashtable stuff once the system is in place. A good system hides all of the complicated stuff behind the scenes and gives the user an easy to use interface to work with.

I replied on an upper message)
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,534
We all get Notifications (the bell in the top right) the moment anything happens in this thread. But editing a comment won't create a notification. Feel free to post a new reply since it makes things a bit easier to follow, just don't spam.

Anyway, the Object Editor cannot communicate with the Trigger Editor so it can't reference Variables and what not. The ability tooltip should be updated through triggers, so you wouldn't need to edit the tooltip inside of the Object Editor at all.

Edit:
I created a stat system for you (credits to Nichilus as well) using your example as a base for it. I personally find it easier to learn when I can see the triggers in the editor and mess around with them myself rather than reading them from a forum post. Obviously you would edit these stats to fit your game instead of using the fruit example.

An example of adding 50 moisture to a unit:
  • DEMO 2
    • Events
      • Unit - A unit Learns a skill
    • Conditions
      • (Learned Hero Skill) Equal to Divine Shield
    • Actions
      • -------- This will add 50 to the Paladin's Moisture stat: --------
      • Set VariableSet Stat_Target = (Triggering unit)
      • Set VariableSet Stat_Amount = 50
      • Trigger - Run Add Moisture <gen> (ignoring conditions)
But maybe you want to add some more stats:
  • DEMO 2
    • Events
      • Unit - A unit Learns a skill
    • Conditions
      • (Learned Hero Skill) Equal to Divine Shield
    • Actions
      • -------- This will add 50 to the Paladin's Moisture stat: --------
      • Set VariableSet Stat_Target = (Triggering unit)
      • Set VariableSet Stat_Amount = 50
      • Trigger - Run Add Moisture <gen> (ignoring conditions)
      • -------- This will add 200 to the Paladin's Ripeness stat: --------
      • Set VariableSet Stat_Amount = 200
      • Trigger - Run Add Ripeness <gen> (ignoring conditions)

So all you have to do is set the Stat_Target variable and the Stat_Amount variable and then Run the desired Add Stat trigger. I have an Add trigger for each stat, Moisture, Ripeness, Sweetness, Seed Density, and a 5th one that does ALL of them at once.

If you wanted to add a new stat to the system you would need to update these triggers:
Setup Custom Stats, Add Base Stats To Hashtable, Initialize Base Stats, Load Stats Variables, Update Stats Tooltip, and Add All

And create a new trigger for the stat the way I did it for the other 4 stats. So just copy and paste an existing trigger like Add Moisture and edit it to use your new stat's variables.

It shouldn't take more than a few minutes once you get the hang of it. The stats all use the same design pattern so it's just a matter of following this pattern. Copy and paste comes in handy here!
 

Attachments

  • Stat System 1.w3m
    25.4 KB · Views: 12
Last edited:
Level 3
Joined
Sep 25, 2021
Messages
30
We all get Notifications (the bell in the top right) the moment anything happens in this thread. But editing a comment won't create a notification. Feel free to post a new reply since it makes things a bit easier to follow, just don't spam.

Anyway, the Object Editor cannot communicate with the Trigger Editor so it can't reference Variables and what not. The ability tooltip should be updated through triggers, so you wouldn't need to edit the tooltip inside of the Object Editor at all.

Edit:
I created a stat system for you (credits to Nichilus as well) using your example as a base for it. I personally find it easier to learn when I can see the triggers in the editor and mess around with them myself rather than reading them from a forum post. Obviously you would edit these stats to fit your game instead of using the fruit example.

An example of adding 50 moisture to a unit:
  • DEMO 2
    • Events
      • Unit - A unit Learns a skill
    • Conditions
      • (Learned Hero Skill) Equal to Divine Shield
    • Actions
      • -------- This will add 50 to the Paladin's Moisture stat: --------
      • Set VariableSet Stat_Target = (Triggering unit)
      • Set VariableSet Stat_Amount = 50
      • Trigger - Run Add Moisture <gen> (ignoring conditions)
But maybe you want to add some more stats:
  • DEMO 2
    • Events
      • Unit - A unit Learns a skill
    • Conditions
      • (Learned Hero Skill) Equal to Divine Shield
    • Actions
      • -------- This will add 50 to the Paladin's Moisture stat: --------
      • Set VariableSet Stat_Target = (Triggering unit)
      • Set VariableSet Stat_Amount = 50
      • Trigger - Run Add Moisture <gen> (ignoring conditions)
      • -------- This will add 200 to the Paladin's Ripeness stat: --------
      • Set VariableSet Stat_Amount = 200
      • Trigger - Run Add Ripeness <gen> (ignoring conditions)

So all you have to do is set the Stat_Target variable and the Stat_Amount variable and then Run the desired Add Stat trigger. I have an Add trigger for each stat, Moisture, Ripeness, Sweetness, Seed Density, and a 5th one that does ALL of them at once.

If you wanted to add a new stat to the system you would need to update these triggers:
Setup Custom Stats, Add Base Stats To Hashtable, Initialize Base Stats, Load Stats Variables, Update Stats Tooltip, and Add All

And create a new trigger for the stat the way I did it for the other 4 stats. So just copy and paste an existing trigger like Add Moisture and edit it to use your new stat's variables.

It shouldn't take more than a few minutes once you get the hang of it. The stats all use the same design pattern so it's just a matter of following this pattern. Copy and paste comes in handy here!

Alright, i will not do description edits.

Thanks for the time on doing this trigger.
It is a shame that i cannot open the file for the error "Level data is either missing or invalid".
I understand how target is the unit and value the amount, although i cannot see the curious triggers Add moisture and Add rippeness with methods of modification, as i cannot open the map.

Good morning.
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,534
Ah, you're using an older version of warcraft 3. I'll attach the triggers.
What you need to do:
  • Download the attached trigger file.
  • Create a new map.
  • Go into the Object Editor and copy and paste the Devotion Aura ability.
  • Edit it so that it's a Unit ability with 1 level, Targets Allowed set to None, and Area of Effect 0.
  • Give the Paladin/Archmage heroes this ability in the Object Editor (Abilities - Normal).
  • Go into the Trigger Editor and click File/Import Triggers. Import the attached trigger file.
  • Click the Setup Custom Stats trigger and make sure that the Stat_TooltipAbility variable is set to the new ability you created.
  • Click the Initialize Base Stats trigger and make sure that the Condition is setup properly, it should reference the new ability.
 

Attachments

  • Stat System Triggers.wtg
    23.1 KB · Views: 13

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,534
Maybe it's because your editor isn't in English, I don't really know. You can try downloading and importing the triggers again, I edited them slightly.

What version of warcraft 3 are you using?

Edit: Updated the system slightly. Fixed a minor bug.
 

Attachments

  • Stat System 2.w3m
    25.4 KB · Views: 20
  • Stat System 2.wtg
    22.4 KB · Views: 12
Last edited:
Level 3
Joined
Sep 25, 2021
Messages
30
Maybe it's because your editor isn't in English, I don't really know. You can try downloading and importing the triggers again, I edited them slightly.

What version of warcraft 3 are you using?

Edit: Updated the system slightly. Fixed a minor bug.
Nice to get corrected.
I cannot open your files.

Could i change the language in my pirate version? I saw some tutorials involving a prebuilt app called regedit, but what i see is different from the sites.

Unknown version on the world editor
1.27.1.7085 on the warcraft game

Alternatively may it be because the route of the game and editor do not come from C:/Apps but from C:/Doccuments?

There is a bug as well - in my editor, if a map has tiles from the tileset Urban/City, it crashes.
 
Level 3
Joined
Sep 25, 2021
Messages
30
I would buy the game, lol. Editor matches the version of the game. I'm using the latest version 1.32+.
Alternatively, could you cut a few screens of the triggers and add a mininote in case that there is something, so i can replicate it on the editor?
Then i would come with questions again, an so on.
It can lead to the creation of a slightly good map.

Sadly i dont earn in dollars neither got a card for dollar transactions.

--As side note, i have been told that blizzard is legally on possesions of whatever you create with the world editor.
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,534
I can post the triggers soon.

But the possession thing isn't something to worry about. Starcraft 2 has had the same terms all of these years and they've never "taken" someone's map, it's just not going to happen. They don't care about your map even if it's a lot of fun. They've practically abandoned the game at this point anyway.
  • Setup Custom Stats
    • Events
      • Map initialization
    • Conditions
    • Actions
      • -------- Set this to the tooltip ability created in the object editor: --------
      • Set VariableSet Stat_TooltipAbility = Bonus Stats
      • -------- --------
      • -------- Then create and store the hashtable: --------
      • Hashtable - Create a hashtable
      • Set VariableSet Stat_Hashtable = (Last created hashtable)
      • -------- --------
      • -------- Then give each stat key a unique value (follow the pattern for new stats): --------
      • Set VariableSet Moisture_Key = 0
      • Set VariableSet Ripeness_Key = 1
      • Set VariableSet Sweetness_Key = 2
      • Set VariableSet SeedDensity_Key = 3
      • -------- --------
      • -------- Then define how many units will use this system (update this whenever you add a new unit): --------
      • Set VariableSet Stat_TotalUnitTypes = 2
      • -------- --------
      • -------- Then define the units that use this stat system and their base stats: --------
      • Set VariableSet Stat_UnitType[1] = Paladin
      • Set VariableSet Stat_Moisture[1] = 5
      • Set VariableSet Stat_Ripeness[1] = 10
      • Set VariableSet Stat_Sweetness[1] = 15
      • Set VariableSet Stat_SeedDensity[1] = 20
      • -------- --------
      • Set VariableSet Stat_UnitType[2] = Archmage
      • Set VariableSet Stat_Moisture[2] = 12
      • Set VariableSet Stat_Ripeness[2] = 24
      • Set VariableSet Stat_Sweetness[2] = 36
      • Set VariableSet Stat_SeedDensity[2] = 48
      • -------- --------
      • -------- Finally, run a trigger which will add these base stats to the hashtable: --------
      • Trigger - Run Add Base Stats To Hashtable <gen> (ignoring conditions)
  • Add Base Stats To Hashtable
    • Events
    • Conditions
    • Actions
      • -------- This will loop over all of the units in Stat_UnitType and save their base stats to the hashtable: --------
      • -------- ( Note: This data is used to initialize a unit's base stats ) --------
      • For each (Integer Stat_Loop) from 1 to Stat_TotalUnitTypes, do (Actions)
        • Loop - Actions
          • Custom script: set udg_Stat_Id = udg_Stat_UnitType[udg_Stat_Loop]
          • Hashtable - Save Stat_Moisture[Stat_Loop] as Moisture_Key of Stat_Id in Stat_Hashtable.
          • Hashtable - Save Stat_Ripeness[Stat_Loop] as Ripeness_Key of Stat_Id in Stat_Hashtable.
          • Hashtable - Save Stat_Sweetness[Stat_Loop] as Sweetness_Key of Stat_Id in Stat_Hashtable.
          • Hashtable - Save Stat_SeedDensity[Stat_Loop] as SeedDensity_Key of Stat_Id in Stat_Hashtable.
  • Initialize Base Stats
    • Events
      • Unit - A unit enters (Playable map area)
    • Conditions
      • (Level of Stat_TooltipAbility for (Triggering unit)) Equal to 1
    • Actions
      • -------- This custom script sets the Stat_Id variable to be equal to the unit's Unit-Type id. --------
      • -------- Each Unit-Type in warcraft 3 has it's own unique Unit-Type id (also known as a rawcode) that sets them apart: --------
      • Set VariableSet Stat_Target = (Triggering unit)
      • Custom script: set udg_Stat_Id = GetUnitTypeId(udg_Stat_Target)
      • Custom script: set udg_Stat_TargetKey = udg_Stat_Target
      • -------- --------
      • -------- Now that we have the unit's Unit-Type id, we can use that to load it's base stats from the hashtable and save them directly to the unit: --------
      • -------- ( Note: I'm reusing these Stat_ variables since their [0] array is unused in our Setup trigger. This is just to use less variables ) --------
      • Set VariableSet Stat_Moisture[0] = (Load Moisture_Key of Stat_Id from Stat_Hashtable.)
      • Set VariableSet Stat_Ripeness[0] = (Load Ripeness_Key of Stat_Id from Stat_Hashtable.)
      • Set VariableSet Stat_Sweetness[0] = (Load Sweetness_Key of Stat_Id from Stat_Hashtable.)
      • Set VariableSet Stat_SeedDensity[0] = (Load SeedDensity_Key of Stat_Id from Stat_Hashtable.)
      • -------- --------
      • -------- We've loaded the base stats into these variables and now we can save them directly to the unit: --------
      • Hashtable - Save Stat_Moisture[0] as Moisture_Key of (Key Stat_TargetKey.) in Stat_Hashtable.
      • Hashtable - Save Stat_Ripeness[0] as Ripeness_Key of (Key Stat_TargetKey.) in Stat_Hashtable.
      • Hashtable - Save Stat_Sweetness[0] as Sweetness_Key of (Key Stat_TargetKey.) in Stat_Hashtable.
      • Hashtable - Save Stat_SeedDensity[0] as SeedDensity_Key of (Key Stat_TargetKey.) in Stat_Hashtable.
      • -------- --------
      • Trigger - Run Update Stats Tooltip <gen> (ignoring conditions)
  • Add Moisture
    • Events
    • Conditions
    • Actions
      • Custom script: set udg_Stat_TargetKey = udg_Stat_Target
      • -------- --------
      • -------- Load the unit's current stat and adjust it: --------
      • Trigger - Run Load Stats Variables <gen> (ignoring conditions)
      • -------- --------
      • Set VariableSet Stat_Moisture[0] = (Stat_Moisture[0] + Stat_Amount)
      • -------- --------
      • -------- Prevent the adjusted stat from going below 1: --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Stat_Moisture[0] Less than or equal to 0
        • Then - Actions
          • Set VariableSet Stat_Moisture[0] = 1
        • Else - Actions
      • -------- --------
      • -------- Save the new stat: --------
      • Hashtable - Save Stat_Moisture[0] as Moisture_Key of (Key Stat_TargetKey.) in Stat_Hashtable.
      • -------- --------
      • -------- Run this last to update the ability tooltip: --------
      • Trigger - Run Update Stats Tooltip <gen> (ignoring conditions)
  • Add Ripeness
    • Events
    • Conditions
    • Actions
      • Custom script: set udg_Stat_TargetKey = udg_Stat_Target
      • -------- --------
      • -------- Load the unit's current stat and adjust it: --------
      • Trigger - Run Load Stats Variables <gen> (ignoring conditions)
      • -------- --------
      • Set VariableSet Stat_Ripeness[0] = (Stat_Ripeness[0] + Stat_Amount)
      • -------- --------
      • -------- Prevent the adjusted stat from going below 1: --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Stat_Ripeness[0] Less than or equal to 0
        • Then - Actions
          • Set VariableSet Stat_Ripeness[0] = 1
        • Else - Actions
      • -------- --------
      • -------- Save the new stat: --------
      • Hashtable - Save Stat_Ripeness[0] as Ripeness_Key of (Key Stat_TargetKey.) in Stat_Hashtable.
      • -------- --------
      • -------- Run this last to update the ability tooltip: --------
      • Trigger - Run Update Stats Tooltip <gen> (ignoring conditions)
  • Add Sweetness
    • Events
    • Conditions
    • Actions
      • Custom script: set udg_Stat_TargetKey = udg_Stat_Target
      • -------- --------
      • -------- Load the unit's current stat and adjust it: --------
      • Trigger - Run Load Stats Variables <gen> (ignoring conditions)
      • -------- --------
      • Set VariableSet Stat_Sweetness[0] = (Stat_Sweetness[0] + Stat_Amount)
      • -------- --------
      • -------- Prevent the adjusted stat from going below 1: --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Stat_Sweetness[0] Less than or equal to 0
        • Then - Actions
          • Set VariableSet Stat_Sweetness[0] = 1
        • Else - Actions
      • -------- --------
      • -------- Save the new stat: --------
      • Hashtable - Save Stat_Sweetness[0] as Sweetness_Key of (Key Stat_TargetKey.) in Stat_Hashtable.
      • -------- --------
      • -------- Run this last to update the ability tooltip: --------
      • Trigger - Run Update Stats Tooltip <gen> (ignoring conditions)
  • Add Seed Density
    • Events
    • Conditions
    • Actions
      • Custom script: set udg_Stat_TargetKey = udg_Stat_Target
      • -------- --------
      • -------- Load the unit's current stat and adjust it: --------
      • Trigger - Run Load Stats Variables <gen> (ignoring conditions)
      • -------- --------
      • Set VariableSet Stat_SeedDensity[0] = (Stat_SeedDensity[0] + Stat_Amount)
      • -------- --------
      • -------- Prevent the adjusted stat from going below 1: --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Stat_SeedDensity[0] Less than or equal to 0
        • Then - Actions
          • Set VariableSet Stat_SeedDensity[0] = 1
        • Else - Actions
      • -------- --------
      • -------- Save the new stat: --------
      • Hashtable - Save Stat_SeedDensity[0] as SeedDensity_Key of (Key Stat_TargetKey.) in Stat_Hashtable.
      • -------- --------
      • -------- Run this last to update the ability tooltip: --------
      • Trigger - Run Update Stats Tooltip <gen> (ignoring conditions)
  • Add All
    • Events
    • Conditions
    • Actions
      • Custom script: set udg_Stat_TargetKey = udg_Stat_Target
      • -------- --------
      • -------- Load the unit's current stats and adjust them: --------
      • Trigger - Run Load Stats Variables <gen> (ignoring conditions)
      • -------- --------
      • Set VariableSet Stat_Moisture[0] = (Stat_Moisture[0] + Stat_Amount)
      • Set VariableSet Stat_Ripeness[0] = (Stat_Ripeness[0] + Stat_Amount)
      • Set VariableSet Stat_Sweetness[0] = (Stat_Sweetness[0] + Stat_Amount)
      • Set VariableSet Stat_SeedDensity[0] = (Stat_SeedDensity[0] + Stat_Amount)
      • -------- --------
      • -------- Prevent the adjusted stats from going below 1: --------
      • -------- Moisture: --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Stat_Moisture[0] Less than or equal to 0
        • Then - Actions
          • Set VariableSet Stat_Moisture[0] = 1
        • Else - Actions
      • -------- Ripeness: --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Stat_Ripeness[0] Less than or equal to 0
        • Then - Actions
          • Set VariableSet Stat_Ripeness[0] = 1
        • Else - Actions
      • -------- Sweetness: --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Stat_Sweetness[0] Less than or equal to 0
        • Then - Actions
          • Set VariableSet Stat_Sweetness[0] = 1
        • Else - Actions
      • -------- Seed Density: --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Stat_SeedDensity[0] Less than or equal to 0
        • Then - Actions
          • Set VariableSet Stat_SeedDensity[0] = 1
        • Else - Actions
      • -------- --------
      • -------- Save the new stats: --------
      • Hashtable - Save Stat_Moisture[0] as Moisture_Key of (Key Stat_TargetKey.) in Stat_Hashtable.
      • Hashtable - Save Stat_Ripeness[0] as Ripeness_Key of (Key Stat_TargetKey.) in Stat_Hashtable.
      • Hashtable - Save Stat_Sweetness[0] as Sweetness_Key of (Key Stat_TargetKey.) in Stat_Hashtable.
      • Hashtable - Save Stat_SeedDensity[0] as SeedDensity_Key of (Key Stat_TargetKey.) in Stat_Hashtable.
      • -------- --------
      • -------- Run this last to update the ability tooltip: --------
      • Trigger - Run Update Stats Tooltip <gen> (ignoring conditions)
  • Load Stats Variables
    • Events
    • Conditions
    • Actions
      • -------- Load all of the unit's stats and store them in these variables temporarily: --------
      • Set VariableSet Stat_Moisture[0] = (Load Moisture_Key of (Key Stat_TargetKey.) from Stat_Hashtable.)
      • Set VariableSet Stat_Ripeness[0] = (Load Ripeness_Key of (Key Stat_TargetKey.) from Stat_Hashtable.)
      • Set VariableSet Stat_Sweetness[0] = (Load Sweetness_Key of (Key Stat_TargetKey.) from Stat_Hashtable.)
      • Set VariableSet Stat_SeedDensity[0] = (Load SeedDensity_Key of (Key Stat_TargetKey.) from Stat_Hashtable.)
  • Update Stats Tooltip
    • Events
    • Conditions
    • Actions
      • -------- Finally we update the unit's Bonus Stats ability to display these base stats: --------
      • Set VariableSet Stat_Tooltip = (Moisture: + (String(Stat_Moisture[0])))
      • Set VariableSet Stat_Tooltip = ((Stat_Tooltip + |nRipeness: ) + (String(Stat_Ripeness[0])))
      • Set VariableSet Stat_Tooltip = ((Stat_Tooltip + |nSweetness: ) + (String(Stat_Sweetness[0])))
      • Set VariableSet Stat_Tooltip = ((Stat_Tooltip + |nSeed Density: ) + (String(Stat_SeedDensity[0])))
      • -------- --------
      • -------- This adjusts the abilities extended tooltip to be equal to Stat_Tooltip: --------
      • Ability - Set Ability: (Unit: Stat_Target's Ability with Ability Code: Stat_TooltipAbility)'s String Level Field: Tooltip - Normal - Extended ('aub1') of Level: 0 to Stat_Tooltip
      • Unit - Increase level of Stat_TooltipAbility for Stat_Target
      • Unit - Decrease level of Stat_TooltipAbility for Stat_Target

You probably want to edit this stuff:
  • -------- Prevent the adjusted stat from going below 1: --------
  • If... Set Stat to 1
It's there to prevent a stat from going below 1. You could change it to prevent the stat from going below 0 instead or just delete it entirely and allow stats to become negative. I designed it to work like Hero Attributes since those can't go below 1.

I attached a picture showing all of the variables.
 

Attachments

  • Variables.png
    Variables.png
    853 KB · Views: 14
Last edited:
Level 3
Joined
Sep 25, 2021
Messages
30
You can think of hashtables as two dimensional arrays. The action
  • Hashtable - Save <value> as <ChildKey> of <ParentKey> in Hashtable.
would be an equivalent to a two-dimensional array:
Code:
TwoDimensionalArray[ParentKey][ChildKey] = value
You access values of first array via ParentKey. What is stored under index ParentKey is actually another array. You access/set values in the second array via ChildKey.

In my example, I had the ParentKey as "Key (Picked unit)" - this returns the unit's HandleID - a unique identifier amongst all objects (handles) in the game. This way I am sure that only the specific unit can access its own data in the hashtable and no other unit will overwrite them.
You are not limited to only handle IDs - you can use an integer, or in my case, create a key from string (in my example, that's the "Key sweetness").
Do note that string keys are case-sensitive, so "Sweetness" (capital S) and "sweetness" are two different keys.

Another thing to note: I wrote that you can think of hashtables as two-dimensional arrays, but they are not exactly the same (e.g. hashtable can save multiple data types, while array can save only single data type, ...).
If you want a tutorial, you can check this: A Complete Beginners Guide to Hashtables


The "Hashtable - Save ..." actions set values in hashtables. If you use the same pair of ParentKey and ChildKey, you will overwrite existing values (if any) in the hashtable. So this way you can update your watermelon characteristics.
When you are setting a value to a variable, you have the option to "Hashtable - Load ...", which will read the value from the hashtable, provided you use the correct pair of ParentKey and ChildKey.
  • Hashtable - Save 0.00 as (Key Sweetness.) of (Key (Picked unit).) in WatermelonValues. //sets value
  • Set VariableSet sweetness = (Load (Key Sweetness.) of (Key (Picked unit).) from WatermelonValues.) //gets value


This is one of the annoying things about hashtables - if you cannot refer to your unit via event responses like (Triggering unit), (Last created unit), (Picked unit), etc., then you will have to use a custom script to get the handleID of your unit.
  • Set VariableSet UnitVar = Paladin 0000 <gen>
  • Custom script: set udg_HandleIdVar = GetHandleId(udg_UnitVar)
  • Hashtable - Save 0.00 as (Key Sweetness.) of HandleIdVar in WatermelonValues.
  • UnitVar is a variable of type "unit"
  • HandleIdVar is a variable of type "int"
  • When referring to global variables (created via GUI) in custom script, you have to prefix them with "udg_"


Floating texts are pretty lightweight and they don't leak if you dispose of them properly. I don't think many floating texts would lag your game
But from user experience, 10+ characteristics is too much to display, considering you have ~100 watermelons in the game - even if you do it via floating text or UI widgets as Uncle pointed out, all you would see in your map would be clusters or floating texts/widgets, hiding the game beneath them.

The loading bar via floating texts basically uses 10 dot '.' characters and changes their color to represent the value. E.g. 30% would be displayed as 3 blue dots and 7 black dots: "oooooooooo". You could also do a linear interpolation between blue and black to show values between... e.g. 35% could be "oooooooooo"
I think there were also progress/loading bars as special effects in the resource section on this site - similar to the floating texts, you would manipulate the special effect to show your progress.
In both cases, you are limited by the "display granularity" of the bar
  • the floating text has 10 dots, so you can display states by 10%. The linear interpolation may somewhat help
  • special effects are limited by how many "frames" the animation has. If the bar has only 20 frames to display progress bar going from empty to full, then your granularity is 5%
Both of those are way too small numbers, considering your sweetness has max value 1000.
Or do it via the UI frames that Uncle wrote about - but that will require jass or lua knowledge.
Edit: OR consider using something else - change the units color, size to determine ripeness and sweetness, add some watery effect to show moisture, etc.


If you want to do it via an ability, then you will need to base the ability off an aura-type ability (e.g. devotion aura) - for some reason I am unable to change tooltips of passive abilities (like evasion, critical strike, etc.).
In your aura-type ability, just change the "Stats - Area of Effect" to some low value like 10.0 and change "Stats - Targets allowed" to "None". This way nobody will benefit from the aura.

What you want is to update values only of units that are selected (since you cannot mouse-over the ability of units you did not select).
The following will fire when player selects a unit. It will load its values from hashtable, build the tooltip text and update the tooltip of its "Stats" ability:
  • Untitled Trigger 002
    • Events
      • Player - Player 1 (Red) Selects a unit
    • Conditions
      • (Unit-type of (Triggering unit)) Equal to Watermelon
    • Actions
      • -------- load values --------
      • Set VariableSet sweetness = (Load (Key Sweetness.) of (Key (Triggering unit).) from WatermelonValues.)
      • Set VariableSet ripeness = (Load (Key Ripeness.) of (Key (Triggering unit).) from WatermelonValues.)
      • Set VariableSet moisture = (Load (Key Moisture.) of (Key (Triggering unit).) from WatermelonValues.)
      • -------- create tooltip --------
      • Set VariableSet Tooltip = (Sweetness: + (String(sweetness)))
      • Set VariableSet Tooltip = (Tooltip + (|nRipeness: + (String(ripeness))))
      • Set VariableSet Tooltip = (Tooltip + (|nMoisture: + (String(moisture))))
      • -------- update tooltip --------
      • Ability - Set Ability: (Unit: (Triggering unit)'s Ability with Ability Code: Stats )'s String Level Field: Tooltip - Normal - Extended ('aub1') of Level: 0 to Tooltip
      • Unit - Increase level of Stats for (Triggering unit)
      • Unit - Decrease level of Stats for (Triggering unit)

Or you can periodically get player's current unit selection, check if any watermelons are selected and update their values:
  • Untitled Trigger 003
    • Events
      • Time - Every 1.00 seconds of game time
    • Conditions
    • Actions
      • Custom script: set bj_wantDestroyGroup = true
      • Unit Group - Pick every unit in (Units currently selected by Player 1 (Red)) and do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Unit-type of (Picked unit)) Equal to Watermelon
            • Then - Actions
              • -------- update tooltip --------
            • Else - Actions
Good midday.

You said:
  • Hashtable - Save 0.00 as (Key Sweetness.) of (Key (Picked unit).) in WatermelonValues. //sets value
  • Set VariableSet sweetness = (Load (Key Sweetness.) of (Key (Picked unit).) from WatermelonValues.) //gets value
This clarified urges.

For now it is new to me to know that these handles play part on avoiding overriding of units, this was one of my objectives.
If an unit gets identified by a Triggering Unit referal, or the others, will it be referable permanently?
Should i have to create 1 variable for each unit that will spawn on the map, so i can give a handle on each one?

It is creative to use hex colors as an indicator, or as 3, but i tried it, and units that have dark skin are hard to determine as well as to see.
Effects, it is a bit tedious to scale and too much visual sparks and lights ruins a bit the soberness of the ambience.

I didnt know about the 10 characters. Yes, it is not very accurate rute.

There may be other forms of tooltip uploading as well?

Thanks for the trigger of selects, it makes sense to the statement. I hope that the systems do not heat up the memory.

--- A new question that i have is, if you remember where i could locate a spellbook ability as the units would have around 20 different abilities and although i cannot think of more than 9 spaces i may have to rely on this.

Surprise question: could i update the tooltip of an ability that is "inside of a spellbook"?
 
Level 3
Joined
Sep 25, 2021
Messages
30
I can post the triggers soon.

But the possession thing isn't something to worry about. Starcraft 2 has had the same terms all of these years and they've never "taken" someone's map, it's just not going to happen. They don't care about your map even if it's a lot of fun. They've practically abandoned the game at this point anyway.
  • Setup Custom Stats
    • Events
      • Map initialization
    • Conditions
    • Actions
      • -------- Set this to the tooltip ability created in the object editor: --------
      • Set VariableSet Stat_TooltipAbility = Bonus Stats
      • -------- --------
      • -------- Then create and store the hashtable: --------
      • Hashtable - Create a hashtable
      • Set VariableSet Stat_Hashtable = (Last created hashtable)
      • -------- --------
      • -------- Then give each stat key a unique value (follow the pattern for new stats): --------
      • Set VariableSet Moisture_Key = 0
      • Set VariableSet Ripeness_Key = 1
      • Set VariableSet Sweetness_Key = 2
      • Set VariableSet SeedDensity_Key = 3
      • -------- --------
      • -------- Then define how many units will use this system (update this whenever you add a new unit): --------
      • Set VariableSet Stat_TotalUnitTypes = 2
      • -------- --------
      • -------- Then define the units that use this stat system and their base stats: --------
      • Set VariableSet Stat_UnitType[1] = Paladin
      • Set VariableSet Stat_Moisture[1] = 5
      • Set VariableSet Stat_Ripeness[1] = 10
      • Set VariableSet Stat_Sweetness[1] = 15
      • Set VariableSet Stat_SeedDensity[1] = 20
      • -------- --------
      • Set VariableSet Stat_UnitType[2] = Archmage
      • Set VariableSet Stat_Moisture[2] = 12
      • Set VariableSet Stat_Ripeness[2] = 24
      • Set VariableSet Stat_Sweetness[2] = 36
      • Set VariableSet Stat_SeedDensity[2] = 48
      • -------- --------
      • -------- Finally, run a trigger which will add these base stats to the hashtable: --------
      • Trigger - Run Add Base Stats To Hashtable <gen> (ignoring conditions)
  • Add Base Stats To Hashtable
    • Events
    • Conditions
    • Actions
      • -------- This will loop over all of the units in Stat_UnitType and save their base stats to the hashtable: --------
      • -------- ( Note: This data is used to initialize a unit's base stats ) --------
      • For each (Integer Stat_Loop) from 1 to Stat_TotalUnitTypes, do (Actions)
        • Loop - Actions
          • Custom script: set udg_Stat_Id = udg_Stat_UnitType[udg_Stat_Loop]
          • Hashtable - Save Stat_Moisture[Stat_Loop] as Moisture_Key of Stat_Id in Stat_Hashtable.
          • Hashtable - Save Stat_Ripeness[Stat_Loop] as Ripeness_Key of Stat_Id in Stat_Hashtable.
          • Hashtable - Save Stat_Sweetness[Stat_Loop] as Sweetness_Key of Stat_Id in Stat_Hashtable.
          • Hashtable - Save Stat_SeedDensity[Stat_Loop] as SeedDensity_Key of Stat_Id in Stat_Hashtable.
  • Initialize Base Stats
    • Events
      • Unit - A unit enters (Playable map area)
    • Conditions
      • (Level of Stat_TooltipAbility for (Triggering unit)) Equal to 1
    • Actions
      • -------- This custom script sets the Stat_Id variable to be equal to the unit's Unit-Type id. --------
      • -------- Each Unit-Type in warcraft 3 has it's own unique Unit-Type id (also known as a rawcode) that sets them apart: --------
      • Set VariableSet Stat_Target = (Triggering unit)
      • Custom script: set udg_Stat_Id = GetUnitTypeId(udg_Stat_Target)
      • Custom script: set udg_Stat_TargetKey = udg_Stat_Target
      • -------- --------
      • -------- Now that we have the unit's Unit-Type id, we can use that to load it's base stats from the hashtable and save them directly to the unit: --------
      • -------- ( Note: I'm reusing these Stat_ variables since their [0] array is unused in our Setup trigger. This is just to use less variables ) --------
      • Set VariableSet Stat_Moisture[0] = (Load Moisture_Key of Stat_Id from Stat_Hashtable.)
      • Set VariableSet Stat_Ripeness[0] = (Load Ripeness_Key of Stat_Id from Stat_Hashtable.)
      • Set VariableSet Stat_Sweetness[0] = (Load Sweetness_Key of Stat_Id from Stat_Hashtable.)
      • Set VariableSet Stat_SeedDensity[0] = (Load SeedDensity_Key of Stat_Id from Stat_Hashtable.)
      • -------- --------
      • -------- We've loaded the base stats into these variables and now we can save them directly to the unit: --------
      • Hashtable - Save Stat_Moisture[0] as Moisture_Key of (Key Stat_TargetKey.) in Stat_Hashtable.
      • Hashtable - Save Stat_Ripeness[0] as Ripeness_Key of (Key Stat_TargetKey.) in Stat_Hashtable.
      • Hashtable - Save Stat_Sweetness[0] as Sweetness_Key of (Key Stat_TargetKey.) in Stat_Hashtable.
      • Hashtable - Save Stat_SeedDensity[0] as SeedDensity_Key of (Key Stat_TargetKey.) in Stat_Hashtable.
      • -------- --------
      • Trigger - Run Update Stats Tooltip <gen> (ignoring conditions)
  • Add Moisture
    • Events
    • Conditions
    • Actions
      • Custom script: set udg_Stat_TargetKey = udg_Stat_Target
      • -------- --------
      • -------- Load the unit's current stat and adjust it: --------
      • Trigger - Run Load Stats Variables <gen> (ignoring conditions)
      • -------- --------
      • Set VariableSet Stat_Moisture[0] = (Stat_Moisture[0] + Stat_Amount)
      • -------- --------
      • -------- Prevent the adjusted stat from going below 1: --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Stat_Moisture[0] Less than or equal to 0
        • Then - Actions
          • Set VariableSet Stat_Moisture[0] = 1
        • Else - Actions
      • -------- --------
      • -------- Save the new stat: --------
      • Hashtable - Save Stat_Moisture[0] as Moisture_Key of (Key Stat_TargetKey.) in Stat_Hashtable.
      • -------- --------
      • -------- Run this last to update the ability tooltip: --------
      • Trigger - Run Update Stats Tooltip <gen> (ignoring conditions)
  • Add Ripeness
    • Events
    • Conditions
    • Actions
      • Custom script: set udg_Stat_TargetKey = udg_Stat_Target
      • -------- --------
      • -------- Load the unit's current stat and adjust it: --------
      • Trigger - Run Load Stats Variables <gen> (ignoring conditions)
      • -------- --------
      • Set VariableSet Stat_Ripeness[0] = (Stat_Ripeness[0] + Stat_Amount)
      • -------- --------
      • -------- Prevent the adjusted stat from going below 1: --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Stat_Ripeness[0] Less than or equal to 0
        • Then - Actions
          • Set VariableSet Stat_Ripeness[0] = 1
        • Else - Actions
      • -------- --------
      • -------- Save the new stat: --------
      • Hashtable - Save Stat_Ripeness[0] as Ripeness_Key of (Key Stat_TargetKey.) in Stat_Hashtable.
      • -------- --------
      • -------- Run this last to update the ability tooltip: --------
      • Trigger - Run Update Stats Tooltip <gen> (ignoring conditions)
  • Add Sweetness
    • Events
    • Conditions
    • Actions
      • Custom script: set udg_Stat_TargetKey = udg_Stat_Target
      • -------- --------
      • -------- Load the unit's current stat and adjust it: --------
      • Trigger - Run Load Stats Variables <gen> (ignoring conditions)
      • -------- --------
      • Set VariableSet Stat_Sweetness[0] = (Stat_Sweetness[0] + Stat_Amount)
      • -------- --------
      • -------- Prevent the adjusted stat from going below 1: --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Stat_Sweetness[0] Less than or equal to 0
        • Then - Actions
          • Set VariableSet Stat_Sweetness[0] = 1
        • Else - Actions
      • -------- --------
      • -------- Save the new stat: --------
      • Hashtable - Save Stat_Sweetness[0] as Sweetness_Key of (Key Stat_TargetKey.) in Stat_Hashtable.
      • -------- --------
      • -------- Run this last to update the ability tooltip: --------
      • Trigger - Run Update Stats Tooltip <gen> (ignoring conditions)
  • Add Seed Density
    • Events
    • Conditions
    • Actions
      • Custom script: set udg_Stat_TargetKey = udg_Stat_Target
      • -------- --------
      • -------- Load the unit's current stat and adjust it: --------
      • Trigger - Run Load Stats Variables <gen> (ignoring conditions)
      • -------- --------
      • Set VariableSet Stat_SeedDensity[0] = (Stat_SeedDensity[0] + Stat_Amount)
      • -------- --------
      • -------- Prevent the adjusted stat from going below 1: --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Stat_SeedDensity[0] Less than or equal to 0
        • Then - Actions
          • Set VariableSet Stat_SeedDensity[0] = 1
        • Else - Actions
      • -------- --------
      • -------- Save the new stat: --------
      • Hashtable - Save Stat_SeedDensity[0] as SeedDensity_Key of (Key Stat_TargetKey.) in Stat_Hashtable.
      • -------- --------
      • -------- Run this last to update the ability tooltip: --------
      • Trigger - Run Update Stats Tooltip <gen> (ignoring conditions)
  • Add All
    • Events
    • Conditions
    • Actions
      • Custom script: set udg_Stat_TargetKey = udg_Stat_Target
      • -------- --------
      • -------- Load the unit's current stats and adjust them: --------
      • Trigger - Run Load Stats Variables <gen> (ignoring conditions)
      • -------- --------
      • Set VariableSet Stat_Moisture[0] = (Stat_Moisture[0] + Stat_Amount)
      • Set VariableSet Stat_Ripeness[0] = (Stat_Ripeness[0] + Stat_Amount)
      • Set VariableSet Stat_Sweetness[0] = (Stat_Sweetness[0] + Stat_Amount)
      • Set VariableSet Stat_SeedDensity[0] = (Stat_SeedDensity[0] + Stat_Amount)
      • -------- --------
      • -------- Prevent the adjusted stats from going below 1: --------
      • -------- Moisture: --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Stat_Moisture[0] Less than or equal to 0
        • Then - Actions
          • Set VariableSet Stat_Moisture[0] = 1
        • Else - Actions
      • -------- Ripeness: --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Stat_Ripeness[0] Less than or equal to 0
        • Then - Actions
          • Set VariableSet Stat_Ripeness[0] = 1
        • Else - Actions
      • -------- Sweetness: --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Stat_Sweetness[0] Less than or equal to 0
        • Then - Actions
          • Set VariableSet Stat_Sweetness[0] = 1
        • Else - Actions
      • -------- Seed Density: --------
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Stat_SeedDensity[0] Less than or equal to 0
        • Then - Actions
          • Set VariableSet Stat_SeedDensity[0] = 1
        • Else - Actions
      • -------- --------
      • -------- Save the new stats: --------
      • Hashtable - Save Stat_Moisture[0] as Moisture_Key of (Key Stat_TargetKey.) in Stat_Hashtable.
      • Hashtable - Save Stat_Ripeness[0] as Ripeness_Key of (Key Stat_TargetKey.) in Stat_Hashtable.
      • Hashtable - Save Stat_Sweetness[0] as Sweetness_Key of (Key Stat_TargetKey.) in Stat_Hashtable.
      • Hashtable - Save Stat_SeedDensity[0] as SeedDensity_Key of (Key Stat_TargetKey.) in Stat_Hashtable.
      • -------- --------
      • -------- Run this last to update the ability tooltip: --------
      • Trigger - Run Update Stats Tooltip <gen> (ignoring conditions)
  • Load Stats Variables
    • Events
    • Conditions
    • Actions
      • -------- Load all of the unit's stats and store them in these variables temporarily: --------
      • Set VariableSet Stat_Moisture[0] = (Load Moisture_Key of (Key Stat_TargetKey.) from Stat_Hashtable.)
      • Set VariableSet Stat_Ripeness[0] = (Load Ripeness_Key of (Key Stat_TargetKey.) from Stat_Hashtable.)
      • Set VariableSet Stat_Sweetness[0] = (Load Sweetness_Key of (Key Stat_TargetKey.) from Stat_Hashtable.)
      • Set VariableSet Stat_SeedDensity[0] = (Load SeedDensity_Key of (Key Stat_TargetKey.) from Stat_Hashtable.)
  • Update Stats Tooltip
    • Events
    • Conditions
    • Actions
      • -------- Finally we update the unit's Bonus Stats ability to display these base stats: --------
      • Set VariableSet Stat_Tooltip = (Moisture: + (String(Stat_Moisture[0])))
      • Set VariableSet Stat_Tooltip = ((Stat_Tooltip + |nRipeness: ) + (String(Stat_Ripeness[0])))
      • Set VariableSet Stat_Tooltip = ((Stat_Tooltip + |nSweetness: ) + (String(Stat_Sweetness[0])))
      • Set VariableSet Stat_Tooltip = ((Stat_Tooltip + |nSeed Density: ) + (String(Stat_SeedDensity[0])))
      • -------- --------
      • -------- This adjusts the abilities extended tooltip to be equal to Stat_Tooltip: --------
      • Ability - Set Ability: (Unit: Stat_Target's Ability with Ability Code: Stat_TooltipAbility)'s String Level Field: Tooltip - Normal - Extended ('aub1') of Level: 0 to Stat_Tooltip
      • Unit - Increase level of Stat_TooltipAbility for Stat_Target
      • Unit - Decrease level of Stat_TooltipAbility for Stat_Target

You probably want to edit this stuff:
  • -------- Prevent the adjusted stat from going below 1: --------
  • If... Set Stat to 1
It's there to prevent a stat from going below 1. You could change it to prevent the stat from going below 0 instead or just delete it entirely and allow stats to become negative. I designed it to work like Hero Attributes since those can't go below 1.

I attached a picture showing all of the variables.
Much thanks, i may get on the map later on.
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,534
So when you use Pick Every Unit in Group and do Actions... here's what's happening. Let's say there's 3 units to pick from.
Each unit is picked one by one in sequential order:

1st unit -> Set (Picked unit) = this unit, then Run the Actions
2nd unit -> Set (Picked unit) = this unit, then Run the Actions
3rd unit -> Set (Picked unit) = this unit, then Run the Actions

(Picked unit) is an Event Response which is basically a global variable (Unit variable in this case). It provides us with a temporary reference to whatever unit we're currently working with. In this case we're working with a group of units, so (Picked unit) will be set to each unit one by one. This allows us to run a SINGLE set of actions once for EACH unit.

You should never be creating non-array Variables for EACH unit. If you're ever doing anything repetitive like that then you're probably making a mistake. Loops and Arrays are solutions to these issues and should be mastered if you wish to make a good map.

Regarding the Hashtable, when you're saving data to Key (Picked unit) you're saving it to that specific unit's handle id. Picked unit is just a temporary reference to that unit. Key is just another way of saying the handle id of said unit (or whatever object you're referencing, it doesn't need to be a unit).

Each unit in the game generates it's own unique handle id (Key) upon creation. A handle id is a long integer like 12312395. Think of it like a phone number or social security number, no two people share the same numbers, it's what sets us apart and makes us unique. Units have the same thing and it's what allows the game to know the difference between them. Other game objects like Items have handle ids as well.

So you're actually doing something like this when saving stats to a unit in a hashtable:
  • Set Variable Moisture[unit handle id] = 100
  • Set Variable Ripeness[unit handle id] = 200
It's very similar to an Array but you're using a unit's handle id as the [index]. Since no two units share the same handle id then there won't be any issues of unit's overwriting each other's data. I should mention that the [Index] size limit of an Array is 32,768, so you couldn't actually fit a unit's handle id inside of it. Hashtables don't have this limitation which is why they become necessary, plus a single Hashtable can store way more information due to it's additional "index" (Parent/Child indexes).

Also, you can test the Spellbook stuff yourself, I think it should work.
 
Last edited:

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,534
The Key needs to be an integer, which is why in my map I created a unique Integer Key for each stat.
  • Set Variable Ripeness_Key = 0
  • Set Variable Sweetness_Key = 1
  • Set Variable SeedDensity_Key = 2
etc.

  • Hashtable - Save 100.00 as Sweetness_Key of (Key(Picked unit)) in TableWithEverything

So the above action is saving 100.0 as 1 of Picked unit's id and storing this data inside of your TableWithEverything hashtable.
Since each stat has it's own unique Key value (0, 1, 2, etc) then the different Keys won't conflict with one another.
 
Last edited:
Level 25
Joined
Sep 26, 2009
Messages
2,378
@Muchonaso you are doing it correct, but you are using wrong keys - you are loading MinorKeyMoisture of Target of unit of ability, but saving it as MinorKeySweetness of picked unit.
Easy way to also check if you are doing it correct is to load the value from the hashtable, print the value as game message, then save the value into hashtable, load it again and print it again - you should see the original value and new increased values.

Something along the lines of this pseudo-code
Code:
var originalValue = Load XY from hashtable
print game message: "Original value: " + originalValue
Save originalValue + 0.1 as XY in hashtable
var newValue = Load XY from hashtable
print game message: "New value: " + newValue
Assuming the original value in the hashtable was for example 2.2, then you should see messages like:
"Original value: 2.2"
"New value: 2.3"
If you do not see the new value incremented, then you are probably incorrectly storing/loading values from the hashtable


Also, what I wrote about problems obtaining handle Ids - that is only an issue if you want to save/load values from a unit, which cannot be referred in your trigger as one of the event responses (i.e. triggering unit, target unit of ability being cast, picked unit, ...). But for those cases you can use the custom script I wrote about.
 
Level 3
Joined
Sep 25, 2021
Messages
30
@Nichilus
Okay, thanks. Yes, I noticed that i mixed the stats up. I needed to do a checker as the one you wrote, so it comes handy.
Could you give me an example of instances where you could not get the handle of the unit from an event? I may run across one on the future, preparation may do.

@Uncle @Nichilus
I added your name to the milestone of thanks on the map, i may post a screenshot when i learn how to screenshot in png or jpeg, but not tga.
 
Level 25
Joined
Sep 26, 2009
Messages
2,378
An example of trigger that does not have event responses is a periodic timer trigger.
Below is an example of a periodic trigger and each time the trigger is executed, I want to load some real value from hashtable for a unit referenced via unit variable 'MySpellCaster'. You cannot reference a variable as one of the keys in "Save/Load X of Y in hashtable" actions so you need to set the handleID of MySpellCaster via the custom script into a variable called UnitHandleID and in the "Save/Load X of Y in hashtable" actions use the variable UnitHandleID as one of the keys

  • PeriodicLoop
    • Events
      • Time - Every 0.50 seconds of game time
    • Conditions
    • Actions
      • Custom script: set udg_UnitHandleId = GetHandleId(udg_MySpellCaster)
      • Set VariableSet someReal = (Load (Key SomeValue.) of UnitHandleId from MyHashtable.)
      • -------- do stuff... --------
 
Level 3
Joined
Sep 25, 2021
Messages
30
How many slots can a hash table hold, what is the max extent if not infinite?

I assume that it is a multiple of 9x9 digits, if they have to store handles that have 8 digits.

UPDATE 1

@Nichilus
I see, I may keep the convo later on.

The map can resemble a game in which you handle a character and guide him, and role, and fight, and level with him, but you handle a handful of them, as a multiplied Sims. The units on the map have, as persons, many properties, even though persons are "the same type of unit". You have the unlikable chore to drive with your units taking in account the characteristics that they posses, what they can or will not do.
There are for the moment 138 properties (equivalent of sweetness, ripeness, etc.) for each unit! And many still to remember.
 
Last edited:
How many slots can a hash table hold, what is the max extent if not infinite?

...

There are for the moment 138 properties (equivalent of sweetness, ripeness, etc.) for each unit! And many still to remember.
If I remember correctly, there can be 2^32 (2^32 = 4294967296, aka a big number) keys for ("of") 2^32 other keys (units, handles).
The range is -2^31 to 2^31 - 1.

This means each unit having somewhere around 10000 is no problem. One kinda have to be mindful of the keys as the number of entries for a subtable increases.
 
Level 6
Joined
Jul 12, 2021
Messages
95
I hope it's not too late for my reply.


I would take a different approach than the other posters.

Request of solution:

Should i use arrays or hash tables...
I would go for arrays. In my personal opinion it is more simple, though, it is very important to mention that I'm very familiarized with arrays and a particular Unit Indexer System. To use my method you need this Unit Indexer System. This system assigns an integer to each unit. This integer is an unique identifier for each unit.
In my map there are 31 custom stats for each hero, and each stat for each hero is tracked with arrays.

Physical Critical Percentage: The chance to do a critical strike with a physical attack.
Physical Critical Multiplier: The multiplier of the critical strike of a physical attack.
Physical Critical Percentage Reduction: Reduces the chance to recieve a critical strike from a physical attack.
Physical Critical Multiplier Reduction: Reduces the multiplier of the physical critical strikes you recieve.


How do you obtain and modify the values of a characteristic of a key/watermelon, or are the values uneditable after you put on the table?
In the next example it is shown how to obtain and modify the values when an item is acquired. It can, of course, be done with different events.


FourStats.png


The variables are integers and have an array size of one. The triggers are this ones:
  • ZPhysicalCriticalPercentage
    • Events
      • Unit - A unit Acquires an item
    • Conditions
    • Actions
      • If ((Item-type of (Item being manipulated)) Equal to Physical Critical Percentage) then do (Set VariableSet ZPhysicalCriticalPercentage[(Custom value of (Triggering unit))] = (ZPhysicalCriticalPercentage[(Custom value of (Triggering unit))] + 1.00)) else do (Do nothing)
  • ZPhysicalCriticalMultiplier
    • Events
      • Unit - A unit Acquires an item
    • Conditions
    • Actions
      • If ((Item-type of (Item being manipulated)) Equal to Physical Critical Multiplier) then do (Set VariableSet ZPhysicalCriticalMultiplier[(Custom value of (Triggering unit))] = (ZPhysicalCriticalMultiplier[(Custom value of (Triggering unit))] + 1.00)) else do (Do nothing)
  • ZPhysicalCritPercentageRed
    • Events
      • Unit - A unit Acquires an item
    • Conditions
    • Actions
      • If ((Item-type of (Item being manipulated)) Equal to Physical Critical Percentage Reduction) then do (Set VariableSet ZPhysicalCritPercentageRed[(Custom value of (Triggering unit))] = (ZPhysicalCritPercentageRed[(Custom value of (Triggering unit))] + 1.00)) else do (Do nothing)
  • ZPhysicalCriticalMultiplierReduction
    • Events
      • Unit - A unit Acquires an item
    • Conditions
    • Actions
      • If ((Item-type of (Item being manipulated)) Equal to Physical Critical Multiplier Reduction) then do (Set VariableSet ZPhysicalCritMultiplierRed[(Custom value of (Triggering unit))] = (ZPhysicalCritMultiplierRed[(Custom value of (Triggering unit))] + 1.00)) else do (Do nothing)
There are also triggers with the event: "A unit Loses an item". In this case the variables are updated but their value is reduced by 1 instead of increased.
The custom value of each unit is the integer assigned to each unit with the Unit Indexer System.

I did not emphasize that watermelons can born on the map, not all exist beforehand, so i would need a way to store them on the Almighty Table Of Characteristics everytime that they enter the map.
The Unit Indexer System provides a custom value for every that exists at map initialization and also for every unit that is created.

It is important to mention that if a unit is removed from game, the custom value that was cleared will be assigned later to another unit. This means you have to reset the value of the variables or the new unit will be assigned the variables with the same value as the last unit. It is very easy:
The next trigger will only work if you have the Unit Indexer System I recommended.

  • IfAUnitIsRemovedFromGameResetArrayIndexValueOfVariable1
    • Events
      • Game - UnitIndexEvent becomes Equal to 2.00
    • Conditions
    • Actions
      • Set VariableSet StatX[UDex] = 0
Here is an explanation of the trigger:
Event: When UnitIndexEvent becomes equal to 2 the system detects a unit has been deindexed (The custom value that was assigned to a unit is now free and it will be assigned to another unit later).
Action: The index of the variable StatX will be reset to zero. UDex is the custom value of the unit which was deindexed.


If an unit gets identified by a Triggering Unit referal, or the others, will it be referable permanently?
Should i have to create 1 variable for each unit that will spawn on the map, so i can give a handle on each one?
You only need 1 variable for each stat:
  • Set VariableSet StatX[(Custom value of (Triggering unit))] = x

Could you give me an example of instances where you could not get the handle of the unit from an event? I may run across one on the future, preparation may do.
I'm going to give an example similar to the one given by Nichilus.
In this example you are going to need two triggers and, if you dont have a hashtable yet, another trigger to create a hashtable. The first trigger needs an event response. The event will be "A unit acquires an item" but, of course, it can be a different event.

Arrays.png

  • Create Hashtable1
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Hashtable - Create a hashtable
      • Set VariableSet Hashtable1 = (Last created hashtable)
  • ZPhysicalCriticalPercentage
    • Events
      • Unit - A unit Acquires an item
    • Conditions
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Key0[(Custom value of (Triggering unit))] Equal to 0
        • Then - Actions
          • Set VariableSet Unit[(Custom value of (Triggering unit))] = (Triggering unit)
          • Custom script: set Timer[GetUnitUserData(GetTriggerUnit())]=CreateTimer()
          • Countdown Timer - Start Timer[(Custom value of (Triggering unit))] as a One-shot timer that will expire in 0.5 seconds
          • Trigger - Add to ZPhysicalCriticalPercentage2 <gen> the event (Time - (Last started timer) expires)
          • Hashtable - Save (Custom value of (Triggering unit)) as 1 of (Key (Last started timer).) in Hashtable1.
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • Key0[(Custom value of (Triggering unit))] Equal to 1
        • Then - Actions
          • Countdown Timer - Start Timer[(Custom value of (Triggering unit))] as a One-shot timer that will expire in 1.00 seconds
        • Else - Actions
  • ZPhysicalCriticalPercentage2
    • Events
    • Conditions
    • Actions
      • Countdown Timer - Start (Expiring timer) as a One-shot timer that will expire in 0.5 seconds
      • Set VariableSet StatX[(Load 1 of (Key (Expiring timer).) from Hashtable1.)] = x
      • -------- Do other actions --------
In this last trigger "[(Load 1 of (Key (Expiring timer).) from Hashtable1.)]" is the custom value of the triggering unit of the previous trigger.

It is similar to the example of Nichilus because the trigger is run every 0.5 seconds. The event is different ("Time - Periodic Event" vs "Time - Timer Expires") but it functions in a very similar way.



Additional miscellaneous information:
All the variables used in this post that are arrays have an array size of 1.
You need a variable for each stat. The array size of the variables can be 1.
 
Last edited:

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,534
@hugope
Array Size limit is 32,768, increased in patch 1.31 (or maybe 1.30?).

The reason I was against Arrays/Unit Indexing for this type of system is that I wanted function calls that could be customized as well as the greater flexibility that a Hashtable offers. For example, what if every time you added CritDamage this value was updated on a Multiboard? Or what if you wanted an Ability Tooltip to reflect these changes? You wouldn't want to have to manually run that additional code every single time. Also, you have access to an additional [Array] which could be used to hold additional information per stat.

That being said, Arrays/Unit Indexing is still a viable choice if that added complexity isn't needed. You could make a system with Unit Indexing that uses function calls as well.

Now I realize my system requires 3 actions rather than 1 but that's ALL it'll ever need. Plus the system could be done in Jass/Lua to allow for a single action:
  • Custom script: call AddStat(udg_YourUnit, Stat_CritDamage, Value)
Then the system could increase CritDamage to this new Value for you and apply it to the given Unit. Then it could call a trigger like "OnCritDamageChange" where you could then add in your extra actions like updating a Multiboard to reflect these changes. The goal is to remove any and all redundancy, and if you ever want to change something there will only ever be a SINGLE function/trigger that requires changing rather than having to go through all of your triggers and adjusting them 1 by 1.

A great example of this: New Bonus [vJASS][LUA]

Also, I really dislike this Timer arrays method you're using. I say this not to criticize you but to help you save yourself a future headache. I really feel like you're asking for trouble with this design. For starters, you can't remove Events from a trigger, so registering a temporary thing like a timer to a trigger WILL leak once that timer is destroyed. Additionally, you're initializing a massive array of Timers when alternatively you could rely on a system that creates local timers when you need them, no array required. I just can't help but think that there is even more issues with this besides what I listed.

If you want the true power of timers but in GUI I have to recommend this timer system I made. It's simple in it's current form but can technically do anything you want, plus it can easily be expanded upon. One action will start your timer and allow you to link unit(s) and a trigger to the timer. Whenever that timer expires it will run the given trigger and give you access to the linked units with GUI variables. The only other thing you need to do beyond that is Clear a Repeating timer when you want it to end. Again, this is done with 1 action. Like any system you need to get used to it and learn how it works but it really is quite simple.
 

Attachments

  • GUI Timer System 3.w3m
    24.9 KB · Views: 4
Last edited:
Status
Not open for further replies.
Top