Frozenhelfir
set Gwypaas = Guhveepaws
- Reaction score
- 56
I wanted to experiment with cJass by making a useful spell. This chain spell template is currently setup to work much like chain lightning, where it bounces amongst the closest enemies. The bouncing mechanism isn't very modular except for the filter, but I can change this if requested. The cool part about this spell, is that you can easily specify what you want it to do in the jumpTo method. The jumpTo method can do any action to the next target and the previous one, such as creating a lightning effect between them (this part is commented out in the code, but it is there in a sample). This also stores the caster in this.caster, so you can have the caster deal damage, steal mana, or heal them. Do whatever, it is a template , making it a Good Idea™
JASS:
/*
This is a chain spell template by Frozenhelfire
Requires cJass: <a href="http://www.thehelper.net/forums/showthread.php?t=137979" class="link link--internal">http://www.thehelper.net/forums/showthread.php?t=137979</a>
Requires KT by Jesus4Lyf, download from: <a href="http://www.thehelper.net/forums/showthread.php?t=78392" class="link link--internal">http://www.thehelper.net/forums/showthread.php?t=78392</a>
Requires Recycle by Nestharus, download from: <a href="http://www.thehelper.net/forums/showthread.php?t=136087" class="link link--internal">http://www.thehelper.net/forums/showthread.php?t=136087</a>
Sample code has a commented line that uses TL by Flare, download from: <a href="http://www.thehelper.net/forums/showthread.php?t=92877" class="link link--internal">http://www.thehelper.net/forums/showthread.php?t=92877</a>
This spell is made to be casted on a unit, then it will bounce to the next closest unit.
Each bounce performs the actions in the .jumpTo method
private bool Filt() decides what units it can bounce to. At default settings, it will only bounce to
enemies of the casting unit that are alive and not a structure.
*/
include "cj_types.j"
include "cj_typesEx.j"
include "cj_types_priv.j"
include "cj_typesEx_priv.j"
library ChainTemplate initializer init uses KT /*, TL , TT*/{
define{
private NUMBER_OF_BOUNCES = 10 //this bounces 10 times, not 11, changeable in the create method
private SPELL_ID = 039;AHbn039; //Change this to the rawcode of your dummy spell
private BOUNCE_RANGE = 500
private PERIOD = 0.10 //Time between bounces
}
private player FILTER_PLAYER //This is used in the filter, if you only want the spell to hit enemies or allies of the casting player
private real x1, y1, x2, y2, DISTANCE = BOUNCE_RANGE * BOUNCE_RANGE
private boolexpr filterFunction
private bool Filt(){ //Sample Filter, checks if unit is enemy of caster and not a structure and not dead
//This impersonates a standard chain lightning, but the filter can be changed to do other things
return IsUnitEnemy(GetFilterUnit(),FILTER_PLAYER) && !IsUnitType(GetFilterUnit(),UNIT_TYPE_STRUCTURE) && GetWidgetLife(GetFilterUnit()) > .405
}
struct ChainTemplate{
void jumpTo(unit target /*unit the spell is jumping to*/){
/*this.u is the unit the spell is jumping from
this.caster is the caster of the spell
Any actions in here happen every jump*/
//TL_Unit("CLPB", this.u, target, 1, false, 1, 1) // If you have FLARE's Timed Lightning system...
//you can uncomment the line above to see the actual jumps.
//TL can be gotten from:
this.bounces += 1 //jumping to a new unit, so add 1 to bounces.
this.u = target //stores the target for the next bounce (comparing unit distances)
GroupAddUnit(this.immune,target)
}
int bounces, maxBounces
group immune
unit caster, u
player castingPlayer
static thistype create(unit caster, unit target){
thistype D = thistype.allocate()
D.bounces = 0
D.maxBounces = NUMBER_OF_BOUNCES
D.caster = caster
D.u = caster
D.immune = CreateGroup()
D.jumpTo(target)
D.castingPlayer = GetOwningPlayer(caster)
return D
}
/*private static thistype create(unit caster, unit target, int abilLevel){
thistype D = thistype.allocate()
D.bounces = 0
D.maxBounces = abilLevel * 2//By default, bounces 2x the ability level
D.caster = caster
D.u = caster
D.immune = Group.get()
D.jumpTo(target)
D.castingPlayer = GetOwningPlayer(caster)
return D
}*/
void onDestroy(){
DestroyGroup(this.immune)
this.immune = null
this.caster = null
this.u = null
}
}
private bool Cond(){
return GetSpellAbilityId() == SPELL_ID
}
group g = CreateGroup()
private bool TimerCallback(){
ChainTemplate D = KT_GetData()
unit u = null
unit t = null
DISTANCE = BOUNCE_RANGE * BOUNCE_RANGE
FILTER_PLAYER = D.castingPlayer
x1 = GetUnitX(D.u)
y1 = GetUnitY(D.u)
GroupEnumUnitsInRange(g,x1,y1,BOUNCE_RANGE,filterFunction)
loop{
u = FirstOfGroup(g)
exitwhen u == null
if (IsUnitInGroup(u,D.immune) == false) {
x2 = GetUnitX(u) - x1
y2 = GetUnitY(u) - y1
if (x2*x2 + y2*y2 < DISTANCE) {
DISTANCE = x2*x2 + y2*y2
t = u
}
}
GroupRemoveUnit(g,u)
}
if (t == null) { //if there is no unit to jump to, end the spell
u = null
t = null
D.destroy()
return true
}
D.jumpTo(t)
u = null
t = null
if (D.bounces >= D.maxBounces) { //max bounces reached, end the spell.
D.destroy()
return true
}
return false
}
private void Act(){
ChainTemplate D = ChainTemplate.create(GetTriggerUnit(),GetSpellTargetUnit())
//ChainTemplate D = ChainTemplate.create(GetTriggerUnit(),GetSpellTargetUnit(), GetUnitAbilityLevel(GetTriggerUnit(),SPELL_ID))
//uncomment the line above if using the ability level
KT_Add(function TimerCallback,D, PERIOD)
}
private void init(){
trigger t = CreateTrigger()
int i = 0
filterFunction = Condition(function Filt)
loop {
TriggerRegisterPlayerUnitEvent(t,Player(i),EVENT_PLAYER_UNIT_SPELL_EFFECT,null)
exitwhen i >= 11
i += 1
}
TriggerAddCondition(t,Condition(function Cond))
TriggerAddAction(t,function Act)
}
}
Updated the code a bit, here's a test map for anyone who wants to see it in action. Learn banish, 0 mana, 0 cd, 0 casting time, 0 casting animation on the bloodmage. Spam it as much as you'd like. The other skills do nothing.