HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Spell Fixing Help Needed

06-23-2008, 01:52 PM#1
anXieTy
Sorry for the bad topic, but i just didnt know how to call this here.

At first, what does the following spell do?
Pretty easy: 20 Missiles created 800 distance around the Target Point fly towards it, and in the very inner when they meet all units in an AoE of X get damaged and an effect is shown.

So, the problem is, when spamming this spell quickly, the missile dummys are removed or killed before they reach the center point. Why? If i cast this spell just once and wait until its finished, everything works fine, but shouldnt it with spamming, too? If i remove the KillUnit and RemoveUnitTimed (Removes a unit after a certain time) functions then the dummys sometimes just stop moving at half of their way, while timer is running out and the final effect is still shown.

Any help?

Here we go with the code:
Collapse JASS:
function Trig_Soul_Valley_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A001'
endfunction

struct SoulValleyData
unit caster
unit array dummys[20]
real centerx
real centery
integer executions
method onDestroy takes nothing returns nothing
local integer i = 0
loop
    exitwhen .dummys[i] == null
    if .dummys[i] == null then
    call BJDebugMsg("DUMMY IS NULL")
    endif
    call KillUnit(.dummys[i])
    call RemoveUnitTimed(.dummys[i],2.)
    set i = i +1
endloop
set .caster = null
endmethod
endstruct

function SoulValley_Final takes real centerx, real centery, unit caster returns nothing
local group g = CreateGroup()
local unit u
local real dmg = 200.

call DestroyEffect(AddSpecialEffect(GetAbilityEffectById('A001',EFFECT_TYPE_AREA_EFFECT,0),centerx,centery))
call GroupEnumUnitsInRange(g,centerx,centery,350.,null)

loop
    set u = FirstOfGroup(g)
    exitwhen u == null
    if IsUnitEnemy(u,GetOwningPlayer(caster)) then
    call UnitDamageTarget(caster,u,dmg,true,false,ATTACK_TYPE_MAGIC,DAMAGE_TYPE_NORMAL,null)
    endif
    call GroupRemoveUnit(g,u)
endloop

call DestroyGroup(g)
set g = null
set u = null
set caster = null
endfunction

function SoulValley_callback takes nothing returns nothing
local timer t = GetExpiredTimer()
local SoulValleyData a = GetAttachedInt(t,"data")
local integer i = 0
local real angle
local real nx
local real ny
local real ux
local real uy

loop
    exitwhen i > 19
    set ux = GetUnitX(a.dummys[i])
    set uy = GetUnitY(a.dummys[i])
    set angle = Atan2(a.centery - uy, a.centerx-ux)
    set nx = ux + 30 * Cos(angle)
    set ny = uy + 30 * Sin(angle)
    call SetUnitX(a.dummys[i],nx)
    call SetUnitY(a.dummys[i],ny)
    set i = i +1
endloop

set a.executions = a.executions -1
call AttachInt(t,"data",a)

if a.executions <=0 then
call SoulValley_Final(a.centerx,a.centery,a.caster)
call a.destroy()
call CleanAttachedVars(t)
call ReleaseTimer(t)
endif
endfunction

function Trig_Soul_Valley_Actions takes nothing returns nothing
local SoulValleyData a = SoulValleyData.create()
local timer t = NewTimer()
local location tp = GetSpellTargetLoc()
local integer i = 0
local real angle
local real nx
local real ny

set a.caster = GetTriggerUnit()
set a.centerx = GetLocationX(tp)
set a.centery = GetLocationY(tp)
set a.executions = 800/30
loop
    exitwhen i > 19
    set angle = bj_DEGTORAD*360/20*i
    set nx = a.centerx + 800 *Cos(angle)
    set ny = a.centery + 800 *Sin(angle)
    set a.dummys[i] = CreateUnit(GetOwningPlayer(a.caster),'h001',nx,ny,270.)
    call SetUnitX(a.dummys[i],nx)
    call SetUnitY(a.dummys[i],ny)
    set i = i +1
endloop

call AttachInt(t,"data",a)
call TimerStart(t,0.03,true,function SoulValley_callback)
endfunction

//===========================================================================
function InitTrig_Soul_Valley takes nothing returns nothing
    set gg_trg_Soul_Valley = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Soul_Valley, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( gg_trg_Soul_Valley, Condition( function Trig_Soul_Valley_Conditions ) )
    call TriggerAddAction( gg_trg_Soul_Valley, function Trig_Soul_Valley_Actions )
endfunction


Edit: Okay, if i change the code to the oldsql way of transferring data with timers, everything works properly. where is the mistake now?

Collapse JASS:
function Trig_Soul_Valley_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A001'
endfunction

struct SoulValleyData
unit caster
unit array dummys[20]
real centerx
real centery
integer executions
method onDestroy takes nothing returns nothing
local integer i = 0
local unit u 
call BJDebugMsg("DESTROY")
loop
    exitwhen .dummys[i] == null
    if .dummys[i] == null then
    call BJDebugMsg("DUMMY IS NULL")
    endif
  //  call KillUnit(.dummys[i])
  set u = .dummys[i]
    call RemoveUnitTimed(u,2.)
    call KillUnit(u)
    set i = i +1
endloop
set .caster = null
endmethod
endstruct

function SoulValley_Final takes real centerx, real centery, unit caster returns nothing
local group g = CreateGroup()
local unit u
local real dmg = 200.

