• 🏆 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 [Vjass]

This bundle is marked as useful / simple. Simplicity is bliss, low effort and/or may contain minor bugs.
This code was written by x-dardas (me),
for a request.. but eventually the requester needed it gui.. so i just finished it anyways..
heres the code, read the introduction to understend this.

JASS:
library ShieldSystem initializer OnInit requires /*
    */DamageEvent, /* http://www.wc3c.net/showthread.php?t=108009
    */ AutoIndex, /*  http://www.wc3c.net/showthread.php?t=105643
    */ GroupUtils /*  http://www.wc3c.net/showthread.php?t=104464
    */
    //* ========================= Credits ==================================================*
    //* Created by x-dardas                                                                 *
    //* Math (Equations) by Naitsirk                                                        *
    //* Mui tested in garena, with Minimage                                                 *
    //* Gotta credit Naitsirk again, for his help on all my systems =]                      *
    //* ====================================================================================*
    //* ========================= Introduction =============================================*
    //* This system is used to create shields, like the 1 in the example.                   *
    //* Those shields have a specific amount of life,                                       *
    //* And they take damage for the hero.                                                  *
    //* When creating a shield, you also pick the damage reduction,                         *
    //* Which reduces the damage by percents (1 - 100).                                     *
    //* This code also supports shield explosions on death.                                 *
    //* Which will cause your shield to explode for X% the damage it took                   *
    //* In Total. (All hits togheter).                                                      *
    //* ====================================================================================*
    //* ========================= User Api =================================================*
    //* local ShieldData shieldData = ShieldData.create(shieldWielder, string shielfSFX,    *
    //* real shieldMaxLife, real damageReduction, string ShieldAttachPoint)                 *
    //* call createShield(shieldData) returns nothing                                       *
    //* call shieldData.isShieldAlive() returns boolean                                     *
    //* call shieldData.damage(real damage) returns nothing                                 *
    //* call shieldData.registerDamageEvent(ShieldTakesDamage (function interface)          *
    //* call shieldData.allowExplosion(real damageReduction,                                *
    //* real explosionRange, boolexpr groupFilter)                                          *
    //* ====================================================================================*
    
    function interface ShieldTakesDamage takes unit wielder, real shieldLifeLeft, real dealtDamage, real dealtDamageTotal returns nothing
    
    struct ShieldData
        public unit wielder
        public string shieldSFX
        public effect sEffect
        
        public real shieldCurrentLife
        public real shieldMaximumLife
        public real damageReduction
        public real currentDamage
        public real damageHoldoff
        
        public real explosionDamageReduction
        public real explosionRadius
        public boolexpr explosionBer
        public group explosionGroup
        
        public ShieldTakesDamage eventFunction
        
        public static method create takes unit shieldWielder, string shieldSFX, real shieldMaxLife, real damageReduction, string shieldAttachPoint returns thistype
            local thistype t = allocate()
                set t.wielder = shieldWielder
                set t.shieldSFX = shieldSFX
                
                set t.shieldCurrentLife = shieldMaxLife
                set t.shieldMaximumLife = shieldMaxLife
                set t.damageReduction = damageReduction
                set t.currentDamage = 0
                set t.explosionRadius = 0
                
                set t.sEffect = AddSpecialEffectTarget(t.shieldSFX, t.wielder, shieldAttachPoint)
                set t.explosionGroup = NewGroup()
            return t
        endmethod
        
        public method allowExplosion takes real explosionDamageReduction, real explosionRange, boolexpr groupFilter returns nothing
            set this.explosionDamageReduction = damageReduction
            set this.explosionRadius = explosionRange
            set this.explosionBer = groupFilter
        endmethod
        
        public method registerDamageEvent takes ShieldTakesDamage func returns nothing
            set eventFunction = func
        endmethod
        
        public method isShieldAlive takes nothing returns boolean
            return .shieldCurrentLife > 0
        endmethod
        
        public method damage takes real damage returns nothing
            local unit enemy = null
            local real equation = 0
            if isShieldAlive() then
                set shieldCurrentLife = shieldCurrentLife - damage
                set currentDamage = currentDamage + damage
                call eventFunction.execute(wielder, shieldCurrentLife, damage, currentDamage)
                if isShieldAlive() == false then
                    call DestroyEffect(sEffect)
                    //Explode It Here
                    call GroupEnumUnitsInArea(explosionGroup, GetUnitX(wielder), GetUnitY(wielder), explosionRadius, explosionBer)
                    //function GroupEnumUnitsInArea takes group whichGroup, real x, real y, real radius, boolexpr filter returns nothing
                    loop
                    set enemy = FirstOfGroup(explosionGroup)
                    exitwhen enemy == null
                        set equation = currentDamage * explosionDamageReduction / 100
                        call UnitDamageTarget(wielder, enemy, equation, false, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_NORMAL, null)
                        call GroupRemoveUnit(explosionGroup, enemy)
                    endloop
                    call ReleaseGroup(explosionGroup)
                endif
                
            endif
        endmethod
    endstruct
    
    globals
        public ShieldData array shieldData
    endglobals
    
    function createShield takes ShieldData data returns nothing
        set shieldData[GetUnitId(data.wielder)] = data
    endfunction
    
    public function UnitUnderAttack takes unit damagedUnit, unit damageSource, real damage returns nothing
        local integer count = 0
        local real equation = 0
        set count = GetUnitId(damagedUnit)
            if shieldData[count].isShieldAlive() then
                set equation = damage * shieldData[count].damageReduction / 100
                call shieldData[count].damage(equation)
                call SetWidgetLife(damagedUnit, GetWidgetLife(damagedUnit) + equation)
            endif
    endfunction
    
    public function OnInit takes nothing returns nothing
        call RegisterDamageResponse(UnitUnderAttack)
    endfunction
    
