I've recreated a spell of mine and it is completly finished, but when casting it on units it creates a huge lag. It's supposed to create two missles, each flying on it's own path and damaging units once. If a unit gets struck by both, a special effect should happen, but that's not inserted fully at the moment.
However, if I cast it on three creeps the game lags like hell for this moment:
code
Jass:
scope ChillingStreams initializer InitStreams
privatekeyword Streams
globalsprivateconstantinteger SPELL_ID ='A000'privateconstantinteger STUN_ID ='A001'privateconstantinteger BUFF_ID ='B000'privateconstantreal PERIOD =0.04privateconstantstring SFX_PATH ="Abilities\\Weapons\\FrostWyrmMissile\\FrostWyrmMissile.mdl"privateconstantstring SFX_ATTACH ="chest"privateconstantreal SPEED =400.privateconstantreal SIDEDIST =100.privateconstantreal COLLISION =100.privateconstantinteger MISSLE_COUNT =2privateconstantreal STEP = SPEED*PERIOD
private Streams TempStream
privateinteger Current
privateinteger test =0endglobalsprivateconstantfunction GetMaxDist takesinteger lvl returnsrealreturn500.+lvl*200.endfunctionprivateconstantfunction GetDamage takesinteger lvl returnsrealreturn lvl*70.endfunctionprivatestruct Streams
privateunit caster
privateplayer owner
privateunitarray missle[MISSLE_COUNT]privateeffectarray sfx[MISSLE_COUNT]privaterealarray vecx[MISSLE_COUNT]privaterealarray vecy[MISSLE_COUNT]privategrouparray hit[MISSLE_COUNT]privatereal dist
privatereal maxdist
privatereal damage
privatetimer movetim
method onDestroy takesnothingreturnsnothinglocalinteger i =0set.caster=nullloopexitwhen i >= MISSLE_COUNT
call ReleaseDummy(.missle[i])callDestroyEffect(.sfx[i])set.sfx[i]=nullcall ReleaseGroup(.hit[i])set.hit[i]=nullset i = i+1endloopcall ReleaseTimer(movetim)endmethodstaticmethod collisionCheck takesnothingreturnsbooleanlocalthistypethis= TempStream
localunit u =GetFilterUnit()localunit dummy
localboolean second =falselocalinteger i =0loopexitwhen i >= MISSLE_COUNT
ifIsUnitInGroup(u,.hit[i])thenif i != Current thenset second =trueelsereturnfalseendifelseset i = i+1endifendloopset test = test+1callBJDebugMsg(I2S(test))callBJDebugMsg(GetPlayerName(.owner))ifGetWidgetLife(u)>0.405andIsUnitEnemy(u,.owner)andnotIsUnitType(u,UNIT_TYPE_STRUCTURE)thencallUnitDamageTarget(.caster, u,.damage,false,true,ATTACK_TYPE_MAGIC,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)callGroupAddUnit(.hit[Current], u)callBJDebugMsg("Damage")if second thenset dummy = NewDummy(GetUnitX(u),GetUnitY(u),0.)callUnitAddAbility(dummy, STUN_ID)callIssueTargetOrder(dummy,"thunderbolt", u)call ReleaseDummy(dummy)endifendifreturnfalseendmethodstaticmethod movement takesnothingreturnsnothinglocalthistypethis= GetTimerData(GetExpiredTimer())localreal x
localreal y
localinteger i =0set TempStream =thisloopexitwhen i >= MISSLE_COUNT
set x =GetUnitX(.missle[i])+.vecx[i]set y =GetUnitY(.missle[i])+.vecy[i]callSetUnitX(.missle[i], x)callSetUnitY(.missle[i], y)set Current = i
call GroupEnumUnitsInArea(ENUM_GROUP, x, y, COLLISION,Condition(functionthistype.collisionCheck))set i = i+1endloopset.dist=.dist+STEP
if.dist>=.maxdistthencall.destroy()endifendmethodstaticmethod createStreams takesnothingreturnsnothinglocalthistypethis=thistype.allocate()localreal spellx =GetSpellTargetX()localreal spelly =GetSpellTargetY()localreal x
localreal y
localreal casterx
localreal castery
localreal angle
localreal facing
localinteger i =0set.caster=GetTriggerUnit()set casterx =GetUnitX(.caster)set castery =GetUnitY(.caster)set facing =Atan2(spelly-castery, spellx-casterx)set.owner=GetOwningPlayer(.caster)loopexitwhen i >= MISSLE_COUNT
set facing = facing+bj_PI*(i+1)/2set x = PolarX(casterx, facing, SIDEDIST)set y = PolarY(castery, facing, SIDEDIST)set angle =Atan2(spelly-y, spellx-x)set.missle[i]= NewDummy(x, y, angle)callAddSpecialEffectTarget(SFX_PATH,.missle[i], SFX_ATTACH)set.vecx[i]= PolarX(0, angle, STEP)set.vecy[i]= PolarY(0, angle, STEP)set.hit[i]= NewGroup()set i = i+1endloopset.dist=0.set.maxdist= GetMaxDist(GetUnitAbilityLevel(.caster, SPELL_ID))set.damage= GetDamage(GetUnitAbilityLevel(.caster, SPELL_ID))set.movetim= NewTimer()call SetTimerData(.movetim,this)callTimerStart(.movetim, PERIOD,true,functionthistype.movement)endmethodendstructprivatefunction InitStreams takesnothingreturnsnothingcall RegisterSpellAction(SPELL_ID, Streams.createStreams)endfunctionendscope
For debugging, "test" counts the picked units. After 5 spells this value is around 800, seems to be ok for 0.04 evaluations per second and picks each time. The owner is also correct, but damage is displayed only once for three creeps. I also used the blizzard pick-natives, same result.
At first glance I'd think it to be just in general due to loops within timers and the collision check, but I don't know if that is necessarily it. From what I can tell, you don't have any leaks other than maybe nulling your unit vars in collisionCheck, and as far as I know boolexprs don't need to be/shouldn't be destroyed.
I'd suggest attaching a test map, but otherwise you can try // commenting out the debug messages and special effects and see if that has an impact on it. This way you can tell whether it is your computer or the actual code itself.
The loop was the problem, but not just because it's a loop.
In case that the unit was hit once, the second hit was an endless loop.
I didn't think of this possibility because my computer normaly completly laggs and you can end warcraft because nothing works in such situations.
However, the code isn't lagging anymore, but units can be struck twice (they get stunned) but they take damage even more often. Why?
The current instance is safed in "current" and if the unit is already in the "current" group the emthod should return false and end.
code
Jass:
scope ChillingStreams initializer InitStreams
privatekeyword Streams
globalsprivateconstantinteger SPELL_ID ='A000'privateconstantinteger STUN_ID ='A001'privateconstantinteger BUFF_ID ='B000'privateconstantreal PERIOD =0.04privateconstantstring SFX_PATH ="Abilities\\Weapons\\FrostWyrmMissile\\FrostWyrmMissile.mdl"privateconstantstring SFX_ATTACH ="chest"privateconstantreal SPEED =400.privateconstantreal SIDEDIST =100.privateconstantreal COLLISION =100.privateconstantinteger MISSLE_COUNT =2privateconstantreal STEP = SPEED*PERIOD
private Streams TempStream
privateinteger Current
privateinteger test =0endglobalsprivateconstantfunction GetMaxDist takesinteger lvl returnsrealreturn500.+lvl*200.endfunctionprivateconstantfunction GetDamage takesinteger lvl returnsrealreturn lvl*70.endfunctionprivatestruct Streams
privateunit caster
privateplayer owner
privateunitarray missle[MISSLE_COUNT]privateeffectarray sfx[MISSLE_COUNT]privaterealarray vecx[MISSLE_COUNT]privaterealarray vecy[MISSLE_COUNT]privategrouparray hit[MISSLE_COUNT]privatereal dist
privatereal maxdist
privatereal damage
privatetimer movetim
method onDestroy takesnothingreturnsnothinglocalinteger i =0set.caster=nullloopexitwhen i >= MISSLE_COUNT
call ReleaseDummy(.missle[i])callDestroyEffect(.sfx[i])set.sfx[i]=nullcall ReleaseGroup(.hit[i])set.hit[i]=nullset i = i+1endloopcall ReleaseTimer(movetim)endmethodstaticmethod collisionCheck takesnothingreturnsbooleanlocalthistypethis= TempStream
localunit u =GetFilterUnit()localunit dummy
localboolean second =falselocalinteger i =0loopexitwhen i >= MISSLE_COUNT
ifIsUnitInGroup(u,.hit[i])thenif i != Current thenset second =trueset i = MISSLE_COUNT
elsereturnfalseendifelseset i = i+1endifendloopset test = test+1ifGetWidgetLife(u)>0.405andIsUnitEnemy(u,.owner)andnotIsUnitType(u,UNIT_TYPE_STRUCTURE)thencallUnitDamageTarget(.caster, u,.damage,false,true,ATTACK_TYPE_MAGIC,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)callGroupAddUnit(.hit[Current], u)if second thenset dummy = NewDummy(GetUnitX(u),GetUnitY(u),0.)callUnitAddAbility(dummy, STUN_ID)callIssueTargetOrder(dummy,"thunderbolt", u)call ReleaseDummy(dummy)endifendifset u =nullreturnfalseendmethodstaticmethod movement takesnothingreturnsnothinglocalthistypethis= GetTimerData(GetExpiredTimer())localreal x
localreal y
localinteger i =0set TempStream =thisloopexitwhen i >= MISSLE_COUNT
set x =GetUnitX(.missle[i])+.vecx[i]set y =GetUnitY(.missle[i])+.vecy[i]callSetUnitX(.missle[i], x)callSetUnitY(.missle[i], y)set Current = i
call GroupEnumUnitsInArea(ENUM_GROUP, x, y, COLLISION,Condition(functionthistype.collisionCheck))set i = i+1endloopset.dist=.dist+STEP
if.dist>=.maxdistthencall.destroy()endifendmethodstaticmethod createStreams takesnothingreturnsnothinglocalthistypethis=thistype.allocate()localreal spellx =GetSpellTargetX()localreal spelly =GetSpellTargetY()localreal x
localreal y
localreal casterx
localreal castery
localreal angle
localreal facing
localinteger i =0set.caster=GetTriggerUnit()set casterx =GetUnitX(.caster)set castery =GetUnitY(.caster)set facing =Atan2(spelly-castery, spellx-casterx)set.owner=GetOwningPlayer(.caster)loopexitwhen i >= MISSLE_COUNT
set facing = facing+bj_PI*(i+1)/2set x = PolarX(casterx, facing, SIDEDIST)set y = PolarY(castery, facing, SIDEDIST)set angle =Atan2(spelly-y, spellx-x)set.missle[i]= NewDummy(x, y, angle)callAddSpecialEffectTarget(SFX_PATH,.missle[i], SFX_ATTACH)set.vecx[i]= PolarX(0, angle, STEP)set.vecy[i]= PolarY(0, angle, STEP)set.hit[i]= NewGroup()set i = i+1endloopset.dist=0.set.maxdist= GetMaxDist(GetUnitAbilityLevel(.caster, SPELL_ID))set.damage= GetDamage(GetUnitAbilityLevel(.caster, SPELL_ID))set.movetim= NewTimer()call SetTimerData(.movetim,this)callTimerStart(.movetim, PERIOD,true,functionthistype.movement)endmethodendstructprivatefunction InitStreams takesnothingreturnsnothingcall RegisterSpellAction(SPELL_ID, Streams.createStreams)endfunctionendscope
based on other threads: you should use parentheses after not because it overwrites any other checker.... your trigger would work something like this one...