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

[Trigger] hashtable value not properly incrementing.

Level 8
Joined
Dec 1, 2010
Messages
316
Hey,

I have the following trigger:
  • snare Copy 2
    • Events
      • Time - Every 0.10 seconds of game time
    • Conditions
    • Actions
      • Unit Group - Pick every unit in (Units of type gaurd) and do (Actions)
        • Loop - Actions
          • Set VariableSet tempUnit = (Picked unit)
          • Set VariableSet tempUnits = (Random (2 - (Load 0 of (Key (Picked unit).) from hashtable.)) units from (Units within 200.00 of (Position of (Picked unit)) matching (((Owner of (Matching unit)) Equal to Player 21 (Coal)) and (((Matching unit) is in tauntedUnits.) Equal to False)).))
          • Hashtable - Save Handle OftempUnit as 0 of (Key (Picked unit).) in hashtable.
          • Unit Group - Pick every unit in tempUnits and do (Actions)
            • Loop - Actions
              • Hashtable - Save ((Load 0 of (Key tempUnitHandle.) from hashtable.) + 1) as 0 of (Key tempUnitHandle.) in hashtable.
              • Unit Group - Add (Picked unit) to tauntedUnits
              • Unit - Order (Picked unit) to Attack tempUnit
              • Floating Text - Create floating text that reads TAUNTED above (Picked unit) with Z offset 0.00, using font size 10.00, color (100.00%, 100.00%, 100.00%), and 0.00% transparency
              • Floating Text - Change (Last created floating text): Disable permanence
              • Floating Text - Change the lifespan of (Last created floating text) to 0.50 seconds

The goal of this trigger is to make it so a unit of type gaurd, can taunt 2 nearby units once they are in his range. At any point in time the gaurd only taunts two units. Since this is for a TD type project it's important for other units to continue using their move script. The current trigger correctly taunts units but it's not limited to two. After some testing i noticed the hashtable value for the gaurd unit is not properly incrementing. I'm still very new to hashtables. And haven't used handles as a variable before, How do i fix this trigger?

[EDIT] I solved it, still looking for a way to update it to also save the units that are taunted to that specific gaurd so that i can decrease the number keeping track of how many units are taunted by that unit when the taunted unit dies.


[EDIT2] entire thing is functioning as intended now, and i'm a retard

  • Gaurd Taunt
    • Events
      • Time - Every 0.10 seconds of game time
    • Conditions
    • Actions
      • Unit Group - Pick every unit in (Units of type gaurd) and do (Actions)
        • Loop - Actions
          • Set VariableSet tempUnit = (Picked unit)
          • Set VariableSet tempUnitHandle = (Picked unit)
          • Set VariableSet tempUnits = (Random (2 - (Load 1 of (Key (Picked unit).) from hashtable.)) units from (Units within 200.00 of (Position of (Picked unit)) matching (((Owner of (Matching unit)) Equal to Player 21 (Coal)) and (((Matching unit) is in tauntedUnits.) Equal to False)).))
          • Unit Group - Pick every unit in tempUnits and do (Actions)
            • Loop - Actions
              • Hashtable - Save ((Load 1 of (Key tempUnitHandle.) from hashtable.) + 1) as 1 of (Key tempUnitHandle.) in hashtable.
              • Hashtable - Save Handle Of(Picked unit) as (4 - (Load 1 of (Key tempUnitHandle.) from hashtable.)) of (Key tempUnitHandle.) in hashtable.
              • Unit Group - Add (Picked unit) to tauntedUnits
              • Unit - Order (Picked unit) to Attack tempUnit
              • Floating Text - Create floating text that reads TAUNTED above (Picked unit) with Z offset 0.00, using font size 10.00, color (100.00%, 100.00%, 100.00%), and 0.00% transparency
              • Floating Text - Change (Last created floating text): Disable permanence
              • Floating Text - Change the lifespan of (Last created floating text) to 0.50 seconds
 
