//===============================================================
//| game_war48 Presents
//| Twister
//| ¯¯¯¯¯¯¯
//| Requires:
//| - JassNewGen v1.5d
//| - TimerUtils
//|
//| How to Import:
//| - Copy ability: "Twister" (A002)
//| - Copy unit: Dummy Unit - Twister and Storm Spiral (n001)
//| - Copy trigger: Twister and TimerUtils (if you don't have it)
//| - Changes the raw id of abilities, units,... in the globals.
//| - And MUST remember to change the raw id of XE Dummy in "xebasic"
//|
//| Modification:
//| - Values in the globals block and functions below it
//|
//| Credit
//| - Thanks Vexorian for TimerUtils and xe
//| - Thanks Cohadar for OID
//| - Thanks Tom_Kazansky for helping me
//| - Thanks Tink3 for his template map
//| - Thanks Rising_Dusk for GroupUtils
//===============================================================
scope Twister initializer InitTW
globals
private constant integer ABILITYID = 'A002' // Rawcode of the ability
private constant integer DUMMYID = 'n001' // Rawcode of the "wind" dummy
private constant integer DAMAGEID = 'A001' // Rawcode of the damage ability
private constant integer DAMAGEORDERID = OID_thunderbolt // Order ID of the damage ability from OID Library by Cohadar(important, needed to cast damage ability)
private constant string EFFECTDAMAGE = "Abilities\\Spells\\Human\\FlakCannons\\FlakTarget.mdl" // Path effect when damage on ground
private constant real FLYHEIGHT = 500. // Maximum height to "fly"
//------------------------------
private constant real PERIOD = 0.04 // period of time, but i think that shouldn't edit this
endglobals
private function GetDamage takes integer lvl returns real
return 200. + 0. * lvl // Damage deals when touching enemy units on ground, configurable
endfunction
//=============================================================================
globals
private integer I
endglobals
//=============================================================================
private struct eo
unit c
unit array d[6]
boolean array inc[6]
boolean b = false
boolean b2 = false
real dx
real dy
real tx
real ty
real df
real array hs[6]
real h = 100.
real hb = 150
real dist
real height = 500
real ang
real array a[6]
real dam
integer tick
integer tk
integer toss
integer lvl
group g
endstruct
private function TwisterG takes nothing returns nothing
local eo d = I
local unit e = GetEnumUnit()
local real x = GetUnitX(e)
local real y = GetUnitY(e)
local real dist = DistanceXY( d.dx, d.dy, x, y )
if not d.b2 then
if GetUnitFlyHeight(e) < FLYHEIGHT then
call SetUnitZ( e, d.height * Sin( (90/d.tk) * d.tick * bj_DEGTORAD ) )
endif
endif
set e = null
endfunction
private function TwisterUP takes nothing returns nothing
local eo d = I
local xecast xe
local unit e = GetEnumUnit()
local real x = GetUnitX(e)
local real y = GetUnitY(e)
local real z = GetUnitDefaultFlyHeight(e)
set xe = xecast.createBasicA( DAMAGEID, DAMAGEORDERID, GetOwningPlayer( d.c ) )
call xe.setSourcePoint( x, y, 0. )
call xe.castOnTarget( e, d.lvl )
call SetUnitX( e, x )
call SetUnitY( e, y )
//call SetUnitPosition( e, x, y )
call SetUnitZ( e, z )
call DestroyTreesInCircle( x, y, 200 )
set e = null
endfunction
private function TwisterM takes nothing returns nothing
local eo d = I
local unit e = GetEnumUnit()
local real sinr = 90 / 25 * d.tick
local real r1 = d.dist * Sin(sinr * bj_DEGTORAD)
local real dx = GetPPX( d.dx, r1, d.df )
local real dy = GetPPY( d.dy, r1, d.df )
call SetUnitX( e, dx )
call SetUnitY( e, dy )
//call SetUnitPosition( e, dx, dy )
call DestroyTreesInCircle( dx, dy, 200. )
call DestroyEffect( AddSpecialEffect( EFFECTDAMAGE, GetUnitX(e), GetUnitY(e) ) )
set e = null
endfunction
private function TwisterF takes nothing returns boolean
local eo d = I
local unit u = GetFilterUnit()
local boolean ok = false
if IsUnitEnemy (u, GetOwningPlayer(d.c)) /*
*/and IsUnitVisible (u, GetOwningPlayer(d.c)) /*
*/and not IsUnitType (u, UNIT_TYPE_MAGIC_IMMUNE) /*
*/and not IsUnitType (u, UNIT_TYPE_STRUCTURE) /*
*/and not IsUnitType (u, UNIT_TYPE_DEAD) /*
*/and not IsUnitInGroup (u, d.g) then
set ok = true
endif
set u = null
return ok
endfunction
private function TwisterT takes nothing returns nothing
local timer ti = GetExpiredTimer()
local eo d = GetTimerData(ti)
local group g
local unit p
local integer i
local integer j
local integer k
local real dx
local real dy
local real h
local real sinr
local real r1
if d.toss == 2 then
if d.tick < 0 then
set j = 0
loop
exitwhen j > 5
call KillUnit(d.d[j])
set j = j + 1
endloop
set I = d
call ForGroup(d.g, function TwisterUP)
call ReleaseGroup(d.g)
call ReleaseTimer(ti)
set ti = null
call d.destroy()
return
endif
endif
if d.toss == 0 then
if d.tick > 25 then
set d.dx = d.tx
set d.dy = d.ty
call GroupEnumUnitsInArea(d.g, d.dx, d.dy, 300., Condition(function TwisterF) )
set k = 0
loop
exitwhen k > 5
set d.a[k] = 60 * k
set k = k + 1
endloop
set d.tick = 0
set d.toss = 2
set d.hb = 0
set p = null
endif
endif
if d.toss == 0 then
set sinr = 90 / 25 * d.tick
set r1 = d.dist * Sin(sinr * bj_DEGTORAD)
set dx = GetPPX( d.dx, r1, d.df )
set dy = GetPPY( d.dy, r1, d.df )
endif
set i = 0
loop
set i = i + 1
exitwhen i > 8
set j = 0
loop
exitwhen j > 5
if d.toss == 0 then
//*****************************************************
if d.inc[j] and d.hs[j] == 1 then
set d.inc[j] = false
endif
if not d.inc[j] and d.hs[j] == -1 then
set d.inc[j] = true
endif
if d.inc[j] then
set d.hs[j] = d.hs[j] + 0.05
else
set d.hs[j] = d.hs[j] - 0.05
endif
call SetUnitX(d.d[j],GetPPX( dx, d.h * d.hs[j], d.df - 90. ) )
call SetUnitY(d.d[j],GetPPY( dy, d.h * d.hs[j], d.df - 90. ) )
call DestroyTreesInCircle( dx, dy, 200. )
set h = SquareRoot( d.h * d.h - d.h * d.hs[j] * d.h * d.hs[j] )
if d.inc[j] then
call SetUnitZ(d.d[j], d.hb + h )
else
call SetUnitZ(d.d[j], d.hb - h )
endif
//*****************************************************
endif
set j = j + 1
endloop
endloop
set j = 0
loop
exitwhen j > 5
if d.toss == 2 then
if d.tick >= 50 then
set d.height = 0
set d.tk = 5
set d.tick = 5
set d.b2 = true
else
set d.height = FLYHEIGHT
set d.tk = 50
endif
if d.a[j] >= 360 then
set d.a[j] = 0.
else
set d.a[j] = d.a[j] + 10.
endif
if not d.b2 then
call SetUnitX(d.d[j],GetPPX( d.dx, 250., d.a[j] ) )
call SetUnitY(d.d[j],GetPPY( d.dy, 250., d.a[j] ) )
call SetUnitZ(d.d[j], d.height * Sin( (90/d.tk) * d.tick * bj_DEGTORAD ) )
else
call SetUnitZ(d.d[j], d.height * Sin( (90/d.tk) * d.tick * bj_DEGTORAD ) + 10 )
endif
call DestroyTreesInCircle( d.dx, d.dy, 200. )
set I = d
call ForGroup(d.g, function TwisterG)
endif
set j = j + 1
endloop
if d.toss == 0 then
set g = NewGroup()
set I = d
call GroupEnumUnitsInArea(g, dx, dy, 200., Condition(function TwisterF) )
loop
set p = FirstOfGroup(g)
exitwhen p == null
call GroupRemoveUnit(g, p)
call GroupAddUnit(d.g, p)
call UnitDamageTarget(d.c, p, d.dam, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_DIVINE, null)
endloop
call ReleaseGroup(g)
set g = null
set I = d
call ForGroup(d.g, function TwisterM)
endif
if d.b2 then
set d.tick = d.tick - 1
else
set d.tick = d.tick + 1
endif
//set ti = null
endfunction
private function Twister takes nothing returns nothing
local eo d = eo.create()
local timer ti = NewTimer()
set d.c = GetTriggerUnit()
set d.dx = GetUnitX(d.c)
set d.dy = GetUnitY(d.c)
set d.tx = GetSpellTargetX()
set d.ty = GetSpellTargetY()
set d.df = AngleXY( d.dx, d.dy, d.tx, d.ty )
set d.dist = DistanceXY( d.dx, d.dy, d.tx, d.ty )
set d.hs[0] = 1
set d.d[0] = CreateUnit(GetOwningPlayer(d.c),DUMMYID,GetPPX(d.dx,d.h*d.hs[0],d.df-90.),GetPPY(d.dy,d.h*d.hs[0],d.df-90.),d.df-90)
call SetUnitZ(d.d[0],d.hb)
call SetUnitVertexColor(d.d[0], 255, 255, 255, 0)
set d.inc[0] = true
set d.hs[1] = -1
set d.d[1] = CreateUnit(GetOwningPlayer(d.c),DUMMYID,GetPPX(d.dx,d.h*d.hs[1],d.df+90.),GetPPY(d.dy,d.h*d.hs[1],d.df+90.),d.df+90)
call SetUnitZ(d.d[1],d.hb)
call SetUnitVertexColor(d.d[1], 255, 255, 255, 0)
set d.inc[1] = false
set d.hs[2] = 0.
set d.d[2] = CreateUnit(GetOwningPlayer(d.c),DUMMYID,GetPPX(d.dx,d.h*d.hs[2],d.df+90.),GetPPY(d.dy,d.h*d.hs[2],d.df+90.),d.df+90)
call SetUnitZ(d.d[2],d.hb+d.h)
call SetUnitVertexColor(d.d[2], 255, 255, 255, 0)
set d.inc[2] = true
set d.hs[3] = 0.
set d.d[3] = CreateUnit(GetOwningPlayer(d.c),DUMMYID,GetPPX(d.dx,d.h*d.hs[3],d.df+90.),GetPPY(d.dy,d.h*d.hs[3],d.df+90.),d.df+90)
call SetUnitZ(d.d[3],d.hb-d.h)
call SetUnitVertexColor(d.d[3], 255, 255, 255, 0)
set d.inc[3] = false
set d.hs[4] = 0.5
set d.d[4] = CreateUnit(GetOwningPlayer(d.c),DUMMYID,GetPPX(d.dx,d.h*d.hs[4],d.df-90.),GetPPY(d.dy,d.h*d.hs[4],d.df-90.),d.df-90)
call SetUnitZ(d.d[4],d.hb)
call SetUnitVertexColor(d.d[4], 255, 255, 255, 0)
set d.inc[4] = true
set d.hs[5] = -0.5
set d.d[5] = CreateUnit(GetOwningPlayer(d.c),DUMMYID,GetPPX(d.dx,d.h*d.hs[5],d.df+90.),GetPPY(d.dy,d.h*d.hs[5],d.df+90.),d.df+90)
call SetUnitZ(d.d[5],d.hb)
call SetUnitVertexColor(d.d[5], 255, 255, 255, 0)
set d.inc[5] = false
set d.lvl = GetUnitAbilityLevel( d.c, ABILITYID )
set d.toss = 0
set d.tick = 0
set d.dam = GetDamage( d.lvl )
set d.g = NewGroup()
call SetTimerData( ti, d )
call TimerStart( ti, PERIOD, true, function TwisterT )
//set ti = null
endfunction
private function TwisterC takes nothing returns boolean
return GetSpellAbilityId() == ABILITYID
endfunction
//===========================================================================
private function InitTW takes nothing returns nothing
local trigger TrigTW = CreateTrigger( )
local integer index
set index = 0
loop
call TriggerRegisterPlayerUnitEvent( TrigTW, Player(index), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
set index = index + 1
exitwhen index == bj_MAX_PLAYER_SLOTS
endloop
call TriggerAddCondition( TrigTW, Condition( function TwisterC ) )
call TriggerAddAction( TrigTW, function Twister )
call XE_PreloadAbility( DAMAGEID )
//set TrigTW = null
endfunction
endscope