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

IsUnitDead

Level 8
Joined
Aug 4, 2006
Messages
357
Basically, using a unit's life to detect if it's dead is a bad idea because a dead unit's life can still be modified when it is dead.

The best way to detect dead units is to use this library (requires vJASS):
(Special thanks to azlier for showing me this)
JASS:
library dead

//returns true if the unit is alive. requires JassHelper
// to declare the AI native "UnitAlive" as a JASS native, so that
// we can use it in the trigger editor. If you trigger in vJASS,
// you should DEFINITELY use this since it is the only way to be
// sure that a unit is alive.
native UnitAlive takes unit id returns boolean

//returns true if the unit is dead. inline friendly.
function UnitDead takes unit u returns boolean
    return not UnitAlive(u)
endfunction

//returns true if the unit exists in the game. inline friendly.
function DoesUnitExist takes unit u returns boolean
    return GetUnitTypeId(u) != 0
endfunction

endlibrary
I also included the DoesUnitExist function, since that seems to be a useful and popular check that not many people know about.

Plain JASS alternative (put this in your trigger editor map header):
JASS:
//returns true if the unit exists in the game
function DoesUnitExist takes unit u returns boolean
    return GetUnitTypeId(u) != 0
endfunction

//returns true if the unit is dead (or does not exist)
function IsUnitDead takes unit u returns boolean
    return IsUnitType(u, UNIT_TYPE_DEAD) or not DoesUnitExist(u) 
endfunction
Summary

How do you detect if a unit is dead? Check if the unit’s life is less than .405, right? Wrong. There is only one way to tell if a unit is actually dead (or not alive):
JASS:
function IsUnitDead takes unit u returns boolean
      return IsUnitType(u, UNIT_TYPE_DEAD) or GetUnitTypeId(u) == 0
endfunction
Stuff like GetUnitState(yourUnit, UNIT_STATE_LIFE) < 0.405 or GetWidgetLife(yourUnit) < .405 can and will cause bugs.


Why?

When a live unit's health goes anywhere below 0.405, it becomes dead. Its health is set to 0.000 and its unittype becomes UNIT_TYPE_DEAD. Once the unit is dead, its life can still be changed by triggers. This serves no practical purpose that I know of, and it does not revive the unit if its life is set above 0.405. However, this can result in bugs if you rely on using the unit's health to tell if it is dead or not. For example, if you forget to have a triggered AOE heal spell filter out dead units, it can heal a bunch of corpses. This would result in all of your other triggered spells thinking that the corpses are "alive." Then imagine the corpses being accidentally knocked back, frozen, meat-hooked, etc. Regardless of whether or not one spell remembers to check for dead units, it should not screw up all of your other spells.

So, the obvious solution is to use the unit's unittype. This unittype is updated automatically whenever the unit is killed, exploded, revived, etc. Unfortunately, IsUnitType returns false when the unit does not exist, meaning we could think a non-existent unit is alive. To make my function work for removed/null units, I also check if the unit's type id is 0. Now units that are null or no longer exist are considered "dead." No matter what mistakes you make, this function will always tell you whether a unit is dead or not.


Some of you may want to verify the above information. For that reason, I have provided the map that I used to test things. In it, you will find a peasant whose basic information is displayed. You can damage, heal, and revive the peasant to see how the information changes. To damage the peasant, type "-damage x" where x is a real number. To heal the peasant, type "-heal x" where x is a real number. I disabled the peasant's health regeneration for testing purposes. To revive the peasant, use the paladin's skill. A zeppelin and necromancer are provided for further testing.


Please do NOT give me credits for this function. I do not know who first used unittype to detect dead units. I first saw it somewhere on wc3c and am only posting it here for the benefit of the community.

I did, however, do all the research on this topic and create the String library used in the test map.

Despite the small size of this function, I found it important enough to be in its own thread rather than in Small Code Snippets. After all, nearly every spell and map needs to detect dead units.
 

Attachments

  • dead test.w3x
    26.2 KB · Views: 287
Last edited:
Level 8
Joined
Aug 4, 2006
Messages
357
No offense, but I do not understand you people. Why use a function that is guaranteed to screw up some of the time? Who cares if it is insignificantly faster... the function I have posted does EXACTLY what yours is meant to do, no strings attached. Yours has to come with a disclaimer: "Oh and be careful never to modify the life of a dead unit or this function will cause all of your spells to screw up".

My function is modular programming and is user friendly. No matter what experience level you are, you can count on it to do what IsUnitDeadBJ should have done in the first place.
 
Level 8
Joined
Aug 6, 2008
Messages
451
People usually make some custom HealUnit function, which checks healed units health before changing it, so I dont really see why GetWidgetLife as a death check is so bad.

