scope Torrent
/*
Requires Status, T32, TimerUtils, AutoFly
Thus Status requires AIDS and DummyCaster as well.
*Torrent v1.1d by baassee
Description:
Using his unparalleled knowledge of the sea,
Kunkka is able to summon a blast of water at
a targeted area. After 2 seconds a fierce
torrent of water erupts from the ground, the
stream blasting enemies caught in the AoE into
the sky and dealing damage.
Level 1 - 120 damage.
Level 2 - 180 damage.
Level 3 - 240 damage.
Level 4 - 300 damage.
*FAQ about code
The code contains two structs, one for just the initial delay of two seocnds
and the second for the actual eruption.
I used GT as I am used to it.
I used Status because it's the best out there at the moment.
I used AutoFly(Aids Version) because I had AIDS already with Status
I recommend though using UnitIndexer by Nestharus with the AIDS BC
Can be found at this link below:
http://www.hiveworkshop.com/forums/jass-functions-413/system-unit-indexer-172090/
Yes I didn't want the spell to stack with itself because it would have looked ridiculous with the height changes.
And I was lazy so that's the reason behind the stackgroup.
Typical parabola function, first made by Moyack and Spec(?) anyway it's way too common to be credited.
And there are two boolean constants
one for pausing or not pausing (will stun if not paused)
second for preloading or not preloading
*Information
Yes this spell is based on DotA's Admiral's Torrent spell. It's exactly the same except
the slowing part and the height (couldn't find the maximum height at playdota).
Also added an option to pause or not pause the units thrown up in the air.
I cannot use any custom icon although I recommend using this icon:
http://www.hiveworkshop.com/forums/icons-541/btntorrent-162809/?prev=search%3Dtorrent%26d%3Dlist%26r%3D20
The TidalEruption model was found in a spellpack by RMX, no credits were actually given in that spellpack
thus I don't know who's the author of the model but it's not mine.
*Credits
*Status, AIDS, T32, GTrigger, DummyCaster - Jesus4Lyf
*TimerUtils - Vexorian
*GroupUtils - Rising_Dusk
*Autofly - Azlier
*TidalEruption model - Unknown Author
Also remember to give me credits if the spell is used along with the authors above.
*How to import
1. Import all required Libraries and create the object data (AIDS, Status, DummyCaster)
2. Copy this code and paste into a trigger or copy the trigger.
3. Copy the ability and change the ABILID to the new id given.
4. Give the spell to a hero, credit me and the authors in the credits section above and enjoy!
*Changelog
v1.0 - Released
v1.1 - Made GTrigger optional along with making SpellEffectEvent optional as well.
- Made Damage optional.
- Made GroupUtils optional.
- Changed Condition into Filter.
v1.1b- Fixed a mistake with optionalizing GT and SpellEffectEvent.
v1.1c- Forgot to static if out GroupEnumUnitsInArea which made it uncompileable.
v1.1d- Removed GetWidgetLife(u) > 0.405 and just because of "I could add this"
I added a FoG loop instead of groupenumeration + filter.
Also made the filter among the configuration functions.
**************************************************************************************************************************
*Configurables
*/
//CONSTANTS
globals
//The abilityid when pasting into the object editor
private constant integer ABILID = 'A000'
//the ground effect that will be on the ground during the 2 seconds delay
private constant string GROUNDEFFECT = "Objects\\Spawnmodels\\Other\\IllidanFootprint\\IllidanWaterSpawnFootPrint.mdl"
//the splash effect when the delay reached 0.
private constant string SPLASHEFFECT = "war3mapImported\\TidalEruption.mdx"
//the attacktype of the damage
private constant attacktype ATT = ATTACK_TYPE_NORMAL
//damagetype of the damage
private constant damagetype DAM = DAMAGE_TYPE_MAGIC
//weapontype of the damage
private constant weapontype WEA = null
//if you want the spell to pause the units or not
//if false then it will stun them instead
private constant boolean PAUSE = false
//preload the specialeffects used?
private constant boolean PRELOAD = true
//don't touch this, it's because it would look stupid without it
//and I'm lazy of course
private group stackgroup = CreateGroup()
endglobals
//FUNCTIONS
//the delay before the eruption
private function GetDelay takes integer lvl returns real
return 2. + lvl * 0.
endfunction
//the aoe of the spell
private function GetAoe takes integer lvl returns real
return 200. + lvl * 0.
endfunction
//the damage dealt
private function GetDmg takes integer lvl returns real
return 60. + 60. * lvl
endfunction
//the duration in the air, taken from playdota.com
private function GetDur takes integer lvl returns real
return 1.53 + lvl*0.
endfunction
//the maximum height the units thrown in the air will reach
//no idea what the original value is
private function GetHei takes integer lvl returns real
return 400. + lvl * 0.
endfunction
private function GetFilter takes unit u, player p returns boolean
return not IsUnitType(u, UNIT_TYPE_DEAD) and/*
*/ IsUnitEnemy(u, p) and/*
*/ not IsUnitInGroup(u, stackgroup) and/*
*/ not IsUnitType(u, UNIT_TYPE_STRUCTURE) and/*
*/ not IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE)
endfunction
// END OF CONFIGURABLES
//standard parabola formula
private function ParabolaZ takes real h, real d, real x returns real
return (4 * h / d) * (d - x) * (x / d)
endfunction
//eruption struct, the struct throwing units in the air
private struct Eruption extends array
unit u //unit in the air
real counter //counter to cheat the parabola function
real dur //duration in the air, cheats the parabola function as maxdistance
real h //maximum height
//recycling variables
static integer ic = 0
static thistype r = 0
thistype rn
//loop method
private method periodic takes nothing returns nothing
set .counter = .counter + T32_PERIOD //increasing "x" in the parabola function
call SetUnitFlyHeight(.u, ParabolaZ(.h, .dur, .counter), 0.) //sets the new flyheight of the unit
if .counter >= .dur then //checks if the spell has ended or not
static if PAUSE then //static if to check if pause is allowed or not
call Status[.u].removePause()
else
call Status[.u].removeStun()
endif
call SetUnitFlyHeight(.u, GetUnitDefaultFlyHeight(.u), 0.) //return to the default flying height
call GroupRemoveUnit(stackgroup, .u) //remove the unit from the stackgroup
call .stopPeriodic()//stop the periodic
set rn = r //recycling structs
set r = this // - || -
endif
endmethod
implement T32x
//create method
static method create takes unit u, real dur, real h returns thistype
local thistype this //dunno what to call it, indexing?
if (r == 0) then
set ic = ic + 1
set this = ic
else
set this = r
set r = r.rn
endif
set .u = u //unit
set .counter = 0. //initializing the counter
set .dur = dur //duration
set .h = h //height
call GroupAddUnit(stackgroup, u)//add the unit to the stackgroup
static if PAUSE then //static if about pausing
call Status[u].addPause()
else
call Status[u].addStun() //else we stun the unit
endif
call .startPeriodic() //fire the periodic (t32)
return this
endmethod
endstruct
//the delay struct
private struct Torrent extends array
unit caster //casting unit
real dmg //dmg
real aoe //aoe
real x //the targetx
real y //the targety
real dur //duration for the eruption struct
real h //height yes we need it here as well
effect eff //special effect on the ground
//recycle variables
static integer ic = 0
static thistype r = 0
thistype rn
static thistype dat //for the filter function
static if not LIBRARY_GroupUtils then
static group ENUM_GROUP = CreateGroup()
endif
static method secondphase takes nothing returns nothing
local timer t = GetExpiredTimer() //track the timer
local thistype this = GetTimerData(t) //get the data
local unit u
call DestroyEffect(.eff) //destroy the effect on the ground
set dat = this //for the filter method
call DestroyEffect(AddSpecialEffect(SPLASHEFFECT, .x, .y)) //create the eruption effect
// just because this is faster...
static if LIBRARY_GroupUtils then
call GroupEnumUnitsInArea(ENUM_GROUP, .x, .y, .aoe, null) //enum
else
call GroupEnumUnitsInRange(ENUM_GROUP, .x, .y, .aoe, null)
endif
loop
set u = FirstOfGroup(ENUM_GROUP)
exitwhen null == u
if GetFilter(u, GetOwningPlayer(.caster)) then
static if LIBRARY_Damage then
call Damage_Spell(.caster, u, .dmg)
else
call UnitDamageTarget(.caster, u, .dmg, false,false, ATT, DAM, WEA)
endif
call Eruption.create(u, .dur, .h)
endif
call GroupRemoveUnit(ENUM_GROUP, u)
endloop
//endfaster
call ReleaseTimer(t) //recycle timer
set t = null //null local
set u = null
//recycle part
set rn = r
set r = this
endmethod
static method create takes nothing returns thistype
local thistype this
local integer lvl = GetUnitAbilityLevel(GetTriggerUnit(), ABILID) //because I want to set it at declaration not after
local timer t = NewTimer() //get timer
local string s = GROUNDEFFECT //local player thingie
if (r == 0) then //indexing part?
set ic = ic + 1
set this = ic
else
set this = r
set r = r.rn
endif
set .caster = GetTriggerUnit() //casting unit
set .dmg = GetDmg(lvl) //dmg
set .aoe = GetAoe(lvl) //aoe
if IsPlayerEnemy(GetLocalPlayer(), GetTriggerPlayer()) then //to make the effect only show for allies
set s = ""
endif
set .x = GetSpellTargetX() //targetx
set .y = GetSpellTargetY() //targety
set .dur = GetDur(lvl) //duration
set .h = GetHei(lvl) //height
set .eff = AddSpecialEffect(s, .x, .y) //create the effect
call SetTimerData(t, this)
call TimerStart(t, GetDelay(lvl), false, function thistype.secondphase) //fire timer with the delay
set t = null //nullling
return this
endmethod
static method condition takes nothing returns boolean
static if not LIBRARY_GT then
static if not LIBRARY_SpellEffectEvent then
if GetSpellAbilityId() == ABILID then
call thistype.create()
endif
else
call thistype.create()
endif
else
call thistype.create()
endif
return false
endmethod
//initializing
private static method onInit takes nothing returns nothing
local trigger t
static if LIBRARY_GT then
call TriggerAddCondition(GT_RegisterStartsEffectEvent(CreateTrigger(), ABILID), Filter(function thistype.condition))
else
static if LIBRARY_SpellEffectEvent then
call RegisterSpellEffectEvent(ABILID, function thistype.condition)
else
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, Filter(function thistype.condition))
set t = null
endif
endif
static if PRELOAD then //to preload or not preload
call Preload(GROUNDEFFECT)
call Preload(SPLASHEFFECT)
endif
endmethod
endstruct //end of story
endscope