System Toggle HP Regen

Discussion in 'Systems and Snippets' started by the Immortal, May 1, 2010.

  1. the Immortal

    the Immortal I know, I know...

    Ratings:
    +51 / 0 / -0
    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


    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.
     

    Attached Files:

    • Like Like x 2
  2. Chaos_Knight

    Chaos_Knight New Member

    Ratings:
    +39 / 0 / -0
    AWSOME!

    What's the cons? :p
     
  3. 13lade619

    13lade619 is now a game developer :)

    Ratings:
    +399 / 0 / -0
  4. the Immortal

    the Immortal I know, I know...

    Ratings:
    +51 / 0 / -0
    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.
     
  5. kingkingyyk3

    kingkingyyk3 Visitor (Welcome to the Jungle, Baby!)

    Ratings:
    +216 / 0 / -0
    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
     
  6. the Immortal

    the Immortal I know, I know...

    Ratings:
    +51 / 0 / -0
    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.
    Documented ;o Should I implement an optional hook?
     
  7. kingkingyyk3

    kingkingyyk3 Visitor (Welcome to the Jungle, Baby!)

    Ratings:
    +216 / 0 / -0
    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.
     

    Attached Files:

  8. Viikuna

    Viikuna No Marlo no game.

    Ratings:
    +265 / 0 / -0
    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.
     
  9. the Immortal

    the Immortal I know, I know...

    Ratings:
    +51 / 0 / -0
    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!
     
  10. kingkingyyk3

    kingkingyyk3 Visitor (Welcome to the Jungle, Baby!)

    Ratings:
    +216 / 0 / -0
    Wait for the mod to review it. :)
     
  11. Darthfett

    Darthfett Super Mod

    Ratings:
    +614 / 0 / -0
    Useful little snippet. I don't see any memory leaks, I'm going to approve it. :)
     

Share This Page