• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

Shield System(for both GUI and Jass users) v1.0.1

This bundle is marked as useful / simple. Simplicity is bliss, low effort and/or may contain minor bugs.
  • Like
Reactions: GywGod133
Description: This is a shield system that can easily create a shield for a certain unit to absorb damage. It is lightweight and does not require any other resource (TimerUtils is only optional but recommended for better efficiency). It can be used both for GUI and Jass users.

For GUI users:
  • Custom script: call ShieldSetUp(gg_unit_Hamg_0002, 5000, 120, "Abilities\\Spells\\Undead\\AntiMagicShell\\AntiMagicShell.mdl", "overhead")
The first perimeter is the unit to whom you want to give the shield, "5000" is the HP of the shield, "120" is the duration of the shield, "Abilities\\......" is the effect of the shield, "overhead" is the attach point of the effect. The perimeters are changeable. There are detailed explanations in the script bellow.

Requirement: JNGP.


Credits:
To Vexorian if you choose to use TimerUtils



1. Copy the "ShieldSystem" trigger to your map;
2. Copy the "Life Saver Ability" to your map;
3. Make sure to match the ability ID of the "Life Saver Ability" with the constant integer LIFE_SAVER_AB;
4. You can copy the "TimerUtils" trigger to your map if you want better efficiency.
Done!