o_O

My personal favorite is:
JASS:
IsUnitInGroup( unit, DeadGuys )

Its just perfect. ( Part of unit recycling system, which naturally handles all death thingies nice and smooth )
 
Level 8
Joined
Aug 4, 2006
Messages
357
Okay. I would prefer having the function as just return IsUnitType(u, UNIT_TYPE_DEAD) but this would not return the correct value for null units or units that no longer exist. For example, IsUnitType(null, UNIT_TYPE_DEAD) would return false, making you believe a non-existent unit is actually alive.

So if the unit does not exist, we need to return true. Otherwise, check if the unittype is UNIT_TYPE_DEAD. I have only found one way to check if a unit does not exist, and that is if GetUnitTypeId(u) == 0. Then our function comes out to return GetUnitTypeId(u) == 0 or IsUnitType(u, UNIT_TYPE_DEAD)

I am 99% sure this function will always work. If you find any cases where it does not work, please let me know. Otherwise, I believe there is no point in using GetWidgetLife or GetUnitState to check for dead units.
 
Level 8
Joined
Aug 4, 2006
Messages
357
If any of you have a big enough ego to think your map will always work when you want it to, use GetWidgetLife. If you are more obsessed with speed than functionality, use GetWidgetLife. Otherwise, use my function and rest assured that when you think a unit is dead, IT IS FUCKING DEAD

…or has been removed.

If you only need to check for dead units in filters, you can use IsUnitType(yourUnit, UNIT_TYPE_DEAD) in place of GetWidgetLife(yourUnit) < .405. Otherwise, call this function (IsUnitDead(yourUnit)). It is shorter to type, not noticeably slower, and guaranteed to work for every circumstance.


Okay I'm done ranting. Sorry for the bit of swearing, kiddies.
 
Level 8
Joined
Aug 6, 2008
Messages
451
"Oh and be careful never to modify the life of a dead unit or this function will cause all of your spells to screw up".


There is difference between being careful and not being stupid.

This function is useful, but so is GetWidgetLife and there is nothing wrong with GetWidgetLife, if you know how to code your stuff properly.
 
Level 8
Joined
Aug 4, 2006
Messages
357
Meh, I would never purposefully modify the life of a dead unit. I meant in case I somehow accidentally did so, my function would still work.

I know how to not be stupid and how to code well, but I recognize that I am (like you) only human, and prone to make mistakes. When these mistakes inevitably occur, I won't have to worry about this function making matters worse.

Anyway, thank you for recognizing the usefulness of this function.
 
Level 11
Joined
Apr 6, 2008
Messages
760
call this function (IsUnitDead(yourUnit)). It is shorter to type, not noticeably slower, and guaranteed to work for every circumstance.

why not this function instead then

JASS:
constant function A takes unit u returns boolean
    return IsUnitType(u,UNIT_TYPE_DEAD)
endfunction

it's much shorter to type! and not abit slower!
 
Level 8
Joined
Aug 4, 2006
Messages
357
I see where you're going with this... but the main point of my function was that it would always work ("A" wouldn't)... and that is why I will use it in the future.
I have decided I am going to stop arguing. Those of you who like my function may use it. Those of you who prefer GetWidgetLife may continue to use it, and I will respect your decision. Sorry if I have offended you in any way; that was not my intention; rather, it was to help the community.
aznricepuff - I leave the fate of this thread up to you.
 
Level 8
Joined
Aug 6, 2008
Messages
451
It cant bug, it can just fail as a dead check because of bad coding, but meh whatever.
 
Last edited:
Level 13
Joined
Nov 22, 2006
Messages
1,260
I like this function a lot. Great explanation, I learned a lot.

It cant bug, it can just fail as a dead check because of bad coding, but meh whatever.

If you accidentally screw around with a dead unit's hp, absolutely nothing happens, it can only bug GetWidgetLife. So I don't see any harm in being careful and preventing that from happening, because other than that, increasing a dead unit's hp doesn't have any downside.

Just imagine how many hours of work you would lose before you find out that one of your spell isn't working because of ANOTHER spell where you accidentally increase the life of dead units. When I come to think about it, I would probably have never figured out what is causing the problem.
 
Level 8
Joined
Aug 6, 2008
Messages
451
There is a neat feature called function in Jass that nicely solves this problem.

Instead of SetWidgetLife( myunit, myreal) you should be using some custom ModifyUnitLife function, which checks units health before changing it.

You might also wanna add some custom event script for that function later, in case you want to know when some units health is being modified or do whatever weird stuff you like.

My point is that this problem is so easy to avoid ( unless you are being stupid ) that this function is not usefull just because of that so called problem. It does what it is supposed to do, yes, but it is still not better than GetWidgetLife. ( Maybe GetWidgetLife is not better either, I dont know, but its deffinetly not worse. )
 
