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

Shield System v.3.0

  • Like
Reactions: Devalut and Nuclear
This is a mui shield system, it's like in the game halo.

You are able to add shield points to any unit which work like additional life...

if the unit is attacked its shield loses hp but not the unit itself as long as the shield has hp left.
the shield can regenerate hp.

You can give a shield the following stats:
  • hp value
  • reg per second
  • no attack time till the shield regenerates (0 is constant reg)
  • a factor the damage the shield gets is multiplied with
  • the color of the remaining shieldpoints
  • a boolean whether the shield is destroyed when reaching 0 hp
  • a boolean to show or hide the shields bar
  • the duration the shield lasts (0 is a not timed shield)

functions to change nearly all of these values ingame are included (look at the documentation in the code)

with that it's possible to create powerfull shields^^

it's in vJass so it needs JNGP to work...

have fun^^
Update v.2.0: well,well after some points criticized by TriggerHappy a new update to make him actually "happy" :D
fixed the not destroyed timers, added a adjustable global for the interval, replaced a periodic trigger with a timer and fixed a bug

Update v.3.0: well Anachron has wrote nearly half of the comments here because of a bad size formula so with the help of Frunck I added a new one...
may you be satisfied now :D
In addition the shields can be timed now and they create an effect on the unit they protect


JASS:
library ShieldSystem initializer Init

// The_Witcher's Shield System
//
// This is an easy to use shield system.
// it allows you to add shield points to a unit
// the shield works like in the game halo:
// the attacked unit doesn't receive any dmg, the shield gets it
// when the shield is down the unit is damaged
// the shield can reload constantly or after some seconds of not beeing attacked
//
// to give a unit a shield just use (if duration is 0 the shield will stay without a time limit)
//
//  call AddShield( towhichunit, hitpoints, RegPerSec, TimeTillReg,  damage factor, colorcode, destroy when shieldhp = 0, show the bar, Duration  )
//                    unit         real       real        real         real           string       boolean                  boolean       real
//                                                                                                                  
// you can check whether a unit has already a shield with (it will return a boolean)
//  UnitHasShield( yourunit)
//                  unit
//
// to implement this system, just copy this trigger in your map
// it requires jngp to be edited/saved
//
// To get rid of a shield just use
//   call DestroyShield( which unit's)
//                         unit
//
// to show or hide the shield bar use
//   call ShowShield( WhichUnits, Show? )
//                      unit     boolean
//
// to get information about an existing shield use:
//    HP:           GetShieldHp(  unit  )
//    maxHP:        GetShieldMaxHp(  unit  )
//    percentHP:    GetShieldHpPercent(  unit  )
//    regeneration: GetShieldReg(  unit  ) 
//    TimeTillReg:  GetShieldTimeTillReg(  unit  )
//    DamageFactor: GetShieldDamageFactor(  unit  )
//
// to change the values of an existing shield use:
//    HP:           SetShieldHp(  unit, NewValue  )
//    maxHP:        SetShieldMaxHp(  unit, NewValue  )
//    percentHP:    SetShieldHpPercent(  unit, NewValue  )
//    regeneration: SetShieldReg(  unit, NewValue  )
//    TimeTillReg:  SetShieldTimeTillReg(  unit, NewValue  )
//    DamageFactor: SetShieldDamageFactor(  unit, NewValue  )
//
// have fun^^
// The (very small^^) Setup part
globals
    // the shieldbar's size (should be (7.5 * 0.023 / 10 - 0.00625) or 0.01(which isn't working for everyone) for a good result)
    private constant real size = 7.5 * 0.023 / 10 - 0.00625  
    
    // A ability which gives a high instant life bonus
    private constant integer lifeabi = 'A001'  
    
    // the timer interval (should be 0.01 but if laggy then just change it)
    private constant real interval = 0.01  
    
    //the path of the special effect for untis with a shield
    //another good effect: "Abilities\\Spells\\Human\\DivineShield\\DivineShieldTarget.mdl"
    private constant string sfx = "Abilities\\Spells\\NightElf\\Rejuvenation\\RejuvenationTarget.mdl" 
    
    //the attachement point for sfx
    private constant string AtPoint = "chest"
endglobals
// end of Setup!!
private struct shield
unit u
real hp
real fullhp
real reg
real f
string code
texttag t
real r
effect fx
real remain
timer time
boolean kill 
integer i
real damage = 0
boolean show
endstruct

globals
    private trigger trg = CreateTrigger()
    private group g = CreateGroup()
    private hashtable h = InitHashtable()
    private integer total = 0
    private unit array units
    private timer tim = CreateTimer()
endglobals

function UnitHasShield takes unit u returns boolean
    return LoadInteger(h,GetHandleId(u),0) != 0
