/* 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()) < 120120 //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) < (120120) //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)