• 🏆 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!
  • 🏆 Hive's 6th HD Modeling Contest: Mechanical is now open! Design and model a mechanical creature, mechanized animal, a futuristic robotic being, or anything else your imagination can tinker with! 📅 Submissions close on June 30, 2024. Don't miss this opportunity to let your creativity shine! Enter now and show us your mechanical masterpiece! 🔗 Click here to enter!

[JASS] Heal / Shield Combo Issues

Status
Not open for further replies.
Level 2
Joined
Jan 29, 2009
Messages
21
Here's what this code should do. If the target of this healing ability has one of four certain buffs, it will create a shield of X life that absorbs damage from the unit.

Here's what actually happens. If the unit has buff 'B020' or 'B022', it always works. If it has buff 'B021' it occasionally works. And if the target has buff 'B021', it never works.

For the life of me I cannot figure this out, and have been trying for several hours.

I'm new to JASS, so be lenient about my code.

JASS:
function Trig_Convalesce_Conditions takes nothing returns boolean
    return ( GetSpellAbilityId() == 'A04F' )
endfunction

function HolyWord_Shield takes unit target returns nothing
    local ShieldData data
    local real oldLife = 0
    local real oldMaxLife = 0
    
    //BuffUnit is a simple function I wrote to add a buff of X level to a certain unit for Y player
    //Im fairly sure it has no effect on this, but if you want to see the code just ask
    call BuffUnit(target, GetOwningPlayer(udg_Augur), 'A04G', "lightningshield", GetUnitAbilityLevel(udg_Augur, 'A04F') )
    
    if ( IsUnitInGroup( target, udg_ShieldGroup ) ) then
        set data = GetUnitUserData( target )
        set oldLife = data.Life
        set oldMaxLife = data.MaxLife
        call data.destroy()
        //an if statement that checks for other buffs, not really important for this (but just in case...)
        if ( GetUnitAbilityLevel(target, CORROSIVESHEATH_ID) > 0 ) then
            call UnitRemoveAbility(target, CORROSIVESHEATH_ID)
        elseif ( GetUnitAbilityLevel(target, DEFLECT_ID) > 0 ) then
                call UnitRemoveAbility(target, DEFLECT_ID)
            elseif ( GetUnitAbilityLevel(target, DIVINESHIELD_ID) > 0 ) then
                    call UnitRemoveAbility(target, DIVINESHIELD_ID)
        endif
        call GroupRemoveUnit( udg_ShieldGroup, target )
   endif
    
    set data = ShieldData.create()
    set data.MaxLife = oldMaxLife + udg_HolyWord_Shield
    set data.Life = oldLife + udg_HolyWord_Shield
    call TriggerRegisterUnitEvent( data.t, target, EVENT_UNIT_DAMAGED )
    call TriggerRegisterUnitEvent( data.t, target, EVENT_UNIT_DEATH )
    set data.taction = TriggerAddAction( data.t, function Shield_Absorb )
    call SetUnitUserData( target, data )
    call GroupAddUnit( udg_ShieldGroup, target )
   
    set target = null
endfunction

function Trig_Convalesce_Actions takes nothing returns nothing
    local unit target = GetSpellTargetUnit()
    local real life = GetUnitState(target, UNIT_STATE_LIFE)
    local real maxLife = GetUnitState(target, UNIT_STATE_MAX_LIFE)
    local real percentHeal = 1 - (life / maxLife)
    local boolean holyWord = false
    local ShieldData data
    local real oldLife = 0
    local real oldMaxLife = 0
    
    set udg_Convalesce_Heal = ( ( ( 2.00 + ( 4.00 * I2R(GetUnitAbilityLevel(udg_Augur, 'A04F')) ) ) * I2R(GetHeroInt(udg_Augur, true)) ) + ( 150.00 + ( 150.00 * I2R(GetUnitAbilityLevel(udg_Augur, 'A04F')) ) ) )
    set udg_HolyWord_Shield = ( ( ( 1.50 + ( 0.50 * I2R(GetUnitAbilityLevel(udg_Augur, 'A04F')) ) ) * I2R(GetHeroInt(udg_Augur, true)) ) + ( 50.00 + ( 25.00 * I2R(GetUnitAbilityLevel(udg_Augur, 'A04F')) ) ) )
    
    if (percentHeal < 0.95) then
        set udg_Convalesce_Heal = percentHeal * udg_Convalesce_Heal
    endif
    
    call SetWidgetLife(target, life + udg_Convalesce_Heal)
    
    if ( ( udg_Convalesce_Heal ) != 0.00 ) then
        call CreateTextTagUnitBJ( ( I2S(R2I(( udg_Convalesce_Heal ))) + "!" ), target, 0.00, 14.00, ( udg_r[GetConvertedPlayerId(GetOwningPlayer(udg_Augur))] / 2.55 ), ( udg_g[GetConvertedPlayerId(GetOwningPlayer(udg_Augur))] / 2.55 ), ( udg_b[GetConvertedPlayerId(GetOwningPlayer(udg_Augur))] / 2.55 ), 0 )
        call SetTextTagPermanent( bj_lastCreatedTextTag, false )
        call SetTextTagFadepoint( bj_lastCreatedTextTag, 1.00 )
        call SetTextTagLifespan( bj_lastCreatedTextTag, 4.00 )
    endif
    
    if ( GetUnitAbilityLevel(target, 'B01Z') > 0 ) then
        call HolyWord_Shield(target)
    elseif ( GetUnitAbilityLevel(target, 'B020') > 0 ) then
            call HolyWord_Shield(target)
        elseif ( GetUnitAbilityLevel(target, 'B021') > 0 ) then
                call HolyWord_Shield(target)
            elseif ( GetUnitAbilityLevel(target, 'B022') > 0 ) then
                    call HolyWord_Shield(target)
    endif
    
    set target = null