endlibrary

Tell me how to improve, if this leaks, or stuff like that.

Keywords:
Shield System, Shield, VJass, x-dardas
Contents

Just another Warcraft III map (Map)

Reviews
12th Dec 2015 IcemanBo: For long time as NeedsFix. Rejected. 17:58, 1st Jun 2011 Bribe: These functions should be private functions, not public. You also don't need things like "== false". I advise giving this a quality looking-over to make...

Moderator

M

Moderator

12th Dec 2015
IcemanBo: For long time as NeedsFix. Rejected.

17:58, 1st Jun 2011
Bribe:

These functions should be private functions, not public. You also don't need things like "== false". I advise giving this a quality looking-over to make sure that you're still satisfied with the way it looks now that your skills have improved.
 
I may not know that much about vJASS, but i'm sure something's wrong here (-.-) :D

-The first of group function in the loop is bad :p

PLEASE DO NOT FLAME ME:
Instead of using your method, you could use hashtables to store the value of the damage, so this way, you dont need to use the loop. You can refer to the group as a whole.

... I shouldn't have spoken. *Waiting for baassee and Nestharus to call me an idiot in 5 seconds*...
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
->LOL, so, is vJASS the only way to block damage without the unit dying?


Not at all.. you know, this system can actually run off of AdvDamageEvent and it'd be a whole lot easier.

Check it out in the JASS section if you don't know what it is.

Actually, now that I look at this, it doesn't even look like it would block damage if the unit would have died from it... you have to add an ability to block >.<.
 
Level 11
Joined
Sep 12, 2008
Messages
657
Okay.. Nest.. i saw your code, but i cant really use it..
one of the most confusing thing is the //!, since it gives me a error when i try saving.
if you could solve me that error, i'td be awesome, heres the error:

"External not found in config file: "ObjectMerger""

Edit:to use ForGroup, instead of FirstOfGroup loop?
 
Level 11
Joined
Sep 12, 2008
Messages
657
Hmm.. if i use FG, how would i make it? its not a "function ForGroupHandler", its actually a method.. since its a struct, how do i do that?
and ill take a look at some codes to see how to find damage type..
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
DamageEvent is extremely slow, using a really bad method to deal with recursion. That library is grossly inferior to Nestharus' build. I'm not going to reject a resource that uses AutoIndex but UnitIndexer is by far faster if speed is something you personally are looking for.

Overall the code has potential and I am glad to see your JASS developing.
 
Level 11
Joined
Sep 12, 2008
Messages
657
Readed Faq, known bugs, some of the tutorial, looked at pictures, made a search for "external", "not found", etc.. no response,
i couldnt find how to make it work =[
Can you either quote the words, or tell me in your own words? XD

and what do i do about FG?
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
what is a struct interface?

Something you shouldn't use. Well, given that you are already using resources from wc3c, I guess it doesn't matter at this point. Check out the vjass manual and check out interface.

They essentially do this..
JASS:
globals
    trigger t = CreateTrigger()
endglobals
function MyFunction takes nothing returns nothing
endfunction

function CallMyFunction takes nothing returns boolean
    call MyFunction()
    return false
endfunction

function CallMyFunction2 takes nothing returns nothing
    call TriggerEvaluate(t)
endfunction

function OnInit takes nothing returns nothing
    call TriggerAddCondition(t, Condition(function CallMyFunction))
endfunction

The interface would do call CallMyFunction2()


And this is why only the people at wc3c use them >.>.


The fad at THW for events is module interfaces =)

