• 🏆 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!
  • 🏆 Hive's 6th HD Modeling Contest: Mechanical is now open! Design and model a mechanical creature, mechanized animal, a futuristic robotic being, or anything else your imagination can tinker with! 📅 Submissions close on June 30, 2024. Don't miss this opportunity to let your creativity shine! Enter now and show us your mechanical masterpiece! 🔗 Click here to enter!

[Trigger] Get Unit Type Fields - Or Other Soultions

Status
Not open for further replies.
Level 7
Joined
Oct 20, 2010
Messages
184
First off, I do GUI, so I'm a bit limited. I've recently discovered Bribe's Unit Indexer and have been running it through the code on my map to make everything smoother and more easily MUI. Blah blah, but this isn't my question.

I am using a trigger-based Attack Speed system instead of using Attack Speed abilities on Items. Mainly because attack speed increases animation speed and other factors, while my mini system allows me to edit attack speed cooldowns directly with items/abilities. The problem is I'm not sure how to apply to overcome this problem.



Originally, attack speed items and abilities only worked on the two players' heroes. But now, using Bribe's indexer, I can theoretically make this work for all units (as I have already done for critical strike chance, on-hit, etc) except my code for Attack Speed specifically needs to know the units Base (unedited) Attack Cooldown.

Is there a way I can call upon a Unit Types Real Field rather than a Units? Or is there a way to save all unit types base attack speed at the initialization phase?
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,597
There's efficient and inefficient ways of going about this:

Inefficient Way:
Using Arrays you store each Unit-Type and it's base Attack Cooldown.
  • UnitType[1] = Footman
  • UnitAttackCd[1] = 1.20
  • UnitType[2] = Rifleman
  • UnitAttackCd[2] = 1.40
  • UnitType[3] = Knight
  • UnitAttackCd[3] = 1.60
  • etc...
Then you can use a loop to run through the different Unit-Types checking to see if our desired unit is equal to UnitType[X]. When it is you can then reference UnitAttackCd[X] since they share the same Index.

Example:
  • Set YourUnit = The unit that we're modifying
  • For each IntegerA from 1 to TotalUnitTypes do
  • If Unit-type of YourUnit is equal to UnitType[IntegerA] then
  • Set Cooldown = UnitAttackCd[IntegerA]
Cooldown is a Real variable. With this method, Cooldown will be equal to the base Attack Cooldown of your unit.

This is inefficient since you need to loop through every single Unit-Type and make comparison checks for ALL of them.

Efficient Way:
Using Arrays like before but this time we save the data to a Hashtable using the Unit-Type Id (in Integer form) as the Index in the Hashtable. This data is saved as the "Child" of the Hashtable, and it's saved under the "Parent" Index which in this case is UH_AttackCd_Parent.
  • Setup Unit Hashtable
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Hashtable - Create a hashtable
      • Set VariableSet UH_Hashtable = (Last created hashtable)
      • -------- --------
      • -------- Set this to the total "UH_UnitTypes" that you use: --------
      • Set VariableSet UH_TotalUnitTypes = 3
      • -------- --------
      • -------- This is the Index (Parent) where all of the Hashtable data will be saved for the specified values (Children) --------
      • Set VariableSet UH_AttackCd_Parent = 0
      • -------- --------
      • -------- Setup Unit-Types/Custom Stats --------
      • Set VariableSet UH_UnitType[1] = Footman
      • Set VariableSet UH_AttackCd[1] = 1.20
      • Set VariableSet UH_UnitType[2] = Rifleman
      • Set VariableSet UH_AttackCd[2] = 1.40
      • Set VariableSet UH_UnitType[3] = Knight
      • Set VariableSet UH_AttackCd[3] = 1.60
      • -------- --------
      • -------- Save to Hashtable --------
      • For each (Integer UH_Loop) from 1 to UH_TotalUnitTypes, do (Actions)
        • Loop - Actions
          • -------- We're converting UH_UnitType into it's Integer form, and saving that as the "Child" in the UH_Hashtable under the "Parent" Index (UH_AttackCd_Parent) --------
          • Custom script: set udg_UH_Id = udg_UH_UnitType[udg_UH_Loop]
          • Hashtable - Save UH_AttackCd[UH_Loop] as UH_Id of UH_AttackCd_Parent in UH_Hashtable.
