• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

Unit Dies Variable overwrites itself

Level 9
Joined
Jun 13, 2010
Messages
366
Hi,

I experience my variables set for a unit dies event will overwrite itself.

Take this example:
  • TFT SamiTroll Corpse Mine
    • Events
      • Unit - A unit Dies
    • Conditions
      • (Level of Corpse Mine (SamiTroll) for (Killing unit)) Greater than or equal to 1
    • Actions
      • Set VariableSet OnDeath_UnitDying = (Triggering unit)
      • Set VariableSet OnDeath_UnitKilling = (Killing unit)
      • Set VariableSet StatUnit = OnDeath_UnitKilling
      • Trigger - Run Calculate Unit Stat Retriever <gen> (checking conditions)
      • Set VariableSet OnDeath_Real = (2.00 x StatAD)
      • Set VariableSet OnDeath_Point = (Position of OnDeath_UnitDying)
      • Special Effect - Create a special effect at OnDeath_Point using Objects\Spawnmodels\Human\FragmentationShards\FragBoomSpawn.mdl
      • Special Effect - Destroy (Last created special effect)
      • Set VariableSet OnDeath_UnitGroup = (Units within 125.00 of OnDeath_Point.)
      • Unit Group - Pick every unit in OnDeath_UnitGroup and do (Actions)
        • Loop - Actions
          • Set VariableSet OnDeath_UnitPicked = (Picked unit)
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (OnDeath_UnitPicked is alive) Equal to True
              • (OnDeath_UnitPicked is invulnerable) Not equal to True
              • (OnDeath_UnitPicked is Magic Immune) Not equal to True
              • (OnDeath_UnitPicked belongs to an enemy of (Owner of OnDeath_UnitDying).) Equal to True
            • Then - Actions
              • Unit - Cause OnDeath_UnitDying to damage OnDeath_UnitPicked, dealing OnDeath_Real damage of attack type Spells and damage type Normal
            • Else - Actions
      • Custom script: call RemoveLocation(udg_OnDeath_Point)
      • Custom script: call DestroyGroup(udg_OnDeath_UnitGroup)
When a unit dies it is given the OnDeath_UnitDying variable. Then it fetches the unit group for aoe damage and deals damage to them. If one takes enough damage to die it may trigger another Unit Dies event, making OnDeath_UnitDying set to the new dying unit and now making the rest of the units in the original group that needs to take damage not take damage.

How do you make an efficient system for this? Do I really need to make local variables for every Unit Dies event or what is the smartest way (and not too complex for my brain xD) to avoid this?

I couldn't find other posts about this because I don't know how to search properly for this issue in search terms (if it exists). :)
 

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,903
Hey, here's some alternatives:
1) Run a custom damage function that deals damage 1 frame later.
2) Delay all "On Death" events to run 1 frame later.

Note that there could be some unforeseen consequences and perhaps performance costs associated with these methods.

Anyway, to do something 1 frame later you would rely on a 0.00 second Timer. This isn't very practical in GUI, so a Jass system would be ideal.

Here's an example of a system for delaying all death events by 1 frame:
  • Delayed Death Event
    • Events
      • Unit - A unit Dies
    • Conditions
    • Actions
      • Custom script: call DelayThisDeathEvent(GetTriggerUnit(), GetKillingUnit())
vJASS:
library DelayedDeathEvent

globals
    private timer array timers
    private unit array dyingUnits
    private unit array killingUnits
    private integer instanceCount = 0
endglobals

// This runs when the timer expires - 1 frame later
private function OnTimerExpire takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local integer i = 0

    // Find the instance index for this timer
    loop
        exitwhen i >= instanceCount
        if timers[i] == t then
            // Clean up
            call PauseTimer(t)
            call DestroyTimer(t)
            set t = null

            // Track the OnDeath units
            set udg_OnDeath_UnitDying = dyingUnits[i]
            set udg_OnDeath_UnitKilling = killingUnits[i]

            // Remove this instance from the array
            set instanceCount = instanceCount - 1
            set timers[i] = timers[instanceCount]
            set dyingUnits[i] = dyingUnits[instanceCount]
            set killingUnits[i] = killingUnits[instanceCount]

            // Run the OnDeath event
            set udg_OnDeath_Event = 0.00
            set udg_OnDeath_Event = 1.00
            set udg_OnDeath_Event = 0.00
            return
        endif
        set i = i + 1
    endloop
endfunction

// This is the function you call from GUI custom script
function DelayThisDeathEvent takes unit d, unit k returns nothing
    local timer t = CreateTimer()

    set timers[instanceCount] = t
    set dyingUnits[instanceCount] = d
    set killingUnits[instanceCount] = k
    set instanceCount = instanceCount + 1

    call TimerStart(t, 0.00, false, function OnTimerExpire)
    set t = null
endfunction

endlibrary
This requires a new Real variable called OnDeath_Event.

Here's how you would take advantage of the above system to create your Corpse Mine trigger:
  • TFT SamiTroll Corpse Mine
    • Events
      • Game - OnDeath_Event becomes Equal to 1.00
    • Conditions
      • (Level of Corpse Mine (SamiTroll) for OnDeath_UnitKilling) Greater than or equal to 1
    • Actions
      • Set VariableSet StatUnit = OnDeath_UnitKilling
      • Trigger - Run Calculate Unit Stat Retriever <gen> (checking conditions)
      • Set VariableSet OnDeath_Real = (2.00 x StatAD)
      • Set VariableSet OnDeath_Point = (Position of OnDeath_UnitDying)
      • Special Effect - Create a special effect at OnDeath_Point using Objects\Spawnmodels\Human\FragmentationShards\FragBoomSpawn.mdl
      • Special Effect - Destroy (Last created special effect)
      • Set VariableSet OnDeath_UnitGroup = (Units within 125.00 of OnDeath_Point.)
      • Unit Group - Pick every unit in OnDeath_UnitGroup and do (Actions)
        • Loop - Actions
          • Set VariableSet OnDeath_UnitPicked = (Picked unit)
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (OnDeath_UnitPicked is alive) Equal to True
              • (OnDeath_UnitPicked is invulnerable) Not equal to True
              • (OnDeath_UnitPicked is Magic Immune) Not equal to True
              • (OnDeath_UnitPicked belongs to an enemy of (Owner of OnDeath_UnitDying).) Equal to True
            • Then - Actions
              • Unit - Cause OnDeath_UnitDying to damage OnDeath_UnitPicked, dealing OnDeath_Real damage of attack type Spells and damage type Normal
            • Else - Actions
      • Custom script: call RemoveLocation(udg_OnDeath_Point)
      • Custom script: call DestroyGroup(udg_OnDeath_UnitGroup)
So you'll no longer use "A unit Dies", (Dying unit), (Triggering unit), or (Killing unit) in these types of "on death" triggers. Instead, your triggers replace "A unit Dies" with the custom OnDeath Event, and they replace the associated (Event Responses) with their Variable versions.
 

Attachments

  • Delayed Death Event 1.w3m
    19.5 KB · Views: 0
Last edited:
Top