http://www.hiveworkshop.com/forums/jass-ai-scripts-tutorials-280/art-module-interfaces-188742/


Sadly, if you want polymorphic objects, you still have to use the regular interface method ;P, but I've seen like 0 systems that actually required polymorphism ;D.
 
Level 11
Joined
Sep 12, 2008
Messages
657
Okay.. so right now, you'r saying for group is best,
but i cant even use it? XD thats very smart =]
And module interfaces look pretty nice... but i didnt understend how to use it yet..
when i do method "fire", what would it do?
 
Level 11
Joined
Sep 12, 2008
Messages
657
Okay, i just realised what it is.. been too lazy to read the whole tutorial, i just realised this isnt the code you use in your function, and also.. been playing a while Dragon Age ^^

ill start working on this..
1 last question before i start tho,
if i do this:

JASS:
struct test
    public boolexpr TestBoolexpr = UserDeclaredBoolexpr // Thru the function interface
    
    public method ConditionForGroup takes nothing returns boolean
        if TestBoolexpr() == true then
            //My Actions
       endif
        return false
    endmethod
endstruct

would that work? (I wrote this without vjass syntax, right here on the forum.. with spaces XD sry if its not correct, or any syntax mistakes =]
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
This would work
JASS:
if booleanB then
    //Actions
endif

But keep in mind that boolean expressions allow people to plug in their own expressions, like checking a unit type id or w/e.

Check the UnitIndexer module to see some examples of filters.

JASS:
    module UnitIndexStruct
        static method operator [] takes unit u returns thistype
            return GetUnitUserData(u)
        endmethod
        method operator unit takes nothing returns unit
            return e[this]
        endmethod
        
        static if thistype.filter.exists then
            static if thistype.index.exists then
                readonly boolean allocated
            else
                method operator allocated takes nothing returns boolean
                    return filter(e[this])
                endmethod
            endif
        elseif thistype.index.exists then
            static if thistype.deindex.exists then
                readonly boolean allocated
            else
                method operator allocated takes nothing returns boolean
                    return GetUnitUserData(e[this]) == this
                endmethod
            endif
        else
            method operator allocated takes nothing returns boolean
                return GetUnitUserData(e[this]) == this
            endmethod
        endif
        
        static if thistype.index.exists then
            private static method onIndexEvent takes nothing returns boolean
                static if thistype.filter.exists then
                    if (filter(e[o])) then
                        set thistype(o).allocated = true
                        call thistype(o).index()
                    endif
                else
                    static if thistype.deindex.exists then
                        set thistype(o).allocated = true
                    endif
                    call thistype(o).index()
                endif
                return false
            endmethod
        endif
        
        static if thistype.deindex.exists then
            private static method onDeindexEvent takes nothing returns boolean
                static if thistype.filter.exists then
                    static if thistype.index.exists then
                        if (thistype(o).allocated) then
                            set thistype(o).allocated = false
                            call thistype(o).deindex()
                        endif
                    else
                        if (filter(e[o])) then
                            call thistype(o).deindex()
                        endif
                    endif
                else
                    static if thistype.index.exists then
                        set thistype(o).allocated = false
                    endif
                    call thistype(o).deindex()
                endif
                return false
            endmethod
        endif
        
        static if thistype.index.exists then
            static if thistype.deindex.exists then
                private static method onInit takes nothing returns nothing
                    call RegisterUnitIndexEvent(Condition(function thistype.onIndexEvent), UnitIndexer.INDEX)
                    call RegisterUnitIndexEvent(Condition(function thistype.onDeindexEvent), UnitIndexer.DEINDEX)
                endmethod
            else
                private static method onInit takes nothing returns nothing
                    call RegisterUnitIndexEvent(Condition(function thistype.onIndexEvent), UnitIndexer.INDEX)
                endmethod
            endif
        elseif thistype.unitDeindex.exists then
            private static method onInit takes nothing returns nothing
                call RegisterUnitIndexEvent(Condition(function thistype.onDeindexEvent), UnitIndexer.DEINDEX)
            endmethod
        endif
    endmodule
 
Level 11
Joined
Sep 12, 2008
Messages
657
Hmm.. if booleanB then, would kinda fail,
because they cant define targeted unit =] (like GetFilterUnit())
maybe ill make this a module instead? or remake this as functions,
and on worst side, use module interface.. hmm
ill think this thru and edit..
thx for your time to try helping me =] +rep
 
Top