endfunction

//===========================================================================
function InitTrig_Convalesce takes nothing returns nothing
    set gg_trg_Convalesce = CreateTrigger(  )
    call TriggerRegisterUnitEvent( gg_trg_Convalesce, gg_unit_H014_0144, EVENT_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( gg_trg_Convalesce, Condition( function Trig_Convalesce_Conditions ) )
    call TriggerAddAction( gg_trg_Convalesce, function Trig_Convalesce_Actions )
endfunction

JASS:
//Holds all info for every shield ability in game
library Shield
    struct ShieldData
        trigger t = CreateTrigger()
        triggeraction taction
        // ... values for other abilities
        //sum of all shields' max life
        real MaxLife
        //sum of all shields' current life
        real Life
        method onDestroy takes nothing returns nothing
            call TriggerRemoveAction( .t, .taction )
            call DestroyTrigger( .t )
        endmethod
    endstruct
    
    //Buff IDs
    globals
        // ... globals for other abilities
        integer HOLYSHIELD_ID = 'B023'
    endglobals
    
    // ... code for other abilities

    //Holy Word: Shield Trigger
    function Shield_Absorb takes nothing returns nothing
        local unit target = GetTriggerUnit()
        local unit source = GetEventDamageSource()
        local ShieldData data = GetUnitUserData( target )
        local real damage = GetEventDamage()
        local real life = GetWidgetLife( target )
        local real maxlife = GetUnitState( target, UNIT_STATE_MAX_LIFE )
        local real lifeback

        if ( life < 0.405 ) then
            call data.destroy()
            call GroupRemoveUnit( udg_ShieldGroup, target )
            return
        endif
        if ( GetUnitAbilityLevel(target, HOLYSHIELD_ID) == 0 ) then
            call data.destroy()
            call GroupRemoveUnit( udg_ShieldGroup, target )
            return
        endif
        if ( data.Life - damage <= 0.00 ) then
            set lifeback = data.Life
            call UnitRemoveAbility(target, HOLYSHIELD_ID)
            call data.destroy()
            call GroupRemoveUnit( udg_ShieldGroup, target )
        else
            set lifeback = damage
            set data.Life = data.Life - damage
        endif
        if ( life + lifeback >= maxlife ) then
            call SetWidgetLife( target, maxlife )
        else
            call SetWidgetLife( target, life + lifeback )
        endif
        set source = null
        set target = null
    endfunction
endlibrary

Any help would be greatly appreciated, and thanks in advance for lumbering through my code.
 
Level 6
Joined
Nov 3, 2008
Messages
117
well i don't get it why you use vJass, if you can't use structs

and another thing is that you won't get it MUI and MPI with this
JASS:
set data = GetUnitUserData("YourUnit")
because not every unit has his own userdata
at the beginning each units user data = 0

you have to merge the "HolyWord_Shiel" function into a method so you don't even need the the previously thing mentioned by me

to do it better you should do it like this
JASS:
scope Shield
     globals
          //your global list
     endglobals

    function Shield_Absorb takes nothing returns nothing
        local unit target = GetTriggerUnit()
        local unit source = GetEventDamageSource()
        local real damage = GetEventDamage()
        local real life = GetWidgetLife( target )
        call SetWidgetLife( target, life + damage )
        set source = null
        set target = null
        call DestroyTrigger(GetTriggeringTrigger())
    endfunction

    struct "your struct"
        unit target
     
    method HolyWord_Shield takes nothing returns nothing
        local trigger t = CreateTrigger()
        call BuffUnit(target, GetOwningPlayer(udg_Augur), 'A04G',"lightningshield", GetUnitAbilityLevel(udg_Augur, 'A04F') )

        call TriggerRegisterUnitEvent( t, .target, EVENT_UNIT_DAMAGED )
        call TriggerRegisterUnitEvent( t, .target, EVENT_UNIT_DEATH )
        call TriggerAddAction( t, function Shield_Absorb )
        call GroupAddUnit( udg_ShieldGroup, target )
        set target = null
    endmethod
    
    endstruct

function Trig_Convalesce_Actions takes nothing returns nothing
    local unit target = GetSpellTargetUnit()
    local real life = GetUnitState(target, UNIT_STATE_LIFE)
    local real maxLife = GetUnitState(target, UNIT_STATE_MAX_LIFE)
    local real percentHeal = 1 - (life / maxLife)
    local boolean holyWord = false
    local ShieldData data = ShieldData.create()
    set data.target = target

    set udg_Convalesce_Heal = ( ( ( 2.00 + ( 4.00 * I2R(GetUnitAbilityLevel(udg_Augur, 'A04F')) ) ) * I2R(GetHeroInt(udg_Augur, true)) ) + ( 150.00 + ( 150.00 * I2R(GetUnitAbilityLevel(udg_Augur, 'A04F')) ) ) )
    set udg_HolyWord_Shield = ( ( ( 1.50 + ( 0.50 * I2R(GetUnitAbilityLevel(udg_Augur, 'A04F')) ) ) * I2R(GetHeroInt(udg_Augur, true)) ) + ( 50.00 + ( 25.00 * I2R(GetUnitAbilityLevel(udg_Augur, 'A04F')) ) ) )

    if (percentHeal < 0.95) then
        set udg_Convalesce_Heal = percentHeal * udg_Convalesce_Heal
    endif

    call SetWidgetLife(target, life + udg_Convalesce_Heal)

    if ( ( udg_Convalesce_Heal ) != 0.00 ) then
        call CreateTextTagUnitBJ( ( I2S(R2I(( udg_Convalesce_Heal ))) + "!" ), target, 0.00, 14.00, ( udg_r[GetConvertedPlayerId(GetOwningPlayer(udg_Augur))] / 2.55 ), ( udg_g[GetConvertedPlayerId(GetOwningPlayer(udg_Augur))] / 2.55 ), ( udg_b[GetConvertedPlayerId(GetOwningPlayer(udg_Augur))] / 2.55 ), 0 )
        call SetTextTagPermanent( bj_lastCreatedTextTag, false )
        call SetTextTagFadepoint( bj_lastCreatedTextTag, 1.00 )
        call SetTextTagLifespan( bj_lastCreatedTextTag, 4.00 )
    endif

    if ( GetUnitAbilityLevel(target, 'B01Z') > 0 ) then
        call HolyWord_Shield(target)
    elseif ( GetUnitAbilityLevel(target, 'B020') > 0 ) then
        call HolyWord_Shield(target)
    elseif ( GetUnitAbilityLevel(target, 'B021') > 0 ) then
        call HolyWord_Shield(target)
    elseif ( GetUnitAbilityLevel(target, 'B022') > 0 ) then
        call HolyWord_Shield(target)
    endif
    set target = null
endfunction

endscope

but in my oppinion there is no struct needed. You have to make the Spell MPI and MUI. Try to use HandleVars and not global vars, or atleast try to do it with arrays
 
Last edited:
Level 2
Joined
Jan 29, 2009
Messages
21
Thanks Inferior, Ill try to fix it now.

HandleVars are outdated and bad, just use structs or global arrays.

I have a question related to the mechanics of structs (I hope this isn't too off topic). I was wondering since they set they use a unit's custom value, you can't really have two structs on one unit, right? IE if I set a units data a struct X for whatever purpose, then while it still was using that data set it to struct Y, X would get overridden, correct? Or am I wrong?

(I have searched and never found anything specific enough to answer this)

EDIT: Oh crap, I'm an idiot. I figured out the problem - BuffUnit has a delay on it (not intentionally, it's due to the time required for the buff to actually be applied by the dummy). When the unit was damaged immediately after having the ability being cast on it, the buff was not yet applied and it destroyed the struct. Thanks for your help, and Im still curious about the about question.
 
Last edited:
I have a question related to the mechanics of structs (I hope this isn't too off topic). I was wondering since they set they use a unit's custom value, you can't really have two structs on one unit, right? IE if I set a units data a struct X for whatever purpose, then while it still was using that data set it to struct Y, X would get overridden, correct? Or am I wrong?
If you use SetUnitUserData, then you are right, but it is possible to have custom attachment systems, or, even better, static arrays.
 
Level 2
Joined
Jan 29, 2009
Messages
21
If you use SetUnitUserData, then you are right, but it is possible to have custom attachment systems, or, even better, static arrays.

Thanks, that helps a lot. I was getting worried about having so many different structs and how to make them work together

+rep!
 
Status
Not open for further replies.
Top