1. Updated Resource Submission Rules: All model & skin resource submissions must now include an in-game screenshot. This is to help speed up the moderation process and to show how the model and/or texture looks like from the in-game camera.
    Dismiss Notice
  2. The 15th Mini-Mapping Contest came to an end. The Secrets of Warcraft 3 are soon to be revealed! Come and vote in the public poll for your favorite maps.
    Dismiss Notice
  3. The 12th incarnation of the Music Contest is LIVE! The theme is Synthwave. Knight Rider needs a song to listen to on his journey. You should definitely have some fun with this theme!
    Dismiss Notice
  4. Join other hivers in a friendly concept-art contest. The contestants have to create a genie coming out of its container. We wish you the best of luck!
    Dismiss Notice
  5. Check out the Staff job openings thread.
    Dismiss Notice
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

[vJASS] DamagePackage

Discussion in 'JASS Resources' started by Flux, Aug 3, 2016.

  1. Nestharus

    Nestharus

    Joined:
    Jul 10, 2007
    Messages:
    6,149
    Resources:
    8
    Spells:
    3
    Tutorials:
    4
    JASS:
    1
    Resources:
    8
    Hm... so maybe the bug I am thinking of is when the unit has a massive amount of max health but very little health remaining? Like 1 hp remaining out of a 500,000 hp health pool?
     
  2. Wietlol

    Wietlol

    Joined:
    Aug 1, 2013
    Messages:
    4,653
    Resources:
    3
    Spells:
    3
    Resources:
    3
    That may be the problem when you are suffering from a floating point inaccuracy error.

    But I think you sort of remember the issue with health changed events not catching enough change to actually catch the event and run the triggers.
     
  3. MyPad

    MyPad

    Spell Reviewer

    Joined:
    May 9, 2014
    Messages:
    1,258
    Resources:
    6
    Models:
    1
    Icons:
    1
    Spells:
    3
    JASS:
    1
    Resources:
    6
    Talking about health-change events? Is it for the NOT_EQUAL state?

    I tried this approach for my DDS:

    Code (vJASS):

    private static real finalLife = 0.

    private static method onDamage ...
        local trigger trig
        local real currLife = GetWidgetLife(target)
        ...
        ...
        set currLife = currLife + dmg - finalDmg
        // That way, when the unit actually receives the damage, currLife becomes currLife - finalDmg
        ...
        ...
        call SetWidgetLife(target, RMaxBJ(currLife, 0.405))
        if currLife - (2*dmg) + finalDmg < 0.405 then
            // currLife - dmg < 0.405; modify health immediately
            call SetWidgetLife(target, RMaxBJ(currLife, 0.405))
                         
            set finalLife = currLife - dmg
            // currLife is currLife + dmg - finalDmg
            set currLife = finalLife
            // currLife - finalDmg
        else
            // It's safe to delegate the final life to a life-change trigger..
            set finalLife = currLife - dmg
            // modifying current life to expected health...
            set currLife = currLife - (2*dmg) + finalDmg
        endif
        set trig = CreateTrigger()
        // At one point, the NOT_EQUAL limitop did not suit me well, so I changed it to GREATER_THAN or
        // LESS_THAN
        call TriggerRegisterUnitStateEvent(trig, target, UNIT_STATE_LIFE, GREATER_THAN, currLife)
        call TriggerRegisterUnitStateEvent(trig, target, UNIT_STATE_LIFE, LESS_THAN, currLife)
        ...
        set trig = null
     
     
  4. Flux

    Flux

    Joined:
    Feb 6, 2014
    Messages:
    2,334
    Resources:
    28
    Maps:
    1
    Spells:
    19
    Tutorials:
    2
    JASS:
    6
    Resources:
    28
    There's still the bug Nestharus mentioned which can't detect small life change event when the Damage.target's hp is too big. I didn't saw it at first because it only works when the damage is modified or magical.

    EDIT: No wait, managed to fix it. I'll update it after removing all the debug messages.
     
    Last edited: May 25, 2017
  5. Wietlol

    Wietlol

    Joined:
    Aug 1, 2013
    Messages:
    4,653
    Resources:
    3
    Spells:
    3
    Resources:
    3
    @MyPad
    The life events fire immediately so they are a big pro compared to the 0s timers that were ussually implemented.

    However, iirc, the life events only worked when the health changed from above the value given to the event to below the value given to the event, with at least 0.125 health change (this is just from memory, could be something entirely different.
    Nestharus preferred to use 0.5 * damage to be the threshold as it will remove the floating point error, but it also has to remain above that specific value.
    Combinind those two requirements would almost certainly run the trigger and it will work fine.
     
  6. MyPad

    MyPad

    Spell Reviewer

    Joined:
    May 9, 2014
    Messages:
    1,258
    Resources:
    6
    Models:
    1
    Icons:
    1
    Spells:
    3
    JASS:
    1
    Resources:
    6
    @Wietlol
    Yup, they fire immediately. The 0s timer is useful in the sense that it allows blocking of damage greater than one's max health.

    EDIT:

    Never mind the 0s timer. It turns out that it works without it.

    @Flux
    Tested it with Blademaster with 2 damage and a Critical Strike multiplier of 0.01. Damage Detection still detected it. I also studied the nature of the multiplier and came to the conclusion that the minimum damage that you can deal to a unit is 0.01 (due to a multiplier).
     
    Last edited: May 25, 2017
  7. Nestharus

    Nestharus

    Joined:
    Jul 10, 2007
    Messages:
    6,149
    Resources:
    8
    Spells:
    3
    Tutorials:
    4
    JASS:
    1
    Resources:
    8
    So .01 being less than .125 means that the life event would not fire in that case. So a DDS needs a combination of timers and life event in order to work correctly?
     
  8. Flux

    Flux

    Joined:
    Feb 6, 2014
    Messages:
    2,334
    Resources:
    28
    Maps:
    1
    Spells:
    19
    Tutorials:
    2
    JASS:
    6
    Resources:
    28
    Here's a summary of what happens:

    Regarding Magical damage
    Magical LifeEvent register code
    Code (vJASS):

                        if amount < -1.0 then
                            call TriggerRegisterUnitStateEvent(trg, this.stackTarget, UNIT_STATE_LIFE, GREATER_THAN, newHp - 0.125*amount)
                        else
                            call TriggerRegisterUnitStateEvent(trg, this.stackTarget, UNIT_STATE_LIFE, GREATER_THAN, newHp + 0.01)
                        endif
     

    Result

    - A storm bolt with 0.037 damage dealt is detected by life change event (Good)
    - A storm bolt with 0.75 damage dealt is not detected by life change event (Bad)

    Workaround:
    For some reason, a life change event of newHP + 0.01 cannot detect damages greater than 0.125 so another condition needs to be added.
    Magical LifeEvent register code fix
    Code (vJASS):

                        if amount < -1.0 then
                            call TriggerRegisterUnitStateEvent(trg, this.stackTarget, UNIT_STATE_LIFE, GREATER_THAN, newHp - 0.125*amount)
                        elseif amount < -0.125 then
                            call TriggerRegisterUnitStateEvent(trg, this.stackTarget, UNIT_STATE_LIFE, GREATER_THAN, newHp + 0.125)
                        else
                            call TriggerRegisterUnitStateEvent(trg, this.stackTarget, UNIT_STATE_LIFE, GREATER_THAN, newHp + 0.01)
                        endif
     

    Result

    - A storm bolt with 0.037 damage dealt is detected by life change event (Good)
    - A storm bolt with 0.75 damage dealt is detected by life change event (Good)


    Regarding Physical Damage
    Physical LifeEvent register code
    Code (vJASS):

                        if amount > 1.0 then
                            call TriggerRegisterUnitStateEvent(trg, this.stackTarget, UNIT_STATE_LIFE, LESS_THAN, newHp - 0.125*amount)
                        elseif amount > 0.125 then
                            call TriggerRegisterUnitStateEvent(trg, this.stackTarget, UNIT_STATE_LIFE, LESS_THAN, newHp - 0.125)
                        else
                            call TriggerRegisterUnitStateEvent(trg, this.stackTarget, UNIT_STATE_LIFE, LESS_THAN, newHp - 0.01)
                        endif
     

    Result

    - A footman with 1 damage and crit multiplier of 0.13 is detected by life change event (Good)
    - A footman with 1 damage and crit multiplier of 0.12 is not detected by life change event for units with very high hp (Bad)

    Workaround:
    Because dealing physical damage below 0.13 is highly unlikely (can only happen when unit has 1 damage and has crit multiplier of <0.13), I edited the condition to only register the life change event when physical damage is greater than 0.125. Therefore, physical damages below 0.13 cannot be modified via "set Damage.amount" but they are still detectable.
     
  9. MyPad

    MyPad

    Spell Reviewer

    Joined:
    May 9, 2014
    Messages:
    1,258
    Resources:
    6
    Models:
    1
    Icons:
    1
    Spells:
    3
    JASS:
    1
    Resources:
    6
    Sorry for performing a necropost, @Flux, but I want to know where I can find the external snippet for your system.
     
  10. Flux

    Flux

    Joined:
    Feb 6, 2014
    Messages:
    2,334
    Resources:
    28
    Maps:
    1
    Spells:
    19
    Tutorials:
    2
    JASS:
    6
    Resources:
    28
    What do you mean? Everything is in the first post (code + test map).
     
  11. MyPad

    MyPad

    Spell Reviewer

    Joined:
    May 9, 2014
    Messages:
    1,258
    Resources:
    6
    Models:
    1
    Icons:
    1
    Spells:
    3
    JASS:
    1
    Resources:
    6
    In the test map? Perhaps I have not checked that one out.
    I didn't see any external commands in the code section when I copy-pasted it, so I posted the message above.
     
  12. Flux

    Flux

    Joined:
    Feb 6, 2014
    Messages:
    2,334
    Resources:
    28
    Maps:
    1
    Spells:
    19
    Tutorials:
    2
    JASS:
    6
    Resources:
    28
    You mean API? Check the first hidden block titled Documentation.

    EDIT: If you mean the Object Merger, it's only on the test map if I recall correctly on a separate trigger.
     
    Last edited: Nov 26, 2017
  13. Spellbound

    Spellbound

    Joined:
    Jan 9, 2005
    Messages:
    1,916
    Resources:
    15
    Skins:
    5
    Spells:
    9
    JASS:
    1
    Resources:
    15
    So I've been using this for a project of mine and I was wondering if there were any plans to update this with the new
    BlzSetEventDamage
    native?
     
  14. BLOKKADE

    BLOKKADE

    Joined:
    May 18, 2018
    Messages:
    10
    Resources:
    0
    Resources:
    0
    I was having issues with this randomly not detecting damage and I've finally figured out what the problem is. (although I'm not sure exactly why it was a problem)
    Basically my map creates a new unit after every unit that's killed and there's ~700 units on the map at any given time and with 12 players that means sometimes like 50-100units are being created in a second.(not sure if that's relevant but it might be)
    I found that even though I had auto-register enabled some of the freshly created units wouldn't actually be added to a bucket, I managed to track it down to the Damage.add method in DamageEvent where it has an "if DamageBucket.get(unit) != 0 then" statement to check if units that are being added to a bucket are already in a bucket or not, and if not then it adds them to the current bucket.
    Somehow some of the created units were already in a bucket, they were returning 13 or 14 from that (always 13 or 14) for some reason, but if I tried to modify damage from or to them it wouldn't work because they actually weren't in a bucket.
    So I ended up just removing that if statement and it's working fine now. Not sure if it was important or not, if I understand correctly its there to make sure units weren't being added to multiple buckets, but since it's auto-registering them and I'm not manually adding units anywhere it shouldn't be an issue I imagine. (unless it is, then please correct me)
     
  15. Almia

    Almia

    Joined:
    Apr 24, 2012
    Messages:
    4,861
    Resources:
    35
    Spells:
    30
    Tutorials:
    4
    JASS:
    1
    Resources:
    35
    Hmm I am curious, is there any DDS that uses the new native for setting the event damage? or the community is still supporting the pre 1.29 maps
     
  16. Wareditor

    Wareditor

    Joined:
    Jan 16, 2009
    Messages:
    679
    Resources:
    2
    Maps:
    2
    Resources:
    2
    With the new natives, you basically can write it yourself in a few minutes.
    The only thing missing for it being even easier is a generic unit takes damage event.
     
  17. Almia

    Almia

    Joined:
    Apr 24, 2012
    Messages:
    4,861
    Resources:
    35
    Spells:
    30
    Tutorials:
    4
    JASS:
    1
    Resources:
    35
    I actually have written one for my own map, in which I also wrote my own specific unit event leak handling. Tho I am just curious whether there is one that utilises the new native.
     
  18. Astrella

    Astrella

    Joined:
    Oct 3, 2008
    Messages:
    151
    Resources:
    1
    Maps:
    1
    Resources:
    1
    How would you do it using the new natives? The lack of generic unit takes damage event just means you gotta create a new event for every unit you want to track, right?
     
  19. Wareditor

    Wareditor

    Joined:
    Jan 16, 2009
    Messages:
    679
    Resources:
    2
    Maps:
    2
    Resources:
    2
    @Astrella Just like we used to do before the new natives. Refresh the trigger every so often to remove removed units and re-add valid units.
     
  20. NEL

    NEL

    Joined:
    Mar 6, 2017
    Messages:
    112
    Resources:
    0
    Resources:
    0
    Code (vJASS):
            /*
            5. If you want to deal damage inside onDamage callback without causing infinite loops,
               you can do so using Damage.registerTrigger(trigger) and disabling the trigger before
               the new damage is applied then enabling it again after damage is applied. Example:
               */

                    library L initializer Init
                     
                        globals
                            private trigger trg = CreateTrigger()
                        endglobals
                     
                        private function OnDamage takes nothing returns boolean
                            call BJDebugMsg(GetUnitName(Damage.target) " takes " + R2S(Damage.amount) + " damage")
                            call DisableTrigger(thistype.trg)
                            call UnitDamageTarget(Damage.source, Damage.target, 42.0, false, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_MAGIC, null)
                            call EnableTrigger(thistype.trg)
                            call BJDebugMsg(GetUnitName(Damage.target) " takes an extra 42 damage.")
                            return false
                        endfunction
                     
                        private function Init takes nothing returns nothing
                            call Damage.registerTrigger(trg)
                            call TriggerAddCondition(trg, Condition(function OnDamage))
                        endfunction
                     
                    endlibrary


    I don't know why you use
    thistype.trg
    even you are not inside the struct or maybe I'm wrong.