endfunction

function DestroyShield takes unit whichunits returns nothing
    local shield dat = LoadInteger(h,GetHandleId(whichunits),0)
    local shield dat2 = LoadInteger(h,GetHandleId(units[total-1]),0)
    if dat != 0 then
        call DestroyTextTag(dat.t)
        call DestroyTimer(dat.time)
        call DestroyEffect(dat.fx)
        call FlushChildHashtable(h,GetHandleId(whichunits))
        set total = total - 1
        set units[dat.i] = units[total]
        set dat2.i = dat.i
        call dat.destroy()
    endif
    if total == 0 then
        call PauseTimer(tim)
    endif
endfunction

private function regeneration takes nothing returns nothing
    local shield dat
    local string s = "''''''''''''''''''''''''''''''''''''''''''''''''''"
    local integer k
    local integer i = 0
    loop
        exitwhen i >= total
        set dat = LoadInteger(h,GetHandleId(units[i]),0)
        if TimerGetRemaining(dat.time) == 0 then
            if dat.hp < dat.fullhp then
                set dat.hp = dat.hp + dat.reg
            else
                set dat.hp = dat.fullhp
            endif
        endif
        if dat.remain > 0 then
            set dat.remain = dat.remain - interval
        elseif dat.remain != -100 then
            call DestroyShield(dat.u)
        endif
        set k = R2I(50 * (dat.hp / dat.fullhp))
        call SetTextTagText(dat.t, dat.code + SubString(s,0, k ) + "|r"  + SubString(s,k + 1,StringLength(s)) , size)
        call SetTextTagPos(dat.t,GetUnitX(dat.u) -40, GetUnitY(dat.u),-100)
        if dat.damage != 0 then
            if dat.hp > (dat.damage * dat.f) then
                set dat.hp = dat.hp - (dat.damage * dat.f)
                call SetWidgetLife( dat.u,GetWidgetLife(dat.u) + dat.damage)
            else
                call SetWidgetLife( dat.u,GetWidgetLife(dat.u) + dat.hp)
                set dat.hp = 0
            endif
            set dat.damage = 0
        endif
        call UnitRemoveAbility(dat.u,lifeabi)
        if dat.hp <= 0 and dat.kill == true then
            call DestroyShield(dat.u)
            set i = i - 1
        endif
        set i = i + 1
    endloop
    set s = null
endfunction

private function attack takes nothing returns nothing
    local shield dat = LoadInteger(h,GetHandleId(GetTriggerUnit()),0)
    local timer t 
    if dat != 0 then
        if dat.hp > 0 then
            set dat.damage = dat.damage + GetEventDamage()
        endif     
        call TimerStart(dat.time,dat.r,false,null)
    endif
endfunction

function AddShield takes unit towhich, real hp, real RegPerSec, real TimeTillReg, real dmgfactor, string colorcode, boolean destroy, boolean ShowBar, real Duration returns nothing
    local shield dat
    if LoadInteger(h,GetHandleId(towhich),0) != 0 then
        call DestroyShield(towhich)
    endif
    set dat = shield.create()
    set dat.u = towhich
    set dat.fullhp = hp
    set dat.hp = hp
    set dat.reg = RegPerSec / 100
    set dat.f = dmgfactor
    set dat.code = colorcode
    set dat.r = TimeTillReg
    set dat.kill = destroy
    set dat.time = CreateTimer()
    set dat.t = CreateTextTag()
    set dat.show = ShowBar
    set dat.fx = AddSpecialEffectTarget(sfx, dat.u, AtPoint)      
    set dat.remain = Duration
    if dat.remain == 0 then
        set dat.remain = -100 
    endif
    call SetTextTagVisibility(dat.t,ShowBar)
    set dat.i = total
    if not IsUnitInGroup(dat.u,g) then
        call GroupAddUnit(g,dat.u)
        call TriggerRegisterUnitEvent( trg, towhich, EVENT_UNIT_DAMAGED )
    endif
    set units[total] = dat.u
    set total = total + 1
    call SaveInteger(h,GetHandleId(dat.u),0,dat)
    if total == 1 then
        call TimerStart(tim,interval,true,function regeneration)
    endif
endfunction

private function kill takes nothing returns nothing
    call DestroyShield(GetTriggerUnit())
endfunction

function ShowShield takes unit u, boolean flag returns nothing
    local shield dat = LoadInteger(h,GetHandleId(u),0)
    if dat != 0 then
        set dat.show = flag
        call SetTextTagVisibility(dat.t,flag)
    endif
endfunction

function GetShieldHpPercent takes unit u returns real
    local shield dat = LoadInteger(h,GetHandleId(u),0)
    if dat != 0 then
        return dat.hp / dat.fullhp * 100.0
    endif
    return .0
