| 05-21-2011, 04:02 PM | #1 |
i like this spell. but it seems to have performance issues if it starts wiping out a lot of enemies and a lot of tornados spawn. was wondering why that is so. is it the limitations of the timer? or the limitations of xefx? or is there some flaw in the spell coding itself? i'm not sure where to look, since i didn't make the spell. so i'm asking here. JASS:library TornadoOnDeath requires TimerUtils, xefx, xedamage optional BoundSentinel //----------------------------------------------------------------------------------------------- // Tornado by scorpion182 // requires: TimerUtils, BoundSentinel, xe by vexorian // // // // // //----------------------------------------------------------------------------------------------- //----CALIBRATION SECTION------------------------------------------------------------------------ globals private constant integer SPELL_ID = 'A01U' //spell rawcode private constant string TORNADO_PATH = "Abilities\\Spells\\Other\\Tornado\\TornadoElementalSmall.mdl" //tornado effect path private constant real ANGLE_SPEED = .1 //tornado angle speed private constant real TORNADO_SCALE = 1. //tornado scaling value private constant real TICK_INC = 5. //tornado tick increment private constant real MIN_TICK = 80. //tornado minimum tick distance endglobals private constant function GetDuration takes integer lvl returns real return 30.+lvl*0 //spell duration in seconds endfunction private constant function GetCollisionSize takes integer lvl returns real return 150.+lvl*0 //tornado collision size endfunction private constant function GetAoE takes integer lvl returns real return 500.+lvl*0 //tornado aoe endfunction private constant function GetDamage takes integer lvl returns real return 15.*lvl + 30. //does damage per second endfunction //damage filter private function DamageOptions takes xedamage spellDamage returns nothing set spellDamage.dtype = DAMAGE_TYPE_UNIVERSAL set spellDamage.atype = ATTACK_TYPE_SIEGE set spellDamage.exception = UNIT_TYPE_STRUCTURE //don't damage building set spellDamage.visibleOnly = false //only damage visible unit set spellDamage.damageAllies = false //damage allies if true set spellDamage.damageTrees = true endfunction //------------END OF CALIBRATION SECTION--------------------------------------------------------- globals private xedamage xed endglobals private struct data unit caster timer t xefx fx real angle real tick real inc integer lvl real duration static method create takes unit c returns thistype local thistype this = thistype.allocate() local real x = GetUnitX(c) local real y = GetUnitY(c) local real a = GetRandomReal(0, 2*bj_PI) set .lvl = GetUnitAbilityLevel(c, SPELL_ID) set .caster = c set .t = NewTimer() set .fx = xefx.create(x, y, a) set .fx.fxpath = TORNADO_PATH set .fx.scale = TORNADO_SCALE set .tick = GetAoE(.lvl) set .inc = TICK_INC set .angle = a set .duration = GetDuration(.lvl) return this endmethod private method onDestroy takes nothing returns nothing call ReleaseTimer(.t) call .fx.destroy() endmethod static method onLoop takes nothing returns nothing local thistype this = thistype(GetTimerData(GetExpiredTimer())) local real a if .duration>0 and not IsUnitType(.caster, UNIT_TYPE_DEAD) then set .duration = .duration - XE_ANIMATION_PERIOD set a = .angle + ANGLE_SPEED set .fx.x = GetUnitX(.caster) + .tick * Cos(a) set .fx.y = GetUnitY(.caster) + .tick * Sin(a) set .tick = .tick - .inc if .tick < MIN_TICK or .tick > GetAoE(.lvl) then set .inc = .inc * -1 endif set .angle = a call xed.damageAOE(.caster, .fx.x, .fx.y, GetCollisionSize(.lvl), GetDamage(.lvl) * XE_ANIMATION_PERIOD) else call .destroy() endif endmethod static method SpellEffect takes nothing returns boolean local thistype this if GetUnitAbilityLevel(GetKillingUnit(), SPELL_ID)>0 then set this = thistype.create(GetKillingUnit()) call SetTimerData(.t, this) call TimerStart(.t, XE_ANIMATION_PERIOD, true, function thistype.onLoop) endif return false endmethod static method onInit takes nothing returns nothing local trigger t = CreateTrigger() call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_DEATH) call TriggerAddCondition(t, function thistype.SpellEffect) //init xedamage set xed=xedamage.create() call DamageOptions(xed) //call XE_PreloadAbility('A01U') endmethod endstruct endlibrary |
| 05-21-2011, 08:22 PM | #2 |
Since each kill the caster makes creates a circling projectile and each such projectile lasts 30 seconds and deals damage during that time, giving you even more kills, it seems easy to ramp up tens of such projectiles at once. While the most efficient projectile systems out there boast the ability to run hundreds of projectiles on modern hardware, note that this is usually the case only in single-player test maps. In normal gameplay situations, especially with a less efficient system, a few dozen instances is the limit. In the case of your spell, the two main inefficiencies are probably using one timer per instance and using the xedamage AoE method periodically. The first can be easily corrected while the second can't be easily replaced if you want to retain the same functionality - dealing damage to units near the projectile periodically instead of just once whenever they come in range, which would be slightly more efficient. |
| 05-22-2011, 04:29 PM | #3 |
ok, let's start with the apparently larger issue first. the timers. to follow your suggestion, do we simply edit the code in some way or do we make the spell use another timer system, such as TT or KT? i plan to edit the code some...but i certainly want to be able to let's say have the hero kill 30 units in a second or two and still be able to not get hit with 30 timers all at once, i guess...speaking of which...if there's some sort of timer limit with timerutils, why isn't this mentioned? i mean it seems to me sometimes systems are not tested on lower quality hardware so the limitations of the system might not be obvious to the system developer... at this point i'm not sure how damage is going to be done or even if i want something else to happen to units, such as getting tossed into the air. for now, let's focus on the timer problem. |
| 05-22-2011, 07:36 PM | #4 |
Note that TimerUtils were never meant to be used for things like this, they were meant for timers with longer expiration times. For fast periodic updates it is preferable to use a single timer, which you could code from scratch but it's less work to just use a system like TimedLoop. |
| 05-23-2011, 12:31 AM | #5 |
ok i think i got it working, more or less. i'm planning on doing some of my own customizing to the spell so i'm going to work on that. i'm coding in cjass now btw. i'm not sure if anyone cares about cjass or not at this site or about this spell, so unless there's an interest i'll just say thanks to anitarf and keep on working on my map. thanks, anitarf for pointing me at the system i should use. if i suspect the spell is still having trouble i'll bump the thread or make a new one if necessary. |
