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

[System] GetUnitRegeneration

The title explains it all.

JASS:
/********************************************************
*
*   GetUnitRegeneration
*   v2.0.0.0
*   By Magtheridon96
*
*   - Gets unit regeneration values
*
*   Requirements:
*   -------------
*
*       - UnitIndexer by Nestharus
*           - hiveworkshop.com/forums/jass-resources-412/system-unit-indexer-172090/
*       - DamageEvent by Nestharus
*           - hiveworkshop.com/forums/jass-resources-412/snippet-damageevent-186829/
*       - Heal by Magtheridon96
*           - hiveworkshop.com/forums/jass-resources-412/system-heal-203662/
*       - CTL by Nestharus
*           - hiveworkshop.com/forums/jass-resources-412/snippet-constant-timer-loop-32-a-201381/
*
*       Optional:
*       ---------
*
*       - DamageControl by PurgeandFire111
*           - hiveworkshop.com/forums/jass-resources-412/system-damage-control-204672/
*
*   API:
*   ----
*
*       - function IsUnitRegenerating takes unit u returns boolean
*           - Tells whether a unit is regenerating or not.
*       - function IsUnitRegeneratingById takes integer i returns boolean
*           - Tells whether a unit is regenerating or not given the Id.
*       - function GetUnitRegeneration takes unit u returns real
*           - Gets the amount of regeneration for a given unit.
*       - function GetUnitRegenerationById takes integer i returns real
*           - Gets the amount of regeneration for a given unit given the Id.
*       - function IsRegenerationPositive takes unit u returns boolean
*           - Tells whether the regeneration is positive.
*       - function IsRegenerationPositiveById takes integer i returns boolean
*           - Tells whether the regeneration is positive given the Id.
*
********************************************************/
library GetUnitRegeneration requires UnitIndexer, DamageEvent, Heal, CTL, optional DamageControl
    
    private struct UnitRegen extends array
        
        static thistype array next
        static thistype array prev
        
        static real array life
        static real array max
        static real array damaged
        static real array amount
        
        static boolean array regenerating
        
        static method damage takes nothing returns nothing
            static if LIBRARY_DamageControl then
                set damaged[DamageEvent.targetId] = damaged[DamageEvent.targetId] + DamageControl.result
            else
                set damaged[DamageEvent.targetId] = damaged[DamageEvent.targetId] + DamageEvent.amount
            endif
        endmethod
        
        static method heal takes nothing returns nothing
            set damaged[Heal.targetId] = damaged[Heal.targetId] - Heal.effective
        endmethod
        
        static method index takes nothing returns nothing
            // Add index to list
            set next[GetIndexedUnitId()] = 0
            set prev[GetIndexedUnitId()] = prev[0]
            set next[prev[0]] = GetIndexedUnitId()
            set prev[0] = GetIndexedUnitId()
            
            // Setting current life and max life
            set life[GetIndexedUnitId()] = GetWidgetLife(GetIndexedUnit())
            set max[GetIndexedUnitId()] = GetUnitState(GetIndexedUnit(), UNIT_STATE_MAX_LIFE)
        endmethod
        
        static method deindex takes nothing returns nothing
            set regenerating[GetIndexedUnitId()] = false
            
            // Remove from list
            set next[prev[GetIndexedUnitId()]] = next[GetIndexedUnitId()]
            set prev[next[GetIndexedUnitId()]] = prev[GetIndexedUnitId()]
            
            // Resetting Data
            set amount[GetIndexedUnitId()] = 0
            set damaged[GetIndexedUnitId()] = 0
            
            set regenerating[GetIndexedUnitId()] = false
        endmethod
        
        implement CT32
        
            local thistype this = next[0]
            local real hp = 0
            local real ml = 0
            
            loop
                exitwhen 0 == this
                
                set ml = GetUnitState(GetUnitById(this), UNIT_STATE_MAX_LIFE)
                
                if max[this] != ml then
                    set life[this] = life[this] * (ml / max[this])
                endif
                
                set hp = GetWidgetLife(GetUnitById(this)) + damaged[this]
                
                if hp != life[this] then
                    set amount[this] = (hp - life[this]) / 0.03125
                    set regenerating[this] = true
                    set life[this] = hp - damaged[this]
                else
                    set regenerating[this] = false
                    set amount[this] = 0
                endif
                
                set damaged[this] = 0
                set max[this] = ml
                
                set this = next[this]
            endloop
            
        implement CT32End
        
        private static code indexCode
        private static code deindexCode
        private static code damageCode
        private static code healCode
        
        private static method onInit takes nothing returns nothing
        
            set indexCode = function thistype.index
            set deindexCode = function thistype.deindex
            set damageCode = function thistype.damage
            set healCode = function thistype.heal
            
            static if LIBRARY_DamageControl then
                call DamageControl.FINAL.register(Filter(damageCode))
            else
                call DamageEvent.ANY.register(Filter(damageCode))
            endif
            
            call RegisterAnyHealEvent(healCode)
            call UnitIndexer.INDEX.register(Filter(indexCode))
            call UnitIndexer.DEINDEX.register(Filter(deindexCode))
        endmethod
        
    endstruct
    
    function IsUnitRegenerating takes unit u returns boolean
        return UnitRegen.regenerating[GetUnitUserData(u)]
    endfunction
    
    function IsUnitRegeneratingById takes integer i returns boolean
        return UnitRegen.regenerating[i]
    endfunction
    
    function GetUnitRegeneration takes unit u returns real
        return UnitRegen.amount[GetUnitUserData(u)]
    endfunction
    
    function GetUnitRegenerationById takes integer i returns real
        return UnitRegen.amount[i]
    endfunction
    
    function IsRegenerationPositive takes unit u returns boolean
        return UnitRegen.amount[GetUnitUserData(u)] >= 0
    endfunction
    
    function IsRegenerationPositiveById takes integer i returns boolean
        return UnitRegen.amount[i] >= 0
    endfunction
    