JASS:
library ShieldSystem requires optional TimerUtils
/*********************************************************************************************************************
*      This is a shield system that can easily create a shield for a certain unit to absorb damage.It is 
*   lightweight and does not require any other resource (TimerUtils is only optional but recommanded for
*   better efficiency). It can be used both for GUI and Jass users.                
*
*   Version: 1.0.1
*
*   API:
*   function ShieldSetUp takes unit u, real amount, real duration, string sfx, string attach returns nothing
*            "u" stands for the unit to whom you want to give the shield.
*            "amount" is the damage that the shield is able to absorb.
*            "duration" is the duration of the shield.  
*            "sfx" is the string for the effect of the shield.
*            "attach" is the attachment point of the special effect on the unit.
*   
*      The next API has nothing to do with the creation of a protective shield, I just made it for the convenience of 
*  writing this system, some people may find it useful. It is used for adding and removing a certain ability in a 
*  period of time, especially useful for adding buff to a certain unit for a period of time.
*
*  function AbilityTimedSetUp takes unit u, integer ab, real duration returns nothing
*
*  Implementation:
*  1. Copy the "ShieldSystem" trigger to your map;
*  2. Copy the "Life Saver Ability" to your map;
*  3. Make sure to match the ability ID of the "Life Saver Ability" with the constant integer LIFE_SAVER_AB;
*  4. You can copy the "TimerUtils" trigger to your map if you want better efficiency.
*  Done!
*
*///*****************************************************************************************************************
    globals
        private hashtable ht = InitHashtable()
        private constant integer LIFE_SAVER_AB = 'A000'  //The ability to prevent unit from dying when the damage is more than its HP.
    endglobals
    
    //AbilityTimed is used for adding and removing a certain ability in a period of time.
    struct AbilityTimed
        
        private integer abil
        private unit u
        
        private static method Remove takes nothing returns nothing
            local timer t = GetExpiredTimer()
            local thistype this 
            static if LIBRARY_TimerUtils then
                set this = GetTimerData(t)
                call UnitRemoveAbility(this.u, this.abil)
                call ReleaseTimer(t)
            else
                set this = LoadInteger(ht, GetHandleId(t), 0)
                call FlushChildHashtable(ht, GetHandleId(t))
                call UnitRemoveAbility(this.u, this.abil)
                call PauseTimer(t)
                call DestroyTimer(t)
            endif
            set this.u = null
            call this.destroy()
            set t = null
        endmethod
        
        static method Create takes unit u, integer ab, real duration returns thistype
            local thistype this = thistype.allocate()
            local timer t 
            static if LIBRARY_TimerUtils then
                set t = NewTimer()
                call SetTimerData(t, this)
            else
                set t = CreateTimer()
                call SaveInteger(ht, GetHandleId(t), 0, this)
            endif
            call UnitAddAbility(u, ab)
            set this.u = u
            set this.abil = ab
            call TimerStart(t, duration, false, function thistype.Remove)
            set t = null
            return this
        endmethod
    endstruct
    
    function AbilityTimedSetUp takes unit u, integer ab, real duration returns nothing
        call AbilityTimed.Create(u, ab, duration)
    endfunction    
    
    //The core of ShieldSystem
    struct ShieldSystem
        
        private real shieldAmount
        private unit shieldUnit
        private trigger shieldTrig
        private real shieldDuration
        private string shieldSfx
        private effect shieldEff
        private timer shieldTimer
        private real newLife
        private boolean b = false
        
        //Removing the shield when the duration ends
        private static method Remove takes nothing returns nothing
            local timer t = GetExpiredTimer()
            local thistype this 
            static if LIBRARY_TimerUtils then
                set this = GetTimerData(t)
                call ReleaseTimer(t)
            else
                set this = LoadInteger(ht, GetHandleId(t), 0)
                call FlushChildHashtable(ht, GetHandleId(t))
                call PauseTimer(t)
                call DestroyTimer(t)
            endif
            if this.shieldTrig != null then
                call FlushChildHashtable(ht, GetHandleId(this.shieldTrig))
                call DestroyTrigger(this.shieldTrig)
            endif
            set this.shieldTrig = null
            set this.shieldUnit = null
            if this.shieldEff != null then
                call DestroyEffect(this.shieldEff)
            endif
            set this.shieldEff = null
            set this.shieldTimer = null
            call this.destroy()
            set t = null
        endmethod
        
        private static method AdjustHP takes nothing returns nothing
            local timer t = GetExpiredTimer()
            local thistype this 
            static if LIBRARY_TimerUtils then
                set this = GetTimerData(t)
                call ReleaseTimer(t)
            else
                set this = LoadInteger(ht, GetHandleId(t), 0)
                call FlushChildHashtable(ht, GetHandleId(t))
                call PauseTimer(t)
                call DestroyTimer(t)
            endif
            call SetWidgetLife(this.shieldUnit, this.newLife)
            if this.b then
                set this.shieldUnit = null
                call this.destroy()
            endif
            set t = null
        endmethod
        
        private static method DamageHandler takes nothing returns nothing
            local trigger trig = GetTriggeringTrigger()
            local thistype this = LoadInteger(ht, GetHandleId(trig), 0)
            local real dmg = GetEventDamage()
            local real currentLife = GetWidgetLife(this.shieldUnit)
            local real life 
            local timer t 
            
            if dmg > currentLife then
                /*If the damage is able to kill the target, then
                adding Life Saver Ability to prevent the target from dying*/
                call AbilityTimedSetUp(this.shieldUnit, LIFE_SAVER_AB, 0.00)
                //Abosrbing the incoming damage.
                set this.shieldAmount = this.shieldAmount - dmg
                //If the incoming damage is more than the shield can handle, then...
                if this.shieldAmount <= 0 then 
                    //If the reduced damage is still more than the target's current life, then kill the target.
                    if RAbsBJ(this.shieldAmount) >= currentLife then
                        //Stop the duration timer
                        static if LIBRARY_TimerUtils then
                            call ReleaseTimer(this.shieldTimer)
                        else
                            call PauseTimer(this.shieldTimer)
                            call DestroyTimer(this.shieldTimer)
                        endif
                        call KillUnit(this.shieldUnit)
                        //Release memory
                        call DestroyEffect(this.shieldEff)
                        call FlushChildHashtable(ht, GetHandleId(trig))
                        call DestroyTrigger(trig)
                        set this.shieldUnit = null
                        set this.shieldTrig = null
                        set this.shieldEff = null
                        set this.shieldTimer = null
                        call this.destroy()
                    else
                        /*If the reduced damage is less than the target's current life, 
                        then set the target's life to the correct amount by using a 0 second timer. */
                        //Stop the duration timer
                        static if LIBRARY_TimerUtils then
                            call ReleaseTimer(this.shieldTimer)
                        else
                            call PauseTimer(this.shieldTimer)
                            call DestroyTimer(this.shieldTimer)
                        endif
                        set life = currentLife - RAbsBJ(this.shieldAmount)
                        static if LIBRARY_TimerUtils then
                            set t = NewTimerEx(this)
                            set this.newLife = life
                        else
                            set t = CreateTimer()
                            call SaveInteger(ht, GetHandleId(t), 0, this)
                            set this.newLife = life
                        endif
                        //Set this to true in order to to null "this.shieldUnit" in the timer callback
                        set this.b = true
                        call TimerStart(t, 0.00, false, function thistype.AdjustHP)
                        //Release memory
                        call DestroyEffect(this.shieldEff)
                        call FlushChildHashtable(ht, GetHandleId(trig))
                        call DestroyTrigger(trig)
                        set this.shieldTrig = null
                        set this.shieldEff = null
                        set this.shieldTimer = null
                        set t = null
                    endif
                else
                    //If the shield is strong enough to withstand the damage.
                    set life = GetWidgetLife(this.shieldUnit) + dmg
                    call SetWidgetLife(this.shieldUnit, life)
                endif
                
            else
                //If the damage is less than the target's current life.
                set this.shieldAmount = this.shieldAmount - dmg
                //If there is still HP left of the shield, then...
                if this.shieldAmount > 0 then
                    set life = currentLife + dmg
                    static if LIBRARY_TimerUtils then
                        set t = NewTimerEx(this)
                        set this.newLife = life
                    else
                        set t = CreateTimer()
                        call SaveInteger(ht, GetHandleId(t), 0, this)
                        set this.newLife = life
                    endif
                    call TimerStart(t, 0.00, false, function thistype.AdjustHP)
                else
                    //Stop the duration timer
                    static if LIBRARY_TimerUtils then
                        call ReleaseTimer(this.shieldTimer)
                    else
                        call PauseTimer(this.shieldTimer)
                        call DestroyTimer(this.shieldTimer)
                    endif
                    set life = currentLife - RAbsBJ(this.shieldAmount)
                    static if LIBRARY_TimerUtils then
                        set t = NewTimerEx(this)
                        set this.newLife = life
                    else
                        set t = CreateTimer()
                        call SaveInteger(ht, GetHandleId(t), 0, this)
                        set this.newLife = life
                    endif
                    //Set this to true in order to to null "this.shieldUnit" in the timer callback
                    set this.b = true
                    call TimerStart(t, 0.00, false, function thistype.AdjustHP)
                    //Release memory
                    call DestroyEffect(this.shieldEff)
                    call FlushChildHashtable(ht, GetHandleId(trig))
                    call DestroyTrigger(trig)
                    set this.shieldTrig = null
                    set this.shieldEff = null
                    set this.shieldTimer = null
                endif
            endif
            set trig = null
        endmethod
        
        static method Create takes unit u, real amout, real duration, string sfx, string attach returns thistype
            local thistype this = thistype.allocate()
            local timer t 
            local trigger trig = CreateTrigger()
            call SaveInteger(ht, GetHandleId(trig), 0 , this)
            static if LIBRARY_TimerUtils then
                set this.shieldTimer = NewTimerEx(this)
                call SetTimerData(this.shieldTimer, this)
            else
                set this.shieldTimer = CreateTimer()
                call SaveInteger(ht, GetHandleId(this.shieldTimer), 0, this)
            endif
            //Registering damage event
            call TriggerRegisterUnitEvent(trig, u, EVENT_UNIT_DAMAGED)
            call TriggerAddCondition(trig, Condition(function thistype.DamageHandler))
            //Storing data
            set this.shieldUnit = u
            set this.shieldAmount = amout
            set this.shieldTrig = trig
            set this.shieldDuration = duration
            set this.shieldSfx = sfx
            set this.shieldEff = AddSpecialEffectTarget(this.shieldSfx, this.shieldUnit, attach)
            call TimerStart(this.shieldTimer, duration, false, function thistype.Remove)
            set t = null
            set trig = null
            return this
        endmethod
    endstruct
    
    function ShieldSetUp takes unit u, real amount, real duration, string sfx, string attach returns nothing
        call ShieldSystem.Create(u, amount, duration, sfx, attach)
    endfunction
endlibrary


v.1.0.1: fixed a bug related to de-allocation.
v.1.0: initial release.


Keywords:
shield, system, protection, protective, guard, guardian
Contents

只是另外一张魔兽争霸的地图 (Map)

Reviews
12th Dec 2015 IcemanBo: For long time as NeedsFix. Rejected. 00:55, 3rd Feb 2015 IcemanBo: Fix this...
Level 11
Joined
Oct 11, 2012
Messages
711
Sorry, but is there something new here compared to [System] Shield?

Yes, there is a difference. Cokemonkey11's shield system requires other resources, such as DamageType, StructuredDD and Table, mine requires nothing, it is lightweight, easy to use and implement. Moreover, some people may use other DDS systems, such as LFH's, if so, the two DDS systems (StructuredDD and LFH's DDS) may not compatible with each other. Also, the Table required by Cokemonkey11's system is vexorian's, some people may use Bribe's Table. I know Bribe has made a script to fix this, but some people would rather use his Table insead of Vex's.
On the other side, Cokemonkey11 is a better coder than I am, his system provides more functions, although requires more resources.
I just want to offer something with less complexity to people who are also lazy like me. :D


Update: v.1.0.1, fix a bug related to de-allocation.
 
Top