Last edited:

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,557
For the sake of getting something more out of this thread, here's how you can clean up the memory leaks in your trigger:
  • Gaurd Taunt
    • Events
      • Time - Every 0.10 seconds of game time
    • Conditions
    • Actions
      • Set VariableSet guardGroup = (Units of type gaurd)
      • Unit Group - Pick every unit in guardGroup and do (Actions)
        • Loop - Actions
          • Set VariableSet tempUnit = (Picked unit)
          • Set VariableSet tempUnitHandle = (Picked unit)
          • Set VariableSet tempPoint = (Position of tempUnit)
          • Set VariableSet nearbyGroup = (Units within 200.00 of tempPoint matching (((Owner of (Matching unit)) Equal to Player 21 (Coal)) and (((Matching unit) is in tauntedUnits.) Equal to False)) and ((Matching unit) is alive Equal to True).))
          • Set VariableSet tempUnits = (Random (2 - (Load 1 of (Key (Picked unit).) from hashtable.)) units from nearbyGroup
          • Unit Group - Pick every unit in tempUnits and do (Actions)
            • Loop - Actions
              • Hashtable - Save ((Load 1 of (Key tempUnitHandle.) from hashtable.) + 1) as 1 of (Key tempUnitHandle.) in hashtable.
              • Hashtable - Save Handle Of(Picked unit) as (4 - (Load 1 of (Key tempUnitHandle.) from hashtable.)) of (Key tempUnitHandle.) in hashtable.
              • Floating Text - Create floating text that reads TAUNTED above (Picked unit) with Z offset 0.00, using font size 10.00, color (100.00%, 100.00%, 100.00%), and 0.00% transparency
              • Floating Text - Change (Last created floating text): Disable permanence
              • Floating Text - Change the lifespan of (Last created floating text) to 0.50 seconds
              • Unit Group - Add (Picked unit) to tauntedUnits
              • Unit - Order (Picked unit) to Attack tempUnit
          • Custom script: call DestroyGroup( udg_nearbyGroup )
          • Custom script: call DestroyGroup( udg_tempUnits )
          • Custom script: call RemoveLocation( udg_tempPoint)
      • Custom script: call DestroyGroup( udg_guardGroup )
I added three new variables, tempPoint, guardGroup, and nearbyGroup. A Unit Group array would be nice to store all three of these without needing to create so many different variables.

I also made sure that tempUnits only contains alive units as well. Remember, dead units will be added to Unit Groups as long as their corpse is still active.
 
Last edited:
Level 8
Joined
Dec 1, 2010
Messages
316
For the sake of getting something more out of this thread, here's how you can clean up the memory leaks in your trigger:
  • Gaurd Taunt
    • Events
      • Time - Every 0.10 seconds of game time
    • Conditions
    • Actions
      • Set VariableSet guardGroup = (Units of type gaurd)
      • Unit Group - Pick every unit in guardGroup and do (Actions)
        • Loop - Actions
          • Set VariableSet tempUnit = (Picked unit)
          • Set VariableSet tempUnitHandle = (Picked unit)
          • Set VariableSet tempPoint = (Position of tempUnit)
          • Set VariableSet nearbyGroup = (Units within 200.00 of tempPoint matching (((Owner of (Matching unit)) Equal to Player 21 (Coal)) and (((Matching unit) is in tauntedUnits.) Equal to False)) and ((Matching unit) is alive Equal to True).))
          • Set VariableSet tempUnits = (Random (2 - (Load 1 of (Key (Picked unit).) from hashtable.)) units from nearbyGroup
          • Unit Group - Pick every unit in tempUnits and do (Actions)
            • Loop - Actions
              • Hashtable - Save ((Load 1 of (Key tempUnitHandle.) from hashtable.) + 1) as 1 of (Key tempUnitHandle.) in hashtable.
              • Hashtable - Save Handle Of(Picked unit) as (4 - (Load 1 of (Key tempUnitHandle.) from hashtable.)) of (Key tempUnitHandle.) in hashtable.
              • Floating Text - Create floating text that reads TAUNTED above (Picked unit) with Z offset 0.00, using font size 10.00, color (100.00%, 100.00%, 100.00%), and 0.00% transparency
              • Floating Text - Change (Last created floating text): Disable permanence
              • Floating Text - Change the lifespan of (Last created floating text) to 0.50 seconds
              • Unit Group - Add (Picked unit) to tauntedUnits
              • Unit - Order (Picked unit) to Attack tempUnit
          • Custom script: call DestroyGroup( udg_nearbyGroup )
          • Custom script: call DestroyGroup( udg_tempUnits )
          • Custom script: call RemoveLocation( udg_tempPoint)
      • Custom script: call DestroyGroup( udg_guardGroup )
I added three new variables, tempPoint, guardGroup, and nearbyGroup. A Unit Group array would be nice to store all three of these without needing to create so many different variables.

I also made sure that tempUnits only contains alive units as well. Remember, dead units will be added to Unit Groups as long as their corpse is still active.
ah, i think that last one caused a bug for me. since i had some issues with it bugging out at certain points. Not sure if this will solve that but i'd have. points where the gaurds would keep a unit in it's list even after it died which caused them to lose functionality. spent a few hours to try and figure it out and gave up. ( also my vacation ended so i had to pause the project for work) It could be that corpses got added by the random selector, and since the removal happens on death they never get properly removed. But is was difficult to recreate since the random selection makes it hard to test

I'm gonna see if this solves that. Also thanks for de-leaking the trigger.
also in the current version of my trigger I already added a unit guard group.
however i don't destroy that group since I'm using it for other triggers aswell.

Edit: Ok so that doesn't seem to solve the bug i thought it might solve since that's still happening.
 
Last edited:

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,557
Dead units aren't removed from Unit Groups, you'll have to remove them manually when they die.

Also, I think you forgot to update the number of taunted units (Load 1 of Key guard), maybe this would work better:
  • Gaurd Taunt
    • Events
      • Time - Every 0.10 seconds of game time
    • Conditions
    • Actions
      • Set VariableSet guardGroup = (Units of type gaurd)
      • Unit Group - Pick every unit in guardGroup and do (Actions)
        • Loop - Actions
          • Set VariableSet tempUnit = (Picked unit)
          • Set VariableSet tempUnitHandle = (Picked unit)
          • Set VariableSet tauntCount = 0
          • Hashtable - Save 0 as 1 of (Key tempUnitHandle.) in hashtable.
          • If (Load 2 of (Key tempUnitHandle) from hashtable) is Alive Equal to True) then Set VariableSet tauntCount = (tauntCount + 1)
          • If (Load 3 of (Key tempUnitHandle) from hashtable) is Alive Equal to True) then Set VariableSet tauntCount = (tauntCount + 1)
          • If Then Else
            • If - Conditions
              • tauntCount Less than 2
            • Then - Actions
              • Set VariableSet tempPoint = (Position of tempUnit)
              • Set VariableSet nearbyGroup = (Units within 200.00 of tempPoint matching (((Owner of (Matching unit)) Equal to Player 21 (Coal)) and ((Matching unit) is alive Equal to True) and (((Matching unit) is in tauntedUnits.) Equal to False))
              • Set VariableSet tempUnits = (Random (2 - tauntCount) units from nearbyGroup
              • Unit Group - Pick every unit in tempUnits and do (Actions)
                • Loop - Actions
                  • Hashtable - Save ((Load 1 of (Key tempUnitHandle.) from hashtable.) + 1) as 1 of (Key tempUnitHandle.) in hashtable.
                  • Hashtable - Save Handle Of(Picked unit) as (4 - (Load 1 of (Key tempUnitHandle.) from hashtable.)) of (Key tempUnitHandle.) in hashtable.
                  • Floating Text - Create floating text that reads TAUNTED above (Picked unit) with Z offset 0.00, using font size 10.00, color (100.00%, 100.00%, 100.00%), and 0.00% transparency
                  • Floating Text - Change (Last created floating text): Disable permanence
                  • Floating Text - Change the lifespan of (Last created floating text) to 0.50 seconds
                  • Unit Group - Add (Picked unit) to tauntedUnits
                  • Unit - Order (Picked unit) to Attack tempUnit
              • Custom script: call DestroyGroup( udg_nearbyGroup )
              • Custom script: call DestroyGroup( udg_tempUnits )
              • Custom script: call RemoveLocation( udg_tempPoint)
            • Else - Actions
      • Custom script: call DestroyGroup( udg_guardGroup )
At this point I think it would just be better to give each Guard it's own Unit Group since that'll simplify this A LOT.
 
Last edited:
Level 8
Joined
Dec 1, 2010
Messages
316
Dead units aren't removed from Unit Groups, you'll have to remove them manually when they die.
  • Reset movement
    • Events
      • Unit - A unit Dies
    • Conditions
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Unit-type of (Dying unit)) Equal to gaurd
        • Then - Actions
          • Unit Group - Remove (Dying unit) from gaurdUnitGroup.
          • Unit Group - Remove (Load 2 of (Key (Dying unit).) in hashtable.) from tauntedUnits.
          • Unit Group - Remove (Load 3 of (Key (Dying unit).) in hashtable.) from tauntedUnits.
        • Else - Actions
          • Unit Group - Pick every unit in gaurdUnitGroup and do (Actions)
            • Loop - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • (Dying unit) Equal to (Load 2 of (Key (Picked unit).) in hashtable.)
                • Then - Actions
                  • Hashtable - Save ((Load 1 of (Key (Picked unit).) from hashtable.) - 1) as 1 of (Key (Picked unit).) in hashtable.
                • Else - Actions
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • (Dying unit) Equal to (Load 3 of (Key (Picked unit).) in hashtable.)
                    • Then - Actions
                      • Hashtable - Save ((Load 1 of (Key (Picked unit).) from hashtable.) - 1) as 1 of (Key (Picked unit).) in hashtable.
                    • Else - Actions
I think i used the following trigger to handle removal, however i remove them form the hashtable of the gaurd, not from the unit group i think. maybe the issue is that they somehow get added again since they're still in the unit group or something like that?

Basically the trigger runs when a unit dies and checks wheter its a gaurd or one of the two units stored in the gaurds hashtable as the units he is taunting. and removes them from his hashtable if they are.
 
Level 8
Joined
Dec 1, 2010
Messages
316
Dead units aren't removed from Unit Groups, you'll have to remove them manually when they die.

Also, I think you forgot to update the number of taunted units (Load 1 of Key guard), maybe this would work better:
  • Gaurd Taunt
    • Events
      • Time - Every 0.10 seconds of game time
    • Conditions
    • Actions
      • Set VariableSet guardGroup = (Units of type gaurd)
      • Unit Group - Pick every unit in guardGroup and do (Actions)
        • Loop - Actions
          • Set VariableSet tempUnit = (Picked unit)
          • Set VariableSet tempUnitHandle = (Picked unit)
          • Set VariableSet tauntCount = 0
          • Hashtable - Save 0 as 1 of (Key tempUnitHandle.) in hashtable.
          • If (Load 2 of (Key tempUnitHandle) from hashtable) is Alive Equal to True) then Set VariableSet tauntCount = (tauntCount + 1)
          • If (Load 3 of (Key tempUnitHandle) from hashtable) is Alive Equal to True) then Set VariableSet tauntCount = (tauntCount + 1)
          • If Then Else
            • If - Conditions
              • tauntCount Less than 2
            • Then - Actions
              • Set VariableSet tempPoint = (Position of tempUnit)
              • Set VariableSet nearbyGroup = (Units within 200.00 of tempPoint matching (((Owner of (Matching unit)) Equal to Player 21 (Coal)) and ((Matching unit) is alive Equal to True) and (((Matching unit) is in tauntedUnits.) Equal to False))
              • Set VariableSet tempUnits = (Random (2 - tauntCount) units from nearbyGroup
              • Unit Group - Pick every unit in tempUnits and do (Actions)
                • Loop - Actions
                  • Hashtable - Save ((Load 1 of (Key tempUnitHandle.) from hashtable.) + 1) as 1 of (Key tempUnitHandle.) in hashtable.
                  • Hashtable - Save Handle Of(Picked unit) as (4 - (Load 1 of (Key tempUnitHandle.) from hashtable.)) of (Key tempUnitHandle.) in hashtable.
                  • Floating Text - Create floating text that reads TAUNTED above (Picked unit) with Z offset 0.00, using font size 10.00, color (100.00%, 100.00%, 100.00%), and 0.00% transparency
                  • Floating Text - Change (Last created floating text): Disable permanence
                  • Floating Text - Change the lifespan of (Last created floating text) to 0.50 seconds
                  • Unit Group - Add (Picked unit) to tauntedUnits
                  • Unit - Order (Picked unit) to Attack tempUnit
              • Custom script: call DestroyGroup( udg_nearbyGroup )
              • Custom script: call DestroyGroup( udg_tempUnits )
              • Custom script: call RemoveLocation( udg_tempPoint)
            • Else - Actions
      • Custom script: call DestroyGroup( udg_guardGroup )
At this point I think it would just be better to give each Guard it's own Unit Group since that'll simplify this A LOT.
hmm, if i used this would it mean i no longer need to remove them from the hashtable on the point of death since you basically check if it's alive at every iterattion, which could solve the issue of a dead unit being stored somehow and not being removed upon death since it's a one time only event. Could fix it. But i guess i need to remove the one that triggers on death for this to work right? for clarification, the 'reset movement' trigger.
 

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,557
hmm, if i used this would it mean i no longer need to remove them from the hashtable on the point of death since you basically check if it's alive at every iterattion, which could solve the issue of a dead unit being stored somehow and not being removed upon death since it's a one time only event. Could fix it. But i guess i need to remove the one that triggers on death for this to work right? for clarification, the 'reset movement' trigger.
Yeah, you wouldn't need to subtract from the Hashtable anymore since the value increases/resets automatically in the Taunt trigger.

And running this logic anytime ANY non-Guard dies is incredibly inefficient anyway:
  • Else - Actions
    • Unit Group - Pick every unit in gaurdUnitGroup and do (Actions)
So it's good to get rid of it and avoid that kind of excessive logic.
 
Level 8
Joined
Dec 1, 2010
Messages
316
Yeah, you wouldn't need to subtract from the Hashtable anymore since the value increases/resets automatically in the Taunt trigger.

And running this logic anytime ANY non-Guard dies is incredibly inefficient anyway:
  • Else - Actions
    • Unit Group - Pick every unit in gaurdUnitGroup and do (Actions)
So it's good to get rid of it and avoid that kind of excessive logic.

I changed the code to the last example you showed but right now it seems taunt more than 2 units and the counter also.




EDIT= need some more testing but i think its just the hashtable save 0 as 1 that's wrong at the start, i believe it should save tauntcount as1 after the setting is done
  • Gaurd Taunt
    • Events
      • Time - Every 0.10 seconds of game time
    • Conditions
    • Actions
      • Unit Group - Pick every unit in gaurdUnitGroup and do (Actions)
        • Loop - Actions
          • Set VariableSet tempUnit = (Picked unit)
          • Set VariableSet tempUnitHandle = (Picked unit)
          • Set VariableSet tauntCount = 0
          • If (((Load 2 of (Key tempUnitHandle.) in hashtable.) is alive) Equal to True) then do (Set VariableSet tauntCount = (tauntCount + 1)) else do (Do nothing)
          • If (((Load 3 of (Key tempUnitHandle.) in hashtable.) is alive) Equal to True) then do (Set VariableSet tauntCount = (tauntCount + 1)) else do (Do nothing)
          • Hashtable - Save tauntCount as 1 of (Key tempUnitHandle.) in hashtable.
          • Floating Text - Create floating text that reads (String((Load 1 of (Key (Picked unit).) from hashtable.))) above (Picked unit) with Z offset 0.00, using font size 10.00, color (100.00%, 100.00%, 100.00%), and 0.00% transparency
          • Floating Text - Change (Last created floating text): Disable permanence
          • Floating Text - Change the lifespan of (Last created floating text) to 0.10 seconds
though i still need to test if this holds up.

EDIT2: after some more testing, i can no longer replicate the bug.
The text display did break since now it won't always count up when a new unit is taunting after a previous one died however i'm going to remove the text above anyway since it's a feature meant for testing only.

The taunt itself atleast for the few tests i did seems to function properly finally.
 
Last edited:

Uncle

Warcraft Moderator
Level 64
Joined
Aug 10, 2018
Messages
6,557
Here's an example map showcasing the same idea but with a Unit Group array. It was easier for me to just recreate it in the World Editor than constantly typing from memory on here. This uses a Unit Indexer instead of a Hashtable which I prefer in situations like these.

I was a little lazy so hopefully it all makes sense. Order the Peasant to build a Farm near a Footman. The Farm is acting like your "Guard" tower, you'll see it taunts up to 2 nearby Footman at a time. When a taunted footman dies, the Farm will stop tracking it and will reduce it's "taunt count" by 1. When a Farm dies it will untaunt any of it's taunted footman.
 

Attachments

  • Taunt Example 1.w3m
    24.9 KB · Views: 1
Last edited:
Level 8
Joined
Dec 1, 2010
Messages
316
Here's an example map showcasing the same idea but with a Unit Group array. It was easier for me to just recreate it in the World Editor than constantly typing from memory on here. This uses a Unit Indexer instead of a Hashtable which I prefer in situations like these.

I was a little lazy so hopefully it all makes sense. Order the Peasant to build a Farm near a Footman. The Farm is acting like your "Guard" tower, you'll see it taunts up to 2 nearby Footman at a time. When a taunted footman dies, the Farm will stop tracking it and will reduce it's "taunt count" by 1. When a Farm dies it will untaunt any of it's taunted footman.
that's fair enough. I'm just happy it's currently working with hashtables. Since I learned hashtables specifically for this trigger.
And now that it's finally working I just want to move on with my map. This was the trickiest trigger i had to do for this project luckily.
 
Top