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

[vJASS] PreventDeathIssue library

Level 25
Joined
Jun 5, 2008
Messages
2,572
This is a small library which prevents the increase of a widget/unit's life in case it is dead.

It simply runs a timer which sets it's health to 0.0 after 0.000001 seconds delay which is fairly short.

Anyway it serves as a prevention of increasing dead unit's health meaning all methods of determining whether a unit is dead should work fine now.

This aplies for 2 natives that is:

native SetUnitState takes unit whichUnit, unitstate whichUnitState, real newVal returns nothing

native SetWidgetLife takes widget whichWidget, real newLife returns nothing

Increasing life via object editor spells probably won't be detected but i haven't tested it.

I seriously don't know if this is useful or not, i won't find myself offended if you graveyard this as it took little time to write anyway.

Here is the code(requires TimerUtils):

JASS:
//************************************************************************************************************
//**                            PreventDeathBug (PDI) library v1.0                                          **
//**                                                                                                        **
//************************************************************************************************************
//**                                                                                                        **
//**    What does PreventDeathIssue do for users? Well as some of your know unit dies                       **
//**    when it's health drops below .405, still if you increase it's health afterwards                     **
//**    it can cause issues with group filters and generally count the unit as alive.                       **
//**                                                                                                        **
//**    This system puts 2 hooks on 2 blizzard natives:                                                     **
//**    native SetUnitState takes unit whichUnit, unitstate whichUnitState, real newVal returns nothing     **
//**    native SetWidgetLife takes widget whichWidget, real newLife returns nothing                         **
//**                                                                                                        **
//**    Whenever the natives are used the hooks fire off and check the widget/unit's life values            **
//**    Depending on their life value and the new value, it decides whether to fire the prevention or not.  **
//**    Prevention is fired if a widget/unit's life is less or equal to .405 and the new life value         **
//**    we wish to set is larger than 0.00.                                                                 **
//**    In case they both are true the hook will start a timer which expires in 0.000001 seconds and        **
//**    sets the unit/widget's life to 0.00 preventing it from having a larger value of health than         **
//**    0.00 for more than 0.000001 seconds.                                                                **
//**                                                                                                        **
//**    To use this library you must use TimerUtils and simply copy this to your map.                       **
//************************************************************************************************************

library PreventDeathBug requires TimerUtils

globals
    private constant real TIMEOUT = 0.000001 // after this timeout the widget's health is set to 0 to avoid bugs
endglobals

private struct prevent

    timer t
    widget w

    static method create takes widget u returns thistype
        local thistype this = thistype.allocate()

        set this.w = u
        set this.t = NewTimer()
        call SetTimerData(this.t, integer(this))
        call TimerStart(this.t, TIMEOUT, false, function thistype.preventWidgetIssue)

        return this
    endmethod

    static method preventWidgetIssue takes nothing returns nothing
        local thistype this = GetTimerData(GetExpiredTimer())
        call SetWidgetLife(this.w,0)
        call ReleaseTimer(this.t)
        call this.destroy()
    endmethod

endstruct



private function SetUnitState_hook takes unit whichUnit, unitstate whichUnitState, real newVal returns nothing
    if GetWidgetLife(whichUnit) <= .405 and newVal > 0.00 then
        call prevent.create(whichUnit)
    endif
endfunction

private function SetWidgetLife_hook takes widget whichWidget,real newLife returns nothing
    if GetWidgetLife(whichWidget) <= .405 and newLife > 0.00 then
        call prevent.create(whichWidget)
    endif
endfunction

private function UnitDamageTarget_hook takes unit whichUnit, widget target, real amount, boolean attack, boolean ranged, attacktype attackType, damagetype damageType, weapontype weaponType returns nothing
     if GetWidgetLife(whichUnit) <= .405 and amount < 0.00 then
        call prevent.create(whichUnit)
    endif
endfunction

hook UnitDamageTarget UnitDamageTarget_hook

hook SetUnitState SetUnitState_hook

hook SetWidgetLife SetWidgetLife_hook

endlibrary
 
Last edited:
Level 11
Joined
Apr 29, 2007
Messages
826
Few improvements:
JASS:
    static method create takes nothing returns thistype
        local thistype this = thistype.allocate()
        return this
    endmethod
What's that? You did not change anything, so you can just leave the create method out.

JASS:
    private method onDestroy takes nothing returns nothing
        set .w = null
        call PauseTimer(.t)
        call ReleaseTimer(.t)
        set .t = null
    endmethod
Two things:
-There's absolutely no need to null struct members.
-TimerUtils automatically pauses timers.

So merge your struct to this:
JASS:
private struct prevent

    timer t
    widget w

    static method preventWidgetIssue takes nothing returns nothing
        local thistype this = GetTimerData(GetExpiredTimer())
        call SetWidgetLife(.w,0)
        call ReleaseTimer(.t)
        call this.destroy()
    endmethod

endstruct


Other than that, I don't see a real reason in this. Most coders who use this stuff here are advanced enough to know that healing dead units might cause issues.
But whatever, just my opinion, it could still be useful for some people.
 
Last edited by a moderator:
Level 11
Joined
Apr 29, 2007
Messages
826
I guess this would be even more efficient. :p

JASS:
library PreventDeathBug requires TimerUtils

globals
    private constant real TIMEOUT = 0.000001 // after this timeout the widget's health is set to 0 to avoid bugs
endglobals

private struct prevent

    timer t
    widget w

    static method create takes widget u returns thistype
        local thistype this = thistype.allocate()

        set this.w = u
        set this.t = NewTimer()
        call SetTimerData(this.t, integer(this))
        call TimerStart(this.t, TIMEOUT, false, function thistype.preventWidgetIssue)

        return this
    endmethod

    static method preventWidgetIssue takes nothing returns nothing
        local thistype this = GetTimerData(GetExpiredTimer())
        call SetWidgetLife(this.w,0)
        call ReleaseTimer(this.t)
        call this.destroy()
    endmethod

endstruct



private function SetUnitState_hook takes unit u,unitstate n,real val returns nothing
    if GetWidgetLife(u) <= .405 and val > 0.00 then
        prevent.create(u)
    endif
endfunction

private function SetWidgetLife_hook takes widget whichWidget,real newLife returns nothing
    if GetWidgetLife(whichWidget) <= .405 and newLife > 0.00 then
        prevent.create(whichWidget)
    endif
endfunction

hook SetUnitState SetUnitState_hook

hook SetWidgetLife SetWidgetLife_hook

endlibrary

Since hooks are called before the real function, there's no actual need to set the widget's life to 0 within the hook.
 
Last edited:
Level 8
Joined
Oct 3, 2008
Messages
367
You know, SetUnitState and SetWidgetLife aren't the only ways which a dead unit can gain life through. So it's still better to use the UnitAlive native. And if you're using the UnitAlive native, this is useless.
 
Top