• 🏆 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] Weird behavior with adding and removing unit from unit group

Status
Not open for further replies.

Kusanagi Kuro

Hosted Project: SC
Level 10
Joined
Mar 11, 2012
Messages
708
Hello guys.
I have a spell which works like this: Create a hammer and rotate it around the user for 9s, each full rotation is 1.8s, with the distance between it and the user extends as time passes. This hammer will deal damage to enemies every 0.2s if the enemies havent been damaged by the hammer within the last 0.85s.
The bug:
-When I cast the 1st hammer, it works fine.
-When I cast the 2nd hammer, it still works fine until the 1st hammer is destroyed, which then cause the 2nd hammer to deal 2 instances of damage.
-When I cast the 3rd hammer while the 1st and 2nd hammer are still alive, it works fine. When the 1st hammer is destroyed, it the 2nd hammer to deal 2 instances of damage, but the 3rd hammer is still fine. When the 2nd hammer is destroyed, then the 3rd hammer is bugged.
Currently I'm using Unit Indexer included in Damage Engine 3.7.0.1 by Bribe.
So here are my triggers:


[trigger=""]
Hammer Spawn
Events
Unit - A unit Starts the effect of an ability
Conditions
(Ability being cast) Equal to Berserk
Actions
Set Generic_Point = (Position of (Triggering unit))
Unit - Create 1 Dummy (Hammer) for Player 1 (Red) at (Generic_Point offset by 100.00 towards (Facing of (Triggering unit)) degrees) facing ((Facing of (Triggering unit)) - 90.00) degrees
Set CV = (Custom value of (Last created unit))
Set BH_Angle[CV] = ((Facing of (Triggering unit)) - 90.00)
Set BH_Distance[CV] = 100.00
Set BH_HostUnit[CV] = (Triggering unit)
Unit - Add a 9.00 second Generic expiration timer to (Last created unit)
Unit Group - Add (Last created unit) to BH_UnitGroup
Custom script: call SaveGroupHandle(udg_BH_Hash, udg_CV, udg_CV, CreateGroup())
Custom script: call RemoveLocation(udg_Generic_Point)
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
(Hammer Periodic <gen> is on) Equal to False
Then - Actions
Trigger - Turn on Hammer Periodic <gen>
Else - Actions
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
(Hammer Rotation <gen> is on) Equal to False
Then - Actions
Trigger - Turn on Hammer Rotation <gen>
Else - Actions
[/trigger]


[trigger=""]
Hammer Rotation
Events
Time - Every 0.03 seconds of game time
Conditions
Actions
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
(Number of units in BH_UnitGroup) Greater than 0
Then - Actions
Unit Group - Pick every unit in BH_UnitGroup and do (Actions)
Loop - Actions
Set CV = (Custom value of (Picked unit))
Set BH_DamageHammer = (Picked unit)
Set Generic_Point = (Position of BH_HostUnit[CV])
Set Generic_Point2 = (Generic_Point offset by BH_Distance[CV] towards BH_Angle[CV] degrees)
Unit - Move BH_DamageHammer instantly to Generic_Point2, facing BH_Angle[CV] degrees
Set BH_Distance[CV] = (BH_Distance[CV] + 0.20)
Set BH_Angle[CV] = (BH_Angle[CV] + 6.00)
Custom script: call RemoveLocation(udg_Generic_Point)
Custom script: call RemoveLocation(udg_Generic_Point2)
Else - Actions
Trigger - Turn off (This trigger)
[/trigger]


[trigger=""]
Hammer Periodic
Events
Time - Every 0.20 seconds of game time
Conditions
Actions
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
(Number of units in BH_UnitGroup) Greater than 0
Then - Actions
Unit Group - Pick every unit in BH_UnitGroup and do (Actions)
Loop - Actions
Set CV = (Custom value of (Picked unit))
Set Generic_Point = (Position of (Picked unit))
Set Generic_Group = (Units within 100.00 of Generic_Point matching ((Owner of (Matching unit)) Not equal to Player 1 (Red)))
Set BH_DamageHammer = (Picked unit)
Unit Group - Pick every unit in Generic_Group and do (Actions)
Loop - Actions
-------- This will fire the real damage trigger --------
Unit - Cause BH_DamageHammer to damage (Picked unit), dealing 0.01 damage of attack type Spells and damage type Normal
Custom script: call RemoveLocation(udg_Generic_Point)
Custom script: call DestroyGroup(udg_Generic_Group)
Else - Actions
Trigger - Turn off (This trigger)
[/trigger]


[trigger=""]
Hammer Damage
Events
Game - DamageEvent becomes Equal to 1.00
Conditions
(Unit-type of DamageEventSource) Equal to Dummy (Hammer)
DamageEventAmount Less than 1.00
(DamageEventTarget is in (Load (Custom value of DamageEventSource) of (Custom value of DamageEventSource) in BH_Hash)) Equal to False
Actions
Custom script: local unit udg_BH_DamageHammer
Custom script: local unit udg_BH_DamagedTarget
Custom script: local integer udg_CV
Set BH_DamageHammer = DamageEventSource
Set BH_DamagedTarget = DamageEventTarget
Set CV = (Custom value of BH_DamageHammer)
Unit - Cause BH_HostUnit[CV] to damage BH_DamagedTarget, dealing 5.00 damage of attack type Spells and damage type Normal
Unit Group - Add BH_DamagedTarget to (Load CV of CV in BH_Hash)
Wait 0.85 seconds
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
(BH_DamageHammer is alive) Equal to True
Then - Actions
Unit Group - Remove BH_DamagedTarget from (Load CV of CV in BH_Hash)
Else - Actions
Custom script: set udg_BH_DamagedTarget = null
Custom script: set udg_BH_DamageHammer = null
[/trigger]


