/* 4 Packages included..
Projectile superclass
TimedBlasts (main system)
Kamehameha (2d example of TimedBlasts System)
AngryKame (3d example of TimedBlasts System
TimedBlasts attempts to give a system to create various "timed blasts" that can be customized to create tons of different spells that follow the general layout
User begins channeling animation, creating the projectile near them..
after a certain size is reached, the projectile is launched to the target point inflicting damage.
If two "clashable" blasts hit each other, the two casters will be in a struggle until one runs out of mana, and the winning blast will change target to its opposing caster unit.
*visual example of what this code attempts to achieve in the case of a 3d clashable blast https://www.youtube.com/watch?v=M7i5Z3C5ZOk
*note clashable and 3d hasn't been tested/made yet*
protected real impactAoe - size of aoe for damage to be done
protected real damage - damage to be done
protected real endScale - final scale of the blast before launching
protected boolean trailOn - creates a trail following the blast as it flies to the target
protected boolean dustOn - creates a dust effect around the caster as he fires
protected boolean pulseOn - makes the missile pulsate as it flies to the targeted area
protected boolean launchOn - creates a launch effect as the missile is launched
protected boolean dropOn - if the missile is fired from an aerial position, the missile is lowered to the targetted area
protected boolean flightOn - if the missile will be fired from an aerial position
protected string trailSFX - specify what SFX will be used for the trail
protected string pulseSFX - specify what SFX will be used for the pulse
protected string launchSFX - " "
protected string finalSFX - " "
protected string dustSFX - " "
protected real trailSize - size of trail created
protected real pulseSize - size of pulses
protected real launchSize - size of launch
protected colorA missileCol - color of missile
protected colorA trailCol = color of trail
protected colorA pulseCol = color of pulse
protected real speed - speed of missile during travel
protected int channelIndex - animation index to channel
protected int launchIndex - animation index to launch
protected real offsetDistance = 50 - small offset from caster
protected real realDropSpeed = -15 if there is a drop, reasonable dropspeed, can be changed
private real timeSinceLastTrail = 0 - used to create trail
private real timeSinceLastPulse = 0 - used to create pulses
private real timeSinceLastChannel = 0 - uses to create channel
protected real timeDistance - how long trails and pulses should last, depends on speed, and missile sizes, should be configured to each spell accordingly
protected sound throwSound = generic missile size
protected real lowerRate = 150. speed that a missile will lower if it is a 3d missile
protected real destroyExplode = 1.5 how long the destruction sfx will be played
protected boolean clashing - setting if the missile is ready to clash
protected boolean clashable - saves true value for clashable until channeling is complete
protected boolean clashed - if a missile has clashed, prevents further clashs
protected boolean channeling = if a missile is still channeling, it cannot clash yet
*/
package Projectile
import public Entity
public class Projectile extends FxEntity
// Angles
protected angle xyAngle
private vec3 startpos
private boolean timed = false
private boolean ranged = false
// Moving Speed
private real speed = 0
private real acc = 1.0
protected real dist = 0
private real maxDist = 0
protected real lifespan = 0
protected real dropSpeed = 0
construct( vec3 pos, real radius, player owner, angle xyAngle, string fxpath )
super(pos, radius, owner, xyAngle, fxpath)
startpos = pos
setXYAngle(xyAngle)
active = false
function setRanged(real maxDistance)
this.maxDist = maxDistance*maxDistance
ranged = true
function setTimed(real lifespan)
this.lifespan = lifespan
timed = true
function setSpeed(real speed)
this.speed = speed
//angle.direction(real distance)
setVel(vec3(xyAngle.cos()*speed, xyAngle.sin()*speed, dropSpeed))
function setSpeed(real speed, real drop)
this.speed = speed
//angle.direction(real distance)
setVel(vec3(xyAngle.cos()*speed, xyAngle.sin()*speed, drop))
function setAcc(real factor)
this.acc = factor
function getSpeed() returns real
return speed
function setXYAngle(angle xyA)
this.xyAngle = xyA
fx.setXYAngle(xyA)
function setZAngle(angle zA)
fx.setZAngle(zA)
override function update()
vel *= acc
pos += vel
fixPos()
if timed
lifespan -= ANIMATION_PERIOD
if lifespan <= 0
done = true
return
if ranged
if startpos.distToVecSquared(pos) > maxDist
done = true
package TimedBlasts
import Projectile
import LinkedListModule
import Fx
import Constants
import ClosureTimers
import Terrain
import LinkedList
public class TimedBlasts extends Projectile
use LinkedListModule
//Editable values
protected real impactAoe
protected real damage
protected real endScale
protected boolean trailOn = false
protected boolean dustOn = false
protected boolean pulseOn = false
protected boolean launchOn = false
protected boolean dropOn = false
protected boolean flightOn = true
protected string trailSFX
protected string pulseSFX
protected string launchSFX
protected string finalSFX
protected string dustSFX = dustWave
protected real trailSize
protected real pulseSize
protected real launchSize
protected colorA missileCol = colorA(255,255,255,255)
protected colorA trailCol = colorA(255,255,255,255)
protected colorA pulseCol = colorA(255,255,255,255)
protected real speed
protected int channelIndex
protected int launchIndex
protected real offsetDistance = 50
protected real realDropSpeed = -15
private real timeSinceLastTrail = 0
private real timeSinceLastPulse = 0
private real timeSinceLastChannel = 0
protected real timeDistance = 1
protected sound throwSound = gg_snd_kamehameha_fire
protected real lowerRate = 150.
protected real destroyExplode = 1.5
protected boolean clashing = false
protected boolean clashable = false
protected boolean clashed = false
protected boolean channeling = false
protected LinkedList<Fx> trailList = new LinkedList<Fx>()
//Instance Variables
private vec3 target
protected unit u
private timer t = getTimer()
protected real scale
protected angle targetAngle
private boolean missileCast = false
construct(unit actor,vec3 pos, player owner, vec3 target, string SFX, real originalScale)
super(pos.addReals(0, 0, pos.withTerrainZ().z), 0, owner, pos.angleTo2d(target), SFX)
this.targetAngle = pos.angleTo2d(target)
this.u = actor
this.target = target
this.u.pause()
this.scale = originalScale
function startMissile()
this.setSpeed(0)
this.pos = pos.offset2d(pos.angleTo2d(target), offsetDistance)
this.pos.z += 50
this.fixPos()
this.fx.setColor(missileCol)
this.fx.setScale(this.scale)
this.t.setData(this castTo int)
this.t.startPeriodic(.1, function callExpandMissile)
//if dust is activated
if this.dustOn
this.createDust()
function createDust()
effect x = AddSpecialEffectTarget(dustSFX, u, "origin")
DestroyEffectBJ(x)
static function callExpandMissile()
(GetExpiredTimer().getData() castTo TimedBlasts).expandMissile()
function expandMissile()
if this.timeSinceLastChannel == 0
this.u.setAnimation(channelIndex)
if this.timeSinceLastChannel >= (.18)
this.u.setAnimation(channelIndex)
this.timeSinceLastChannel -= (.17)
this.timeSinceLastChannel += ANIMATION_PERIOD
this.scale += .05
this.fx.setScale(this.scale)
if this.scale >= endScale
if this.flightOn
this.u.setFlyHeight(0, lowerRate)
if this.launchOn
this.createLaunchFX()
if this.dropOn
this.dropSpeed = realDropSpeed
this.setSpeed(speed)
this.t.release()
this.u.setAnimation(launchIndex)
PlaySoundOnUnitBJ(this.throwSound, 70, this.u)
this.missileCast = true
if not this.channeling
this.u.unpause()
if this.clashing
this.clashable = true
//calculate frequency of trail creation
function createLaunchFX()
Fx launch = new Fx(fx.getPos2(),this.targetAngle, kameLaunch)
launch.setScale(launchSize)
doAfter(.5, () -> destroy launch)
function createTrail()
Fx trail = new Fx(fx.getPos3d(), this.targetAngle, trailSFX)
..setScale(trailSize)
..setColor(trailCol)
if flightOn == false
trail.setZ(100)
// doAfter(timeDistance, () -> trail.hiddenDestroy())
this.trailList.add(trail)
function createPulse()
Fx pulse = new Fx(fx.getPos3d(), this.targetAngle, pulseSFX)
..setScale(pulseSize)
..setZAngle(-5200)
..setColor(pulseCol)
if this.flightOn == false
pulse.setZ(100)
// pulse.getDummy().setAnimation(0)
doAfter(timeDistance, () -> pulse.hiddenDestroy())
override function update()
super.update()
//should be speed dependent at some level.
if pos.toVec2().distToVecSquared(target.toVec2()) < 120*120
//timeDistance = 0.15
if this.getSpeed() > 0
if this.trailOn
if this.timeSinceLastTrail > (2/speed)
this.createTrail()
this.timeSinceLastTrail -= (2/speed)
this.timeSinceLastTrail += ANIMATION_PERIOD
if this.pulseOn
if this.timeSinceLastPulse > (2/speed)
this.createPulse()
this.timeSinceLastPulse -= (2/speed)
this.timeSinceLastPulse += ANIMATION_PERIOD
if not this.clashed
if this.clashable
Entity e = Entity.getFirst()
while e != null
if e!= this and this.owner != e.owner
if this.owner.isAllyOf(e.owner)
TimedBlasts blast2 = e castTo TimedBlasts
if blast2.clashable and not blast2.clashed
if this.pos.distToVecSquared(e.pos) < 40000.
print(this.pos.distToVecSquared(e.pos).toString())
if this.pos.distToVecSquared(e.pos) < (120*120)
//print("hi6!")
this.onHit(blast2)
e=e.next
if ((this.u.getPos().distToVecSquared(target.toVec2()) < 150*150) or (pos.toVec2().distToVecSquared(target.toVec2()) < 64*64)) and missileCast
for unit enemy from ENUM_GROUP..enumUnitsInRange(pos.toVec2(), impactAoe)
if enemy.isEnemy(owner)
this.u.damageTarget(enemy, damage)
done = true
terminate()
function onHit(TimedBlasts blast2)
boolean winner1 = false
boolean winner2 = false
//print("hi7!")
this.clashed = true
blast2.clashed = true
blast2.setSpeed(0)
this.setSpeed(0)
blast2.active = false
this.active = false
//this.fx.setScale(endScale+ 1)
//blast2.fx.setScale(endScale+ 1)
doPeriodically(.25, (CallbackPeriodic cb) -> begin
Fx effect1 = new Fx(fx.getPos2(),this.targetAngle, iceNova)
..setScale(1.8)
..setZ(100)
..setZAngle(-5200)
Fx effect2 = new Fx(blast2.fx.getPos2(),this.targetAngle, iceNova)
..setScale(1.8)
..setZ(100)
..setZAngle(-5200)
Fx effect5 = new Fx(((fx.getPos2() + blast2.fx.getPos2()) *.5).toVec3().addReals(0, 0, 50), this.targetAngle, sparklyExplosion)
..setScale(5)
doAfter(.25, () -> begin
destroy(effect1)
destroy(effect2)
destroy(effect5)
end)
if this.u.getMana() == 0
winner2 = true
if blast2.u.getMana() == 0
winner1 = true
this.u.setMana(u.getMana()-1)
blast2.u.setMana(blast2.u.getMana()-2)
if winner1
print(this.u.getName())
blast2.terminate()
this.target = blast2.u.getPos3()
this.setSpeed(this.speed)
this.active = true
destroy cb
if winner2 and not winner1
print(blast2.u.getName())
terminate()
blast2.target = this.u.getPos3()
blast2.setSpeed(blast2.speed)
blast2.active = true
destroy cb
end)
ondestroy
if this.channeling
this.u.unpause()
Fx final = new Fx(fx.getPos3d(), this.targetAngle, finalSFX)
final.setScale(2)
doAfter(destroyExplode, () -> final.hiddenDestroy())
for i = 0 to (this.trailList.getSize() -1)
this.trailList.get(i).hiddenDestroy()
this.done = true
package Kamehameha
import Constants
import TimedBlasts
constant real originalScale = .2
public class Kamehameha extends TimedBlasts
construct(unit actor,vec3 pos, player owner, vec3 target, int level)
super(actor,pos.addReals(0, 0, 50),owner,target,bigKamehamehaBall,originalScale)
//if (actor.getTypeId() == 'H001')
this.impactAoe = 500
this.damage = 150*level.toReal() + (GetHeroInt(actor, true)*10)
this.trailOn = true
this.dustOn = true
this.pulseOn = true
this.launchOn = true
int actorID = actor.getTypeId()
if actorID == 'H000'
this.channelIndex = 11
this.launchIndex = 12
this.throwSound = gg_snd_Kamehameha_Voice
if actorID == 'H005' or actorID == 'H009'
this.channelIndex = 20
this.launchIndex = 18
if actorID == 'H00A'
this.channelIndex = 5
this.launchIndex = 4
if actorID == 'H001' or actorID == 'H008'
this.channelIndex = 7
this.launchIndex = 8
this.throwSound = gg_snd_GohanKame
if actorID == 'H00D' or actorID == 'H00E' or actorID == 'H00F'
this.channelIndex = 8
this.launchIndex = 12
if actorID == 'H007'
this.channelIndex = 9
this.launchIndex = 13
if actorID == 'H00G'
this.channelIndex = 12
this.launchIndex = 11
this.speed = 32
this.endScale = .6
this.trailSFX = bigKamehamehaBall
this.trailSize = .3
this.pulseSFX = bluePulse
this.launchSFX = kameLaunch
this.launchSize = 5
this.finalSFX = bigBlueExplosion
this.pulseSize = 1
this.trailCol = colorA(255,255,255,255)
this.clashing = true
this.channeling = true
startMissile()
package AngryKame
import Constants
import TimedBlasts
import ClosureTimers
constant real originalScale = .2
public class AngryKame extends TimedBlasts
construct(unit actor,vec3 pos, player owner, vec3 target, int level)
super(actor,pos.addReals(0, 0, 700),owner,target,dummy2,originalScale)
this.impactAoe = 500
actor.setFlyHeight(700, 700.)
this.flightOn = true
this.dropOn = true
this.offsetDistance = 0
this.missileCol = colorA(150,150,0,255)
this.speed = 25
this.endScale = 1.5
this.dustSFX = dustWave
this.damage = 5000*level.toReal() + (GetHeroInt(actor, true)*20)
this.finalSFX = nuclearExplosion
this.trailOn = true
this.dustOn = true
this.pulseOn = true
this.launchOn = false
this.channelIndex = 20
this.launchIndex = 10
this.trailSFX = pinkBall
this.trailSize = .6
this.launchSFX = kameLaunch
this.launchSize = 5
this.trailCol = colorA(150,150,0,255)
this.lowerRate = 300.
this.realDropSpeed = -25
this.destroyExplode = 3
this.pulseSFX = windBlue
this.pulseSize = 1.2
this.pulseCol = colorA(150,150,0,255)
effect x = AddSpecialEffectTarget(kamelightning, u, "origin")
doAfter(1.5, () -> begin
doAfter(1, () -> begin
PlaySoundOnUnitBJ(gg_snd_angrykame, 70, this.u)
end)
startMissile()
fx.setFx(pinkBall)
end)
doAfter(12, () -> begin
DestroyEffectBJ(x)
end)