scope Haunt initializer init
//===================================================================================
//= Haunt by Ciebron v1.21
//=
//= Requires: -The Custom Model in the Import list
//=
//=
//= Description: Shoots a projectile towards target unit it will deal Damage to him
//= and then return to the caster and heal him for % of the damage
//=
//= Extra: This spell needs the imported model 'dummy.mdx'. else you wont be able to
//= attach a SFX to the dummy
//===================================================================================
globals
//The RawCode of the spell
private constant integer Abil_id = 'A000'
//The RawCode of the dummy
private constant integer Dummy_id = 'h000'
//NOTE: only change this if u have changed the crow from ability in the editor
private constant integer Fly_id = 'Amrf'
//The SFX that will apear when the projectile hits the Target
private constant string HitSFX = "Abilities\\Spells\\Undead\\DeathCoil\\DeathCoilSpecialArt.mdl"
//The SFX that will apear when the projectile hits the Caster
private constant string HealSFX = "Abilities\\Spells\\Items\\AIil\\AIilTarget.mdl"
//The SFX that will attach too the projectile when it travels to the target
private constant string Projectile1 = "Abilities\\Spells\\Undead\\DeathCoil\\DeathCoilMissile.mdl"
//The SFX that will attach too the projectile when it travels back to the caster
private constant string Projectile2 = "Abilities\\Weapons\\IllidanMissile\\IllidanMissile.mdl"
//Where the SFX will get attached to the projectile
private constant string AttachPoint = "origin"
//Where the SFX will attach when the projectile hits the target/caster
private constant string AttachTargetPoint = "origin"
// Defines how fast the projectile will move
private constant real Move_Speed = 20.
//How much the caster will be healed of the procentage. eg. 1. is 100% of the dmg, 0.75 is 75% of the damage.
private constant real Heal_Amount = .50
//The Dummy's Fly Height (set it to what ever that fit's your SFX)
private constant real Dummy_Height = 75.
//The Attacktype of the spell
//Usefull information about damage types. http://www.wc3campaigns.net/showpost.php?p=1030046&postcount=19
private constant attacktype AtkType = ATTACK_TYPE_MAGIC
//The Damagetype of the spell
private constant damagetype DmgType = DAMAGE_TYPE_MAGIC
//The Weapontype of the spell (sound)
private constant weapontype WepType = null
//Timer Intervals
private constant real Interval = 0.03
endglobals
//This function is for setting the spells damage
private constant function Damage takes integer Level returns real
return 100.+(Level*50)
endfunction
//===========================================================================================
globals
private constant real Projectile_Size = Move_Speed * 2 + 1
endglobals
private struct Data
unit Caster
unit Target
unit Dummy
real Damage
real z
player Play
effect SFX
static integer array Ar
static integer Total = 0
static timer Time = CreateTimer()
static real x
static real y
static real tx
static real ty
static real x2
static real y2
static real angle
static real nH
method NewHeight takes real h returns real // A method used for setting the missile's height
set .nH = (h-.z) / ( SquareRoot((.tx-.x)*(.tx-.x)+(.ty - .y)*(.ty-.y)) / Move_Speed * Interval ) //DSG - Works out rate of change needed by working out the change in height and the time to reach target.
if .nH < 0 then //DSG - If rate of change of height is - it will not work so this inverts it to be positive.
set .nH = -.nH
endif
call SetUnitFlyHeight(.Dummy, h+Dummy_Height, .nH ) // Setting the missiles new height at a calculated rate
return h
endmethod
static method create takes unit u,unit t returns Data
local Data Dat = Data.allocate()
local real Height = GetUnitFlyHeight(t)
set Dat.Caster = u
set Dat.Target = t
set Dat.x = GetUnitX(Dat.Caster)
set Dat.y = GetUnitY(Dat.Caster)
set Dat.tx = GetUnitX(Dat.Target)
set Dat.ty = GetUnitY(Dat.Target)
set Dat.angle = Atan2(Dat.ty-Dat.y,Dat.tx-Dat.x)
set Dat.Play = GetOwningPlayer(Dat.Caster)
set Dat.Dummy = CreateUnit(Dat.Play,Dummy_id,Dat.x+50*Cos(Dat.angle),Dat.y+50*Sin(Dat.angle),(Dat.angle*57.29582))
set Dat.Damage = Damage(GetUnitAbilityLevel(Dat.Caster,Abil_id))
set Dat.SFX = AddSpecialEffectTarget(Projectile1,Dat.Dummy,AttachPoint)
set Dat.z = Dummy_Height
call UnitAddAbility(Dat.Dummy, Fly_id)
call SetUnitFlyHeight(Dat.Dummy,Dummy_Height,0.)
call UnitRemoveAbility(Dat.Dummy, Fly_id)
if Height > 0. then
set Dat.z = Dat.NewHeight(Height)
endif
if Dat.Total == 0 then
call TimerStart(Dat.Time, Interval, true, function Data.Loop)
endif
set Dat.Ar[Dat.Total] = Dat
set Dat.Total = Dat.Total + 1
set u = null
set t = null
return Dat
endmethod
static method Loop takes nothing returns nothing
local Data Dat
local integer i = 0
loop
exitwhen i >= Dat.Total
set Dat = Dat.Ar[i]
set Dat.x = GetUnitX(Dat.Dummy)
set Dat.y = GetUnitY(Dat.Dummy)
set Dat.tx = GetUnitX(Dat.Target)
set Dat.ty = GetUnitY(Dat.Target)
set Dat.x2 = Dat.tx-Dat.x
set Dat.y2 = Dat.ty-Dat.y
if SquareRoot(Dat.x2 * Dat.x2 + Dat.y2 * Dat.y2) <= Projectile_Size then
if Dat.Target != Dat.Caster then
call DestroyEffect(AddSpecialEffectTarget(HitSFX,Dat.Target,AttachTargetPoint))
call DestroyEffect(Dat.SFX)
call KillUnit(Dat.Dummy)
if not IsUnitType(Dat.Target,UNIT_TYPE_MAGIC_IMMUNE) and GetWidgetLife(Dat.Target) > .305 then
call UnitDamageTarget(Dat.Caster,Dat.Target,Dat.Damage,false,false,AtkType,DmgType,WepType)
set Dat.Target = Dat.Caster
set Dat.x = GetUnitX(Dat.Target)
set Dat.y = GetUnitY(Dat.Target)
set Dat.angle = Atan2(Dat.y-Dat.ty,Dat.x-Dat.tx)
//! Yes i could reuse the old dummy but cause it will look wierd i create a new one
set Dat.Dummy = CreateUnit(Dat.Play,Dummy_id,Dat.tx+50*Cos(Dat.angle),Dat.ty+50*Sin(Dat.angle),Dat.angle*57.29582)
//! New dummy new "fly hack"
call UnitAddAbility(Dat.Dummy, Fly_id)
call SetUnitFlyHeight(Dat.Dummy, Dat.z,0. )
call UnitRemoveAbility(Dat.Dummy, Fly_id)
//! Make so it will fly down to the caster again smoothly
call Dat.NewHeight(GetUnitFlyHeight(Dat.Target))
set Dat.SFX = AddSpecialEffectTarget(Projectile2,Dat.Dummy,AttachPoint)
else
set Dat.Total = Dat.Total - 1
set Dat.Ar[i] = Dat.Ar[Dat.Total]
set i = i - 1
call Dat.destroy()
endif
else
call SetWidgetLife(Dat.Caster,GetWidgetLife(Dat.Caster)+(Dat.Damage*Heal_Amount))
call DestroyEffect(AddSpecialEffectTarget(HealSFX,Dat.Caster,AttachTargetPoint))
call KillUnit(Dat.Dummy)
call DestroyEffect(Dat.SFX)
set Dat.Total = Dat.Total - 1
set Dat.Ar[i] = Dat.Ar[Dat.Total]
set i = i - 1
call Dat.destroy()
endif
else
set Dat.angle = Atan2(Dat.ty-Dat.y,Dat.tx-Dat.x)
call SetUnitX(Dat.Dummy,Dat.x+Move_Speed*Cos(Dat.angle))
call SetUnitY(Dat.Dummy,Dat.y+Move_Speed*Sin(Dat.angle))
call SetUnitFacing(Dat.Dummy,(Dat.angle*57.29582))
endif
set i = i + 1
endloop
if Dat.Total == 0 then
call PauseTimer(Dat.Time)
endif
endmethod
method onDestroy takes nothing returns nothing
set .Caster = null
set .Target = null
set .Play = null
set .Dummy = null
set .SFX = null
endmethod
endstruct
private function OnCast takes nothing returns boolean
local Data Dat
local unit u
local unit t
if GetSpellAbilityId()==Abil_id then
set u = GetTriggerUnit()
set t = GetSpellTargetUnit()
set Dat = Data.create(u,t)
set u = null
set t = null
endif
return false
endfunction
private function init takes nothing returns nothing
local trigger trig = CreateTrigger()
local integer index = 0
loop
call TriggerRegisterPlayerUnitEvent(trig,Player(index),EVENT_PLAYER_UNIT_SPELL_EFFECT,null)
set index = index + 1
exitwhen index == bj_MAX_PLAYER_SLOTS
endloop
call TriggerAddCondition(trig,Filter(function OnCast))
call Preload(HitSFX)
call Preload(HealSFX)
call Preload(Projectile1)
call Preload(Projectile2)
set trig = null
endfunction
endscope