[trigger=""]
Hammer Remove
Events
Unit - A unit Dies
Conditions
(Unit-type of (Triggering unit)) Equal to Dummy (Hammer)
Actions
Set CV = (Custom value of (Triggering unit))
Unit Group - Remove (Triggering unit) from BH_UnitGroup
Set Generic_Group = (Load CV of CV in BH_Hash)
Hashtable - Clear all child hashtables of child CV in BH_Hash
Custom script: call DestroyGroup(udg_Generic_Group)
[/trigger]


-------------------------------------------------------------------------------------------------------------------
If I change 2 of the triggers above to this:

[trigger=""]
Hammer Damage
Events
Game - DamageEvent becomes Equal to 1.00
Conditions
(Unit-type of DamageEventSource) Equal to Dummy (Hammer)
DamageEventAmount Less than 1.00
(DamageEventTarget is in (Load (Custom value of DamageEventSource) of (Custom value of DamageEventSource) in BH_Hash)) Equal to False
Actions
Custom script: local unit udg_BH_DamageHammer
Custom script: local unit udg_BH_DamagedTarget
Custom script: local integer udg_CV
Set BH_DamageHammer = DamageEventSource
Set BH_DamagedTarget = DamageEventTarget
Set CV = (Custom value of BH_DamageHammer)
Unit - Cause BH_HostUnit[CV] to damage BH_DamagedTarget, dealing 5.00 damage of attack type Spells and damage type Normal
Unit Group - Add BH_DamagedTarget to (Load CV of CV in BH_Hash)
Wait 0.85 seconds
Unit Group - Remove BH_DamagedTarget from (Load CV of CV in BH_Hash)
Custom script: set udg_BH_DamagedTarget = null
Custom script: set udg_BH_DamageHammer = null
[/trigger]


[trigger=""]
Hammer Remove
Events
Unit - A unit Dies
Conditions
(Unit-type of (Triggering unit)) Equal to Dummy (Hammer)
Actions
Unit Group - Remove (Triggering unit) from BH_UnitGroup
[/trigger]

Then the bug is fixed. However, I'm not sure if this will leave memory leaks or not.
 
Last edited:
Point with an offset, is a new point. It may leak, if not removed properly. You require 2 point variables for here.

  • Set Generic_Group = (Units within 100.00 of Generic_Point matching ((Owner of (Matching unit)) Not equal to Player 1 (Red)))
^Player 1 might be wrong wrong, as it should probably be "Owner of HostingUnit".

You must always destroy the group, not only when it's empty. It doesn't make sense to me otherwise. You don't want to track/countdown any exceptions anymore, when the hammer is gone. Everything else must go at this point, too.

After the wait in "Game - DamageEvent becomes Equal to 1.00" event trigger -- if the Hammer is still after the wait, then only remove the unit from exception group, nothing else.
If the hammer is dead, then do absolutly nothing, because the group, and hashtable must be cleared at this moment already from the other "Remove Hammer" trigger.
 

Kusanagi Kuro

Hosted Project: SC
Level 10
Joined
Mar 11, 2012
Messages
708
This is only for testing purpose, so the owner and such will be changed accordingly in the real map :D
Thks for the advice. I'll try them out to see if the bug still happens or not.
Just curious, what will happen when u try to remove a unit from an already-destroyed unit group?
 

Kusanagi Kuro

Hosted Project: SC
Level 10
Joined
Mar 11, 2012
Messages
708
Currently I cant dig deep into JASS and such. I do have programming knowledge but well, dont have time for that atm. Plus I kinda want to know why my triggers dont work to avoid it later on.
 
Is the hashtable being initialisized?

  • Set Generic_Point = (Position of (Picked unit))
  • Set BH_DamageHammer = (Picked unit)
  • Set Generic_Point = (Position of BH_HostUnit[CV])
The first point assignment is useless and leads to location leak.

What happens in the caster gets moved instantly, like teleports, or gets removed from game? Such cases should be considered.

In damage event, after wait, only remove from group if the hammer is still alive.

In onDeath trigger you need to destroy thed hammer's target group.
 

Kusanagi Kuro

Hosted Project: SC
Level 10
Joined
Mar 11, 2012
Messages
708
The Hashtable is initialized properly.
In the onDeath trigger, if I destroy the group, it will make the bug happened.
When the caster gets moved instantly, the hammer will follow since the hammer's position is calculated by the position of the caster offset by distance and angle.
And the damaged unit group will leak if I dont destroy it right?
 
Last edited:
No need to keep old versions of outdated triggers.

The Hashtable is initialized properly.
I can not see it.
In the onDeath trigger, if I destroy the group, it will make the bug happened.
The group is binded to the hammer. When then hammer is gone, the group needs to be destroyed.

And the unit group will leak if I dont destroy it right?
Yes.

I am not sure what causes the bug. Can you attach a demo?
 
Status
Not open for further replies.
Top