| 09-18-2008, 09:18 PM | #1 |
For some weird reason, projectiles from random instances of my spell freeze (in mid-air or on their spawn point), and sometimes their movement is (re)started by subsequent spell instances - at one point, about 4 spell instances (5 projectiles each) were frozen on the ground, and after spamming the spell, those projectiles started moving again, and I can't figure out why. I would make it with TimerUtils because it's getting really frustrating, but I'd really like to keep the spell system-independent if possible JASS://Phantasmal Barrage //By Flare //Requires: Projectile dummy (h000) // Launcher Dummy (h001) // Phantasmal Barrage ability (A000) // NewGen WE // dummy.mdx //Thanks to: //Shadow1500 - Parabola function //??? - dummy.mdx //Please let me know who the creator of the dummy.mdx model is, so I can credit them :) struct PB //Configurables //Ability rawcode private static constant integer SID = 'AOsh' //Launcher Dummy rawcode private static constant integer LID = 'h001' //Projectile Dummy rawcode private static constant integer PID = 'h000' //Timer interval private static constant real TIMER_INT = 0.03125 //Number of projectiles used private static constant integer PROJCOUNT = 5 //Projectile effect private static constant string PROJ_FX = "Abilities\\Spells\\Other\\BlackArrow\\BlackArrowMissile.mdl" //Explosion effect private static constant string END_FX = "Objects\\Spawnmodels\\Undead\\UndeadDissipate\\UndeadDissipate.mdl" //Number of effects spawned per ring private static constant integer FX_COUNT = 5 //Number of rings spawned private static constant integer RING_COUNT = 1 //Ring offset private static constant real RING_OFFSET = 75. //Spawn offset private static constant real SPAWN_OFFSET = 300. //Attachment point for projectile private static constant string ATTACH_PT = "origin" //Low bound for projectile speed - projectile speed will be somewhere between SPEED_LOW and SPEED_HIGH private static constant real SPEED_LOW = 300 //High bound for projectile speed private static constant real SPEED_HIGH = 1000 //Projectile's target offset - base value for how far from the target point the projectile will land private static constant real TARGET_OFFSET = 0. //Intensity of curve - lower values result in a "sharper" curve, higher values result in a bow-shaped curve private static constant real CURVE = 2. //Accurate range private static constant real ACC_RANGE = 800. //Accuracy discrepancy - higher values result in a less accurate barrage at longer distance //Discrepancy only takes effect if the target point if more than ACC_RANGE units away from the caster private static constant real ACC_DISCREP_MULTI = 75 //For every ACC_DISCREP_MULTI units beyond ACC_RANGE, the projectiles' targeting will be off by up to ACC_DISCREP units //e.g. (using current values) if you cast the spell 1400 units away //the projectiles will land up to ((1400-800)/50)*25 (300) units away from their original target //NOTE: Projectile's original target is the target point offset by TARGET_OFFSET towards a random angle private static constant real ACC_DISCREP = 25 //Minimum damage percentage - percentage of whole damage that is dealt at the edge of damage radius private static constant real MIN_DMG_PERCENT = 0.25 //Attack type, damage type, weapon type private static constant attacktype ATYPE = ATTACK_TYPE_MAGIC private static constant damagetype DTYPE = DAMAGE_TYPE_NORMAL private static constant weapontype WTYPE = WEAPON_TYPE_WHOKNOWS //Animation played by the launcher dummies private static constant string ANIM = "attack" //Lifespan of launcher dummies private static constant real LIFESPAN = 1. //Damage radius calculation private static method DamageRadius takes unit u returns real local real base = 150. local real m1 = I2R (GetUnitAbilityLevel (u, .SID)) local real m2 = 50. return base + m1*m2 endmethod //Damage calculation private static method Damage takes unit u returns real local real base = 15 local real m1 = GetUnitAbilityLevel (u, .SID) local real m2 = 5 return base + m1*m2 endmethod //Required globals private static location tempLoc = Location (0,0) private static group genGroup = CreateGroup () private static timer spellTimer = CreateTimer () private static PB array data private static PB gdata private static integer N = 0 private static real groupX = 0 private static real groupY = 0 private static real doublePi = bj_PI * 2 private static boolean grounded = false //Required struct members unit caster unit array proj[.PROJCOUNT] real array speed[.PROJCOUNT] real array pcos[.PROJCOUNT] real array psin[.PROJCOUNT] real array curdist[.PROJCOUNT] real array maxdist[.PROJCOUNT] boolean array done[.PROJCOUNT] effect array pfx[.PROJCOUNT] integer destroyed = 0 //Required helper functions private static method RingEffect takes string fxString, real ringCount, real effectCount, real offset, real x, real y returns nothing local integer i1 = 1 local integer i2 = 1 local real angle = GetRandomReal (0, .doublePi) local real x2 local real y2 loop exitwhen i1 > ringCount loop exitwhen i2 > effectCount set angle = angle + .doublePi/effectCount set x2 = x + Cos (angle) * (i1 * offset) set y2 = y + Sin (angle) * (i1 * offset) call DestroyEffect(AddSpecialEffect (fxString, x2, y2)) set i2 = i2 + 1 endloop set i1 = i1 + 1 endloop endmethod private static constant method JumpParabola takes real dist, real maxdist,real curve returns real local real t = (dist*2)/maxdist-1 return (-t*t+1)*(maxdist/curve) endmethod private static method SetUnitXY takes unit u,real x,real y returns nothing if x<GetRectMaxX(bj_mapInitialPlayableArea) and x>GetRectMinX(bj_mapInitialPlayableArea) and y<GetRectMaxY(bj_mapInitialPlayableArea) and y>GetRectMinY(bj_mapInitialPlayableArea) then call SetUnitX(u,x) call SetUnitY(u,y) endif endmethod private static method GetCoordZ takes real x, real y returns real call MoveLocation (.tempLoc, x, y) return GetLocationZ (.tempLoc) endmethod private static method SetUnitZ takes unit u, real h returns boolean local real z = h - .GetCoordZ (GetUnitX (u), GetUnitY (u)) if z > 0 then call SetUnitFlyHeight (u, z, 0) return false else return true endif endmethod private static method GetUnitZ takes unit u returns real return .GetCoordZ (GetUnitX (u), GetUnitY (u)) + GetUnitFlyHeight (u) endmethod private static method GetRandOffsetX takes real x, real dist returns real local real discrepdist = ((dist - .ACC_RANGE)/.ACC_DISCREP_MULTI) * .ACC_DISCREP local real angle = Cos (GetRandomReal (0, .doublePi)) return x + angle * discrepdist endmethod private static method GetRandOffsetY takes real y, real dist returns real local real discrepdist = ((dist - .ACC_RANGE)/.ACC_DISCREP_MULTI) * .ACC_DISCREP local real angle = Sin (GetRandomReal (0, .doublePi)) return y + angle * discrepdist endmethod //Spell functions private static method GroupFunc takes nothing returns boolean local PB a = .gdata local unit u = GetFilterUnit () local real ux = GetUnitX (u) local real uy = GetUnitY (u) local real x = .groupX - ux local real y = .groupY - uy local real dist = SquareRoot (x*x + y*y) local real percent = (.DamageRadius (a.caster) - dist)/.DamageRadius (a.caster) local real dmg if percent < .MIN_DMG_PERCENT then set percent = .MIN_DMG_PERCENT endif set dmg = .Damage (a.caster) * percent call UnitDamageTarget (a.caster, u, dmg, false, true, .ATYPE, .DTYPE, .WTYPE) return false endmethod private static method Move takes nothing returns nothing local integer i = 0 local integer i2 = 0 local real fxAngle = 0 local real x = 0 local real y = 0 local real x2 = 0 local real y2 = 0 local real z = 0 local real uz = 0 local real ex = 0 local real ey = 0 local boolean b = false local real hDist = 0 local real zDif = 0 local integer animindex = 0 local PB a loop exitwhen i > .N set i = i + 1 set a = .data[i] loop exitwhen i2 > .PROJCOUNT //Projectile handling if a.done[i2] == false then set x = GetUnitX (a.proj[i2]) set y = GetUnitY (a.proj[i2]) set x2 = x + a.pcos[i2]*a.speed[i2] set y2 = y + a.psin[i2]*a.speed[i2] set z = .JumpParabola (a.curdist[i2], a.maxdist[i2], .CURVE) set uz = .GetUnitZ (a.proj[i2]) set hDist = SquareRoot ((x2-x)*(x2-x) + (y2-y)*(y2-y)) set zDif = z - uz set animindex = R2I (Atan2 (zDif, hDist) * bj_RADTODEG + 90) if animindex >= 0 and animindex <= 180 then call SetUnitAnimationByIndex (a.proj[i2], animindex) endif call .SetUnitXY (a.proj[i2], x2, y2) set b = .SetUnitZ (a.proj[i2], z) //Clears individual projectiles if b and a.curdist[i2] > 0 then set a.destroyed = a.destroyed + 1 call DestroyEffect (a.pfx[i2]) set a.done[i2] = true set a.curdist[i2] = 0 call KillUnit (a.proj[i2]) set .gdata = a call GroupEnumUnitsInRange (.genGroup, x, y, .DamageRadius (a.caster), Condition (function PB.GroupFunc)) call .RingEffect (.END_FX, .RING_COUNT, .FX_COUNT, .RING_OFFSET, x, y) endif set a.curdist[i2] = a.curdist[i2] + a.speed[i2] endif set i2 = i2 + 1 endloop set i2 = 0 //Clears instances if a.destroyed >= .PROJCOUNT then call a.destroy () set .data[i] = .data[.N] set .N = .N - 1 if .N == 0 then call PauseTimer (.spellTimer) endif set i = i - 1 endif //call BJDebugMsg ("The " + I2S (i) + "th instance of " + I2S (.N) + " instances has ended") endloop //call BJDebugMsg ("i = " + I2S (i) + ", N = " + I2S (.N)) endmethod private static method SpellCond takes nothing returns boolean return GetSpellAbilityId () == .SID endmethod private static method SpellActions takes nothing returns nothing local PB a = PB.create () local integer i = 0 local unit u local unit c = GetTriggerUnit () local real cx = GetUnitX (c) local real cy = GetUnitY (c) local real sx local real sy local location l = GetSpellTargetLoc () local real tx = GetLocationX (l) local real ty = GetLocationY (l) local real x = tx - cx local real y = ty - cy local real rx local real ry local real angle = Atan2 (y, x) local real dist = SquareRoot (x*x + y*y) set a.caster = c set c = null set rx = cx + Cos (angle) * dist set ry = cy + Sin (angle) * dist call RemoveLocation (l) set l = null loop exitwhen i == .PROJCOUNT set sx = cx + Cos (GetRandomReal (0, .doublePi)) * GetRandomReal (0, .SPAWN_OFFSET) set sy = cy + Sin (GetRandomReal (0, .doublePi)) * GetRandomReal (0, .SPAWN_OFFSET) set u = CreateUnit (GetOwningPlayer (a.caster), .LID, sx, sy, angle * bj_RADTODEG) call SetUnitAnimation (u, .ANIM) call QueueUnitAnimation (u, "stand") call UnitApplyTimedLife (u, 'BTLF', .LIFESPAN) if dist <= .ACC_RANGE then set rx = rx + Cos (GetRandomReal (0, .doublePi)) * GetRandomReal (0, .TARGET_OFFSET) set ry = ry + Sin(GetRandomReal (0, .doublePi)) * GetRandomReal (0, .TARGET_OFFSET) else set rx = .GetRandOffsetX (rx, dist) set ry = .GetRandOffsetY (ry, dist) endif set x = rx-cx set y = ry-cy set angle = Atan2 (y, x) set a.pcos[i] = Cos (angle) set a.psin[i] = Sin (angle) set a.maxdist[i] = SquareRoot (x*x + y*y) set a.proj[i] = CreateUnit (GetOwningPlayer (a.caster), .PID, sx, sy, angle * bj_RADTODEG) call UnitAddAbility (a.proj[i], 'Arav') call UnitRemoveAbility (a.proj[i], 'Arav') set a.curdist[i] = 0 set a.speed[i] = GetRandomReal (.SPEED_LOW, .SPEED_HIGH) * .TIMER_INT set a.done[i] = false set a.pfx[i] = AddSpecialEffectTarget (.PROJ_FX, a.proj[i], .ATTACH_PT) set i = i + 1 endloop if .N == 0 then call TimerStart (.spellTimer, .TIMER_INT, true, function PB.Move) endif set .N = .N + 1 set .data[.N] = a //call BJDebugMsg (I2S (.N)) set u = null endmethod private static method onInit takes nothing returns nothing local trigger t = CreateTrigger () call TriggerRegisterAnyUnitEventBJ (t, EVENT_PLAYER_UNIT_SPELL_EFFECT) call TriggerAddCondition (t, Condition (function PB.SpellCond)) call TriggerAddAction (t, function PB.SpellActions) endmethod endstruct |
| 09-18-2008, 10:58 PM | #2 |
For one thing, your array members within each struct instance are destroying your maximum instance limit. Take 8190 (which is struct maximum instance limit) and divide it by 5 ^ 8 (8 is the number of arrays), which yields less than one instance that your spell can sustain. I would reccommend using dynamic arrays instead that each have a limit of five and you can then instanciate them quite a few times as members of your struct. Even if my calculation or reasoning is off, you still won't be able to make many stable projectiles with your current system. EDIT: Whoops, my reasoning was way off, sorry about that, your arrays aren't limiting much... |
