Name | Type | is_array | initial_value |
TempLoc | location | No |
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_Init_Actions takes nothing returns nothing
call FogEnable(false)
call FogMaskEnable(false)
endfunction
//===========================================================================
function InitTrig_Init takes nothing returns nothing
set gg_trg_Init = CreateTrigger( )
call TriggerAddAction( gg_trg_Init, function Trig_Init_Actions )
endfunction
//TESH.scrollpos=22
//TESH.alwaysfold=0
library_once TimerUtils initializer init
//*********************************************************************
//* TimerUtils (Blue flavor for 1.23b or later)
//* ----------
//*
//* To implement it , create a custom text trigger called TimerUtils
//* and paste the contents of this script there.
//*
//* To copy from a map to another, copy the trigger holding this
//* library to your map.
//*
//* (requires vJass) More scripts: htt://www.wc3campaigns.net
//*
//* For your timer needs:
//* * Attaching
//* * Recycling (with double-free protection)
//*
//* set t=NewTimer() : Get a timer (alternative to CreateTimer)
//* ReleaseTimer(t) : Relese a timer (alt to DestroyTimer)
//* SetTimerData(t,2) : Attach value 2 to timer
//* GetTimerData(t) : Get the timer's value.
//* You can assume a timer's value is 0
//* after NewTimer.
//*
//* Blue Flavor: Slower than the red flavor, it got a 408000 handle id
//* limit, which means that if more than 408000 handle ids
//* are used in your map, TimerUtils might fail, this
//* value is quite big and it is much bigger than the
//* timer limit in Red flavor.
//*
//********************************************************************
//==================================================================================================
globals
private hashtable hasht //I <3 blizz
endglobals
//It is dependent on jasshelper's recent inlining optimization in order to perform correctly.
function SetTimerData takes timer t, integer value returns nothing
call SaveInteger(hasht,0, GetHandleId(t), value)
endfunction
function GetTimerData takes timer t returns integer
return LoadInteger(hasht, 0, GetHandleId(t))
endfunction
//==========================================================================================
globals
private timer array tT
private integer tN = 0
private constant integer HELD=0x28829022
//use a totally random number here, the more improbable someone uses it, the better.
endglobals
//==========================================================================================
function NewTimer takes nothing returns timer
if (tN==0) then
set tT[0]=CreateTimer()
else
set tN=tN-1
endif
call SetTimerData(tT[tN],0)
return tT[tN]
endfunction
//==========================================================================================
function ReleaseTimer takes timer t returns nothing
if(t==null) then
debug call BJDebugMsg("Warning: attempt to release a null timer")
return
endif
if (tN==8191) then
debug call BJDebugMsg("Warning: Timer stack is full, destroying timer!!")
//stack is full, the map already has much more troubles than the chance of bug
call DestroyTimer(t)
else
call PauseTimer(t)
if(GetTimerData(t)==HELD) then
debug call BJDebugMsg("Warning: ReleaseTimer: Double free!")
return
endif
call SetTimerData(t,HELD)
set tT[tN]=t
set tN=tN+1
endif
endfunction
private function init takes nothing returns nothing
set hasht = InitHashtable()
endfunction
endlibrary
//TESH.scrollpos=135
//TESH.alwaysfold=0
// ||-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-||
// || ||
// || Knockback System v1.3a ||
// || By Dynasti ||
// || ||
// ||-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-||
// || Members of the Struct Data ||
// ||-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-||
// || ||
// || u - The unit that is being draged. ||
// || v - The Velocity the unit is traveling in ||
// || vd - The Velocity decreasement ||
// || cos - The Cos value for the angle. ||
// || sin - The Sin value for the angle. ||
// || r - A real value used to kill destructables within a desired range ||
// || s - A String used to call an effect. ||
// || e - Effect that is used for a trail effect. ||
// || i - Real used to count up the time between effects( Only used if the parameter "real EffectSpawn" ||
// || is greater than 0 ||
// || er - Integer used to tell the system when to create the effect, read below to understand more of it.||
// || p - A boolean used to determine if you want the unit to be paused or not while beign knocked ||
// || nX - A Static value used for handling the unit ' u 's X. ||
// || nY - A Static value used for handling the unit ' u 's Y. ||
// || R - A Static rect used to kill nearby destructables ||
// || ||
// ||-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-||
// || Global Memebers ||
// ||-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-||
// || ||
// || FPS(40) - A constant value used for the looping function, Lower values = Less lag. ||
// || EffectRandom(4) - A constant value used for creating the trail effects. Higher numbers will result in ||
// || higher randomness of effects.(This does only apply if you want a random effectspawn ||
// || Index - An integer array used for an indexing system. ||
// || Total - An integer used for an indexing system. ||
// || Tim - A Timer used for the looping action. ||
// || MAX_X - A Real used for checking if the knocked unit gets off bounds. ||
// || MAX_Y - A Real used for checking if the knocked unit gets off bounds. ||
// || MIN_X - A Real used for checking if the knocked unit gets off bounds. ||
// || MIN_Y - A Real used for checking if the knocked unit gets off bounds. ||
// || ||
// ||-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-||
// || Tips'n tricks ||
// ||-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-||
// || ||
// || 1. - If you dont want any trees/destructables to be destroyed in it's path then call the radius with 0 ||
// || ||
// || 2. - On the call you need one integer called EffectInt and 2 strings called Effect and EffectAttach, If ||
// || want a looping effect( an effect that is spawned at each interval ) then you do the call with the ||
// || EffectInt being '1' and the Effect being "YourEffect" and dont forget to set the EffectAttach to "".||
// || If you want a constant effect that stays on the unit untill the end of the knockback, do the call ||
// || with the EffectInt being '2' and the Effect being "YourEffect" and for the EffectAttach being ||
// || "YourEffectAttach". ||
// || If you want both at the same time you call with EffectInt being '3'. ||
// || ||
// || 3. - As i have experienced there are times when you need to pause the unit while knocking it and ||
// || sometimes not. That is why i have added a boolean to the call, called Pause. ||
// || It is really simple, just set it to false if you dont want the knocked unit to be paused and false ||
// || for not. ||
// || ||
// ||-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-||
// || The Call ||
// ||-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-||
// || ||
// || KnockbackEx function: ||
// || - unit Unit : The unit being knocked. ||
// || - real Distance : The distance the knoced unit is going to travlel. ||
// || - real RadAngle : The angle the knocked unit is being knocked( In Radians ). ||
// || - real Time : The time it takes to knock the unit. ||
// || - real Radius : The radius to kill nearby destructables( for example trees ) on collision. ||
// || - boolean Pause : If you want the knocked unit to be paused while knocked then call it with true. ||
// || - real EffectSpawn : This determines if you want the effect spawning to be random or not. ||
// || Set it to ' 0 ' for random spawning of effect. Else if it is greater than ||
// || ' 0 ' then the effect will be created every "EffectSpawn" interval. ||
// || Lets say it is set to ' 0.25 ', then the effect will be created ||
// || every 0.25 secs of knockback time. ||
// || - integer EffectInt : The effect integer( read above for more info ). ||
// || - string Effect : The path of the effect( read above for more info ). ||
// || - string EffectAttach : The path for the attaching of the Effect( read above for more info ). ||
// || ||
// || Knockback function( Good for less complicated knockbacks): ||
// || - unit Unit : The unit being knocked. ||
// || - real Distance : The distance the knoced unit is going to travlel. ||
// || - real RadAngle : The angle the knocked unit is being knocked( In Radians ). ||
// || - real Time : The time it takes to knock the unit. ||
// || - boolean Pause : If you want the knocked unit to be paused while knocked then call it with true. ||
// ||-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-||
library Knockback initializer Init
globals
private constant integer FPS = 40 // Higher than 40 may cause lags. Because 40 fps is 0.025 interval and 60 is 0.01.
private constant integer EffectRandom = 4 // 4 is 25% chance of the effect spawning( Looping effect )
private integer array Index
private integer Total = 0
private timer Tim = CreateTimer()
private real MAX_X
private real MAX_Y
private real MIN_X
private real MIN_Y
private boolexpr FilterDestructables
private real Interval
endglobals
private function DestructableFilter takes nothing returns boolean
local destructable d = GetFilterDestructable()
if GetWidgetLife(d) > .405 and not IsDestructableInvulnerable(d) then
call KillDestructable(d)
endif
set d = null
return false
endfunction
private keyword Data // If not here then the loop cannot be put over the struct( Why is because the struct needs the function for the timer )
private function Loop takes nothing returns nothing
local Data dat
local integer i=0
loop
exitwhen i >= Total
set dat = Index[i]
if dat.v <= 0 then
if dat.s != "" and dat.s != null then
if dat.e != null then
call DestroyEffect(dat.e)
set dat.e = null
endif
set dat.s = null
elseif dat.e != null then
call DestroyEffect(dat.e)
set dat.e = null
endif
if dat.p then
call PauseUnit(dat.u, false)
set dat.p = false
endif
call SetUnitPosition(dat.u, GetUnitX(dat.u), GetUnitY(dat.u))
set dat.u = null
call dat.destroy()
set Total = Total - 1
set Index[i] = Index[Total]
set i = i - 1
else
set dat.nX = GetUnitX(dat.u) + dat.v * dat.cos
set dat.nY = GetUnitY(dat.u) + dat.v * dat.sin
if dat.nX < MAX_X and dat.nY < MAX_Y and dat.nX > MIN_X and dat.nY > MIN_Y and GetWidgetLife(dat.u) > .405 then
call SetUnitX(dat.u, dat.nX)
call SetUnitY(dat.u, dat.nY)
if dat.r > 0 then // If the member ' r ' is greater than 0 it will destroy destructables in a desired range
set dat.R = Rect(dat.nX - dat.r, dat.nY - dat.r, dat.nX + dat.r, dat.nY + dat.r)
call EnumDestructablesInRect(dat.R, FilterDestructables, null)
endif
if dat.s != "" and dat.s != null then
if dat.er == 0 then
if GetRandomInt(1, EffectRandom) == EffectRandom then // Here is where the global random integer is used
call DestroyEffect(AddSpecialEffect(dat.s, dat.nX, dat.nY))
endif
elseif dat.i >= dat.er then
call DestroyEffect(AddSpecialEffect(dat.s, dat.nX, dat.nY))
set dat.i = 0
else
set dat.i = dat.i + Interval
endif
endif
set dat.v = dat.v - dat.vd
else
set dat.v = 0
endif
endif
set i = i + 1
endloop
if Total == 0 then
call PauseTimer(Tim)
endif
endfunction
private struct Data
unit u
real v = 0
real vd
real cos
real sin
real r = 0
string s
effect e
real i = 0
real er = 0
boolean p
static real nX
static real nY
static rect R = Rect(0,0,0,0)
static method Start takes unit u, real d, real a, integer t, real r, boolean p, real er, integer i, string s, string s2 returns nothing
local Data dat = Data.allocate()
set dat.u = u
set dat.er = er
set dat.v = 2*d / (t + 1)
set dat.vd = dat.v / t
set dat.cos = Cos(a)
set dat.sin = Sin(a)
if s != "" and s != null then
if i == 1 then
set dat.s = s
elseif i == 2 then
set dat.e = AddSpecialEffectTarget(s, u, s2)
elseif i == 3 then
set dat.s = s
set dat.e = AddSpecialEffectTarget(s, u, s2)
endif
endif
if p then
call PauseUnit(u, true)
set dat.p = p
endif
if r > 0 then
set dat.r = r
endif
if Total == 0 then
call TimerStart(Tim, Interval, true, function Loop)
endif
set Index[Total] = dat
set Total = Total + 1
endmethod
endstruct
function KnockbackEx takes unit Unit, real Distance, real RadAngle, real Time, real Radius, boolean Pause, real EffectSpawn, integer EffectInt, string Effect, string EffectAttach returns nothing
call Data.Start(Unit, Distance, RadAngle, R2I(Time / Interval), Radius, Pause, EffectSpawn, EffectInt, Effect, EffectAttach)
endfunction
function Knockback takes unit Unit, real Distance, real RadAngle, real Time, boolean Pause returns nothing
call Data.Start(Unit, Distance, RadAngle, R2I(Time / Interval), 0, Pause, 0, 0, "", "")
endfunction
private function Init takes nothing returns nothing
set MAX_X = GetRectMaxX(bj_mapInitialPlayableArea)
set MAX_Y = GetRectMaxY(bj_mapInitialPlayableArea)
set MIN_X = GetRectMinX(bj_mapInitialPlayableArea)
set MIN_Y = GetRectMinY(bj_mapInitialPlayableArea)
set FilterDestructables = Condition(function DestructableFilter)
set Interval = (1.0 / FPS)
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope BoulderSwing initializer Init
//*************************************************//
// USER INIT //
// //
// MODIFY THESE CONSTANTS AND FUNCTIONS FOR YOUR //
// OWN USE //
//*************************************************//
globals
//The rawcode for the spell in the object editor. Obtain by pressing CTRL+D and
//looking at the 4 letters before the colon ( : ) in the name of the ability
private constant integer ABIL_ID = 'A000'
//The size of the boulder. This affects the amount of units it can hit.
//WARNING: Setting this to a very low number could make the spell never hit
//anything.
private constant real BOULDER_SIZE = 64.00
//The distance the parts of the chain attaching the boulder to the hero are
//from each other. If in doubt, leave it at 25. WARNING: the smaller this
// number is the more lag this spell may cause. Setting it to 0 will cause
//the spell not to work and maybe even crash the map.
private constant real CHAIN_PART_LENGTH = 25.00
//The total length of the chain attaching the boulder to the hero, AKA the area
//of effect of the spell. Raising this number without raising the
//CHAIN_PART_DISTANCE constant could cause lag.
private constant real CHAIN_LENGTH = 200.00
//The height of the dummies off the ground. Note that this does not effect the
//targets it can hit.
private constant real DUMMY_HEIGHT = 43.84534345734
//Set this to CHAIN_LENGTH / CHAIN_PART_LENGTH (rounded down)
private constant integer CHAIN_NUM = 8
//The attack type of the damage, affects what it can hit
private constant attacktype ATTACK_TYPE = ATTACK_TYPE_NORMAL
//The damage type of the damage, affects how much damage it does
private constant damagetype DAMAGE_TYPE = DAMAGE_TYPE_NORMAL
//The weapon type of the damage, affects the sound upon damage
private constant weapontype WEAPON_TYPE = WEAPON_TYPE_ROCK_HEAVY_BASH
endglobals
//The amount of damage the boulder does when it hits a unit based on the level of the
//ability.
private function Damage takes integer level returns real
return 10.00 * level
endfunction
//How long the spell lasts based on the level of the ability
private function Duration takes integer level returns real
return 10.00 * level
endfunction
//How fast the boulder spins round the hero in degrees per second based on the level of
//the ability.
private function Speed takes integer level returns real
return 120.00 * level
endfunction
//The distance units hit by the boulder are knocked back based on the level of the
//ability.
private function KnockbackDist takes integer level returns real
return Speed(level) / 2
endfunction
//The speed at which units are knocked back in seconds
private function KnockbackSpeed takes integer level returns real
return KnockbackDist(level) / Speed(1) / 3
endfunction
//*************************************************//
// END USER INIT //
//*************************************************//
private function Debug takes string msg returns nothing
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0.00, 0.00, 60.00, "|cffff0000Boulder Swing:|r "+msg)
endfunction
private keyword BoulderSwing
globals
private constant integer DUMMY_BOULDER = 'BSd1'
private constant integer DUMMY_CHAIN = 'BSd2'
private constant real TIMER_INTERVAL = 0.035
private timer tim = CreateTimer()
private BoulderSwing array Swingers
private integer Index = 0
private location TempLoc = Location(0.00, 0.00)
private boolexpr Boolexpr
private group EnumGroup = CreateGroup()
private real TempKnd = 0.
private real TempAngle = 0.
private real TempKns = 0.
private unit TempCaster = null
private real TempDmg = 0.
private BoulderSwing This
endglobals
private function EnumFilter takes nothing returns boolean
local unit u = GetFilterUnit()
if not IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE) then
call Knockback(u, This.knd, This.angle, This.kns, false)
if IsPlayerEnemy(GetOwningPlayer(u), GetOwningPlayer(This.caster)) then
call UnitDamageTarget(This.caster, u, This.dmg, false, true, ATTACK_TYPE, DAMAGE_TYPE, WEAPON_TYPE)
endif
endif
return false
endfunction
private function Execute takes nothing returns nothing
local integer i = 0
local integer j
local real dist = 0.00
local real cos
local real sin
local real x
local real y
local real x2
local real y2
local real height
local unit u
local real angle
loop
exitwhen i >= Index
set This = Swingers[i]
set This.angle = This.angle + This.spd
set cos = Cos(This.angle)
set sin = Sin(This.angle)
set x = GetUnitX(This.caster)
set y = GetUnitY(This.caster)
call MoveLocation(TempLoc, x, y)
set height = GetLocationZ(TempLoc)
set j = 0
loop
set dist = dist + CHAIN_PART_LENGTH
exitwhen j >= CHAIN_NUM
set x2 = x + dist * cos
set y2 = y + dist * sin
call SetUnitX(This.chain[j], x2)
call SetUnitY(This.chain[j], y2)
call MoveLocation(TempLoc, x2, y2)
call SetUnitFlyHeight(This.chain[j], DUMMY_HEIGHT - GetLocationZ(TempLoc) + height, 0.00)
set j = j + 1
endloop
set x2 = x + dist * cos
set y2 = y + dist * sin
call SetUnitX(This.boulder, x2)
call SetUnitY(This.boulder, y2)
call MoveLocation(TempLoc, x2, y2)
call SetUnitFlyHeight(This.boulder, DUMMY_HEIGHT - GetLocationZ(TempLoc) + height, 0.00)
call GroupEnumUnitsInRange(EnumGroup, x2, y2, BOULDER_SIZE, Boolexpr)
set i = i + 1
endloop
endfunction
private function SpellFinished takes nothing returns nothing
local timer t = GetExpiredTimer()
local BoulderSwing this = GetTimerData(t)
call this.destroy()
call ReleaseTimer(t)
set t = null
endfunction
private struct BoulderSwing
unit caster
real dmg
real spd
real knd
real kns
real angle
unit array chain [CHAIN_NUM]
unit boulder
timer tim
integer ID
static method create takes unit caster, integer level returns BoulderSwing
local BoulderSwing this = BoulderSwing.allocate()
local real dist = CHAIN_PART_LENGTH
local unit u
local player id = GetOwningPlayer(caster)
local real angle = GetUnitFacing(caster)
local real cos = Cos(angle * bj_DEGTORAD)
local real sin = Sin(angle * bj_DEGTORAD)
local real casterX = GetUnitX(caster)
local real casterY = GetUnitY(caster)
local real x
local real y
local real height
local integer i = 0
set this.caster = caster
set this.dmg = Damage(level)
set this.spd = Speed(level) * TIMER_INTERVAL * bj_DEGTORAD
set this.knd = KnockbackDist(level)
set this.kns = KnockbackSpeed(level)
set this.angle = angle * bj_DEGTORAD
call MoveLocation(TempLoc, casterX, casterY)
set height = GetLocationZ(TempLoc)
loop
exitwhen dist >= CHAIN_LENGTH
set x = casterX + dist * cos
set y = casterY + dist * sin
set this.chain[i] = CreateUnit(id, DUMMY_CHAIN, x, y, angle)
call SetUnitTimeScale(this.chain[i], 0.00)
call MoveLocation(TempLoc, x, y)
call SetUnitFlyHeight(this.chain[i], DUMMY_HEIGHT - GetLocationZ(TempLoc) + height, 0.00)
set i = i + 1
set dist = dist + CHAIN_PART_LENGTH
endloop
debug if CHAIN_NUM != i+1 then
debug call Debug("You have set CHAIN_NUM wrong! Please set it to " + I2S(i+1))
debug endif
set x = casterX + (dist + CHAIN_PART_LENGTH) * cos
set y = casterY + (dist + CHAIN_PART_LENGTH) * sin
set this.boulder = CreateUnit(id, DUMMY_BOULDER, x, y, angle)
call SetUnitTimeScale(this.boulder, 0.00)
call MoveLocation(TempLoc, x, y)
call SetUnitFlyHeight(this.boulder, DUMMY_HEIGHT - GetLocationZ(TempLoc) + height, 0.00)
set this.tim = NewTimer()
call SetTimerData(this.tim, this)
call TimerStart(this.tim, Duration(level), false, function SpellFinished)
set this.ID = Index
set Swingers[Index] = this
set Index = Index + 1
if this.ID == 0 then
call TimerStart(tim, TIMER_INTERVAL, true, function Execute)
endif
set u = null
set id = null
return this
endmethod
method onDestroy takes nothing returns nothing
local integer i = 0
loop
exitwhen i >= CHAIN_NUM
call RemoveUnit(this.chain[i])
set i = i + 1
endloop
call RemoveUnit(.boulder)
set Index = Index - 1
set Swingers[this.ID] = Swingers[Index]
set Swingers[this.ID].ID = this.ID
if Index == 0 then
call PauseTimer(tim)
endif
endmethod
endstruct
private function Conditions takes nothing returns boolean
return GetSpellAbilityId() == ABIL_ID
endfunction
private function Actions takes nothing returns nothing
call BoulderSwing.create(GetTriggerUnit(), GetUnitAbilityLevel(GetTriggerUnit(), ABIL_ID))
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, Condition(function Conditions))
call TriggerAddAction(t, function Actions)
set Boolexpr = Filter(function EnumFilter)
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
'Spell: Boulder Swing
'Importation Instructions
1. Create the ability in the object manager. If in doubt, just copy mine.
2. Give the ability to your hero (or unit)
3. Copy the trigger "Create Units" to your map, enable it, and save the map. This will create
the dummy units used by the spell. You must reload the map before the dummy units will
show in the Object Editor
4. Delete the trigger "Create Units" from your map. Its work is done.
5. Feel free to change the model files / scale / colour of the dummy units, but leave all
other values as they are.
6. Copy the trigger folder "Boulder Swing" to your map.
7. In the trigger "User Init" make sure you change the constant integer ABIL_ID to the rawcode
of your own spell. Read the instructions above it if you need to know how to get the rawcode
of an ability
8. Change any the values or functions in "User Init" to whatever you like. Be sure to read the
instructions above each value or function! Also, if you change CHAIN_PART_LENGTH or
CHAIN_LENGTH, be sure to change CHAIN_NUM as well!
//TESH.scrollpos=0
//TESH.alwaysfold=0
-Vexorian: TimerUtils
-Dynasti: Knockback System
//TESH.scrollpos=0
//TESH.alwaysfold=0
//These external commands make use if JassNewGenPack v5c's extension - the Object Merger. They
//create the dummy units necessary for the spell.
//! external ObjectMerger w3u ewsp BSd1 uico "" umdl "Abilities\Weapons\MakuraMissile\MakuraMissile.mdl" umvt fly unam "BoulderSwing Dummy" unsf "(Boulder)" ufoo 0 uclr 0 uclg 0 uclb 0 uabi Aloc,Avul usca 5 ushu "" ucol 0 usid 0 usin 0 urac other uspe 1 utyp "" uhhd 1 uhhb 1 uhhm 1
//! external ObjectMerger w3u ewsp BSd2 uico "" umdl "Abilities\Weapons\GlaiveMissile\GlaiveMissile.mdl" umvt fly unam "BoulderSwing Dummy" unsf "(Chain)" ufoo 0 uclr 0 uclg 0 uclb 0 uabi Aloc,Avul usca 0.2 ushu "" ucol 0 usid 0 usin 0 urac other uspe 1 utyp "" uhhd 1 uhhb 1 uhhm 1