endfunction

function GetShieldHp takes unit u returns real
    local shield dat = LoadInteger(h,GetHandleId(u),0)
    if dat != 0 then
        return dat.hp
    endif
    return .0
endfunction

function GetShieldMaxHp takes unit u returns real
    local shield dat = LoadInteger(h,GetHandleId(u),0)
    if dat != 0 then
        return dat.fullhp
    endif
    return .0
endfunction

function GetShieldReg takes unit u returns real
    local shield dat = LoadInteger(h,GetHandleId(u),0)
    if dat != 0 then
        return dat.reg*100
    endif
    return .0
endfunction

function GetShieldTimeTillReg takes unit u returns real
    local shield dat = LoadInteger(h,GetHandleId(u),0)
    if dat != 0 then
        return dat.r
    endif
    return .0
endfunction

function GetShieldDamageFactor takes unit u returns real
    local shield dat = LoadInteger(h,GetHandleId(u),0)
    if dat != 0 then
        return dat.f
    endif
    return .0
endfunction

function SetShieldHpPercent takes unit u, real new returns nothing
    local shield dat = LoadInteger(h,GetHandleId(u),0)
    if dat != 0 then
        set dat.hp = dat.fullhp * new
        if dat.fullhp < dat.hp then
            set dat.hp = dat.fullhp
        endif
    endif
endfunction

function SetShieldHp takes unit u, real new returns nothing
    local shield dat = LoadInteger(h,GetHandleId(u),0)
    if dat != 0 then
        set dat.hp = new
        if dat.fullhp < dat.hp then
            set dat.hp = dat.fullhp
        endif
    endif
endfunction

function SetShieldMaxHp takes unit u, real new returns nothing
    local shield dat = LoadInteger(h,GetHandleId(u),0)
    if dat != 0 then
        set dat.fullhp = new
        if dat.fullhp < dat.hp then
            set dat.hp = dat.fullhp
        endif
    endif
endfunction

function SetShieldReg takes unit u, real new returns nothing
    local shield dat = LoadInteger(h,GetHandleId(u),0)
    if dat != 0 then
        set dat.reg = new/100
    endif
endfunction
                                                                            
function SetShieldTimeTillReg takes unit u, real new returns nothing
    local shield dat = LoadInteger(h,GetHandleId(u),0)
    if dat != 0 then
        set dat.r = new
        call TimerStart(dat.time,dat.r,false,null)
    endif
endfunction

function SetShieldDamageFactor takes unit u, real new returns nothing
    local shield dat = LoadInteger(h,GetHandleId(u),0)
    if dat != 0 then
        set dat.f = new
    endif
endfunction

private function Init takes nothing returns nothing
    local trigger tt = CreateTrigger()
    call TriggerAddAction(tt, function kill)
    call TriggerRegisterAnyUnitEventBJ( tt, EVENT_PLAYER_UNIT_DEATH )    
    
    call TriggerAddAction(trg, function attack)    
endfunction

endlibrary

Keywords:
shield, halo, vjass, hp, regeneration, mui, defend, bar, system, customize, effect, protect
Contents

Shield System (Map)

Reviews
17:37, 9th Nov 2009 TriggerHappy187: Decent enough to be approved.

Moderator

M

Moderator

17:37, 9th Nov 2009
TriggerHappy187:

Decent enough to be approved.
 
Level 14
Joined
Nov 18, 2007
Messages
816
Okay, there are various Shielding Systems already, and this is one of the bad ones, imo.
Theres a reason we have DD systems and systems to create bars out of texttags. Use them. Also, preventing damage is highly complex, you might want to look into it thoroughly.

Oh, and btw, i currently wouldnt approve this.
 
Level 5
Joined
Jul 2, 2005
Messages
60
Well i don't see any reason why you guys want him to use your systems lol .... i mean the prevent dmg thing might be a good reason ... but how he displays the texttag ... is his choice i mean... if you dont like it ... dont use it...
In case that he finds a bug .. he will look arround for a system on his own ^^ bah
 
Level 14
Joined
Nov 18, 2007
Messages
816
I DO NOT want to advertise my system. Frankly, i dont care which one you use (there are three or so). I just want you to USE one.
And yes, its totally my concern if he uses his own crappy (hardcoded) implementation, or another more feature rich one. Mainly because i will have to maintain all libraries i import into a map. And sharing code is one of the best ways to improve maintainability (since i will only have to update one place to fix problems in multiple places). It also decreases the amount of code i have to be familiar with.
 
No he's not right!!

thats just because of my test map -_-

JASS:
if UnitHasShield(GetTriggerUnit()) then
    call DestroyShield(GetTriggerUnit())