call DestroyEffect(AddSpecialEffect(GetAbilityEffectById('A001',EFFECT_TYPE_AREA_EFFECT,0),centerx,centery))
call GroupEnumUnitsInRange(g,centerx,centery,350.,null)

loop
    set u = FirstOfGroup(g)
    exitwhen u == null
    if IsUnitEnemy(u,GetOwningPlayer(caster)) then
    call UnitDamageTarget(caster,u,dmg,true,false,ATTACK_TYPE_MAGIC,DAMAGE_TYPE_NORMAL,null)
    endif
    call GroupRemoveUnit(g,u)
endloop

call DestroyGroup(g)
set g = null
set u = null
set caster = null
endfunction

function SoulValley_callback takes nothing returns nothing
local timer t = GetExpiredTimer()
local unit caster = GetAttachedUnit(t,"caster")
local real centerx = GetAttachedReal(t,"centerx")
local real centery = GetAttachedReal(t,"centery")
local integer executions = GetAttachedInt(t,"executions")
local unit dummy
local integer i = 0
local real angle
local real nx
local real ny
local real ux
local real uy

loop
    exitwhen i > 19
    set dummy = GetAttachedUnit(t,"dummys"+I2S(i))
    set ux = GetUnitX(dummy)
    set uy = GetUnitY(dummy)
    set angle = Atan2(centery - uy, centerx-ux)
    set nx = ux + 30 * Cos(angle)
    set ny = uy + 30 * Sin(angle)
    call SetUnitX(dummy,nx)
    call SetUnitY(dummy,ny)
    set i = i +1
endloop

set executions = executions -1
call AttachInt(t,"executions",executions)

if executions <=0 then
set i = 0
loop
    exitwhen i > 19
    call KillUnit(GetAttachedUnit(t,"dummys"+I2S(i)))
    set i = i +1
endloop
call BJDebugMsg("EXECUTIONS NULL")
call SoulValley_Final(centerx,centery,caster)
call CleanAttachedVars(t)
call ReleaseTimer(t)
endif
endfunction

function Trig_Soul_Valley_Actions takes nothing returns nothing
local unit caster = GetTriggerUnit()
local unit array dummys [20]
local timer t = NewTimer()
local location tp = GetSpellTargetLoc()
local integer i = 0
local real angle
local real nx
local real ny
local real centerx = GetLocationX(tp)
local real centery = GetLocationY(tp)
local integer executions = 800/30

loop
    exitwhen i > 19
    set angle = bj_DEGTORAD*360/20*i
    set nx = centerx + 800 *Cos(angle)
    set ny = centery + 800 *Sin(angle)
    set dummys[i] = CreateUnit(GetOwningPlayer(caster),'h001',nx,ny,270.)
    call SetUnitX(dummys[i],nx)
    call SetUnitY(dummys[i],ny)
    call AttachObject(t,"dummys"+I2S(i),dummys[i])
    set i = i +1
endloop

call AttachObject(t,"caster",caster)
call AttachReal(t,"centerx",centerx)
call AttachReal(t,"centery",centery)
call AttachInt(t,"executions",executions)

call TimerStart(t,0.03,true,function SoulValley_callback)
endfunction

//===========================================================================
function InitTrig_Soul_Valley_Copy takes nothing returns nothing
    set gg_trg_Soul_Valley_Copy = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Soul_Valley_Copy, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( gg_trg_Soul_Valley_Copy, Condition( function Trig_Soul_Valley_Conditions ) )
    call TriggerAddAction( gg_trg_Soul_Valley_Copy, function Trig_Soul_Valley_Actions )
endfunction


Edit2: It seems to have something to do with the unit array definitely, but as i tested a.executions never gets 0 immediately, its always reduced by 1 until it hits 0 and struct is destroyed. There seems to be a conflict with multiple structs used in this spell at the same time.
06-23-2008, 08:25 PM#2
Themerion
Collapse JASS:
exitwhen .dummys[i] == null

Try changing that to exitwhen i>=20. Might work.

Why do I think so?

vJASS works by creating a single array for every variable in a struct. Your .dummys[20] is transformed into:

unit array SoulValleyData_dummys

For each new SoulValleyData-object you create, it will assign the variables like this:

data1.dummys[0] = SoulValleyData_dummys[0]
data1.dummys[1] = SoulValleyData_dummys[1]
data1.dummys[19] = SoulValleyData_dummys[19]

data2.dummys[0] = SoulValleyData_dummys[20]
data2.dummys[1] = SoulValleyData_dummys[21]
//etc...

What would happen if you tried to get data1.dummys[20] ?

data1.dummy[20] = SoulValleyData_dummys[20] = data2.dummys[0]
data1.dummy[20] = data2.dummy[0]

Therefore, it might be inappropriate with:
exitwhen dummy[i]==null
(Since data1.dummy[20] won't be null if data2 is created)


__________________________________________________________________
You code pretty well, if you used some more spaces/tabs (intendation) I would be more than happy, but that's probably just a matter of personal taste.

In the looping part, you do not have to re-set the int.

Collapse JASS:
set a.executions = a.executions -1
call AttachInt(t,"data",a)

Also, you have forgotten set t=null.

In the Final-part, you do not need to null caster, since it's an argument for the function.
set caster = null
06-23-2008, 08:57 PM#3
anXieTy
Ty very much!

+rep