System Toggle HP Regen

the Immortal

I know, I know...
Reaction score
51
A hack-ish way to disable unit's life regeneration. Has its cons, and as such, I suppose, non-suitable for approval. But still worth the submission imo, as I haven't seen a better way to disable a unit's HP regeneration (actually haven't seen any).

Requires AIDS
Optionally uses Damage

API / Usage / Cons list and everything is in the script.

JASS:
library ToggleHPRegen initializer onInit requires AIDS optional Damage
    /*
      Overview:
        Allows toggling of unit's life regeneration / healing. 
        Uses kinda hack-ish method but works without problems from what I observed. 
        Optionally uses Damage to register for onDamage events.
        
      API:
        ToggleRegen(unit u, boolean disable)
            - disables or enables the unit's regeneration. 
        
        SetUnitLifeEx(unit whichUnit, real newLife)
            - sets whichUnit's life to newLife. Works when its regen is disabled
        
      How to import: 
         - Make sure you have a vJASS compiler (JassHelper) and then simply
         - Copy this script into any trigger object
         
      Inner workings:
        Mantains a stack with all units who have their regens disabled and re-sets 
        their life several times per second (default - 33) to a value. Thus regeneration 
        (and respectively any heal) gets disabled. That value also gets updated each 
        time the unit takes damage so it doesnt become immune to damage. 
        
      Cons:
         - life regeneration over ~100/sec gets visible at default PERIOD (0.03)
           FIX: use smaller period. 
           
         - Any heals also get disabled. Not sure if it counts as a 'con' though. 
           Still, the SetUnitLifeEx function is here for such heals. 
           Can also add a SetWidgetLife/SetUnitState hook if someone thinks it'd be useful
           
      Thx to:
         - J4L's nicey systems
         - Tyrande_Ma3x for original idea. 
    */
    
    globals
        //How often to update unit's HP
        //33 fps should be pretty enough for most maps
        private constant real PERIOD = 0.03
    endglobals
    
    //----------------------------------------------------------------------------------------
    
    private struct RegData extends array
        real HP
        boolean e
        integer num
        trigger trgOnDmg
        
        private method AIDS_onDestroy takes nothing returns nothing
            set e = false
        endmethod
        
        // Really just better/faster with AIDS_RegisterOnLeave(..)
        // but J4L said not to use it!! Q_Q
        //! runtextmacro AIDS()
    endstruct
    
    globals
        private trigger trgOnDamage = CreateTrigger()
        private timer timPeriodic = CreateTimer()
        private unit array ug
        private integer uc = 0
        private RegData rd
    endglobals
    
    private function onPeriod takes nothing returns nothing
        set rd = 0  //use as iterator. -1 var!
        loop
            exitwhen rd == uc
            call SetWidgetLife(ug[rd], RegData[ug[rd]].HP)
            set rd = rd + 1
        endloop
    endfunction
    
    private function onDamage takes nothing returns boolean
        set rd = RegData[GetTriggerUnit()]
        static if LIBRARY_Damage then
            if rd.e then
                set rd.HP = rd.HP - GetEventDamage()
                call SetWidgetLife(GetTriggerUnit(), rd.HP)   //fixes cheat death bug
            endif
        else    //no need for check since only units with disabled regen trigger this
            set rd.HP = rd.HP - GetEventDamage()
            call SetWidgetLife(GetTriggerUnit(), rd.HP)   //fixes cheat death bug
        endif
        return false
    endfunction
    
    function SetUnitLifeEx takes unit whichUnit, real newLife returns nothing
        set RegData[whichUnit].HP = newLife
        call SetWidgetLife(whichUnit, newLife)
    endfunction
    
    function ToggleRegen takes unit u, boolean stop returns nothing
        set rd = RegData<u>
        if rd.e == stop then
            return
        endif
        
        set rd.e = stop
        
        if stop == true then
            set rd.HP = GetWidgetLife(u)
            
            if uc == 0 then
                //ResumeTimer bugs? :/
                call TimerStart(timPeriodic, PERIOD, true, function onPeriod)
            endif
            
            set ug[uc] = u
            set rd.num = uc
            set uc = uc + 1
            
            static if not LIBRARY_Damage then
                if rd.trgOnDmg == null then
                    set rd.trgOnDmg = CreateTrigger()
                    call TriggerAddCondition(rd.trgOnDmg, Condition(function onDamage))
                    call TriggerRegisterUnitEvent(rd.trgOnDmg, u, EVENT_UNIT_DAMAGED)
                endif
            endif
        else
            
            set uc = uc - 1
            set RegData[ug[uc]].num = rd.num
            set ug[rd.num] = ug[uc]
            
            static if not LIBRARY_Damage then
                call DestroyTrigger(rd.trgOnDmg)
                set rd.trgOnDmg = null
            endif
            
            if uc == 0 then
                call PauseTimer(timPeriodic)
            endif
            
        endif
    endfunction
    
    private function onInit takes nothing returns nothing
        static if LIBRARY_Damage then
            call Damage_RegisterEvent(trgOnDamage)
        endif
        call TriggerAddCondition(trgOnDamage, Condition(function onDamage))
        call TimerStart(timPeriodic, PERIOD, true, function onPeriod)
        call PauseTimer(timPeriodic)
    endfunction
