Need Help debugging a system please test map,
I am having trouble with a spell called Meteor Shower, the first cast works the second cast buggs, it sends way to many meteors, the meteors don't deal damage and some of them don't move.
I am having trouble with a spell called Meteor Shower, the first cast works the second cast buggs, it sends way to many meteors, the meteors don't deal damage and some of them don't move.
library Effects uses Target
globals
private force eval = CreateForce()
spelleffect RUNNING
spellprojectile PROJECTILE
private boolean FINISHED
endglobals
function ReturnEffect takes boolean continue returns nothing
set FINISHED = continue
endfunction
module Rarray
real d0
real d1
real d2
real d3
method operator [] takes integer i returns real
if i < 2 then
if i == 0 then
return d0
endif
return d1
endif
if i == 2 then
return d2
endif
return d3
endmethod
method operator []= takes integer i, real r returns nothing
if i < 2 then
if i == 0 then
set d0 = r
return
endif
set d1 = r
return
endif
if i == 2 then
set d2 = r
return
endif
set d3 = r
return
endmethod
endmodule
struct spelleffect_root extends array
static thistype array Rc
static integer c = 0
boolexpr action
integer instance
integer model
static method allocate takes nothing returns thistype
local thistype this = Rc[0]
if 0 == this then
set this = c+1
set c = this
else
set Rc[0] = Rc[this]
endif
return this
endmethod
method deallocate takes nothing returns nothing
if 0 == this then
return
endif
set Rc[this]= Rc[0]
set Rc[0] = this
endmethod
implement Rarray
static method create takes nothing returns thistype
local thistype this = allocate()
return this
endmethod
/*static method createEx takes boolexpr b, real d0, real d1, real d2, real d3 returns thistype
local thistype this = allocate()
set action = b
set this[0]= d0
set this[1]= d1
set this[2] = d2
set this[3] = d3
set instance = 0
return this
endmethod*/
method unlock takes nothing returns nothing
if this!= 0 then
set instance = instance-1
if instance < 1 then
call this.deallocate()
endif
endif
endmethod
method lock takes nothing returns nothing
set instance = instance+1
endmethod
endstruct
struct spelleffect extends array
static thistype array Rc
static integer c = 0
boolexpr action
Spell_Cast spell
integer next
integer model
Target caster
Target target
spelleffect master
static method allocate takes nothing returns thistype
local thistype this = Rc[0]
if 0 == this then
set this = c+1
set c = this
else
set Rc[0] = Rc[this]
endif
return this
endmethod
method deallocate takes nothing returns nothing
set Rc[this]= Rc[0]
set Rc[0] = this
endmethod
method destroy takes nothing returns nothing
if 0 == this then
return
endif
debug call BJDebugMsg("Destroying Effect "+I2S(this))
if this.isProxy then
call target.unlock()
call caster.unlock()
call spell.unlock()
endif
set this.action = null
call this.deallocate()
endmethod
method operator isProxy takes nothing returns boolean
return master != 0
endmethod
implement Rarray
static method create takes spelleffect_root root, Spell_Cast boss returns thistype
local thistype this = allocate()
set action = root.action
set this[0] = root[0]
set this[1] = root[1]
set this[2] = root[2]
set this[3] = root[3]
set this.spell = boss
set this.model = root.model
set this.target = boss.target
set this.master = 0
set this.caster = boss.caster
set boss[boss.effects]= this
set boss.effects = boss.effects+1
return this
endmethod
method run takes nothing returns boolean
set RUNNING = this
set FINISHED = true
call ForceEnumPlayersCounted(eval,action,1)
return FINISHED
endmethod
static method createProxy takes spelleffect master,Target caster, Target t returns thistype
local thistype this = allocate()
set .action = master.action
set this[0]= master[0]
set this[1]= master[1]
set this[2]= master[2]
set this[3]= master[3]
set .next = master.next
set .master = master
set .target = t
set .spell = master.spell
set .model = master.model
set .caster = caster
call caster.lock()
call t.lock()
call .spell.lock()
return this
endmethod
endstruct
function CreateSpellEffect takes boolexpr b, real d0, real d1, real d2, real d3, integer model returns spelleffect_root
local spelleffect_root this = spelleffect_root.create()
set this.action = b
set this[0] = d0
set this[1] = d1
set this[2] = d2
set this[3] = d3
set this.model = model
return this
endfunction
endlibrarylibrary SpellGenerator /* v0.2.3.0
*************************************************************************************
*
* Enables the generation of spells in game and can also be used
* to easily make new spells with just a few keystrokes
*
*************************************************************************************
*
* */uses /*
* */ Target /*
* */ SFX /*
* */ Effects /*
* */ SpellProjectile/*
***************************************************************************************
*
* struct Spell extends array
* boolean permanent whether to keep or destroy the spell when it has no instances
*
* method operator [] takes integer i returns integer
* this retur
* method operator []= takes integer i integer returns nothing
* be warned you can leak effects if you do not unlock the effect first
* method lock takes nothing returns nothing
* locks the spell preventing it from getting destroyed
* method unlock takes nothing returns nothing
* when you are done with a spell you should unlock it
* has no effect on permanent spells
*
* static method createEx takes nothing returns Spell
*
*****/
private module allocator
static integer array recycle
static integer c = 0
static method allocate takes nothing returns thistype
local thistype this = recycle[0]
if this == 0 then
set this = c+1
set c = this
else
set recycle[0] = recycle[this]
endif
endmodule
private module deallocate
method deallocate takes nothing returns nothing
if 0 == this then
call BJDebugMsg("Attempted to deallocate a null struct")
return
endif
set recycle[this] = recycle[0]
set recycle[0] = this
endmethod
endmodule
private module serarray
spelleffect_root d0
spelleffect_root d1
spelleffect_root d2
spelleffect_root d3
method operator [] takes integer i returns spelleffect_root
if i < 2 then
if i == 0 then
return d0
endif
return d1
endif
if i == 2 then
return d2
endif
return d3
endmethod
method operator []= takes integer i, integer what returns nothing
if i < 2 then
if i ==0 then
set d0 = what
return
endif
set d1 = what
return
endif
if i == 2 then
set d2 = what
return
endif
set d3 = what
endmethod
endmodule
private module searray
spelleffect d0
spelleffect d1
spelleffect d2
spelleffect d3
method operator [] takes integer i returns spelleffect
if i < 2 then
if i == 0 then
return d0
endif
return d1
endif
if i == 2 then
return d2
endif
return d3
endmethod
method operator []= takes integer i, integer what returns nothing
if i < 2 then
if i ==1 then
set d1 = what
return
endif
set d0 = what
return
endif
if i == 2 then
set d2 = what
return
endif
set d3 = what
endmethod
endmodule
struct Spell_Cast extends array
Target caster
Target target
Spell root
//integer current
integer instance
integer effects
implement searray
implement allocator
//set instance = 0
set effects = 0
return this
endmethod
implement deallocate
method lock takes nothing returns nothing
set .instance = .instance+1
endmethod
method destroy takes nothing returns nothing
debug call BJDebugMsg("Destroyed Spell"+I2S(this))
call this[0].destroy()
call this[1].destroy()
call this[2].destroy()
call this[3].destroy()
call root.unlock()
call target.unlock()
call caster.unlock()
call deallocate()
endmethod
method unlock takes nothing returns nothing
if .instance > 0 then
set .instance = .instance-1
if .instance == 0 then
call destroy()
endif
endif
endmethod
method core takes spelleffect current returns boolean
local spelleffect Snext = 0
local integer next
debug call BJDebugMsg("Running core for "+I2S(current))
if current < 0 then
set next = 1
set Snext = this[0]
elseif current == 0 then
call unlock()
return true
else
set next = current.next
if current.isProxy then
debug call BJDebugMsg(I2S(current)+" is a Proxy")
if next != 0 then
debug call BJDebugMsg("creating new Proxy")
set Snext = spelleffect.createProxy(this[next],current.caster, current.target)
endif
call current.destroy()
else
set Snext = this[next]
endif
endif
if next == 0 then
call unlock()
call BJDebugMsg("Next = 0 .instance ="+I2S(this.instance))
return true
endif
if Snext.run() then
debug call BJDebugMsg("The effect ran, going to next effect")
call core(Snext)
return false
endif
debug call BJDebugMsg("The effect ran, and is waiting to finish")
return false
endmethod
static method create takes Spell root, Target t returns thistype
local thistype this = allocate()
local integer i = 0
set target = t
set instance = 1
call t.lock()
loop
if root[i] == 0 then
set i = i -1
exitwhen true
endif
set this[i] = spelleffect.create( root[i], this)
set this[i].next = i+1
set i = i+1
exitwhen i == 4
endloop
set this[i].next = 0
set .root = root
return this
endmethod
endstruct
struct Spell extends array
boolean permanent
private integer instance
implement serarray
implement allocator
return this
endmethod
implement deallocate
method destroy takes nothing returns nothing
call deallocate()
call this[0].unlock()
call this[1].unlock()
call this[2].unlock()
call this[3].unlock()
endmethod
static method create takes spelleffect_root first returns thistype
local thistype this = allocate()
set this[0] = first
return this
endmethod
static method createEx takes spelleffect_root s0, spelleffect_root s1, spelleffect_root s2, spelleffect_root s3, boolean destroy returns thistype
local thistype this = allocate()
call s0.lock()
call s1.lock()
call s2.lock()
call s3.lock()
set this[0] = s0
set this[1] = s1
set this[2] = s2
set this[3] = s3
set permanent = not destroy
return this
endmethod
method lock takes nothing returns nothing
set .instance = .instance+1
endmethod
method unlock takes nothing returns nothing
set .instance = .instance-1
if not permanent and .instance < 0 then
call destroy()
endif
endmethod
method cast takes unit caster, Target target returns boolean // the return value is whether the spell completed every thing instantly, or if it is waiting.
local Spell_Cast cast = Spell_Cast.create(this,target)
call lock()
//call cast.lock()
set cast.caster = Target[caster]
call cast.caster.lock()
//set cast.target = target
//call cast.caster.lock()
return cast.core(-1)
endmethod
endstruct
function CreateSpell takes spelleffect_root s0, spelleffect_root s1, spelleffect_root s2, spelleffect_root s3, boolean destroy returns Spell
local Spell this = Spell.allocate()
call s0.lock()
call s1.lock()
call s2.lock()
call s3.lock()
static if DEBUG_MOD then
if s0 == 0 then
call BJDebugMsg("Trying to create a spell with a null first effect")
return 0
endif
endif
set this[0] = s0
set this[1] = s1
set this[2] = s2
set this[3] = s3
set this.permanent = not destroy
return this
endfunction
endlibrarylibrary LibraryOfEffects uses Effects, SpellGenerator
globals
private boolexpr epcast
private spelleffect array next
private spelleffect array prev
private real array Sangle
private real array Eangle
private integer array left
private integer total = 0
private real array time
private real array distance
private timer EP_Timer = CreateTimer()
private constant real PERIOD = .0325000
endglobals
private function ep takes nothing returns nothing
local spelleffect this = next[0]
local real angle
local real dis
call BJDebugMsg("its working total ="+I2S(total))
if total == 0 then
set next[0] = 0
set prev[0] = 0
return
endif
if this.spell[1].action == epcast then
call BJDebugMsg("Effect "+I2S(this.spell[1])+" has the wrong action")
endif
loop
exitwhen 0 == this
set time[this] = time[this]-PERIOD
if time[this]<= 0 then
set angle = GetRandomReal(Sangle[this],Eangle[this])
set dis = GetRandomReal(0,distance[this])
call this.spell.core(spelleffect.createProxy(this,this.caster, /*
*/Target.create(this.target.x+Cos(angle)*dis,this.target.y+Sin(angle)*dis,0)))
set left[this] = left[this]-1
if left[this]<= 0 then
call BJDebugMsg("In EP periodic With next["+I2S(this)+"]="+I2S(next[this])+" and prev["+I2S(this)+"]="+I2S(prev[this]))
set next[prev[this]]=next[this]
set prev[next[this]]=prev[this]
set total = total-1
call this.spell.unlock()//this is neccessary as it always calls back to the core via proxy
if this.isProxy then
call this.destroy()//also neccessary to prevent leaks
endif
if total == 0 then
set next[0] = 0
set prev[0] = 0
return
endif
else
set time[this] = time[this]+this[1]
endif
endif
set this = next[this]
endloop
call TimerStart(EP_Timer,PERIOD,false,function ep)
endfunction
function ep_cast takes nothing returns boolean
local spelleffect this = RUNNING
local real face = GetUnitFacing(this.spell.caster.unit)
call BJDebugMsg("Running ep_Cast for "+I2S(RUNNING))
set epcast = Filter(function ep_cast)
//call BJDebugMsg("checking if it is already running")
if total == 0 then
//call BJDebugMsg("Nope, it wasn't")
set next[0] = this
set prev[0] = this
set next[this] = 0
set prev[this] = 0
call TimerStart(EP_Timer,PERIOD,false,function ep)
else
//call BJDebugMsg("Still not broken yet")
set next[this] = 0
set prev[this] = prev[0]
set next[prev[0]]=this
set prev[0] = this
endif
set total = total +1
call this.spell.lock()
set distance[this] = this[2]
set Sangle[this] = (face-this[3])*bj_DEGTORAD
set Eangle[this] = (face+this[3])*bj_DEGTORAD
set left[this] = R2I(this[0])
//call BJDebugMsg("left[this]="+I2S(left[this]))
call ReturnEffect(false)
return true
endfunction
endlibrarylibrary SpellProjectile uses Missile Target Effects
globals
boolexpr RegProjectile
boolexpr Meteor
endglobals
struct spellprojectile extends array
static method onRemove takes Missile this returns boolean
local spelleffect se = this.data
debug call BJDebugMsg("Missile for Effect "+I2S(se)+" Calling core")
call se.spell.core(se)
return true
endmethod
// meteor 0 is fall time, 1 is height, 2 makes it circle as it falls
static method meteor takes nothing returns boolean
local Spell_Cast spell = RUNNING.spell
local real x = RUNNING.target.x
local real y = RUNNING.target.y
local integer i = 0
local real sp = 5/RUNNING[0]*0.0325000
local group g
local Target u
local Missile new// = Missile.create(x,y,65,x+1000*Cos(a),y+1000*Sin(a),0)
debug call BJDebugMsg("Running Meteor RUNNING="+I2S(RUNNING)+"\nRUNNING[0]="+R2S(RUNNING[0])+"Target="+I2S(RUNNING.target))
if RUNNING.target.isGroup then
set g = CreateGroup()
call GroupAddGroup(g,RUNNING.target.group)
loop
set u = Target[FirstOfGroup(g)]
exitwhen 0 == u
set new = Missile.createLoc(AdvLoc.create(u.x+5, u.y, u.z+RUNNING[1]),AdvLoc.create(u.x,u.z,u.z))
set new.target = u.unit
//set new.height = RUNNING[1]
set new.open = RUNNING[2]
set new.speed=sp
set new.model=GetSFXPath(RUNNING.model)
set new.source=spell.caster.unit
set new.collision=80
//set new.distance = 200
set new.data = spelleffect.createProxy(RUNNING, spell.caster, u)
call launch(new)
endloop
call DestroyGroup(g)
set g =null
else
set u = RUNNING.target
if RUNNING.target.isUnit then
set new = Missile.createLoc(AdvLoc.create(x+5, y, u.z+RUNNING[1]),AdvLoc.create(x,y,u.z))
set new.target = RUNNING.target.unit
else
set new = Missile.createLoc(AdvLoc.create(x+5, y, 500/*+RUNNING[1]*/),AdvLoc.create(x,y,u.z))
endif
//set new.arc= RUNNING[1]
//set new.height = u.z+RUNNING[1]
set new.speed=sp
set new.model=GetSFXPath(RUNNING.model)
set new.source=spell.caster.unit
//set new.distance = 200
set new.open = RUNNING[2]
set new.collision=80
set new.data = RUNNING
call launch(new)
endif
call ReturnEffect(false)
return true
endmethod
implement MissileStruct
static method onInit takes nothing returns nothing
set RegProjectile= Filter(function spellprojectile.reg)
set Meteor = Filter(function thistype.meteor)
endmethod
endstruct
endlibraryscope SpellTest initializer init
private function test_cast takes nothing returns boolean
if GetSpellAbilityId() == 'A001' then
debug call BJDebugMsg("casting Spell")
call EffectDepository_pillaroffire.cast(GetTriggerUnit(),Target.create(GetSpellTargetX(),GetSpellTargetY(),0))
debug call BJDebugMsg("Spell cast")
elseif GetSpellAbilityId() == 'A002' then
debug call BJDebugMsg("castingMeteor")
call EffectDepository_MeteorShower.cast(GetTriggerUnit(),Target.create(GetSpellTargetX(),GetSpellTargetY(),0))
endif
return false
endfunction
function init takes nothing returns nothing
//debug call BJDebugMsg("Creating Spell PillarofFire")
//set EffectDepository_pillaroffire = CreateSpell(CreateSpellEffect(RegProjectile, 900, 150, 35, 0,GetSFX(SFX_FIRE_EFFECTS, 1, 6)),CreateSpellEffect(Filter(function EffectDepository_pof_cast), 300, 15, 3, 0,GetSFX(SFX_FIRE_EFFECTS, 0, 4)),CreateSpellEffect(Filter(function EffectDepository_pof_cast),300,5,12,0,GetSFX(SFX_FIRE_EFFECTS, 1, 3)),0,false)
//debug call BJDebugMsg("SpellCreated "+I2S(EffectDepository_pillaroffire))
set EffectDepository_pillaroffire = CreateSpell(CreateSpellEffect(Filter(function spellprojectile.meteor), 1, 600, 0, 0,GetSFX(SFX_FIRE_EFFECTS, 1, 3)),CreateSpellEffect(Filter(function EffectDepository_pof_cast), 300, 15, 3, 0,GetSFX(SFX_FIRE_EFFECTS, 0, 6))/*
*/,CreateSpellEffect(Filter(function EffectDepository_pof_cast),300,5,12,0,GetSFX(SFX_FIRE_EFFECTS, 0, 3)),0,false)
set EffectDepository_MeteorShower = CreateSpell(/*
*/CreateSpellEffect(Filter(function ep_cast),12,.15,300,180,0),/*
*/CreateSpellEffect(Filter(function spellprojectile.meteor),1,600,0,0,GetSFX(SFX_FIRE_EFFECTS, 1, 3)),/*
*/CreateSpellEffect(Filter(function EffectDepository_Pure_Damage),125,25,0,0,GetSFX(SFX_MAGIC_EFFECTS, 0, 3)),/*
*/0,false)
// set EffectDepository_MeteorShower = CreateSpell(/*
// */CreateSpellEffect(Filter(function ep_cast),1,0.13,300,180,0),/*
// */CreateSpellEffect(Filter(function spellprojectile.meteor),1,600,0,0,GetSFX(SFX_FIRE_EFFECTS, 1, 3)),/*
// */0,0,false)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_SPELL_CAST,function test_cast)
endfunction
endscopelibrary EffectDepository uses Effects SpellProjectile
globals
public Spell pillaroffire
public Spell MeteorShower
private spelleffect array pof_next
private spelleffect array pof_prev
public boolexpr Damage
private integer pof_start = 0
private integer pof_t= 0
private timer pof = CreateTimer()
private group temp = CreateGroup()
private real pof_period = .5
endglobals
private function forDamageGroup takes nothing returns nothing
call UnitDamageTarget(RUNNING.spell.caster.unit, GetEnumUnit(),RUNNING[1],false,false,ATTACK_TYPE_CHAOS,DAMAGE_TYPE_ENHANCED,null)
call DestroyEffect( AddSpecialEffectTarget(GetSFXPath(RUNNING.model),GetEnumUnit(),"chest"))
endfunction
public function Pure_Damage takes nothing returns boolean
local Target target = RUNNING.target
local unit u
if target.isUnit or target.isDestructable then
call DestroyEffect( AddSpecialEffectTarget(GetSFXPath(RUNNING.model),RUNNING.target.widget,"chest"))
call UnitDamageTarget(RUNNING.spell.caster.unit, target.widget,RUNNING[1],false,false,ATTACK_TYPE_CHAOS,DAMAGE_TYPE_ENHANCED,null)
elseif target.isGroup then
call ForGroup(target.group,function Pure_Damage)
else
call GroupEnumUnitsInRange(temp,target.x,target.y,RUNNING[0],null)
call DestroyEffect( AddSpecialEffect(GetSFXPath(RUNNING.model),target.x,target.y))
loop
set u = FirstOfGroup(temp)
exitwhen null == u
call GroupRemoveUnit(temp,u)
call UnitDamageTarget(RUNNING.spell.caster.unit, u,RUNNING[1],false,false,ATTACK_TYPE_CHAOS,DAMAGE_TYPE_ENHANCED,null)
endloop
endif
call ReturnEffect(true)
return true
endfunction

