Flare
Stops copies me!
- Reaction score
- 662
EDIT: Solved the first part (was incrementing i2 within the If ), still need to figure out how to solve the second problem
1) For some reason, when one or two of my projectiles complete their movement (and hit the ground), it causes the rest of the projectiles in the spell instance to stop in midair (for no particular reason)
(full spell code, if needed)
Trigger action/condition and timer callback functions
2) Whenever I cast the spell for a second/third/fourth (etc) time, the callback function doesn't do anything - the units are created, but no movement takes place and I can't see why that is Any idea why that would happen?
1) For some reason, when one or two of my projectiles complete their movement (and hit the ground), it causes the rest of the projectiles in the spell instance to stop in midair (for no particular reason)
(full spell code, if needed)
JASS:
//Phantasmal barrage
//By Flare
//Requires: dummy.mdx
// Projectile dummy (h000)
// Launcher Dummy (h001)
// Phantasmal Barrage ability (A000)
// NewGen WE
//Thanks to:
//Vexorian - TimerUtils
//Shadow1500 - Parabola function
struct PB
//Configurables
//Ability rawcode
private static constant integer SID = 039;AOsh039;
//Launcher Dummy rawcode
private static constant integer LID = 039;h001039;
//Projectile Dummy rawcode
private static constant integer PID = 039;h000039;
//Timer interval
private static constant real TIMER_INT = 0.1
//Number of projectiles used
private static constant integer PROJCOUNT = 5
//Projectile model
private static constant string PROJ_FX = "Abilities\\Weapons\\ZigguratMissile\\ZigguratMissile.mdl"
//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 = 600
//High bound for projectile speed
private static constant real SPEED_HIGH = 900
//Projectile's target offset - base value for how far from the target point the projectile will land
private static constant real TARGET_OFFSET = 100.
//Intensity of curve - lower values result in a "sharper" curve, higher values result in a bow-shaped curve
private static constant real CURVE = 1.
//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 = 50
//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
local real m1
local real m2
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]
effect array pfx[.PROJCOUNT]
boolean array done[.PROJCOUNT]
integer destroyed = 0
//Required helper functions
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 nothing
local real z = h - .GetCoordZ (GetUnitX (u), GetUnitY (u))
if z > 0 then
call SetUnitFlyHeight (u, z, 0)
set .grounded = false
else
set .grounded = 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
return x + (ModuloReal (dist - .ACC_RANGE, .ACC_DISCREP_MULTI) * .ACC_DISCREP) * Cos (GetRandomReal (0, .doublePi))
endmethod
private static method GetRandOffsetY takes real y, real dist returns real
return y +(ModuloReal (dist - .ACC_RANGE, .ACC_DISCREP_MULTI) * .ACC_DISCREP) * Sin (GetRandomReal (0, .doublePi))
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 = 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
method onDestroy takes nothing returns nothing
call BJDebugMsg ("Struct destroyed")
endmethod
private static method Move takes nothing returns nothing
local integer i = 0
local integer i2 = 0
local real x
local real y
local real z
local boolean b
local real animindex
local PB a
loop
exitwhen i == .N
set a = .data<i>
loop
exitwhen i2 == .PROJCOUNT
if a.done[i2] == false then
set x = GetUnitX (a.proj[i2])
set y = GetUnitY (a.proj[i2])
set x = x + a.pcos[i2]*a.speed[i2]
set y = y + a.psin[i2]*a.speed[i2]
set z = .JumpParabola (a.curdist[i2], a.maxdist[i2], .CURVE)
//call BJDebugMsg ("Current z - " + R2S (z) + ", speed - " + R2S (a.speed[i2]) + ", current distance - " + R2S (a.curdist[i2]))
set animindex = Atan2 (z, a.curdist[i2] - a.maxdist[i2] * 0.5)
call .SetUnitXY (a.proj[i2], x, y)
call .SetUnitZ (a.proj[i2], z)
if .grounded == true and a.curdist[i2] > 0 then
set a.destroyed = a.destroyed + 1
set a.done[i2] = true
set a.curdist[i2] = 0
call KillUnit (a.proj[i2])
call DestroyEffect (a.pfx[i2])
set .gdata = a
call GroupEnumUnitsInRange (.genGroup, x, y, .DamageRadius (a.caster), Condition (function PB.GroupFunc))
endif
set a.curdist[i2] = a.curdist[i2] + a.speed[i2]
set i2 = i2 + 1
endif
endloop
if a.destroyed >= .PROJCOUNT then
call BJDebugMsg ("Value is " + I2S (a.destroyed) + "/" + I2S (.PROJCOUNT))
call a.destroy ()
set .data<i> = .data[.N]
set .N = .N - 1
set i = i - 1
endif
set i = i + 1
endloop
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 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 u = CreateUnit (GetOwningPlayer (a.caster), .LID, cx, cy, angle * bj_RADTODEG)
//call BJDebugMsg ("Angle - " + R2S (angle * bj_RADTODEG))
call SetUnitAnimation (u, .ANIM)
call QueueUnitAnimation (u, "stand")
call UnitApplyTimedLife (u, 039;BTLF039;, .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, cx, cy, angle * bj_RADTODEG)
call UnitAddAbility (a.proj<i>, 039;Arav039;)
call UnitRemoveAbility (a.proj<i>, 039;Arav039;)
set a.curdist<i> = 0
set a.speed<i> = GetRandomReal (.SPEED_LOW, .SPEED_HIGH) * .TIMER_INT
set a.pfx<i> = AddSpecialEffectTarget (.PROJ_FX, a.proj<i>, .ATTACH_PT)
set a.done<i> = false
set i = i + 1
endloop
set .N = .N + 1
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)
call TimerStart (.spellTimer, .TIMER_INT, true, function PB.Move)
endmethod
endstruct</i></i></i></i></i></i></i></i></i></i></i></i></i>
Trigger action/condition and timer callback functions
JASS:
//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]
effect array pfx[.PROJCOUNT]
boolean array done[.PROJCOUNT]
integer destroyed = 0
private static method Move takes nothing returns nothing
local integer i = 0
local integer i2 = 0
local real x
local real y
local real z
local boolean b
local real animindex
local PB a
loop
exitwhen i == .N
set a = .data<i>
loop
exitwhen i2 == .PROJCOUNT
if a.done[i2] == false then
set x = GetUnitX (a.proj[i2])
set y = GetUnitY (a.proj[i2])
set x = x + a.pcos[i2]*a.speed[i2]
set y = y + a.psin[i2]*a.speed[i2]
set z = .JumpParabola (a.curdist[i2], a.maxdist[i2], .CURVE)
//call BJDebugMsg ("Current z - " + R2S (z) + ", speed - " + R2S (a.speed[i2]) + ", current distance - " + R2S (a.curdist[i2]))
set animindex = Atan2 (z, a.curdist[i2] - a.maxdist[i2] * 0.5)
call .SetUnitXY (a.proj[i2], x, y)
call .SetUnitZ (a.proj[i2], z)
if .grounded == true and a.curdist[i2] > 0 then
set a.destroyed = a.destroyed + 1
set a.done[i2] = true
set a.curdist[i2] = 0
call KillUnit (a.proj[i2])
call DestroyEffect (a.pfx[i2])
set .gdata = a
call GroupEnumUnitsInRange (.genGroup, x, y, .DamageRadius (a.caster), Condition (function PB.GroupFunc))
endif
set a.curdist[i2] = a.curdist[i2] + a.speed[i2]
set i2 = i2 + 1
endif
endloop
if a.destroyed >= .PROJCOUNT then
call BJDebugMsg ("Value is " + I2S (a.destroyed) + "/" + I2S (.PROJCOUNT))
call a.destroy ()
set .data<i> = .data[.N]
set .N = .N - 1
set i = i - 1
endif
set i = i + 1
endloop
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 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 u = CreateUnit (GetOwningPlayer (a.caster), .LID, cx, cy, angle * bj_RADTODEG)
//call BJDebugMsg ("Angle - " + R2S (angle * bj_RADTODEG))
call SetUnitAnimation (u, .ANIM)
call QueueUnitAnimation (u, "stand")
call UnitApplyTimedLife (u, 039;BTLF039;, .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, cx, cy, angle * bj_RADTODEG)
call UnitAddAbility (a.proj<i>, 039;Arav039;)
call UnitRemoveAbility (a.proj<i>, 039;Arav039;)
set a.curdist<i> = 0
set a.speed<i> = GetRandomReal (.SPEED_LOW, .SPEED_HIGH) * .TIMER_INT
set a.pfx<i> = AddSpecialEffectTarget (.PROJ_FX, a.proj<i>, .ATTACH_PT)
set a.done<i> = false
set i = i + 1
endloop
set .N = .N + 1
set u = null
endmethod</i></i></i></i></i></i></i></i></i></i></i></i></i>
2) Whenever I cast the spell for a second/third/fourth (etc) time, the callback function doesn't do anything - the units are created, but no movement takes place and I can't see why that is Any idea why that would happen?