Level 11
Joined
Feb 22, 2006
Messages
752
Instead of SetWidgetLife( myunit, myreal) you should be using some custom ModifyUnitLife function, which checks units health before changing it.

How is that any different than using this if all you care about is dead checks? You're just going to replace all instances of another native with a user-made function instead of replacing GetWidgetLife() with IsUnitDead().
 
Level 8
Joined
Aug 6, 2008
Messages
451
Its basicly the same. Thats why there is no reason why this function would be any better than GetWidgetLife. Im just trying to say that there is nothing wrong with GetWidgetLife, if you do things correctly ( This applies to pretty much every function btw ). This IsUnitDead thing works too, but it is not the only option.

I used GetWidgetLife for long time and I never managed to accidentally modify dead units health even without any custom IsUnitDead function. Have any of you guys actually made this mistake and modified dead units health?

Anyways, I dont use neither of this methods anymore, since I recycle my units, which means that they dont really die, so I can just use IsUnitInGroup( unit, DeadGuys ) which works pretty well too.
 
Level 8
Joined
Aug 4, 2006
Messages
357
I like this function a lot. Great explanation, I learned a lot.
Thanks. :grin:

Viikuna, you have some valid points. However, I prefer to use IsUnitDead because it will only return true if a unit is dead. The only time that a unit has unittype UNIT_TYPE_DEAD is when the unit is in the state of being dead. It's kind of like the definition of being dead... I wouldn't want to use your "IsUnitInGroup( unit, DeadGuys )" because it (probably) has to loop through the group to check if the unit is in it. Meh, you can use whatever function you like.
 
Level 12
Joined
Aug 7, 2004
Messages
875
Maskedpoptart is right

The GetWidgetLife or GetUnitState can bug sometimes.

And the problem I've encountered is his perfect example.

In my mini-map, I don't use Heroes, instead I use units, so I devise a trick on how to revive a unit when it's dead. So what I did was I used

JASS:
call SuspendUnitDecay(u)

and after a respawn timer is expired, I move the unit to the respawn location and create a Ressurection dummy.

Now this has messed up my AI. My AI works fine except that they recognize dead players AS ALIVE during the respawn wait period! lol, zombies!... Well even though I used the GetWidgetLife and also tried GetUnitState to differentiate dead units for the AI, it still recognizes those as... alive! So what really happened was AIs hogging dead corpses for 20 seconds (which is the respawn wait period)... lol...

JASS:
IsUnitDead()

This has helped me alot, I didn't know those two functions bugged.

Thanks maskedpoptar, + rep.
 
Level 8
Joined
Aug 6, 2008
Messages
451
I just feel sorry for all those people who do some stuff to save their asses in case they might just screw up with thei code someday, instead of properly structuring and debugging their code and doing things right.
 
Level 12
Joined
Aug 7, 2004
Messages
875
I just feel sorry for all those people who do some stuff to save their asses in case they might just screw up with thei code someday, instead of properly structuring and debugging their code and doing things right.

I feel sorry for all those people who lack understanding of JASS, for instance not knowing the flaws of a GetUnitState call or not knowing that corpses can have full health.
 
Level 17
Joined
Mar 17, 2009
Messages
1,349
maskedpoptart said:
When a live unit's health goes anywhere below 0.405, it becomes dead. Its health is set to 0.000 and its unittype becomes UNIT_TYPE_DEAD.
So basically when we see some amateur Jasser checking if the unit is dead using:
JASS:
GetUnitState(yourUnit, UNIT_STATE_LIFE) < 0.
we shouldn't attack him? :p (ignoring the fact that it could bug)
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
Somebody already said that without any action by trigger, an hero get more than 0.405 hp when he died after some seconds with one ability which isn't supposed to modify life.
I know him and i will ask which ability was involved.
 
Level 8
Joined
Aug 4, 2006
Messages
357
So basically when we see some amateur Jasser checking if the unit is dead using:
JASS:
GetUnitState(yourUnit, UNIT_STATE_LIFE) < 0.
we shouldn't attack him? :p (ignoring the fact that it could bug)
A unit's life can never be negative. So, neither GetUnitState(...) < 0 nor GetWidgetLife(...) < 0 do anything. However, GetUnitState(...) <= 0 or GetUnitState(...) == 0 check effectively the same thing as GetUnitState(...) < 0.405. Going back to your question, you should attack anyone who does not use IsUnitType(u, UNIT_TYPE_DEAD) :wink:, especially amateurs.
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
I was wrong about one thing, the ability involved is able to change life "stone form", but let's explain more where it's the bug.

