Cohadar's ORB system

Expelliarmus

Where to change the sig?
Reaction score
48
EDIT2: Found Crash (Solved!)

- Operator Problem
- Clearing Struct Attachment when finished?
- .execute() a callback?

Updated working code.
JASS:
scope VitalityBind initializer InitTrig
//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
//* FULL CREDITS TO : yukino_silvermaine for the idea
//* <a href="http://www.dotastrategy.com/hero-idea-3181-AthanasiaEnteofushiaTheTranscendent.html" target="_blank" class="link link--external" rel="nofollow ugc noopener">http://www.dotastrategy.com/hero-idea-3181-AthanasiaEnteofushiaTheTranscendent.html</a>
//*
//* V I T A L I T Y  B I N D
//* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//* Athanasia binds her life to a target. Any physical damage dealt to her will also be taken by the affected unit. 
//* Does not work the other way around. 
//* Deals bonus damage whenever the damage dealt by Vitality Bind reaches a certain amount. Lasts 12 seconds. 
//* Level 1 - Affected unit takes 15/30/45/60% of damage dealt to Athanasia. 
//* Whenever Vitality Bind deals 350/300/250/200 damage to the target, it deals an additional 100/150/200/250 damage to it.
//*
//*       
//***************************************************************************************************

globals
    private constant integer DURATION = 12
    private constant integer AID_VITALITY_BIND = &#039;A005&#039;
    private constant integer BID_VITALITY_BIND = &#039;B000&#039;
    private constant string SFX_VITALITY_BIND = &quot;Abilities\\Spells\\Demon\\DemonBoltImpact\\DemonBoltImpact.mdl&quot;
    private keyword Data
    private Data array PUI 
endglobals

private constant function Percent takes integer level returns real
    return level * 0.15
     //15/30/45/60 
endfunction

private constant function Damage takes integer level returns real
    return level * 50 + 50.0
    //100/150/200/250
endfunction

private constant function DamageAmount takes integer level returns real
    return - 50 * level + 400.
    //350/300/250/200
endfunction
    
private struct Data
    unit bind
    real damage
    boolean binded
    trigger damaged
    timer time
    
    private static method End takes nothing returns nothing 
        local timer t = GetExpiredTimer()
        //local Data end = ClearTimerStructA(t)
        local Data end = GetTimerStructA(t)
        set end.binded = false
        set end.damage = 0.
        call UnitRemoveAbility(end.bind, BID_VITALITY_BIND)
        call PauseTimer(end.time) 
        call DisableTrigger(end.damaged)
    endmethod
    
    private method EndEarly takes nothing returns nothing //takes instance
        set .binded = false
        set .damage = 0.
        call UnitRemoveAbility(.bind, BID_VITALITY_BIND)
        call PauseTimer(.time) 
        call DisableTrigger(.damaged)
    endmethod
    
    private static method ORB takes nothing returns nothing
        local unit u = GetTriggerUnit()
        local integer index =GetUnitIndex(u)
        local integer level 
        local real damage  
        local Data d = PUI[index]
   
            if GetUnitState(d.bind, UNIT_STATE_LIFE) &lt;= 0.0405  then
                call d.EndEarly() //excecuting timer early
            else
                set level = GetUnitAbilityLevel(u, AID_VITALITY_BIND)
                set damage = GetEventDamage() * Percent(level)
                call UnitDamageTarget(u, d.bind, damage, false, false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_NORMAL, null)
                set d.damage = d.damage + damage
            
                if d.damage &gt; DamageAmount(level) then
                    set d.damage = d.damage - DamageAmount(level)
                    call UnitDamageTarget(u, d.bind, 50 * level + 50, false, false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_NORMAL, null)
                    call DestroyEffect(AddSpecialEffectTarget( SFX_VITALITY_BIND, d.bind, &quot;chest&quot;))
                endif
                set u = null
            endif
    endmethod
    
    private static method create takes unit pui, unit bind returns Data
        local Data new = Data.allocate()
        local integer index = GetUnitIndex(pui)
        set new.bind = bind
        set new.damaged = CreateTrigger()
        set new.time = NewTimer()
        call TriggerRegisterUnitEvent(new.damaged, pui, EVENT_UNIT_DAMAGED)
        call TriggerAddAction( new.damaged, function Data.ORB )
        call SetTriggerStructA(new.damaged, new) //never removed
        call SetTimerStructA(new.time, new) //never removed
        set PUI[index] = new
        
        return new
    endmethod
    // thanks Sooda!
    static method Get takes unit pui, unit bind returns Data
        local integer index = GetUnitIndex(pui)
        local Data eventStruct = index
        if PUI[index] == 0 then
            debug call BJDebugMsg(&quot;First Instance of struct Get for unit: &quot; + GetUnitName(pui)) //works
            return Data.create(pui, bind) 
        else
        call EnableTrigger( eventStruct.damaged) // event
        call TimerStart(eventStruct.time, DURATION, false, function Data.End)
        // Maybe Data.End will cause syntax error, if it does try:
        //        call TimerStart(eventStruct.time, DURATION, false, function eventStruct.End)
        set eventStruct.bind = bind //update target
        set eventStruct.binded = true
        
        return PUI[index] 
        endif
    endmethod    
    
    //static method Get takes unit pui, unit bind returns Data
        //local integer index = GetUnitIndex(pui)
        //local Data get = index
        //if PUI[index] == 0 then
            //debug call BJDebugMsg(&quot;First Instance of struct Get for unit: &quot; + GetUnitName(pui)) //works
            //return Data.create(pui, bind) 
        //else
        //debug call BJDebugMsg(&quot;Second Instance of struct Get for unit: &quot; + GetUnitName(pui)) //works
        //call EnableTrigger( get.damaged) // event
        //call TimerStart(get.time, DURATION, false, function Data.End) 
        //set get.bind = bind //update target
        //set get.binded = true
        
        //return PUI[index] 
        //endif
    //endmethod