else
    call AddShield(...,100,...) //adds a new shield with full hp
endif

if you want it to be different in your map just make a different shield creation, add a cooldown or do something else.

This is no bug it's just to show what the system is able to do -_-
 
why this doesn't work?
  • MI init
    • Ereignisse
      • Zeit - Elapsed game time is 5.00 seconds
    • Bedingungen
    • Aktionen
      • -------- shield --------
      • Custom script: local string s ="||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||"
      • Custom script: local integer SHp = (100/100)*StringLength(s)
      • -------- ------------------------------------------------ --------
      • -------- hp --------
      • Custom script: local string ss ="|||||||||||||||||||||||||||||||||||||||||"
      • Custom script: local real Hp = ( GetUnitStateSwap(UNIT_STATE_LIFE, udg_ShieldUnit[1]) / GetUnitStateSwap(UNIT_STATE_MAX_LIFE, udg_ShieldUnit[1]) ) * 100.00
      • Custom script: local integer UHp = IMinBJ(R2I(Hp),100)
      • Custom script: set UHp= (UHp/100)*StringLength(ss)
      • -------- ------------------------------------------------ --------
      • Custom script: set s = "|c006772F5"+SubString(s,0, SHp )+"'|r"+SubString(s,SHp+1,StringLength(s))
      • Custom script: set ss = "|c00AEF3FF"+SubString(ss,0, UHp )+"'|r"+SubString(ss,UHp+1,StringLength(ss))
      • Spiel - Display to (All players) the text: run multiboard
      • -------- ------------------------------------------------ --------
      • Set ShieldUnit[1] = Soldat 0000 <gen>
      • Custom script: call AddShield(udg_ShieldUnit[1],100,30,2,true,"|cff089CF7",2, true)
      • -------- ------------------------------------------------ --------
      • Bestenliste - Create a leaderboard for (All players) titled hey
      • Set ShieldBoard[1] = (Last created leaderboard)
      • Bestenliste - Change the display style for ShieldBoard[1] to Zeigen the title, Zeigen labels, Zeigen values, and Zeigen icons
      • Custom script: call LeaderboardAddItem(udg_ShieldBoard[1],s+"|n"+ss,1,Player(0))
      • Bestenliste - Zeigen ShieldBoard[1]
sry for german trigges
working with old shield sys
 
And for this reasons you should use an Bar system. It doesn't need you to make any new extra functions.

Really, whats so bad about using a custom bar system?

NOW you really start to annoy me!!
Shut Up and advertise your bar system in another thread!

UPDATE:
added functions to change nearly all the values of a shield and added the option to show/hide the bar
 
Level 21
Joined
Dec 9, 2007
Messages
3,096
NOW you really start to annoy me!!
Shut Up and advertise your bar system in another thread!

UPDATE:
added functions to change nearly all the values of a shield and added the option to show/hide the bar

Yeah, I know that.
You're not the only one annoyed by his advertising.
He annoyed me too with his bar system a little.


But his idea has a point, somehow.
If more systems in a map require the same system (f.e. a Bars System), makes things easier.
Still, you made your own bars so you can handle them better, You know them, after all!
 
Level 14
Joined
Nov 18, 2007
Messages
816
Originally Posted by http://ajaxian.com/archives/would-y...library-gives-js-what-it-should-have#comments
- Dont solve problems that dont exist.
- Improve the wheel, dont reinvent it.
- Port the wheel if it doesnt exist in your environment.
- Integrate the wheel into your project.
- Make sure you can replace your wooden wheel for a rubber one if someone else invents it.

[Emphasis is mine]
This. Its not like Anachron is the only telling you to use a separate library for handling bars out of texttags.
 
TriggerHappy187:

Rejected until updated.

* TriggerRegisterTimerEventPeriodic -- Seriously..?
* Change the timer from 0.01 to something greater than 0.02.
* None of the texttags show for me.
* You're leaking timers, use a timer recycler (like TimerUtils).

well i updated my system and now it should all work.
see Updates to know what changes were exactly made
 
JASS:
private constant real size = 0.01 // the shieldbar's size (should be 0.01 for best result)
Dude, this is awful! (also wrong)

The size isn't a normal value, its a wc3 value.

In my CustomBar I have put a small description into my documentation about how the size is calculated.

JASS:
    //: Sets the default textsize
    //: of the texttag.
    //: Note: This is the wc3 size,
    //: not the normal word one,
    //: so we recalculate it with
    //: the formula.
    TT_DEFAULT_SIZE = 7.5 * 0.023 / 10
Thats one of the reasons I told you you should use the bar system that are already made, because you don't know that much about texttags.
 
Top