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.
Old Code
NEW CODE (Added private prefix to struct and removed VitalityBind_) Crashes
Thanks Sooda for fixing Syntax Error
Any optimization hints?
- 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;A005039;
private constant integer BID_VITALITY_BIND = 039;B000039;
private constant string SFX_VITALITY_BIND = "Abilities\\Spells\\Demon\\DemonBoltImpact\\DemonBoltImpact.mdl"
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) <= 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 > 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, "chest"))
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("First Instance of struct Get for unit: " + 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("First Instance of struct Get for unit: " + GetUnitName(pui)) //works
//return Data.create(pui, bind)
//else
//debug call BJDebugMsg("Second Instance of struct Get for unit: " + 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(), "stop")
call SimError( GetOwningPlayer( GetTriggerUnit()) , "You have a binded target already" ) //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;A005039;
private constant integer BID_VITALITY_BIND = 039;B000039;
private constant string SFX_VITALITY_BIND = "Abilities\\Spells\\Demon\\DemonBoltImpact\\DemonBoltImpact.mdl"
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("End!") // 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("Damaged") // not appearing when pui is damaged
if GetUnitState(d.bind, UNIT_STATE_LIFE) >= 0.0405 then
call VitalityBind_Data.End.execute() //excecuting timer early
debug call BJDebugMsg("unit not dead") //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 > 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, "chest"))
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("First Instance of struct Get for unit: " + GetUnitName(pui)) //works
return VitalityBind_Data.create(pui, bind)
else
debug call BJDebugMsg("Second Instance of struct Get for unit: " + 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(), "stop")
call SimError( GetOwningPlayer( GetTriggerUnit()) , "You have a binded target already" ) //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
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;A005039;
private constant integer BID_VITALITY_BIND = 039;B000039;
private constant string SFX_VITALITY_BIND = "Abilities\\Spells\\Demon\\DemonBoltImpact\\DemonBoltImpact.mdl"
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("End!") // 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() > 0 then
debug call BJDebugMsg("Damaged") // not appearing when pui is damaged
if GetUnitState(d.bind, UNIT_STATE_LIFE) >= 0.0405 then
call Data.End.execute() //excecuting timer early
debug call BJDebugMsg("unit not dead") //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 > 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, "chest"))
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("First Instance of struct Get for unit: " + GetUnitName(pui)) //works
return Data.create(pui, bind)
else
debug call BJDebugMsg("Second Instance of struct Get for unit: " + 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(), "stop")
call SimError( GetOwningPlayer( GetTriggerUnit()) , "You have a binded target already" ) //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?