Name | Type | is_array | initial_value |
BOM_Caster | unit | No | |
BOM_Damage | real | No | |
HASH | hashtable | No | |
TimerN | integer | No | |
Timers | timer | Yes |
//TESH.scrollpos=70
//TESH.alwaysfold=0
//==========RESPAWN ON ORIGINAL XY INCLUDING HEROES==========
//Created by: Mckill2009
//===HOW TO USE:
//- Create a HASH variable in the trigger editor
//- Initialize the HASH
//- Make a new trigger and convert to custom text via EDIT >>> CONVERT CUSTOM TEXT
//- The trigger name MUST be >>> RespawnThem (or you may change it as long as it matches InitTrig_NAME_OF_TRIGGER below
//- Copy ALL that is written here (overwrite the existing texts in the trigger)
//- You may configure the time
//===============CONFIGURABLES====================
function RESPAWN_TIMER takes nothing returns real
//You may configure this on how many seconds it will respawn
return 15.
endfunction
function RESPAWN_PLAYER_UNIT takes nothing returns integer
//You may configure this on which player respawns, at the moment the default is Neutral Hostile
return PLAYER_NEUTRAL_AGGRESSIVE
endfunction
function RESPAWN_SFX takes nothing returns string
//You may configure youw own SFX
return "Abilities\\Spells\\Items\\TomeOfRetraining\\TomeOfRetrainingCaster.mdl"
endfunction
//===============================================
function FilterThem takes nothing returns boolean
local unit u = GetFilterUnit()
local real x = GetUnitX(u)
local real y = GetUnitY(u)
local real facing = GetUnitFacing(u)
local integer ID = GetHandleId(u)
if GetOwningPlayer(u)==Player(RESPAWN_PLAYER_UNIT()) and IsUnitType(u, UNIT_TYPE_STRUCTURE)==false and IsUnitType(u, UNIT_TYPE_HERO)==false then
//call BJDebugMsg("SAVED!!!")
call SaveUnitHandle(udg_HASH, ID, 1, u)
call SaveReal(udg_HASH, ID, 2, x)
call SaveReal(udg_HASH, ID, 3, y)
call SaveReal(udg_HASH, ID, 4, facing)
endif
set u = null
return false
endfunction
function RespawnGet takes nothing returns boolean
call GroupEnumUnitsInRect(bj_lastCreatedGroup, bj_mapInitialPlayableArea, Filter(function FilterThem))
return false
endfunction
function RespawnNow takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer tID = GetHandleId(t)
local unit u = LoadUnitHandle(udg_HASH, tID, 1)
local integer uID = GetHandleId(u)
local integer utype = GetUnitTypeId(u)
//The dead unit ID
local real x = LoadReal(udg_HASH, uID, 2)
local real y = LoadReal(udg_HASH, uID, 3)
local real facing = LoadReal(udg_HASH, uID, 4)
local unit newunit
local integer newunitID
//Sets the new unit creation
call DestroyEffect(AddSpecialEffect(RESPAWN_SFX(), x, y))
set newunit = CreateUnit(GetOwningPlayer(u), utype, x, y, facing)
set newunitID = GetHandleId(newunit)
call SaveUnitHandle(udg_HASH, newunitID, 1, newunit)
call SaveReal(udg_HASH, newunitID, 2, GetUnitX(newunit))
call SaveReal(udg_HASH, newunitID, 3, GetUnitY(newunit))
call SaveReal(udg_HASH, newunitID, 4, GetUnitFacing(newunit))
call FlushChildHashtable(udg_HASH, tID)
call FlushChildHashtable(udg_HASH, uID)
//call BJDebugMsg("RESPAWN NOW")
call PauseTimer(t)
call DestroyTimer(t)
set t = null
set u = null
set newunit = null
endfunction
function RespawnDeath takes nothing returns boolean
local timer t
local integer ID
local integer tID
if GetTriggerPlayer()==Player(RESPAWN_PLAYER_UNIT()) then
set t = CreateTimer()
set tID = GetHandleId(t)
set ID = GetHandleId(GetTriggerUnit())
call SaveUnitHandle(udg_HASH, tID, 1, LoadUnitHandle(udg_HASH, ID, 1))
call TimerStart(t, RESPAWN_TIMER(), false, function RespawnNow)
endif
set t = null
return false
endfunction
function InitTrig_RespawnThem takes nothing returns nothing
local trigger t1 = CreateTrigger()
local trigger t2 = CreateTrigger()
call TriggerRegisterTimerEvent(t1, 0.5, false)
call TriggerRegisterAnyUnitEventBJ(t2, EVENT_PLAYER_UNIT_DEATH)
call TriggerAddCondition(t1, Condition(function RespawnGet))
call TriggerAddCondition(t2, Condition(function RespawnDeath))
set t1 = null
set t2 = null
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
function FILTER takes nothing returns boolean
call UnitResetCooldown(GetFilterUnit())
return false
endfunction
function COOLDOWN takes nothing returns boolean
call GroupEnumUnitsInRange(bj_lastCreatedGroup, GetRectCenterX(bj_mapInitialPlayableArea), GetRectCenterY(bj_mapInitialPlayableArea), 10000, Filter(function FILTER))
return false
endfunction
function InitTrig_ResetCooldowns takes nothing returns nothing
local trigger t = CreateTrigger()
local integer i = 0
loop
call TriggerRegisterPlayerEvent(t, Player(i), EVENT_PLAYER_END_CINEMATIC)
set i = i + 1
exitwhen i > 11
endloop
call TriggerAddCondition(t, Condition(function COOLDOWN))
set t = null
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=0
library BoundSentinel initializer init
//*************************************************
//* BoundSentinel
//* -------------
//* Don't leave your units unsupervised, naughty
//* them may try to get out of the map bounds and
//* crash your game.
//*
//* To implement, just get a vJass compiler and
//* copy this library/trigger to your map.
//*
//*************************************************
//==================================================
globals
// High enough so the unit is no longer visible, low enough so the
// game doesn't crash...
//
// I think you need 0.0 or soemthing negative prior to patch 1.22
//
private constant real EXTRA = 500.0
endglobals
//=========================================================================================
globals
private real maxx
private real maxy
private real minx
private real miny
endglobals
//=======================================================================
private function dis takes nothing returns nothing
local unit u=GetTriggerUnit()
local real x=GetUnitX(u)
local real y=GetUnitY(u)
if(x>maxx) then
set x=maxx
elseif(x<minx) then
set x=minx
endif
if(y>maxy) then
set y=maxy
elseif(y<miny) then
set y=miny
endif
call SetUnitX(u,x)
call SetUnitY(u,y)
set u=null
endfunction
private function init takes nothing returns nothing
local trigger t=CreateTrigger()
local region r=CreateRegion()
local rect rc
set minx=GetCameraBoundMinX() - EXTRA
set miny=GetCameraBoundMinY() - EXTRA
set maxx=GetCameraBoundMaxX() + EXTRA
set maxy=GetCameraBoundMaxY() + EXTRA
set rc=Rect(minx,miny,maxx,maxy)
call RegionAddRect(r, rc)
call RemoveRect(rc)
call TriggerRegisterLeaveRegion(t,r, null)
call TriggerAddAction(t, function dis)
//this is not necessary but I'll do it anyway:
set t=null
set r=null
set rc=null
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library DestructableLib initializer Initialization
//* ============================================================================ *
//* Made by PitzerMike *
//* *
//* I made this to detect if a destructable is a tree or not. It works not only *
//* for the standard trees but also for custom destructables created with the *
//* object editor. It uses a footie as a dummy with the goul's harvest ability. *
//* The dummy ids can be changed though. I also added the IsDestructableDead *
//* function for completeness. *
//* ============================================================================ *
globals
private constant integer DUMMY_UNIT_ID = 'hfoo' // footman
private constant integer HARVEST_ID = 'Ahrl' // ghouls harvest
private constant player OWNING_PLAYER = Player(15)
private unit dummy = null
endglobals
function IsDestructableDead takes destructable dest returns boolean
return GetDestructableLife(dest) <= 0.405
endfunction
function IsDestructableTree takes destructable dest returns boolean
local boolean result = false
if (dest != null) then
call PauseUnit(dummy, false)
set result = IssueTargetOrder(dummy, "harvest", dest)
call PauseUnit(dummy, true) // stops order
endif
return result
endfunction
private function Initialization takes nothing returns nothing
set dummy = CreateUnit(OWNING_PLAYER, DUMMY_UNIT_ID, 0.0, 0.0, 0.0)
call ShowUnit(dummy, false) // cannot enumerate
call UnitAddAbility(dummy, HARVEST_ID)
call UnitAddAbility(dummy, 'Aloc') // unselectable, invulnerable
call PauseUnit(dummy, true)
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~ Timer32 ~~ By Jesus4Lyf ~~ Version 1.06 ~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// What is Timer32?
// - Timer32 implements a fully optimised timer loop for a struct.
// - Instances can be added to the loop, which will call .periodic every
// PERIOD until .stopPeriodic() is called.
//
// =Pros=
// - Efficient.
// - Simple.
//
// =Cons=
// - Only allows one period.
// - The called method must be named ".periodic".
//
// Methods:
// - struct.startPeriodic()
// - struct.stopPeriodic()
//
// - private method periodic takes nothing returns nothing
//
// This must be defined in structs that implement Periodic Module.
// It will be executed by the module every PERIOD until .stopPeriodic() is called.
// Put "implement T32x" BELOW this method.
//
// Modules:
// - T32x
// Has no safety on .stopPeriodic or .startPeriodic (except debug messages
// to warn).
//
// - T32xs
// Has safety on .stopPeriodic and .startPeriodic so if they are called
// multiple times, or while otherwise are already stopped/started respectively,
// no error will occur, the call will be ignored.
//
// - T32
// The original, old version of the T32 module. This remains for backwards
// compatability, and is deprecated. The periodic method must return a boolean,
// false to continue running or true to stop.
//
// Details:
// - Uses one timer.
//
// - Do not, within a .periodic method, follow a .stopPeriodic call with a
// .startPeriodic call.
//
// How to import:
// - Create a trigger named T32.
// - Convert it to custom text and replace the whole trigger text with this.
//
// Thanks:
// - Infinitegde for finding a bug in the debug message that actually altered
// system operation (when in debug mode).
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
library T32 initializer OnInit
globals
public constant real PERIOD=0.03125
public constant integer FPS=R2I(1/PERIOD)
public integer Tick=0 // very useful.
//==============================================================================
private trigger Trig=CreateTrigger()
endglobals
//==============================================================================
// The standard T32 module, T32x.
//
module T32x
private thistype next
private thistype prev
private static method PeriodicLoop takes nothing returns boolean
local thistype this=thistype(0).next
loop
exitwhen this==0
call this.periodic()
set this=this.next
endloop
return false
endmethod
method startPeriodic takes nothing returns nothing
debug if this.prev!=0 or thistype(0).next==this then
debug call BJDebugMsg("T32 ERROR: Struct #"+I2S(this)+" had startPeriodic called while already running!")
debug endif
set thistype(0).next.prev=this
set this.next=thistype(0).next
set thistype(0).next=this
set this.prev=thistype(0)
endmethod
method stopPeriodic takes nothing returns nothing
debug if this.prev==0 and thistype(0).next!=this then
debug call BJDebugMsg("T32 ERROR: Struct #"+I2S(this)+" had stopPeriodic called while not running!")
debug endif
// This is some real magic.
set this.prev.next=this.next
set this.next.prev=this.prev
// This will even work for the starting element.
debug set this.prev=0
endmethod
private static method onInit takes nothing returns nothing
call TriggerAddCondition(Trig,Condition(function thistype.PeriodicLoop))
endmethod
endmodule
//==============================================================================
// The standard T32 module with added safety checks on .startPeriodic() and
// .stopPeriodic(), T32xs.
//
module T32xs
private thistype next
private thistype prev
private boolean runningPeriodic
private static method PeriodicLoop takes nothing returns boolean
local thistype this=thistype(0).next
loop
exitwhen this==0
call this.periodic()
set this=this.next
endloop
return false
endmethod
method startPeriodic takes nothing returns nothing
if not this.runningPeriodic then
set thistype(0).next.prev=this
set this.next=thistype(0).next
set thistype(0).next=this
set this.prev=thistype(0)
set this.runningPeriodic=true
endif
endmethod
method stopPeriodic takes nothing returns nothing
if this.runningPeriodic then
// This is some real magic.
set this.prev.next=this.next
set this.next.prev=this.prev
// This will even work for the starting element.
set this.runningPeriodic=false
endif
endmethod
private static method onInit takes nothing returns nothing
call TriggerAddCondition(Trig,Condition(function thistype.PeriodicLoop))
endmethod
endmodule
//==============================================================================
// The original T32 module, for backwards compatability only.
//
module T32 // deprecated.
private thistype next
private thistype prev
private static method PeriodicLoop takes nothing returns boolean
local thistype this=thistype(0).next
loop
exitwhen this==0
if this.periodic() then
// This is some real magic.
set this.prev.next=this.next
set this.next.prev=this.prev
// This will even work for the starting element.
debug set this.prev=0
endif
set this=this.next
endloop
return false
endmethod
method startPeriodic takes nothing returns nothing
debug if this.prev!=0 or thistype(0).next==this then
debug call BJDebugMsg("T32 ERROR: Struct #"+I2S(this)+" had startPeriodic called while already running!")
debug endif
set thistype(0).next.prev=this
set this.next=thistype(0).next
set thistype(0).next=this
set this.prev=thistype(0)
endmethod
private static method onInit takes nothing returns nothing
call TriggerAddCondition(Trig,Condition(function thistype.PeriodicLoop))
endmethod
endmodule
//==============================================================================
// System Core.
//
private function OnExpire takes nothing returns nothing
set Tick=Tick+1
call TriggerEvaluate(Trig)
endfunction
private function OnInit takes nothing returns nothing
call TimerStart(CreateTimer(),PERIOD,true,function OnExpire)
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
/**************************************************************
*
* RegisterPlayerUnitEvent
* v5.1.0.0
* By Magtheridon96
*
* I would like to give a special thanks to Bribe, azlier
* and BBQ for improving this library. For modularity, it only
* supports player unit events.
*
* Functions passed to RegisterPlayerUnitEvent must either
* return a boolean (false) or nothing. (Which is a Pro)
*
* Warning:
* --------
*
* - Don't use TriggerSleepAction inside registered code.
* - Don't destroy a trigger unless you really know what you're doing.
*
* API:
* ----
*
* - function RegisterPlayerUnitEvent takes playerunitevent whichEvent, code whichFunction returns nothing
* - Registers code that will execute when an event fires.
* - function RegisterPlayerUnitEventForPlayer takes playerunitevent whichEvent, code whichFunction, player whichPlayer returns nothing
* - Registers code that will execute when an event fires for a certain player.
* - function GetPlayerUnitEventTrigger takes playerunitevent whichEvent returns trigger
* - Returns the trigger corresponding to ALL functions of a playerunitevent.
*
**************************************************************/
library RegisterPlayerUnitEvent // Special Thanks to Bribe and azlier
globals
private trigger array t
endglobals
function RegisterPlayerUnitEvent takes playerunitevent p, code c returns nothing
local integer i = GetHandleId(p)
local integer k = 15
if t[i] == null then
set t[i] = CreateTrigger()
loop
call TriggerRegisterPlayerUnitEvent(t[i], Player(k), p, null)
exitwhen k == 0
set k = k - 1
endloop
endif
call TriggerAddCondition(t[i], Filter(c))
endfunction
function RegisterPlayerUnitEventForPlayer takes playerunitevent p, code c, player pl returns nothing
local integer i = 260 + 16 * GetHandleId(p) + GetPlayerId(pl)
if t[i] == null then
set t[i] = CreateTrigger()
call TriggerRegisterPlayerUnitEvent(t[i], pl, p, null)
endif
call TriggerAddCondition(t[i], Filter(c))
endfunction
function GetPlayerUnitEventTrigger takes playerunitevent p returns trigger
return t[GetHandleId(p)]
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
//============================================================================
// SpellEffectEvent
// - Version 1.1.0.0
//
// API
// ---
// RegisterSpellEffectEvent(integer abil, code onCast)
//
// Requires
// --------
// RegisterPlayerUnitEvent: hiveworkshop.com/forums/showthread.php?t=203338
//
// Optional
// --------
// Table: hiveworkshop.com/forums/showthread.php?t=188084
//
library SpellEffectEvent requires RegisterPlayerUnitEvent, optional Table
//============================================================================
private module M
static if LIBRARY_Table then
static Table tb
else
static hashtable ht = InitHashtable()
endif
static method onCast takes nothing returns nothing
static if LIBRARY_Table then
call TriggerEvaluate(.tb.trigger[GetSpellAbilityId()])
else
call TriggerEvaluate(LoadTriggerHandle(.ht, 0, GetSpellAbilityId()))
endif
endmethod
private static method onInit takes nothing returns nothing
static if LIBRARY_Table then
set .tb = Table.create()
endif
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_SPELL_EFFECT, function thistype.onCast)
endmethod
endmodule
//============================================================================
private struct S extends array
implement M
endstruct
//============================================================================
function RegisterSpellEffectEvent takes integer abil, code onCast returns nothing
static if LIBRARY_Table then
if not S.tb.handle.has(abil) then
set S.tb.trigger[abil] = CreateTrigger()
endif
call TriggerAddCondition(S.tb.trigger[abil], Filter(onCast))
else
if not HaveSavedHandle(S.ht, 0, abil) then
call SaveTriggerHandle(S.ht, 0, abil, CreateTrigger())
endif
call TriggerAddCondition(LoadTriggerHandle(S.ht, 0, abil), Filter(onCast))
endif
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
/*
=====Spell Name: Bombardment v1.4a
=====Created by: Mckill2009
REQUIRES:
- JassNewGenPack by Vexorian
REQUIRED LIBRARIES:
- DestructableLib by PitzerMike (http://www.wc3c.net/showthread.php?t=103927)
- T32 by Jesus4Lyf (http://www.thehelper.net/forums/showthread.php/132538-Timer32)
- RegisterSpellEffectEvent by Bribe (http://www.hiveworkshop.com/forums/jass-resources-412/snippet-spelleffectevent-187193/)
- RegisterPlayerUnitEvent by Magtheridon96 (http://www.hiveworkshop.com/forums/jass-resources-412/snippet-registerplayerunitevent-203338/)
OPTIONAL LIBRARIES:
- BoundSentinel by Vexorian (http://www.wc3c.net/showthread.php?t=102576)
HOW TO USE:
- Make a new trigger and convert to custom text via EDIT >>> CONVERT CUSTOM TEXT
- Copy ALL that is written here (overwrite the existing texts in the trigger)
- Copy ALL the required libraries stated above
- Copy the Dummy unit and the custom ability OR make your own
- You MUST input or change the correct raw ID's (see below)
- To view raw ID, press CTRL+D in the object editor
*/
scope Bombardment
globals
//NOTE: The custom ability should be 'Rain of Fire', or change it if you like
//but the ability order should be equal to CHANNEL_ORDER_ID
private constant integer SPELL_ID = 'A001' //raw code (rain of fire)
private constant integer COPTER_ID = 'h001' //raw code
private constant integer BOMB_ID = 'h000' //raw code
private constant integer CHANNEL_ORDER_ID = 852238 //rain of fire
private constant real FALL_SPEED = 10. //fall speed of the bomb
private constant real MOVE_SPEED = 15. //copter move speed
private constant real COPTER_HEIGHT = 300. //copter default height at creation time
private constant real CREATION_INTERVAL = 1.5 //interval for copter creation
private constant real COPTER_LIFE = 5.0 //life of copter after bomb is released
private constant real AOE = 300.//area of effect for damage
private constant attacktype ATK = ATTACK_TYPE_CHAOS
private constant damagetype DMG = DAMAGE_TYPE_NORMAL
private constant string SFX = "Objects\\Spawnmodels\\Other\\NeutralBuildingExplosion\\NeutralBuildingExplosion.mdl"
private rect Rct
endglobals
private function GetDamage takes integer i returns real
return 25 + i * 25.
endfunction
private function GetDuration takes integer i returns real
return 5 + i * 5.
endfunction
private function UnitAlive takes unit u returns boolean
return not IsUnitType(u, UNIT_TYPE_DEAD)
endfunction
private interface Bomb
unit caster
unit copter
real damage
real distance
real xSpell
real ySpell
endinterface
//===Bombs Explode
private struct BombExplode extends Bomb
unit bomb
real height
static method getDestructables takes nothing returns boolean
local destructable d = GetFilterDestructable()
if IsDestructableTree(d) then
call KillDestructable(d)
endif
set d = null
return false
endmethod
method periodic takes nothing returns nothing
local real x
local real y
local unit first
if .height > 0 then
set .height = .height - FALL_SPEED
call SetUnitFlyHeight(.bomb, .height, 0)
else
set x = GetUnitX(.bomb)
set y = GetUnitY(.bomb)
call DestroyEffect(AddSpecialEffect(SFX, x, y))
call MoveRectTo(Rct, x, y)
call EnumDestructablesInRect(Rct, function thistype.getDestructables, null)
call GroupEnumUnitsInRange(bj_lastCreatedGroup, x, y, AOE, null)
loop
set first = FirstOfGroup(bj_lastCreatedGroup)
exitwhen first==null
if UnitAlive(first) and IsUnitEnemy(first, GetOwningPlayer(.bomb)) or IsUnitType(first, UNIT_TYPE_STRUCTURE) then
call UnitDamageTarget(.bomb, first, .damage, false, false, ATK, DMG, null)
endif
call GroupRemoveUnit(bj_lastCreatedGroup, first)
endloop
call KillUnit(.bomb)
call .stopPeriodic()
call .destroy()
endif
endmethod
implement T32x
static method create takes unit b, real d, real h returns thistype
local thistype this = thistype.allocate()
set .bomb = b
set .damage = d
set .height = h
call .startPeriodic()
return this
endmethod
endstruct
//Copters Appear
private struct Copter extends Bomb
real angle
integer chk
method periodic takes nothing returns nothing
local unit bomb
if UnitAlive(.copter) then
call SetUnitPosition(.copter, GetUnitX(.copter)+MOVE_SPEED*Cos(.angle), GetUnitY(.copter)+MOVE_SPEED*Sin(.angle))
if .distance > 0 then
set .distance = .distance - MOVE_SPEED
elseif .chk==1 then
set .chk = 0
set bomb = CreateUnit(GetOwningPlayer(.copter), BOMB_ID, .xSpell, .ySpell, GetUnitFacing(.copter))
call SetUnitFlyHeight(bomb, COPTER_HEIGHT, 0)
call BombExplode.create(bomb, .damage, COPTER_HEIGHT)
call UnitApplyTimedLife(.copter, 'BTLF', COPTER_LIFE)
endif
else
call .stopPeriodic()
call .destroy()
endif
endmethod
implement T32x
static method create takes unit copter, real damage, real distance, real x, real y returns thistype
local thistype this = thistype.allocate()
set .copter = copter
set .damage = damage
set .angle = Atan2(y-GetUnitY(copter), x-GetUnitX(copter))
set .distance = distance
set .chk = 1
set .xSpell = x
set .ySpell = y
call .startPeriodic()
return this
endmethod
endstruct
//===Cast
private struct Bombardment extends Bomb
real xUnit
real yUnit
real duration
real creationgap
method periodic takes nothing returns nothing
local unit copter
if .duration > 0 and GetUnitCurrentOrder(.caster)==CHANNEL_ORDER_ID and UnitAlive(.caster) then
set .duration = .duration - T32_PERIOD
set .creationgap = .creationgap + T32_PERIOD
if .creationgap >= CREATION_INTERVAL then
set .creationgap = 0
set copter = CreateUnit(GetOwningPlayer(.caster), COPTER_ID, .xUnit, .yUnit, GetUnitFacing(.caster))
call SetUnitFlyHeight(copter, COPTER_HEIGHT, 0)
call Copter.create(copter, .damage, .distance, .xSpell, .ySpell)
set copter = null
endif
else
call IssueImmediateOrder(.caster, "stop")
call .stopPeriodic()
call .destroy()
endif
endmethod
implement T32x
private static method create takes nothing returns thistype
local thistype this = thistype.allocate()
local integer level
set .caster = GetTriggerUnit()
set level = GetUnitAbilityLevel(.caster, SPELL_ID)
set .xUnit = GetUnitX(.caster)
set .yUnit = GetUnitY(.caster)
set .xSpell = GetSpellTargetX()
set .ySpell = GetSpellTargetY()
set .duration = GetDuration(level)
set .damage = GetDamage(level)
set .distance = SquareRoot((.xSpell-.xUnit) * (.xSpell-.xUnit) + (.ySpell-.yUnit) * (.ySpell-.yUnit))
set .creationgap = CREATION_INTERVAL
call .startPeriodic()
return this
endmethod
private static method onInit takes nothing returns nothing
set Rct = Rect(-AOE, -AOE, AOE, AOE)
call RegisterSpellEffectEvent(SPELL_ID, function thistype.create)
call Preload(SFX)
endmethod
endstruct
endscope