endlibrary

library IsUnitRegenerating requires GetUnitRegeneration
endlibrary

Feel free to comment..
 
Last edited:
It only compares the HP that the unit had 0.03125 seconds ago with the HP that it has now :p
Actually, I found a bug in this and I just fixed it :)
It will now return 100% accurate values even while the unit is taking damage (I didn't update yet but I will)

edit
Update.

I tested this thing A LOT.
I even learned something about regeneration..
I created a peasant and when I displayed the regeneration 32x a second, it went from 0.240 to 0.280 to 0.240 all the time..
 
Level 12
Joined
Feb 22, 2010
Messages
1,115
User may change a unit's life with triggers for a spell, or triggered damage block etc.(bad user :ogre_rage:)

Unit may pick up - drop an item that increases his max hp or get a hp bonus skill directly or upgrades.

Unit may gain - lose a level or str.

Dead or removed units.

I suppose skills like heal, regen aura with positive or negative value will count as regeneration so okay :grin:
 
Why would I want to know if a unit is regenerating?

>_<
There are tons of scenarios where this could be useful. Example:
- A spell that depends on a unit's regeneration

I recommend checking if the unit's life has increased/decreased by the exact same amount as the time before.

That wouldn't work :/
I tried it with a peasant:
His regen:
0.240
0.280
0.240
0.280
0.240
0.280
0.240
....
 
Here's a fix for my iteration method:

JASS:
private static method iterate takes nothing returns nothing
            local thistype this = next[0]
            local real hp = 0
            local real ml = 0
            loop
                exitwhen 0 == this
                set ml = GetUnitState(.unit,UNIT_STATE_MAX_LIFE)
                if .maxlife != ml then
                    set .life = .life * (ml/.maxlife)
                endif
                set hp = GetWidgetLife(.unit) + .damaged
                if hp != .life then
                    set .amount = (hp-.life)/PERIOD
                    set .regenerating = true
                    set .positive = (hp > .life)
                    set .life = hp - .damaged
                else
                    set .regenerating = false
                    set .positive = true
                    set .amount = 0.0
                endif
                set .damaged = 0.0
                set .maxlife = ml
                set this = next[this]
            endloop
        endmethod

This won't bug with any HP fluctuations (item pickups, leveling down, leveling up, losing an attribute, etc..).. EXCEPT:
SetWidgetLife(unit,xxxx)

That can't be fixed without hooking SetWidgetLife...
Do you think it would be worth it? :/
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
I still recommend checking to see if the regeneration follows that pattern
of low, high, low, and on that third iteration it's classifiable as regenerating.

Maybe I should create my own Heal library then :D
I could create a heal library that sets the units life and fires an Event that runs a function that modifies the life value ^_^

There is already something like this on wc3c.net. And it sucks of course.
 
Good idea Bribe :)

Oh and you guys inspired me to actually write my own Heal library :p

edit
Actually Bribe, I don't think I'm going to do that :/

edit

Updated.
The only times you're going to use SetWidgetLife:
- Healing a unit
- Setting life to 100%

I made this require "Heal" (which I just posted) so that the only time this system could bug is when you wanna set the unit's life for some unknown reason.
I could fix this by hooking SetWidgetLife, but that would slow the system down.. alot.
 
Last edited:
Level 17
Joined
Mar 17, 2009
Messages
1,349
honestly... since i have already done this in a spell, i dont see the need of a system to check for whether the unit is regenerating cause it would take in a spell or wherever it is being used is 2 variables and a condition (& definetly the timer being used for the spell itself)
 
Level 7
Joined
Dec 3, 2006
Messages
339
then instead of DamageEvent.amount, use DamageEvent.result.
Should be-- then instead of DamageEvent.amount, use DamageControl.result.

But yeah, that works for now. This script should be updated though to incorporate the option of using DamageControl.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
IsUnitRegenerating is pretty much going to return positive in 99% of the cases. The only times I couldn't think of are for undead on blight or elves at night.

Is this seriously worth a library to detect that?

Edit: Well, it works and it does what it's supposed to. The user can decide if it's useful for him/her. Approved.
 
Last edited:
First, you need to install JNGP: http://www.hiveworkshop.com/forums/...456/how-download-install-confige-jngp-160547/

After that, just create a new trigger, paste the code in it, and these are the functions you'll be able to use these functions:

- IsUnitRegenerating(unit) -> boolean
- IsUnitRegeneratingById(integer) -> boolean
- GetUnitRegeneration(unit u) -> real
- GetUnitRegenerationById(integer) -> real
- IsRegenerationPositive(unit) -> boolean
- IsRegenerationPositiveById(integer) -> boolean

To the functions that end with ById, you have to use the custom value as the integer.
The other functions take a unit variable.

Example:

  • Custom script: set udg_TempReal = GetUnitRegeneration(udg_TempUnit)
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
This should be updated to use AdvDamageEvent with a low priority (0 priority).

This should also use DamageType that way you can check, for example, if the damage type is regen =). You should include the type to check for and it should extend off of a DAMAGE_TYPE_HEAL ; ). From there, people can extend off of your type. From here, you'll be able to determine whether to add or subtract the damage resulting from DamageEvent ;p. After all, this should return true if the unit is current under the effect of a healing spell, shouldn't it? : ).


Otherwise it looks quite good, gj.


Do I see any particular uses for this? No, but I see no other problems with the design and it can definitely be used in a map, even if I don't know what that possible use if =P.

I'd totally +rep you if I could ;o.
 
Top