If an hero which have this ability die when it was on the morphed form, after some time (few seconds, and i didn't try to found a link) he get some hp.

So without any coding failed we have a dead unit which have more than 0.405 hp -> GetWigetLife fail.

Also about the IsUnitInGroup way, first you have to check when an unit die (not a big issue i'm agree), but you have also to remove ghost references when an unit inside it is removed of the game.

So in order to prevent any bug i will still use IsUnitDead.

EDIT : At least it was true few patchs older, but i don't think Blizzard has fixed an unknow very specific bug, or accidentely maybe :p
 
Level 8
Joined
Aug 6, 2008
Messages
451
Hrm, gotta agree with that stone form thingy. I just didnt ever get any problems because I trigger all the stuff instead of using default warcraft abilities. But yea, you are right.

And that IsUnitInGroup thingy I was talking about is lil bit different. Those units dont really die, but get recycled, so no ghost problems. ( Check that moyacks UnitRecycler system for example. )

Well, I think it is time for me to admit, that even if some thingy aint useful for me, it might be useful for some other guys.
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
Viikuna said:
...because I trigger all the stuff instead of using default warcraft abilities
I find it a bit silly, but it's your choice anyway, if you have fun do it like this way, i guess it's right.

Viikuna said:
And that IsUnitInGroup thingy I was talking about is lil bit different. Those units dont really die, but get recycled, so no ghost problems. ( Check that moyacks UnitRecycler system for example. )
I know it's only an example but honestly moyack's system is not enough, moyack itself use an other one which recycle better using morph abilities :p
Also you need to manage revive abilities, but if you trigger them i guess it's not overcomplicated to handle them, or why not use grim001's stuff to detect and handle them (which is currently bugged in some cases, no ?)
Meh i guess an unit like that should'nt be considered as dead.
 
Level 8
Joined
Aug 6, 2008
Messages
451
Well, I basicly like to trigger as much as I can, because it allows more control over the stuff. ( So you dont have to worry about accidentally incereasing units life for example )

edit. All default wc3 abilities that deal damage, are absolute no, because I need to use my custom UnitDamageTarget to get some damage and armor type stuff to work.

Stone Form would have to be trigered to get that morph animation and health regeneration bonus to work with time slowing thingies and stuff like that.

The more you trigger stuff the more you have control over it.
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
Well, I basicly like to trigger as much as I can, because it allows more control over the stuff. ( So you dont have to worry about accidentally incereasing units life for example )

edit. All default wc3 abilities that deal damage, are absolute no, because I need to use my custom UnitDamageTarget to get some damage and armor type stuff to work.

Stone Form would have to be trigered to get that morph animation and health regeneration bonus to work with time slowing thingies and stuff like that.

The more you trigger stuff the more you have control over it.

I'm agree but you said "all the stuff", anyway nevermind really.
 
I would say this function is very useful.

I was experimenting some day and found out something very frustrating concerning removed unit checks:

JASS:
globals
    unit lol
endglobals

function Test takes nothing returns boolean
    set lol = CreateUnit('h000', 0, 0, 0)
    call RemoveUnit(lol)
    if lol == null then
        return true
    endif
    return false
endfunction
This function returns false. If you don't believe it: Try it out.
I use unit == null checks a lot in my systems and maps ... it almost made me cry once I found out that it DOES NOT work in some cases ...

The GetUnitTypeId(u) == 0 is a nice solution to that ... if you ask me, far more important than the actual death check.
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
Not really, GetWidgetLife(<unit>) > 0.405 will return true for alive units and false for dead and no valid units.
But if you don't trigger all your abilities, or if you try to change the life of dead units, it can fail.
IsUnitDead() can't be broken in any way, it will protect from yourself.
 
Level 8
Joined
Aug 4, 2006
Messages
357
wait... how does that script work? Did you just define native?

Okay I did some research and it looks like UnitAlive is a function normally only available in AI. I guess vJass just allows you to use it in the trigger editor. Why does no one know this?

Thanks for the script, azlier.
 
Level 8
Joined
Oct 3, 2008
Messages
367
You should edit the first post now that it is proven to be false.

>No matter what mistakes you make, this function will always tell you whether a unit is dead or not.

And this is untrue, too. I can make your function think a dead unit is alive by removing the unit type dead.
 
Last edited:
Level 8
Joined
Aug 4, 2006
Messages
357
You should edit the first post now that it is proven to be false.
I will when I get the time.

>No matter what mistakes you make, this function will always tell you whether a unit is dead or not.

And this is untrue, too. I can make your function think a dead unit is alive by removing the unit type dead.
Hmm, whenever I try to change the unit types of a unit, it doesn't work. I haven't really tried with UNIT_TYPE_DEAD though.
 
Top