endlibrary</u>


Also, if someone is willing to take a look, I had to re-start the timer instead of resuming it as resuming actually runs the timer 2-3 times and then stops. Had the same issue in another project of mine.
Not that it matters performance-wise.


Oh, and yes, the test map sucks. I know.
 

Attachments

  • StopRegen.w3x
    43.1 KB · Views: 417

13lade619

is now a game developer :)
Reaction score
399

the Immortal

I know, I know...
Reaction score
51
You could. But it wouldn't be as precise and good as mine (even though the latter isn't perfect, as well, as I said).

Also from what I see your code will allow a unit to regen at 3/10 speed of its normal reg speed (which is a nice idea btw). But let's say it just disables it. You would also need AIDS. And internally my script does the same as T32 - one timer, one stack - it's just one dependency less. But mine also takes into account damage taken. Look, what if:

First, if a unit gets damaged after a regen tick but before timer tick (which IS possible)? Its life will be [Prev life] + [Regenerated value] - [Damage Taken]. Maybe not that much of a problem, but on a unit with lots of regen it may get noticed or imbalanced.

Then, the continuation. Unit with life locked to X takes X+1 damage (or, really, 1-10 damage more). But it has regenerated some health since the last lock (yeah, a 0.03125 seconds, but still a real possibility on a unit with larger regen rate). So the unit doesn't die until the next tick of the timer due to setting it's life to <0. But now it's counted as a suicide!

Very slim chances, but let's be on the safe side. What makes this script bigger than yours are also the function that can heal through disabled regen and the spaghettiness of the static if's that utilize Damage if it's present. Apart from that (and the damage detection) it does exactly the same.
 

kingkingyyk3

Visitor (Welcome to the Jungle, Baby!)
Reaction score
216
The solution already exists, you don't need this library anyway unless this library provides better functionality than it. :)

Bug report : When ToggleRegen(unit,true) is called, any healing spells will fail for the unit. :S
 

the Immortal

I know, I know...
Reaction score
51
Wasn't aware of your solution, but from what I see it has a real different approach.
Your one triggers the entire regeneration and thus requires setup for every different unit-type. Not that it's bad, it's simply too much work for what mine does - disable HP regen.

And in such a meaning no, it is not 'better', it is just different:
As the fact that not everyone uses Damage for its damage-source-type detecting capabilities (which requires triggering all the damage), nor everyone uses FS inventories (which require importing all items' data in their scripts)... they need far too much setup. (or a good object data reading program ^.-).


My 2 cents on why it could prove useful.
(plus the fact I wanna use it for the Tower Contest)


PS. And, hey, you've added this library after I submitted mine! Darn competition! =O

PPS.
Cons:
- Any heals also get disabled. Not sure if it counts as a 'con' though.
Still, the SetUnitLifeEx function is here for such heals.
Can also add a SetWidgetLife/SetUnitState hook if someone thinks it'd be useful
Documented ;o Should I implement an optional hook?
 

kingkingyyk3

Visitor (Welcome to the Jungle, Baby!)
Reaction score
216
PS. And, hey, you've added this library after I submitted mine! Darn competition! =O
I had the idea for it first, look at the last page. I posted the unit regeneration library long time ago. I planned to release it long time ago, including triggered regeneration abilities on item for units. :p

Your one triggers the entire regeneration and thus requires setup for every different unit-type. Not that it's bad, it's simply too much work for what mine does - disable HP regen.
Hmm, actually that's not much work on it. Just set 0.000 unit regeneration rate and trigger unit hp regeneration rate for the units needed, ignore the units that is not used.
 

Attachments

  • StopRegen.w3x
    39.1 KB · Views: 354

Viikuna

No Marlo no game.
Reaction score
265
Or just make some GSL script for getting those those initial values from object editor and writing them for you.

Anyways, this should be done with some bonus system, like UnitProperties, Bonusmod or Status. This system is not really needed.
 

the Immortal

I know, I know...
Reaction score
51
Still, as a small, snippet-like system, I think it should have its use.. somewhere.

The same way ordinary multi-page inventories exist despite of having Full Screen ones and whatnot - sometimes such a minimalistic approach is better in a given scenario.

Like in the current Tower Contest where that would just one of the side-effects of a tower. I can't use neither GSL nor HealCraft. Plus it'd be both an overkill and unfeasible granted a prerequisite is an easy importing. I needed it, I made it, decided it could be useful, and thus - posted it.

If you think it isn't - feel free to GY it.

//off for the rest of the upcoming night. Cheers!
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top