Jonnycakes
New Member
- Reaction score
- 6
Hi, I am working on (what I think is) a fairly complex spell. It runs, but there are still a couple of things that aren't working quite right and I am not sure why. I will list the problems in a list:
1. Every time multiple instances of the spell are cast, I get the debug message, "Double free of type: deluge__data". I don't know why-I thought I structured the code that gets rid of unused slots in the struct array for data (d).
2. The same thing happens when multiple units are hit with the spell. "Double free of type: deluge__units." I think this is related to number 1, as I structured it the same way.
3. The knockback for units isn't working how I want it to. It seems like units hit by the spell aren't being knocked back every time the timer callback function is called (every .04 seconds). Also, units get stunned when they shouldn't-I think this is either because they aren't getting paused when they should, so they move while being knocked back screwing up the condition that checks if they have actually been moved, or because said condition is triggering when it shouldn't.
Here is my code-please point out any errors you see, related or not:
1. Every time multiple instances of the spell are cast, I get the debug message, "Double free of type: deluge__data". I don't know why-I thought I structured the code that gets rid of unused slots in the struct array for data (d).
2. The same thing happens when multiple units are hit with the spell. "Double free of type: deluge__units." I think this is related to number 1, as I structured it the same way.
3. The knockback for units isn't working how I want it to. It seems like units hit by the spell aren't being knocked back every time the timer callback function is called (every .04 seconds). Also, units get stunned when they shouldn't-I think this is either because they aren't getting paused when they should, so they move while being knocked back screwing up the condition that checks if they have actually been moved, or because said condition is triggering when it shouldn't.
Here is my code-please point out any errors you see, related or not:
JASS:
scope deluge initializer init
private struct data //struct for spell instance
unit caster
real x
real y
real angle
real r
integer level
player p
group gr
endstruct
private struct units //struct for unit hit by the spell
unit u
real r
real x
real y
real angle
endstruct
globals
private timer time=CreateTimer()
private integer ins=0 //instances of the spell
private integer inu=0 //instances of units being knocked back by the spell
private data array d
private units array e
endglobals
private function conditions takes nothing returns boolean
return GetSpellAbilityId()==039;A00R039;
endfunction
private function filter takes nothing returns boolean
return true
endfunction
private function trees takes nothing returns nothing
call KillDestructable(GetEnumDestructable())
endfunction
private function looper takes nothing returns nothing
local integer i=1
local group g=CreateGroup()
local unit u
local rect rct
local real x
local real y
loop
exitwhen i>ins
if d<i>.r<0 then //if the spell is over, set instances minus one and restructure the array-here is one problem
call d<i>.destroy()
if ins>1 and i!=ins then
set d<i>=d[ins]
call d[ins].destroy()
set i=i-1
endif
set ins=ins-1
else
set d<i>.x=d<i>.x+50.*Cos(d<i>.angle) //spell actions-moving spell, getting units hit by it, killing trees
set d<i>.y=d<i>.y+50.*Sin(d<i>.angle)
call DestroyEffect(AddSpecialEffect("Abilities\\Spells\\Other\\CrushingWave\\CrushingWaveDamage.mdl", d<i>.x, d<i>.y))
set d<i>.r=d<i>.r-.04
call GroupEnumUnitsInRange(g, d<i>.x, d<i>.y, 100., Filter(function filter))
loop
set u=FirstOfGroup(g)
exitwhen u==null
call GroupRemoveUnit(g, u)
if not IsUnitAlly(u, d<i>.p) and not IsUnitInGroup(u, d<i>.gr) then //this sets up a struct for a unit affected by the spell
set inu=inu+1
set e[inu]=units.create()
set e[inu].u=u
set e[inu].x=GetUnitX(u)
set e[inu].y=GetUnitY(u)
set e[inu].r=1.
set e[inu].angle=Atan2(e[inu].y-d<i>.y, e[inu].x-d<i>.x)
call UnitDamageTarget(d<i>.caster, u, I2R(d<i>.level)*50.+100, false, false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_MAGIC, WEAPON_TYPE_WHOKNOWS)
call DestroyEffect(AddSpecialEffect("", d<i>.x, d<i>.y))
call GroupAddUnit(d<i>.gr, u)
endif
endloop
set rct=Rect(d<i>.x-100., d<i>.y-100., d<i>.x+100., d<i>.y+100.) //kills trees
call EnumDestructablesInRect(rct, Filter(function filter), function trees)
call RemoveRect(rct)
endif
set i=i+1
endloop
set i=1
loop
exitwhen i>inu
if e<i>.r<0 then //this is for getting rid of unused instances of the units struct
call PauseUnit(e<i>.u, false)
call e<i>.destroy()
if inu>1 and i!=inu then
set e<i>=e[inu]
call e[inu].destroy()
set i=i-1
endif
set inu=inu-1
else
set x=e<i>.x //actions for units-knockback and pause
set y=e<i>.y
set e<i>.x=e<i>.x+40.*Cos(e<i>.angle)
set e<i>.y=e<i>.y+40.*Sin(e<i>.angle)
call DestroyEffect(AddSpecialEffect("Abilities\\Spells\\Other\\CrushingWave\\CrushingWaveDamage.mdl", e<i>.x, e<i>.y))
call SetUnitPosition(e<i>.u, e<i>.x, e<i>.y)
set x=GetUnitX(e<i>.u)-e<i>.x
set y=GetUnitY(e<i>.u)-e<i>.y
if SquareRoot(x*x+y*y)<10. then //stuns, ends knockback, and unpauses if a unit hits something
set e<i>.r=-1.
set u=CreateUnit(Player(8), 039;h009039;, e<i>.x, e<i>.y, 0.)
call UnitApplyTimedLife(u, 039;Bhwd039;, 2.)
call IssueTargetOrder(u, "impale", e<i>.u)
else
call PauseUnit(e<i>.u, true)
set e<i>.r=e<i>.r-.04
endif
endif
set i=i+1
endloop
if ins+inu==0 then
call PauseTimer(time)
endif
set g=null
set u=null
set rct=null
endfunction
private function actions takes nothing returns nothing
local data this=data.create()
local location l=GetSpellTargetLoc()
local real x=GetLocationX(l)
local real y=GetLocationY(l)
call RemoveLocation(l)
set l=null
set this.caster=GetTriggerUnit()
set this.x=GetUnitX(this.caster)
set this.y=GetUnitY(this.caster)
set this.angle=Atan2(y-this.y, x-this.x)
set this.p=GetOwningPlayer(this.caster)
set this.level=GetUnitAbilityLevel(this.caster, 039;A00R039;)
set this.r=I2R(this.level)*0.+1.8
set this.gr=CreateGroup()
set ins=ins+1
set d[ins]=this
if ins==1 and inu==0 then
call TimerStart(time, .04, true, function looper)
endif
endfunction
//===========================================================================
private function init takes nothing returns nothing
local trigger t=CreateTrigger()
local integer i=0
loop
call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
set i=i+1
exitwhen i==8
endloop
call TriggerAddCondition(t, Condition(function conditions))
call TriggerAddAction(t, function actions)
endfunction
endscope</i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i>