Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
Hi... I am having a problem with the native TimerStart.
here's the code:
JASS:
call TimerStart(aTimer, 0.10, false, function LA(caster, aGroup, time, EffectX, EffectY, EFFECT))
Here is the function LA:
JASS:
static method LA takes unit u, group whichGroup, real Time, real x, real y, string whichString returns nothing
local action new = action.allocate()
call DestroyEffectTimed(AddSpecialEffect(whichString, x, y), Time)
call GroupEnumUnitsInRange(whichGroup, x, y, 150, null)
loop
set new.u = FirstOfGroup(whichGroup)
exitwhen new.u == null
if IsUnitEnemy(new.u, GetOwningPlayer(u)) == true then
call UnitDamageTarget(u, new.u, damage(), true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
endif
set new.u = null
endloop
if(DESTROY_DESTRUCTABLE) then
endif
endmethod
Its basically the first time I'm using structs, and I really hope theres nothing wrong with my struct, even though it is quite bad.
The error I get is this: Line 454: Syntax Error, unexpected "("?
private function LoopActions takes nothing returns nothing
local unit caster = GetTriggerUnit()
local location loc = GetSpellTargetLoc()
local real CasterX = GetUnitX(caster)
local real CasterY = GetUnitY(caster)
local real EffectX = GetLocationX(loc)
local real EffectY = GetLocationY(loc)
call LA(caster, aGroup, time, EffectX, EffectY, EFFECT)
endfunction
JASS:
call TimerStart(aTimer, 0.10, false, function LoopActions)
You have to use structs. Think of using a struct as a "container" for whatever you need to pass through. I'll guide you step by step.
Okay, so first we need to make a struct to contain all the variables we need to pass. According to your parameters, we need:
The Caster ; Type: Unit
Some Group ; Type: Group
Time ; Type: Real
X-Coordinate ; Type: Real
Y-Coordinate ; Type: Real
Effect Path ; Type: String
Thus, your members should look like this:
JASS:
struct EffectSpellStuff
unit caster
group aGroup
real time
real EffectX
real EffectY
string EffectPath
endstruct
Now let's basically eliminate what we know won't need to be passed. Assuming the time is constant, we can remove that. Same for the EffectPath. The group can be removed as well since we can just use a normal group.
Okay, so let's say you have a standard spell scope:
JASS:
scope StandardSpell initializer Init
globals
private constant integer RAWCODE = 'A064' //modify this to your spell's rawcode
endglobals
private function Conditions takes nothing returns boolean
if GetSpellAbilityId() == RAWCODE then
endif
return false
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t,Condition(function Conditions))
endfunction
endscope
Now add your struct, and your constants:
JASS:
scope EffectSpellThing initializer Init
globals
private constant integer RAWCODE = 'A064' //modify this to your spell's rawcode
private constant string EFFECT_PATH = "Abilities\\Spells\\Human\\MarkOfChaos\\MarkOfChaosTarget.mdl"
private constant real EFFECT_TIME = 2
private group aGroup = CreateGroup()
private constant boolean DESTROY_DESTRUCTABLE = false
endglobals
private function damage takes nothing returns real
return 150.
endfunction
private struct EffectSpell
unit caster
real EffectX
real EffectY
static method LA takes nothing returns nothing
local unit first
call DestroyEffectTimed(AddSpecialEffect(EFFECT_PATH,.EffectX,.EffectY),EFFECT_TIME)
call GroupEnumUnitsInRange(aGroup,.EffectX,.EffectY,150,null)
loop
set first = FirstOfGroup(aGroup)
exitwhen first == null
if IsUnitEnemy(first,GetOwningPlayer(.caster)) then
call UnitDamageTarget(caster,first,damage(),true,false,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)
endif
call GroupRemoveUnit(aGroup,first)
endloop
if DESTROY_DESTRUCTABLE then
endif
endmethod
static method create takes nothing returns thistype
local thistype this = thistype.allocate()
set .caster = GetTriggerUnit()
set .EffectX = GetSpellTargetX()
set .EffectY = GetSpellTargetY()
return this
endmethod
endstruct
private function Conditions takes nothing returns boolean
if GetSpellAbilityId() == RAWCODE then
call EffectSpell.create()
endif
return false
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t,Condition(function Conditions))
endfunction
endscope
Okay, now we are trying to execute LA after 0.10 seconds with transferring the data. At the moment, LA will create syntax errors because we can't refer to them directly like that. "this" doesn't exist yet. Thus, we must use something like TimerUtils:
JASS:
scope EffectSpellThing initializer Init
globals
private constant integer RAWCODE = 'A064' //modify this to your spell's rawcode
private constant string EFFECT_PATH = "Abilities\\Spells\\Human\\MarkOfChaos\\MarkOfChaosTarget.mdl"
private constant real EFFECT_TIME = 2
private group aGroup = CreateGroup()
private constant boolean DESTROY_DESTRUCTABLE = false
endglobals
private function damage takes nothing returns real
return 150.
endfunction
private struct EffectSpell
unit caster
real EffectX
real EffectY
static method LA takes nothing returns nothing
local timer t = GetExpiredTimer() //retrieve the timer
local thistype this = GetTimerData(t) //get the data
local unit first
call DestroyEffectTimed(AddSpecialEffect(EFFECT_PATH,.EffectX,.EffectY),EFFECT_TIME)
call GroupEnumUnitsInRange(aGroup,.EffectX,.EffectY,150,null)
loop
set first = FirstOfGroup(aGroup)
exitwhen first == null
if IsUnitEnemy(first,GetOwningPlayer(.caster)) then
call UnitDamageTarget(caster,first,damage(),true,false,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)
endif
call GroupRemoveUnit(aGroup,first)
endloop
if DESTROY_DESTRUCTABLE then
endif
endmethod
static method create takes nothing returns thistype
local thistype this = thistype.allocate()
local timer t = NewTimer() //This will create a new timer, or reuse an old one
set .caster = GetTriggerUnit()
set .EffectX = GetSpellTargetX()
set .EffectY = GetSpellTargetY()
call SetTimerData(t,this) //Attach the struct's data to the timer
call TimerStart(t,0.10,false,function thistype.LA) //Start the timer
return this
endmethod
endstruct
private function Conditions takes nothing returns boolean
if GetSpellAbilityId() == RAWCODE then
call EffectSpell.create()
endif
return false
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t,Condition(function Conditions))
endfunction
endscope
Now you have that, which is something like how you would do it. Although it isn't completely optimized, it should get the job done.
Good luck, hopefully this explains it a bit. =)
NewTimer() - This is a function of TimerUtils, which will check if there are any timers that were recycled to be available for use. If there isn't, then it will create a new timer.
SetTimerData(timer,data) - This is a function of TimerUtils, which will "attach" the struct instance to the timer. This way, you can retrieve the data in the callback using GetTimerData(t).
GetTimerData(timer) - This is a function of TimerUtils, which will retrieve the struct instance attached to the timer. Basically, GetTimerData(GetExpiredTimer()).
ReleaseTimer(timer) - This is a function of TimerUtils, which will recycle the timer for later use. If the timer stack is full, it will destroy the timer. (which doesn't happen very often as long as you code well)
This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
By continuing to use this site, you are consenting to our use of cookies.