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

GetEventDamage and GetWidgetLife (Attempt at fix)

Status
Not open for further replies.
I had thought about the damage detection system attempting to detect damage from the high-end to the low end of the spectrum, particularly high-end. As it has been established, the EVENT_UNIT_DAMAGED fires before the unit is actually damaged, and to detect when the unit will actually be damaged, we would use a life change event for the unit.

It has been reported that life change events won't work for units with lots of health due to inaccuracy of floats in warcraft (I'm not really verbose in the inner workings of floats). One way of distinguishing when a unit has a huge amount of health is getting the approximate damage by subtracting the unit's current health by the difference of the unit's current health and actual damage. We then check for the disparities between the approximate damage and actual damage. When the float error springs up, set the current life of the unit to just one hit point above the damage and configure the life change event to detect when the unit has health not equal to 1.00 (I used a variable).

After doing that, restore the health of the unit to its' expected health.

In Pseudo-code:

Code:
unit target = GetTriggerUnit()

// The final health to be applied later on...
real finalH = 0.
real damage = GetEventDamage()

// The approximation derived from subtracting currLife - dmg from currLife...
// Used to detect extremely huge hit points.
real approxDmg = 0.
real curL = GetWidgetLife(target)

finalH = curL - damage

approxDmg = curL - (curL - damage)

if damage != approxDmg then
    if curL - damage == curL - approxDmg then
        // Resolve the float error by adding 64 (to guarantee a unique real)
        curL = damage + 64
        SetWidgetLife(target, curL)

        // Due to the odd behaviour of unit health in real, this will help you detect damage...
        curL = GetWidgetLife(target) - damage
    endif
else
    curL = curL - damage
endif

TriggerRegisterUnitStateEvent(trig, target, UNIT_STATE_LIFE, GREATER_THAN, currLife)
TriggerRegisterUnitStateEvent(trig, target, UNIT_STATE_LIFE, LESS_THAN, currLife)

EDIT:

I've also discovered that when used correctly, TriggerRegisterUnitStateEvent(GREATER_THAN, LESS_THAN) will always run, which is how I got to (apparently) fix my problem here.

To find out how the actual code runs, you can check this map:
Make sure to check only Damage Detection
 

Attachments

  • Library Template.w3x
    105.3 KB · Views: 60
Last edited:

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,201
Oh, I thought that somehow, larger numbers were always being rounded off to the nearest multiple of the aforementioned number (64). Thus, I had used it in order to get a slightly larger number in order to make the life event change trigger work.
The error is defined by machine epsilon. This value is based on the current precision of the float (32 bit floating point).

Be warned that testing if 1 float is equal to another with the "==" operator in JASS actually checks if they are approximately equal to each other. Rather use "not x != y" since the not equal operator "!=" does work as expected.
 
Status
Not open for further replies.
Top