An example of putting it to use:
  • Demo
    • Events
      • Player - Player 1 (Red) Selects a unit
    • Conditions
    • Actions
      • Set VariableSet UH_Unit = (Triggering unit)
      • Custom script: set udg_UH_Id = GetUnitTypeId(udg_UH_Unit)
      • Set VariableSet AttackCooldown = (Load UH_Id of UH_AttackCd_Parent from UH_Hashtable.)
      • Game - Display to (All players) for 4.00 seconds the text: (Selected Unit: + ((Name of UH_Unit) + (, Base Attack Cooldown: + (String(AttackCooldown)))))
A simplified explanation of how the data is saved to the Hashtable:

Each Unit-Type has an Integer Id that is some long string of numbers like 123456. So when you're dealing with Unit-Types in GUI, you're really dealing with these Integers (GUI hides this from you).

Let's say the Footman's Integer Id is "123456".
Let's say the Rifleman's Integer Id is "100001".
Let's say the Knight's Integer Id is "905905".

What we're essentially doing in our Hashtable is saving the data like this:
UH_AttackCd_Parent[123456] = 1.20
UH_AttackCd_Parent[100001] = 1.40
UH_AttackCd_Parent[905905] = 1.60

Since each Unit-Type has it's own unique Integer Id you know that it's safe to use these as the Index for the variables. Then all we have to do is plug our unit's Integer Id into the Index of UH_AttackCd_Parent and it will give us the unit's Attack Cooldown.

So whenever you want to get the Attack Cooldown of one of these 3 units, simply get their Unit-Type Id by using the function GetUnitTypeId(put your unit here) and set this information as an Integer variable (you need to use Custom Script to do this). Then use this Integer variable as the Index for when you Load data from the Hashtable. The Parent Index (UH_AttackCdParent in this case) is basically a way to save different types of data to the same Hashtable. So say you wanted to save more than just the Footman's Attack Cooldown, like it's base Life Regen as well, what you would do is use a different Index than UH_AttackCdParent. In my example map I save each unit's AttackCd to Index 0 and LifeRegen to Index 1.

Then when we Load this data from the Hashtable it works like this:
Load 123456 (Footman) of UH_AttackCd_Parent (Index where we store the Attack Cd data) from our Hashtable.
 

Attachments

  • Unit Hashtable.w3m
    18.4 KB · Views: 18
Last edited:
Level 7
Joined
Oct 20, 2010
Messages
184
Thank you so much. I was using a similar method but the custom script you show is much cleaner and I’ve updated it and, as of now, works the same while being way easier to expand upon.

My only further question is events to use to update this. In your example you used selecting, does this only run when you initially select a unit or continually update while a unit is selected? The current event I’m using is when a unit is attacked, to update the attackers information for attack speed.
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,597
Warcraft 3 is Event based so unfortunately nothing like this is going to just update on it's own.

You have many options, most of which aren't efficient.
1) Use Timers to periodically update each unit's Attack Speed (this is extremely inefficient)
2) Catch whenever the attack speed is applied (unit casts ability/passive effects go off with damage engine) and whenever the attack speed is removed (this can be the hard part to manage without coding everything from scratch)
3) Do what you're doing now with the Unit Is Attacked Event (this actually seems like the easiest and most efficient way)

If you don't notice any performance issues then I would keep using your current method, otherwise, you could expand upon it.

An idea I have is to add a Boolean to each unit, let's call it: needs_AtkSpeed_Update

This is set to False by default, and set to True after you run an Event that modifies attack speed. You can store it using the Hashtable fairly easily.

For example:
  • Events:
  • A unit starts the effect of an ability
  • Conditions:
  • Ability being cast equal to Bloodlust
  • Actions:
  • Save True as Key(Target unit of ability being cast) of needs_AtkSpeed_Update from UH_Hashtable
  • Events:
  • A unit is attacked
  • Conditions:
  • Load Key(Attacking unit) of needs_AtkSpeed_Update from UH_Hashtable equal to True
  • Actions:
  • Update Attacking unit's Attack Speed
  • Save False as Key(Attacking unit) of needs_AtkSpeed_Update from UH_Hashtable
Now like I said before, I wouldn't bother trying to do this unless you see noticeable performance issues. Also, this might not even make it that much more efficient.
 
Last edited:
Status
Not open for further replies.
Top