• 🏆 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] Stagger Damage Trigger Problem

Status
Not open for further replies.

SpasMaster

Hosted Project: SC
Level 23
Joined
Jan 29, 2010
Messages
1,969
Hello, Hive.

Recently, I wanted to create a passive spell with the following effect:

Stagger (Passive): You shrug off 40% of incoming damage, instead delaying it over 5 seconds.

Here are the steps I took to make it work:
1) In my Damage Engine (Damage Engine 3.7.0.1), I permanently reduce the damage taken by the Monk Hero (the one with the ability) by 40%.
2) Then I have 2 triggers: In the first, I set the amount of Staggered damage. In the second, a dummy unit [Dummy (Stagger)] deals the damage over 5 seconds.

[trigger=""]
Stagger
Events
Game - DamageEvent becomes Equal to 1.00
Conditions
DamageEventAmount Not equal to 0.00
(Unit-type of DamageEventSource) Not equal to Dummy (Stagger)
DamageEventTarget Equal to Hero_Monk
Or - Any (Conditions) are true
Conditions
(Owner of DamageEventSource) Equal to Player 10 (Light Blue)
(Owner of DamageEventSource) Equal to Player 12 (Brown)
(Owner of DamageEventSource) Equal to Neutral Hostile
Actions
Set StaggeredDamage_Taken = DamageEventAmount
Set StaggeredDamage = (StaggeredDamage + (0.67 x StaggeredDamage_Taken))
Wait 5.00 game-time seconds
Set StaggeredDamage = (StaggeredDamage - (0.67 x StaggeredDamage_Taken))
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
StaggeredDamage Less than 0.00
Then - Actions
Set StaggeredDamage = 0.00
Else - Actions
[/trigger]


[trigger=""]
Stagger Periodic
Events
Time - Every 1.00 seconds of game time
Conditions
Actions
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
StaggeredDamage Greater than 0.00
Then - Actions
Unit - Cause Stagger_Dummy to damage Hero_Monk, dealing (0.20 x StaggeredDamage) damage of attack type Spells and damage type Magic
Else - Actions
[/trigger]


Here is the problem; Any form of damage reduction (including default Armor) would replace the <StaggeredDamage_Taken> variable:
Let's assume <StaggeredDamage_Taken> is registered at 100 at the 1st trigger.
<StaggeredDamage> then becomes 0 + 67 = 67.
After 5 seconds
<StaggeredDamage> then becomes 67 - 67 = 0.
That's all fine. But things look different if I have some damage reduction.

Let's assume <StaggeredDamage_Taken> is registered at 100 at the 1st trigger.
<StaggeredDamage> then becomes 0 + 67 = 67.
Let's assume I then activate an ability that reduces damage by 20%. And then I get damaged again.
<StaggeredDamage_Taken> is 80.
<StaggeredDamage> then becomes 67 + 53,6 = 120,6.
After 5 seconds
<StaggeredDamage> then becomes 120,6 - 53,6 = 67 [*]
<StaggeredDamage> then becomes 67 - 53,6 = 13,4

The result, as you can see, is I have 13,4 damage left, while it should be 0.

Basically, <StaggeredDamage_Taken> gets overwritten by the reduced amount (53,6) instead of remembering the initial value which was (67) as can be seen next to the red star above.

I am looking for advises regarding how to approach this system. How do I trigger this effect in a way where it would not overwrite the <StaggeredDamage_Taken> value?

Thanks in advance.
 
Level 11
Joined
Jun 2, 2004
Messages
849
What I'd do is have a variable that is set to 1/5 of the total stagger damage every time the hero gets damaged. Every second, a periodic trigger fires to damage the hero and decrement the total damage, until total damage becomes 0.

So hero gets damaged and gains 100 stagger damage.
StaggerTotal = 100
StaggerTaken = StaggerTotal/5 = 20

3 seconds later, the hero gets damaged again and gains 35 stagger damage. As 3 seconds has passed, StaggerTotal is now 40 (decremeted by 20 three times).
StaggerTotal = 40 + 35 = 75
StaggerTaken = StaggerTotal/5 = 15

5 seconds later, no further damage has been taken, StaggerTotal reaches 0, StaggerTaken resets itself to 0, and no more stagger damage is taken until the next damage event. The hero has taken a total of 135 stagger damage ((20 * 3) + (15 * 5)).


