//*************************************************************************************
//*************************************************************************************
//*************************************************************************************
//*************************************************************************************
// D E V I L T O R N A D O
// - Spell Create By:
// + Elphis
//*************************************************************************************
library DevilTornadol /*
*/ requires /*
// -*/ DelFX, /* http://www.hiveworkshop.com/forums/spells-569/delfx-delayed-effects-1-4-2-a-116064/?prev=search%3DDel%2520Effect%26d%3Dlist%26r%3D20%26c%3D112
// -*/ AbilityPreload,/* http://www.wc3c.net/showthread.php?t=105279
// -*/ TimerUtils, /* http://www.wc3c.net/showthread.php?t=101322
// -*/ IsTerrainWalkable, /* I can't found this link of the library, so credits by Maker,anitarf
// -*/ SpellEffectEvent, /* http://www.hiveworkshop.com/forums/jass-resources-412/snippet-spelleffectevent-187193/
// -*/ RegisterPlayerUnitEvent /* http://www.hiveworkshop.com/forums/jass-resources-412/snippet-registerplayerunitevent-203338/
// -*/ xedamage /* http://www.wc3c.net/showthread.php?t=101150
// -*/ SimError /* http://www.wc3c.net/showthread.php?t=101260
// -*/ SJS /* Spell Staus Library
// -*/ IsDestructableTree /* Credits by PitzerMike
// -*/ SpecialEffect /* Spell Staus Library */
//*************************************************************************************
//! novjass
// - Spell Information:
// - Instantly calling a powerful tornado hit a ground
// tornado also blow caster too, when it hit a ground
/* the tornado protect all allies of caster in*/400/* range and blow away all enemies inside of it
// and then, it calling more powerful ice rain hit a ground deals
// */10/20/30/40 /*damages, tornado duration in */10/*seconds.*/
//! endnovjass
//
//*************************************************************************************
// - Installation:
// - Import/copy the required libraries and Devil Tornado code to your map
// - Import/copy the custom ability and unit to your map and change the SPELL_ID if needed
// - You may view the raw ID of the objects by pressing CTRL+D in the object editor
// - You may play with the configurables below
//*************************************************************************************
globals
//==================================CONFIGURABLES=============================================//
//Time run every function called
private constant real LOOP_TIMER = 0.031250000
//Jump speed when caster casted ability
private constant real SPEED_JUMPING = 30.
//Scale of Tornado
private constant real TORNADO_MAX_SIZE = 1.5
//Range of protection tornado when enemy come nearly
private constant real MINIMUM_RANGE = 400.
//Speed of mini tornado when it fly around tornado
private constant real TOR_CALLER_SP = 10.
//Duration of Tornado
private constant real TORNADO_LIFE_TIME = 10.
//Mini tornado calling delay
private constant real DELAY_MINI_TOR = 1.5
//Damage radius when mini tornado hit unit
private constant real MINIMUM_DAMAGE_RA = 100.
//Damage per mini tornado slashed unit
private constant real DAMAGE_PER_SLASH = 10.
//Speed of special effect created around tornadol
private constant real DUST_SPEED = 15.
//Height of Special Effect increase every function called
private constant real DUST_HEIGHT_PER_S = 15.
//Max height of Special Effect
private constant real DUST_MAX_HEIGHT = 400.
//Distance of Special Effect around tornado
private constant real DUST_EFFECT = 200.
//Tornado activator range
private constant real ACTIVE_TOR_RANGE = 100.
//Blow unit minimum range
private constant real ENEMY_BLOW_MIN_RA = 300.
//Blow unit maximum range
private constant real ENEMY_BLOCK_RANGE = 800.
//Blow unit speed
private constant real ENEMY_BLOW_SPEED = 30.
//This value is optional, delay nova effect when the rain hit a ground
private constant real NOVA_DELAY = 0.8
//Rain created intevar, if you want more rain fall per seconds, just decrease this value
private constant real RAIN_INTEVAR = 0.1
//Damage when rain hit a ground
private constant real DAMAGE_RAIN_HIT_G = 10.
//Damage radius when rain hit a ground
private constant real RADIUS_RAIN_HIT_G = 200.
//Auto active tornado power when caster can't leap this region
private constant real AUTO_ACTIVE = 1.5
//=======================================================================================
//Rawcode of Spell, change if needed
private constant integer SPELL_ID = 'A000'
//=======================================================================================
//Model of Tornado
private constant string TORNADO_MODEL = "Abilities\\Spells\\Other\\Tornado\\TornadoElementalSmall.mdl"
//Attach the model Tornado on dummy
private constant string ATTACH_MODEL = "origin"
//Effect when mini tornado hit unit
private constant string EFFECT_SLASHED = ""
//Effect blow unit away from circle (start blow)
private constant string BLOW_EFFECT_S = ""
//Effect blow unit away from circle (finish blow)
private constant string BLOW_EFFECT_E = ""
//Displayed messages when you can't caller tornado
private constant string ERROR = "Can't call TORNADO here"
//Special effect around tornado
private constant string EFFECT_ON_TOR = "Abilities\\Spells\\Human\\FlakCannons\\FlakTarget.mdl"
//Effect of the rain fall when tornado calling
private constant string RAIN_EFFECT = "Abilities\\Spells\\Human\\Blizzard\\BlizzardTarget.mdl"
//Effect of nova when rain hit a ground
private constant string NOVA_GROUND = "Abilities\\Spells\\Undead\\FrostNova\\FrostNovaTarget.mdl"
//Special effect when rain hit enemy
private constant string ENEMY_HIT_EFFECT = "Abilities\\Spells\\Undead\\FrostArmor\\FrostArmorDamage.mdl"
//Attach the special effect on enemy
private constant string ENEMY_ATTACH_EFFECT = "chest"
//=======================================================================================
//Allow deals damage to destructable
private constant boolean DAMAGE_TREE = true
//=======================================================================================
private constant attacktype ATTACKTYPE = ATTACK_TYPE_HERO
private constant damagetype DAMAGETYPE = DAMAGE_TYPE_COLD
private constant weapontype WEAPONTYPE = WEAPON_TYPE_METAL_HEAVY_BASH
//==================================NON - CONFIGURABLES=============================================//
private constant group GROUP = CreateGroup()
//==================================CONFIGURABLES=============================================//
endglobals
//
struct DevilTORNADO
//unit
unit u
unit dummy
//real
real h
real ar
real anglez01
real anglez02
real intevar
real targetx
real targety
real atac
boolean fade
boolean ac
effect e
group g
//xedamage installing
xedamage xed
//Check Unit
static method filterUnit takes unit caster, unit u returns boolean
return /*
*/ IsUnitEnemy(u, GetOwningPlayer(caster)) and /* Target is an enemy of caster
*/ not IsUnitType(u, UNIT_TYPE_DEAD) and GetUnitTypeId(u) != 0 and /* Target is alive
*/ not IsUnitType(u, UNIT_TYPE_STRUCTURE) /* Target is not a structure
*/
endmethod
//Damage per slash settings
static method onDamage takes unit u returns real
return DAMAGE_PER_SLASH // Damage when mini tornado hit enemy
endmethod
//Damage when rain hit a ground settings
static method rainDamage takes unit u returns real
return DAMAGE_RAIN_HIT_G*GetUnitAbilityLevel(u,SPELL_ID) // Damage when rain hit the ground to enemy
endmethod
//Check terrain can casting this spell
private static method terrainCheck takes nothing returns nothing
local unit u = GetTriggerUnit()
if GetSpellAbilityId() != SPELL_ID then
set u = null
return
endif
//
if IsTerrainWalkable(GetSpellTargetX(),GetSpellTargetY()) == false then
call PauseUnit(u, true)
call IssueImmediateOrderById(u, 851972)
call PauseUnit(u, false)
call SimError(GetTriggerPlayer(), ERROR)
endif
set u = null
endmethod
//
static method onPeriodic takes nothing returns nothing
local timer t = GetExpiredTimer()
local thistype this = GetTimerData(t)
local real x
local real y
local real d
local real a
local unit f
//Special Effect Optional
if ac == true then
//
if fade == false then
set h = h + DUST_HEIGHT_PER_S
//
if h >= DUST_MAX_HEIGHT then
set fade = true
endif
else
set h = h - DUST_HEIGHT_PER_S
//
if h <= 0. then
set fade = false
endif
endif
//
set anglez01 = anglez01 + DUST_SPEED
set x = targetx + DUST_EFFECT * Cos(anglez01*0.01747)
set y = targety + DUST_EFFECT * Sin(anglez01*0.01747)
//
call CreateDelayedEffectZ(EFFECT_ON_TOR,x,y,h,0.,0.)
//
set anglez02 = anglez02 - DUST_SPEED
set x = targetx + DUST_EFFECT * Cos(anglez02*0.01747)
set y = targety + DUST_EFFECT * Sin(anglez02*0.01747)
//
call CreateDelayedEffectZ(EFFECT_ON_TOR,x,y,h,0.,0.)
//====================================================
//Rain caller
if intevar >= RAIN_INTEVAR then
set intevar = 0.
set a = GetRandomReal(0, 6.283185)
set d = GetRandomReal(ENEMY_BLOW_MIN_RA,ENEMY_BLOCK_RANGE)
set x = targetx + d * Cos(a)
set y = targety + d * Sin(a)
call DestroyEffect(AddSpecialEffect(RAIN_EFFECT,x,y))
call CreateDelayedEffect(NOVA_GROUND,x,y,NOVA_DELAY,0.)
//
call xed.useSpecialEffect(ENEMY_HIT_EFFECT,ENEMY_ATTACH_EFFECT)
call xed.damageAOE(u,x,y,RADIUS_RAIN_HIT_G,onDamage(u))
else
set intevar = intevar + LOOP_TIMER
endif
//
call GroupEnumUnitsInRange(GROUP,targetx,targety,ENEMY_BLOCK_RANGE,null)
loop
set f = FirstOfGroup(GROUP)
exitwhen f == null
//
if IsUnitInRange(f,dummy,MINIMUM_RANGE) and filterUnit(u,f) then
if IsUnitInGroup(f,g) == false then
call GroupAddUnit(g,f)
set a = Angle(x,y,GetUnitX(f),GetUnitY(f))
set d = GetRandomReal(ENEMY_BLOW_MIN_RA,ENEMY_BLOCK_RANGE)
set x = GetUnitX(f) + d * Cos(a*0.01747)
set y = GetUnitY(f) + d * Sin(a*0.01747)
call J.JumpTarget(f,x,y,ENEMY_BLOW_SPEED,BLOW_EFFECT_S,BLOW_EFFECT_E,false,false)
endif
else
if IsUnitInGroup(f,g) == true then
call GroupRemoveUnit(g,f)
endif
endif
call GroupRemoveUnit(GROUP,f)
endloop
//
if IsUnitType(dummy, UNIT_TYPE_DEAD) and GetUnitTypeId(dummy) != 0 then
call ReleaseTimer(t)
set u = null
call DestroyGroup(g)
call DestroyEffect(e)
set e = null
call RemoveUnit(dummy)
set dummy = null
call xed.destroy()
call destroy()
endif
else
if atac > 0 then
set atac = atac - LOOP_TIMER
else
set ac = true
endif
//
if IsUnitInRangeXY(u,targetx,targety,ACTIVE_TOR_RANGE) then
set ac = true
endif
endif
//
set t = null
endmethod
//Spell cast settings
static method onCast takes nothing returns nothing
local thistype this = allocate()
local real x
local real y
local unit d
local player p = GetTriggerPlayer()
//
set targetx = GetSpellTargetX()
set targety = GetSpellTargetY()
set g = CreateGroup()
set u = GetTriggerUnit()
set x = GetUnitX(u)
set y = GetUnitY(u)
set xed = xedamage.create()
set xed.dtype = DAMAGETYPE
set xed.atype = ATTACKTYPE
set xed.wtype = WEAPONTYPE
set xed.damageEnemies = true
set xed.damageTrees = DAMAGE_TREE
set intevar = 0.
set anglez01 = 0.
set anglez02 = 0.
set atac = AUTO_ACTIVE
set fade = false
set ac = false
set h = 0.
set dummy = CreateUnit(p,'xeca',x,y,GetUnitFacing(u))
call SetUnitScale(dummy,TORNADO_MAX_SIZE,0,0)
set e = AddSpecialEffectTarget(TORNADO_MODEL,dummy,ATTACH_MODEL)
call J.JumpTarget(dummy,targetx,targety,SPEED_JUMPING,"","",false,false)
call J.JumpTarget(u,targetx,targety,SPEED_JUMPING,"","",false,false)
set x = targetx + MINIMUM_RANGE * Cos(GetUnitFacing(u)*0.01747)
set y = targety + MINIMUM_RANGE * Sin(GetUnitFacing(u)*0.01747)
set d = CreateUnit(p,'xeca',x,y,0.)
call Effect.Around(0.,dummy,d,MINIMUM_RANGE,MINIMUM_DAMAGE_RA,TOR_CALLER_SP,TORNADO_LIFE_TIME,true,true,onDamage(u),EFFECT_ON_TOR,0.,EFFECT_SLASHED)
call UnitApplyTimedLife(dummy,'BTLF',TORNADO_LIFE_TIME)
//
call TimerStart(NewTimerEx(this),LOOP_TIMER,true,function thistype.onPeriodic)
//
set d = null
endmethod
//
static method onInit takes nothing returns nothing
call AbilityPreload(SPELL_ID) // Preload this ability before casting
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_SPELL_CAST,function thistype.terrainCheck)
call RegisterSpellEffectEvent(SPELL_ID,function thistype.onCast)
endmethod
endstruct
endlibrary
[/HIDDEN]