endstruct

private function Actions takes nothing returns nothing
    local unit u = GetTriggerUnit()
    local unit bind = GetSpellTargetUnit()
    local Data d = Data.Get(u, bind)
    set u = null // leaks..
    set bind = null
endfunction

private function Conditions takes nothing returns boolean
    return GetSpellAbilityId() == AID_VITALITY_BIND
endfunction

private function Check takes nothing returns boolean
    local unit u 
    local Data check
    if GetSpellAbilityId() == AID_VITALITY_BIND then
        set u = GetTriggerUnit()
        set check = PUI[GetUnitIndex(u)] 
        if check.binded then
            call IssueImmediateOrder(GetTriggerUnit(), &quot;stop&quot;)
            call SimError( GetOwningPlayer( GetTriggerUnit()) , &quot;You have a binded target already&quot; ) //works
            set u = null
        endif
    endif
    
    return false
endfunction

//===========================================================================
private function InitTrig takes nothing returns nothing
    local trigger trig = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( trig, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( trig, Condition( function Conditions ) )
    call TriggerAddAction( trig, function Actions )
    
    set trig = CreateTrigger( )
    call TriggerRegisterAnyUnitEventBJ( trig, EVENT_PLAYER_UNIT_SPELL_CAST )
    call TriggerAddCondition( trig, Condition( function Check ) )
    
    //set trig = null //=P
endfunction

endscope



Old Code
JASS:
scope VitalityBind initializer InitTrig
//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
//* FULL CREDITS TO : yukino_silvermaine for the idea
//* <a href="http://www.dotastrategy.com/hero-idea-3181-AthanasiaEnteofushiaTheTranscendent.html" target="_blank" class="link link--external" rel="nofollow ugc noopener">http://www.dotastrategy.com/hero-idea-3181-AthanasiaEnteofushiaTheTranscendent.html</a>
//*
//* V I T A L I T Y  B I N D
//* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//* Athanasia binds her life to a target. Any physical damage dealt to her will also be taken by the affected unit. 
//* Does not work the other way around. 
//* Deals bonus damage whenever the damage dealt by Vitality Bind reaches a certain amount. Lasts 12 seconds. 
//* Level 1 - Affected unit takes 15/30/45/60% of damage dealt to Athanasia. 
//* Whenever Vitality Bind deals 350/300/250/200 damage to the target, it deals an additional 100/150/200/250 damage to it.
//*
//*       
//***************************************************************************************************

globals
    private constant integer DURATION = 12
    private constant integer AID_VITALITY_BIND = &#039;A005&#039;
    private constant integer BID_VITALITY_BIND = &#039;B000&#039;
    private constant string SFX_VITALITY_BIND = &quot;Abilities\\Spells\\Demon\\DemonBoltImpact\\DemonBoltImpact.mdl&quot;

    VitalityBind_Data array VitalityBind_PUI 
endglobals

private constant function Percent takes integer level returns real
    return level * 0.15
     //15/30/45/60 
endfunction

private constant function Damage takes integer level returns real
    return level * 50 + 50.0
    //100/150/200/250
endfunction

private constant function DamageAmount takes integer level returns real
    return - 50 * level + 400.
    //350/300/250/200
endfunction
    
struct VitalityBind_Data
    unit bind
    real damage
    boolean binded
    trigger damaged
    timer time
    
    private static method End takes nothing returns nothing //replace onDestroy
        local timer t = GetExpiredTimer()
        local VitalityBind_Data end = ClearTimerStructA(t)
        call BJDebugMsg(&quot;End!&quot;) // works after DURATION.
        set end.binded = false
        set end.damage = 0.0
        call UnitRemoveAbility(end.bind, BID_VITALITY_BIND)
        call PauseTimer(end.time) //stop the
        call DisableTrigger(end.damaged)
    endmethod
    
    private static method ORB takes nothing returns nothing
        local unit u = GetTriggerUnit()
        local integer index =GetUnitIndex(u)
        local integer level 
        local real damage  
        local VitalityBind_Data d = VitalityBind_PUI[index]
        // binded unit dead?
        debug call BJDebugMsg(&quot;Damaged&quot;) // not appearing when pui is damaged
        if GetUnitState(d.bind, UNIT_STATE_LIFE) &gt;= 0.0405  then
            call VitalityBind_Data.End.execute() //excecuting timer early
            debug call BJDebugMsg(&quot;unit not dead&quot;) //not at all showing
        else
            set level = GetUnitAbilityLevel(u, AID_VITALITY_BIND)
            set damage = GetEventDamage() * Percent(level)
            call UnitDamageTarget(u, d.bind, damage, false, false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_NORMAL, null)
            set d.damage = d.damage + damage
            debug call BJDebugMsg(R2S(GetEventDamage()))   
            
            if d.damage &gt; DamageAmount(level) then
                set d.damage = d.damage - DamageAmount(level)
                call UnitDamageTarget(u, d.bind, 50 * level + 50, false, false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_NORMAL, null)
                call DestroyEffect(AddSpecialEffectTarget( SFX_VITALITY_BIND, d.bind, &quot;chest&quot;))
            endif
            set u = null
        endif
    endmethod
    
    private static method create takes unit pui, unit bind returns VitalityBind_Data
        local VitalityBind_Data new = VitalityBind_Data.allocate()
        local integer index = GetUnitIndex(pui)
        set new.bind = bind
        set new.damaged = CreateTrigger()
        set new.time = NewTimer()
        call TriggerRegisterUnitEvent(new.damaged, pui, EVENT_UNIT_DAMAGED)
        call TriggerAddAction( new.damaged, function VitalityBind_Data.ORB )
        call SetTriggerStructA(new.damaged, new)
        call SetTimerStructA(new.time, new)
        set VitalityBind_PUI[index] = new
        
        return new
    endmethod
    
    static method Get takes unit pui, unit bind returns VitalityBind_Data
        local integer index = GetUnitIndex(pui)
        if VitalityBind_PUI[index] == 0 then
            debug call BJDebugMsg(&quot;First Instance of struct Get for unit: &quot; + GetUnitName(pui)) //works
            return VitalityBind_Data.create(pui, bind) 
        else
        debug call BJDebugMsg(&quot;Second Instance of struct Get for unit: &quot; + GetUnitName(pui)) //works
        call EnableTrigger( VitalityBind_PUI[index].damaged) // event
        call TimerStart(VitalityBind_PUI[index].time, DURATION, false, function VitalityBind_Data.End) 
        set VitalityBind_PUI[index].bind = bind //update target
        set VitalityBind_PUI[index].binded = true
        
        return VitalityBind_PUI[index] 
        endif
    endmethod
endstruct

private function Actions takes nothing returns nothing
    local unit u = GetTriggerUnit()
    local unit bind = GetSpellTargetUnit()
    local VitalityBind_Data d = VitalityBind_Data.Get(u, bind)
    set u = null // leaks..
    set bind = null
endfunction

private function Conditions takes nothing returns boolean
    return GetSpellAbilityId() == AID_VITALITY_BIND
endfunction

private function Check takes nothing returns boolean
    local unit u 
    local VitalityBind_Data check
    if GetSpellAbilityId() == AID_VITALITY_BIND then
        set u = GetTriggerUnit()
        set check = VitalityBind_PUI[GetUnitIndex(u)] 
        if check.binded then
            call IssueImmediateOrder(GetTriggerUnit(), &quot;stop&quot;)
            call SimError( GetOwningPlayer( GetTriggerUnit()) , &quot;You have a binded target already&quot; ) //works
            set u = null
        endif
    endif
    
    return false
endfunction

//===========================================================================
private function InitTrig takes nothing returns nothing
    local trigger trig = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( trig, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( trig, Condition( function Conditions ) )
    call TriggerAddAction( trig, function Actions )
    
    set trig = CreateTrigger( )
    call TriggerRegisterAnyUnitEventBJ( trig, EVENT_PLAYER_UNIT_SPELL_CAST )
    call TriggerAddCondition( trig, Condition( function Check ) )
    
endfunction

endscope
NEW CODE (Added private prefix to struct and removed VitalityBind_) Crashes
JASS:
scope VitalityBind initializer InitTrig
//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
//* FULL CREDITS TO : yukino_silvermaine for the idea
//* <a href="http://www.dotastrategy.com/hero-idea-3181-AthanasiaEnteofushiaTheTranscendent.html" target="_blank" class="link link--external" rel="nofollow ugc noopener">http://www.dotastrategy.com/hero-idea-3181-AthanasiaEnteofushiaTheTranscendent.html</a>
//*
//* V I T A L I T Y  B I N D
//* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//* Athanasia binds her life to a target. Any physical damage dealt to her will also be taken by the affected unit. 
//* Does not work the other way around. 
//* Deals bonus damage whenever the damage dealt by Vitality Bind reaches a certain amount. Lasts 12 seconds. 
//* Level 1 - Affected unit takes 15/30/45/60% of damage dealt to Athanasia. 
//* Whenever Vitality Bind deals 350/300/250/200 damage to the target, it deals an additional 100/150/200/250 damage to it.
//*
//*       
//***************************************************************************************************

globals
    private constant integer DURATION = 12
    private constant integer AID_VITALITY_BIND = &#039;A005&#039;
    private constant integer BID_VITALITY_BIND = &#039;B000&#039;
    private constant string SFX_VITALITY_BIND = &quot;Abilities\\Spells\\Demon\\DemonBoltImpact\\DemonBoltImpact.mdl&quot;

    private Data array PUI 
endglobals

private constant function Percent takes integer level returns real
    return level * 0.15
     //15/30/45/60 
endfunction

private constant function Damage takes integer level returns real
    return level * 50 + 50.0
    //100/150/200/250
endfunction

private constant function DamageAmount takes integer level returns real
    return - 50 * level + 400.
    //350/300/250/200
endfunction
    
private struct Data
    unit bind
    real damage
    boolean binded
    trigger damaged
    timer time
    
    private static method End takes nothing returns nothing //replace onDestroy
        local timer t = GetExpiredTimer()
        local Data end = ClearTimerStructA(t)
        call BJDebugMsg(&quot;End!&quot;) // works after DURATION.
        set end.binded = false
        set end.damage = 0.0
        call UnitRemoveAbility(end.bind, BID_VITALITY_BIND)
        call PauseTimer(end.time) //stop the
        call DisableTrigger(end.damaged)
    endmethod
    
    private static method ORB takes nothing returns nothing
        local unit u = GetTriggerUnit()
        local integer index =GetUnitIndex(u)
        local integer level 
        local real damage  
        local Data d = PUI[index]
        // binded unit dead?
        if GetEventDamage() &gt; 0 then
            debug call BJDebugMsg(&quot;Damaged&quot;) // not appearing when pui is damaged
            if GetUnitState(d.bind, UNIT_STATE_LIFE) &gt;= 0.0405  then
                call Data.End.execute() //excecuting timer early
                debug call BJDebugMsg(&quot;unit not dead&quot;) //not at all showing
            else
                set level = GetUnitAbilityLevel(u, AID_VITALITY_BIND)
                set damage = GetEventDamage() * Percent(level)
                call UnitDamageTarget(u, d.bind, damage, false, false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_NORMAL, null)
                set d.damage = d.damage + damage
                debug call BJDebugMsg(R2S(GetEventDamage()))   
            
                if d.damage &gt; DamageAmount(level) then
                    set d.damage = d.damage - DamageAmount(level)
                    call UnitDamageTarget(u, d.bind, 50 * level + 50, false, false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_NORMAL, null)
                    call DestroyEffect(AddSpecialEffectTarget( SFX_VITALITY_BIND, d.bind, &quot;chest&quot;))
                endif
                set u = null
            endif
        endif
    endmethod
    
    private static method create takes unit pui, unit bind returns Data
        local Data new = Data.allocate()
        local integer index = GetUnitIndex(pui)
        set new.bind = bind
        set new.damaged = CreateTrigger()
        set new.time = NewTimer()
        call TriggerRegisterUnitEvent(new.damaged, pui, EVENT_UNIT_DAMAGED)
        call TriggerAddAction( new.damaged, function Data.ORB )
        call SetTriggerStructA(new.damaged, new)
        call SetTimerStructA(new.time, new)
        set PUI[index] = new
        
        return new
    endmethod
    
    static method Get takes unit pui, unit bind returns Data
        local integer index = GetUnitIndex(pui)
        if PUI[index] == 0 then
            debug call BJDebugMsg(&quot;First Instance of struct Get for unit: &quot; + GetUnitName(pui)) //works
            return Data.create(pui, bind) 
        else
        debug call BJDebugMsg(&quot;Second Instance of struct Get for unit: &quot; + GetUnitName(pui)) //works
        call EnableTrigger( PUI[index].damaged) // event
        call TimerStart(PUI[index].time, DURATION, false, function Data.End) 
        set PUI[index].bind = bind //update target
        set PUI[index].binded = true
        
        return PUI[index] 
        endif
    endmethod
endstruct

private function Actions takes nothing returns nothing
    local unit u = GetTriggerUnit()
    local unit bind = GetSpellTargetUnit()
    local Data d = Data.Get(u, bind)
    set u = null // leaks..
    set bind = null
endfunction

private function Conditions takes nothing returns boolean
    return GetSpellAbilityId() == AID_VITALITY_BIND
endfunction

private function Check takes nothing returns boolean
    local unit u 
    local Data check
    if GetSpellAbilityId() == AID_VITALITY_BIND then
        set u = GetTriggerUnit()
        set check = PUI[GetUnitIndex(u)] 
        if check.binded then
            call IssueImmediateOrder(GetTriggerUnit(), &quot;stop&quot;)
            call SimError( GetOwningPlayer( GetTriggerUnit()) , &quot;You have a binded target already&quot; ) //works
            set u = null
        endif
    endif
    
    return false
endfunction

//===========================================================================
private function InitTrig takes nothing returns nothing
    local trigger trig = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( trig, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( trig, Condition( function Conditions ) )
    call TriggerAddAction( trig, function Actions )
    
    set trig = CreateTrigger( )
    call TriggerRegisterAnyUnitEventBJ( trig, EVENT_PLAYER_UNIT_SPELL_CAST )
    call TriggerAddCondition( trig, Condition( function Check ) )
    
endfunction

endscope

Thanks Sooda for fixing Syntax Error
Any optimization hints?
 

Sooda

Diversity enchants
Reaction score
318
This should work:
JASS:
static method Get takes unit pui, unit bind returns Data
        local integer index = GetUnitIndex(pui)
        local Data eventStruct = index
        if PUI[index] == 0 then
            debug call BJDebugMsg(&quot;First Instance of struct Get for unit: &quot; + GetUnitName(pui)) //works
            return Data.create(pui, bind) 
        else
        debug call BJDebugMsg(&quot;Second Instance of struct Get for unit: &quot; + GetUnitName(pui)) //works
        call EnableTrigger( eventStruct.damaged) // event
        call TimerStart(eventStruct.time, DURATION, false, function Data.End)
        // Maybe Data.End will cause syntax error, if it does try:
        //        call TimerStart(eventStruct.time, DURATION, false, function eventStruct.End)
        set eventStruct.bind = bind //update target
        set eventStruct.binded = true
        
        return PUI[index] 
        endif
    endmethod

I doubt creating for each new instance timer and trigger is good idea.
 

Expelliarmus

Where to change the sig?
Reaction score
48
This should work:
yep, got rid of the Syntax error. ^^
I doubt creating for each new instance timer and trigger is good idea.
hmm. doesn't my code create a trigger and timer on create (which when)
JASS:
if PUI[index] == 0 then
return Data.create()

otherwise
JASS:
return PUI[index]

and that the trigger & timer gets disabled in method End?

Crash to go.
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top