This has the side effect of spreading out damage if hit multiple times, potentially making a rather big DoT. The only way to really fix that I think is to have dynamic triggers and timers for each damage event, which could be excessive overhead.

Also your system isn't MUI but I imagine you're just doing some tests right now.
 
Level 10
Joined
Oct 5, 2008
Messages
355
You can solve your issue easily by using locals here, just replace Staggeredddamagetaken by a local, that saves the amount of staggered damage. The local cannot be overriden and thus will always contain the proper value in a single trigger run. Would require some custom scripty, though. Just change your first trigger to:


[trigger=""]
Stagger
Events
Game - DamageEvent becomes Equal to 1.00
Conditions
DamageEventAmount Not equal to 0.00
(Unit-type of DamageEventSource) Not equal to Dummy (Stagger)
DamageEventTarget Equal to Hero_Monk
Or - Any (Conditions) are true
Conditions
(Owner of DamageEventSource) Equal to Player 10 (Light Blue)
(Owner of DamageEventSource) Equal to Player 12 (Brown)
(Owner of DamageEventSource) Equal to Neutral Hostile
Actions
Set StaggeredDamage_Taken = DamageEventAmount
Custom script: local u = (udg_StaggeredDamage_Taken * 0.67)
Custom script: set udg_StaggeredDamage = (udg_StaggeredDamage + u)
Wait 5.00 game-time seconds
Custom script: set udg_StaggeredDamage = (udg_StaggeredDamage - u)
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
StaggeredDamage Less than 0.00
Then - Actions
Set StaggeredDamage = 0.00
Else - Actions
Custom script: set u = 0.00
[/trigger]

Edit: when you use Bribes damage engine, you can potentionally make this easily a Mui system, since with the DDS comes always a unit indexer, so you could make a array out of staggereddamage with the ubits custom value as index.
 
Last edited:
Level 18
Joined
Nov 21, 2012
Messages
835
made a simple library for you to make spell mui
JASS:
native UnitAlive takes unit u returns boolean

//--------------------------------------------------------------------------------------
library StaggeredDamage // deals damage every second
//--------------------------------------------------------------------------------------
// Deals delayed damage. Uses dummy unit udg_Stagger_Dummy as damage source
// API
// nothing CreateStaggeredDamge(unit <damagedUnit>, real <damage>, real <duration>)
// examples
// call CreateStaggeredDamge(u, 100.00, 5.00)
// 100.00=total damage
// will damage unit u by 20 dmg every sec, during 5 second

// call CreateStaggeredDamge(u, 20.00, 10.00)
// will deal 2 dmg every sec, during 10 second

globals
    private integer                     maxId = 0
    private unit array                  instTarget
    private real array                  instDmg
    private real array                  instDuration
    private timer                       t = CreateTimer()
endglobals
//---------------------------------------------------------------------------
private function Loop takes nothing returns nothing
    local integer id=1
    loop
        exitwhen id>maxId
        //deal dmg, in GUI: attack type: spells, damage type: magic
        call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "Dmg " + R2S(instDmg[id]))

        call UnitDamageTarget(udg_Stagger_Dummy, instTarget[id], instDmg[id], true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_MAGIC, WEAPON_TYPE_WHOKNOWS)
        set instDuration[id] = instDuration[id] - 1.00
        if (instDuration[id] <= 0.00) or (not UnitAlive(instTarget[id])) then       
            call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "Stagger dmg instance ended " + " on unit " + GetUnitName(instTarget[id]))
            //---
            //dealloc: /move data from max to current/
            set instTarget[id] = instTarget[maxId]
            set instDmg[id] = instDmg[maxId]
            set instDuration[id] = instDuration[maxId]           
            //clean:
            set instTarget[maxId]=null           
            //---
            set maxId=maxId-1
            set id=id-1
            if maxId==0 then
                call PauseTimer(t)
            endif
        endif

        set id=id+1
    endloop
endfunction
//---------------------------------------------------------------------------
function CreateStaggeredDamge takes unit damagedUnit, real damage, real duration returns nothing
    set maxId = maxId + 1
    set instTarget[maxId] = damagedUnit
    set instDmg[maxId] = damage/duration //damage per INTERVAL (per sec)
    set instDuration[maxId] = duration   
    if maxId==1 then
        call TimerStart(t, 1.00, true, function Loop)
    endif
endfunction
endlibrary
 

Attachments

  • StaggeredDamage.w3x
    14.6 KB · Views: 45
Status
Not open for further replies.
Top