Name | Type | is_array | initial_value |
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope xxX initializer Xxx
globals
unit Ranger
integer i = 0
endglobals
private function Act takes nothing returns nothing
set Ranger = gg_unit_N000_0084
call SetHeroLevel(Ranger,10,true)
call SetUnitState(Ranger,UNIT_STATE_LIFE,GetWidgetLife(Ranger)-1000)
call FogMaskEnable(false)
call FogEnable(false)
call BJDebugMsg("Haunt Spell Test")
call BJDebugMsg("- Press ESC to refresh the cooldown and heal to full health/mana.")
endfunction
private function Xxx takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterTimerEvent(t,0.1,false)
call TriggerAddAction(t,function Act)
set t = null
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope Respawn initializer Init
private function Act takes nothing returns nothing
local real x = GetUnitX(GetTriggerUnit())
local real y = GetUnitY(GetTriggerUnit())
local integer id = GetUnitTypeId(GetTriggerUnit())
call TriggerSleepAction(20)
call CreateUnit(GetOwningPlayer(GetTriggerUnit()),id,x,y,270)
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_DEATH)
call TriggerAddAction(t,function Act)
set t = null
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
//TESTING PURPOSES
//UNIT HANDLE COUNTER
globals
integer counter = 0
endglobals
function UnitHandleAdd takes player id, integer unitid, real x, real y, real face returns nothing
set counter = counter + 1
call BJDebugMsg("Create: "+I2S(counter))
endfunction
function UnitHandleModify takes unit u, boolean show returns nothing
if show then
set counter = counter + 1
endif
if not show then
set counter = counter - 1
endif
call BJDebugMsg("Display: "+I2S(counter))
endfunction
hook CreateUnit UnitHandleAdd
hook ShowUnit UnitHandleModify
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope Refresh initializer Init
private function Act takes nothing returns nothing
if UnitAlive(Ranger) then
call SetUnitState(Ranger,UNIT_STATE_LIFE,GetUnitState(Ranger,UNIT_STATE_MAX_LIFE))
call SetUnitState(Ranger,UNIT_STATE_MANA,GetUnitState(Ranger,UNIT_STATE_MAX_MANA))
call UnitResetCooldown(Ranger)
else
call ReviveHero(Ranger,GetUnitX(Ranger),GetUnitY(Ranger),true)
endif
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterPlayerEvent(t,Player(0),EVENT_PLAYER_END_CINEMATIC)
call TriggerAddAction(t,function Act)
set t = null
endfunction
endscope
//TESH.scrollpos=143
//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
//==============================================================================
// 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=362
//TESH.alwaysfold=0
scope Haunt initializer Init
//REQUIRES JASS NEWGEN PACK AND JASSHELPER
//http://www.wc3c.net/showthread.php?t=90999 *JassNewGen Pack Download
//http://www.wc3c.net/showthread.php?t=88142 *JassHelper
//************************************H***********************************HAUNT
//*************************************A**********************************HAUNT
//**************************************U*********************************HAUNT
//***************************************N********************************HAUNT
//****************************************T*******************************HAUNT
//* SPELL - HAUNT v1.6.0
//* By Purgeandfire - Give credits if you can.
//* Description: Sends Sends ghostly souls to travel around the caster which hit any target that comes within
//* range for 10*AbilityLevl+5 damage. It will then return to heal the caster for the total damage dealt.
//* ****Systems Used: Timer32 -- Jesus4Lyf
//* ****Models Used: Dummy.mdx
//***** Documentation *****
//* Required Object Editor Data: "Haunt" Spell, "Dummy" unit
//* Implementation: Copy the Haunt spell, the dummy unit, T32 trigger and the haunt trigger.
//* Required Alterations:
//* - RAWCODE: Change this to the RAWCODE of your haunt spell.
//* - DUMCODE: Change this to the RAWCODE of your dummy unit.
//* Cautions:
//* - RADIUS: Don't set this too high. It *might* cause a crash if it is too large.
//* - SOULRAD: This will look ugly if set too high. It has an emergency execute which will
//* execute the timer drain functions if the soul takes too long to get to the unit.
//* This was made to prevent possible infinite timer loops. (Which would cause extreme lag and crash)
//* - DSPAWNS: This can make your circle look a lot more circular. However, more units results in
//* more attached effects, so it can cause a bit more frame rate drop for the duration of the spell.
//* - waitBeforeEnum: When the spell is cast, black souls spawn and revolve around the caster. This enumeration wait
//* was made so that you can actually see the black souls spawn before they go and steal life from a unit.
//* You can shorten/lengthen this.
//* - angINCFACTOR: This modifies how fast the circles revolve around the caster. Note that this
//* takes RADIANS not degrees. This can go extremely fast if you set it to anything
//* higher than 1. About 0.08 or so is a moderate pace. 0.3 is a fast pace, but makes
//* a good circular effect.
//* - TRANSPARENCY: Modifies the transparency of the ghost that returns to the caster. This is from
//* 0-255, not 0-100. 0 is completely transparent, and 255 is visible.
//* - SOULVELOCITY: This modifies the movement speed of the souls. The only thing to beware of is that
//* a HIGHER input results in a lower speed and vice versa.
//* - GHOSTVELOCITY: Modifies the movement speed of the ghosts that return. Same thing as above, beware
//* that a HIGHER input results in a lower speed and vice versa. Note that setting this
//* too high can result the ghost actually being slower than the ranger. There is now an
//* emergency destroy and an automatic accelerator to have the ghost eventually reach the target.
//* Don't set this too high or else you'll hardly see it, or it will have to rely each time on the
//* emergency destroy to prevent the spell from crashing the game. Be sure that if this is increased,
//* that you set the exittimer_distance global mentioned next.
//* - EXITTIMER_DISTANCE: This modifies the distance the soul/ghost needs to be before it is destroyed.
//* Be careful though, this is distance*distance, not just normal distance. So 35*35 = 1225
//* which will mean that they will be destroyed once they get within a distance of 35.
//* - emergencyExits: These are new which allow you to modify when the soul/ghost timers will perform an emergency exit.
//* This is for those rare occasions where the spell might bug out. This ensures that the timer will
//* be paused eventually, preventing the chances of infinite loops which would most likely lag spike or
//* eventually crash the game.
//***** End Documentation *****
//* Default Values:
//* globals
//* private constant integer RAWCODE = 'A000'
//* private constant integer DUMCODE = 'h003'
//* private constant string DUMMYSFX = "Abilities\\Weapons\\AvengerMissile\\AvengerMissile.mdl"
//* private constant string ONHITSFX = "Abilities\\Weapons\\DemonHunterMissile\\DemonHunterMissile.mdl"
//* private constant string DRAINSFX = "Abilities\\Weapons\\IllidanMissile\\IllidanMissile.mdl"
//* private constant real RADIUS = 300
//* private constant real SOULRAD = 175
//* private constant integer DSPAWNS = 13
//* private constant real waitBeforeEnum = 1.05
//* private constant real angINCFACTOR = 0.3
//* private constant integer SOULRED = 0
//* private constant integer SOULGREEN = 255
//* private constant integer SOULBLUE = 225
//* private constant integer TRANSPARENCY = 100
//* private constant real SOULVELOCITY = 10
//* private constant real GHOSTVELOCITY = 12
//* private group HauntG = CreateGroup()
//* private timer t = CreateTimer()
//* endglobals
globals
private constant integer RAWCODE = 'A000'
//RAWCODE of the Haunt spell.
private constant integer DUMCODE = 'h003'
//RAWCODE of the dummy unit.
private constant real DURATION = 5.005
//Modifies the duration before the effects automatically destroy themselves. (Seconds)
//For most accuracy, be sure that 0.035 is a factor of the value. (It works fine if it isn't though)
private constant string DUMMYSFX = "Abilities\\Weapons\\AvengerMissile\\AvengerMissile.mdl"
//String path of the effects that revolve around the caster.
private constant string ONHITSFX = "Abilities\\Weapons\\DemonHunterMissile\\DemonHunterMissile.mdl"
//String path of the effects that occur when a target unit is hit.
private constant string DRAINSFX = "Abilities\\Weapons\\IllidanMissile\\IllidanMissile.mdl"
//String path of the effect that occurs when the soul returns to the caster.
private constant real RADIUS = 300
//Modifies the radius of the circle that the effects follow.
private constant real SOULRAD = 175
//Modifies the radius in which the soul will jump.
private constant integer DSPAWNS = 13
//Number of souls to create. More units equals more circular motion. However, more units also equals more frame drop.
private constant real waitBeforeEnum = 1.05
//Modifies the time to wait before the souls will start snatching nearby units. (Seconds)
private constant real angINCFACTOR = 0.3
//This is the angle increase factor every 0.035 seconds. It takes radians, not degrees. This can go pretty fast if too high.
private constant integer SOULRED = 0
private constant integer SOULGREEN = 255
private constant integer SOULBLUE = 225
private constant integer TRANSPARENCY = 100
//Modifies the vertex coloring of the soul that returns to the caster. Values are from 0-255 for all.
private constant real SOULVELOCITY = 10
//Modifies the velocity of the souls that rush toward the enemies.
//This isn't very noticeable though, unless the enemy is moving fast.
//LOWER VELOCITY SPECIFIED RESULTS IN A HIGHER SPEED, higher velocity results in a slower speed.
private constant real GHOSTVELOCITY = 12
//Modifies the speed of the ghosts that return to the caster.
//LOWER VELOCITY SPECIFIED RESULTS IN A HIGHER SPEED, higher velocity results in a slower speed.
private constant real EXITTIMER_DISTANCE = 1225
//Modifies the distance the soul/ghost has to be to the target before stopping the timer.
//This distance is actually 35. Use your input distance^2 (your input to the power of 2) and input that value for it to work.
private constant integer SOULHEIGHT = 75
//Modifies the elevation of the black souls.
private constant integer GHOSTHEIGHT = 15
//Modifies the elevation of the ghosts.
private constant attacktype ATTACKTYPE = ATTACK_TYPE_NORMAL
private constant damagetype DAMAGETYPE = DAMAGE_TYPE_ACID
private constant weapontype WEAPONTYPE = WEAPON_TYPE_WHOKNOWS
//Modifies the attacktype, damagetype, and weapontype of the damaging souls. Why did I use acid? No clue.
private constant real emergencyExitSoul = 1.25
//Modifies the duration (seconds) before the souls will be forced to reach they're destination. (To prevent infinite loops)
private constant real emergencyExitGhost = 4
//Modifies the duration (seconds) before the ghosts will be forced to reach they're destination. (To prevent infinite loops)
//Do not change these below.
private group HauntG = CreateGroup()
private timer t = CreateTimer()
endglobals
private constant function HAUNTDAMAGE takes integer LVL returns real
return 10.*LVL+5
//Modify this to modify the damage dealt by the spell per soul to unit.
//10 * Ability_Level + 5
//Rank 1: 15 damage, Rank 2: 25 damage, Rank 3: 35 damage.
endfunction
native UnitAlive takes unit u returns boolean
private function HSCond takes nothing returns boolean
return UnitAlive(GetFilterUnit()) and (not IsUnitType(GetFilterUnit(),UNIT_TYPE_STRUCTURE)) and (not IsUnitType(GetFilterUnit(),UNIT_TYPE_ETHEREAL))
endfunction
//*SPELL CODE*
private struct HauntSReturn
unit a
unit b
unit c
real damage
real mD
effect e
real speedMultiplier
method onDestroy takes nothing returns nothing
set .a = null
set .b = null
set .c = null
set .damage = 0
set .mD = 0
set .speedMultiplier = 0
endmethod
private method periodic takes nothing returns nothing
local real x = GetUnitX(.c)
local real y = GetUnitY(.c)
local real dx = GetUnitX(.a)
local real dy = GetUnitY(.a)
local real distX = dx-x
local real distY = dy-y
local real ang = Atan2(distY,distX)
local real dist = distX*distX+distY*distY
local real newX = x+(.mD/GHOSTVELOCITY)*Cos(ang)*.speedMultiplier
local real newY = y+(.mD/GHOSTVELOCITY)*Sin(ang)*.speedMultiplier
call SetUnitX(.c,newX)
call SetUnitY(.c,newY)
if dist<EXITTIMER_DISTANCE or .speedMultiplier >= ((emergencyExitGhost/0.03125)*.1) then
call SetUnitX(.c,dx)
call SetUnitY(.c,dy)
call DestroyEffect(AddSpecialEffect(ONHITSFX,dx,dy))
call DestroyEffect(.e)
call RemoveUnit(.c)
call SetWidgetLife(.a,GetWidgetLife(.a)+.damage)
call this.stopPeriodic()
call this.destroy()
endif
set .speedMultiplier = .speedMultiplier + .1
endmethod
implement T32x
static method create takes unit caster, unit target, real damageTar returns HauntSReturn
local thistype this = thistype.allocate()
local real x = GetUnitX(target)-GetUnitX(caster)
local real y = GetUnitY(target)-GetUnitY(caster)
local real f = (bj_RADTODEG*Atan2(y,x))+180
set .a = caster
set .b = target
call SetUnitPathing(target,false)
set .c = CreateUnit(Player(15),GetUnitTypeId(.b),GetUnitX(.b),GetUnitY(.b),f)
set .damage = damageTar
set .mD = SquareRoot(x*x+y*y)
set .e = AddSpecialEffectTarget(DRAINSFX,.c,"origin")
set .speedMultiplier = 1
call SetUnitColor(.c,GetPlayerColor(GetOwningPlayer(.b)))
call UnitAddAbility(.c,'Amrf')
call SetUnitPathing(.c,false)
call UnitAddAbility(.c,'Aloc')
call UnitAddAbility(.c,'Avul')
call SetUnitFlyHeight(.c,GHOSTHEIGHT,0)
call PauseUnit(.c,true)
call SetUnitVertexColor(.c,SOULRED,SOULGREEN,SOULBLUE,TRANSPARENCY)
call SetUnitPathing(target,true)
return this
endmethod
endstruct
private struct HauntSGmove
unit a
unit b
effect c
unit d
real mD
integer SCount
method onDestroy takes nothing returns nothing
set .a = null
set .b = null
set .c = null
set .d = null
set .mD = 0
endmethod
private method periodic takes nothing returns nothing
local real x = GetUnitX(.a)
local real y = GetUnitY(.a)
local real tx = GetUnitX(.b)
local real ty = GetUnitY(.b)
local real distX = tx-x
local real distY = ty-y
local real ang = Atan2(distY,distX)
local real dist = distX*distX+distY*distY
local real newX = x+(.mD/SOULVELOCITY)*Cos(ang)
local real newY = y+(.mD/SOULVELOCITY)*Sin(ang)
call SetUnitX(.a,newX)
call SetUnitY(.a,newY)
if dist<EXITTIMER_DISTANCE or .SCount >= (emergencyExitSoul/0.03125) then
call SetUnitX(.a,tx)
call SetUnitY(.a,ty)
call DestroyEffect(AddSpecialEffect(ONHITSFX,tx,ty))
call UnitDamageTarget(.a,.b,HAUNTDAMAGE(GetUnitAbilityLevel(.d,RAWCODE)),true,false,ATTACKTYPE,DAMAGETYPE,WEAPONTYPE)
call DestroyEffect(.c)
call UnitRemoveAbility(.a,'Aloc')
call ShowUnit(.a,false)
call HauntSReturn.create(.d,.b,HAUNTDAMAGE(GetUnitAbilityLevel(.d,RAWCODE))).startPeriodic()
call this.stopPeriodic()
call this.destroy()
endif
set .SCount = .SCount + 1
endmethod
implement T32x
static method create takes unit u, unit tar, effect E, unit caster returns HauntSGmove
local thistype this = thistype.allocate()
local real x = GetUnitX(tar)-GetUnitX(u)
local real y = GetUnitY(tar)-GetUnitY(u)
set .a = u
set .b = tar
set .c = E
set .d = caster
set .mD = SquareRoot(x*x+y*y)
return this
endmethod
endstruct
private struct HauntS
unit u
real x
real y
unit array dum[DSPAWNS]
effect array sfx[DSPAWNS]
real DURATIONx
integer ENUMERATE
boolean array b[DSPAWNS]
method onDestroy takes nothing returns nothing
local integer i = 0
loop
exitwhen i == (DSPAWNS)
if (not IsUnitHidden(.dum[i])) then
call DestroyEffect(AddSpecialEffect(DUMMYSFX,GetUnitX(.dum[i]),GetUnitY(.dum[i])))
endif
call DestroyEffect(.sfx[i])
call UnitRemoveAbility(.dum[i],'Aloc')
call ShowUnit(.dum[i],false)
set .sfx[i] = null
set i = i + 1
endloop
set .x = 0
set .y = 0
set .DURATIONx = 0
set .ENUMERATE = 0
endmethod
private method periodic takes nothing returns nothing
local integer i = 0
local real dumX
local real dumY
local real x = GetUnitX(.u)
local real y = GetUnitY(.u)
local real ang = 0
local unit FoG
set .ENUMERATE = .ENUMERATE + 1
loop
exitwhen i == (DSPAWNS)
if .b[i] == true then
set ang = Atan2(GetUnitY(.dum[i])-y,GetUnitX(.dum[i])-x)+angINCFACTOR
set dumX = x+RADIUS*Cos(ang)
set dumY = y+RADIUS*Sin(ang)
call SetUnitX(.dum[i],dumX)
call SetUnitY(.dum[i],dumY)
if .ENUMERATE >= (waitBeforeEnum/0.035) then
call GroupEnumUnitsInRange(HauntG,dumX,dumY,SOULRAD,Condition(function HSCond))
set FoG = FirstOfGroup(HauntG)
if FoG != null and (not IsUnitAlly(FoG,GetOwningPlayer(.u))) and (not IsUnitHidden(.dum[i])) then
call HauntSGmove.create(.dum[i],FoG,.sfx[i],.u).startPeriodic()
set .b[i] = false
endif
endif
endif
set i = i + 1
endloop
set .DURATIONx = .DURATIONx - 0.035
if .DURATIONx <= 0 then
call this.stopPeriodic()
call this.destroy()
endif
set FoG = null
endmethod
implement T32x
static method create takes unit a returns HauntS
local thistype this = thistype.allocate()
local integer i = 0
local real angle = 360/DSPAWNS
local real dumX
local real dumY
set .u = a
set .x = GetUnitX(a)
set .y = GetUnitY(a)
set .DURATIONx = DURATION
set .ENUMERATE = 0
loop
exitwhen i >= (DSPAWNS)
set dumX = .x+RADIUS*Cos((i*angle)*bj_DEGTORAD)
set dumY = .y+RADIUS*Sin((i*angle)*bj_DEGTORAD)
set .b[i] = true
if (not IsUnitHidden(.dum[i])) or .dum[i] == null then
set .dum[i] = CreateUnit(Player(15),DUMCODE,dumX,dumY,270)
else
call ShowUnit(.dum[i],true)
call SetUnitX(.dum[i],dumX)
call SetUnitY(.dum[i],dumY)
endif
set .sfx[i] = AddSpecialEffectTarget(DUMMYSFX,.dum[i],"origin")
call UnitAddAbility(.dum[i],'Aloc')
call UnitAddAbility(.dum[i],'Amrf')
call SetUnitFlyHeight(.dum[i],SOULHEIGHT,0)
set i = i + 1
endloop
return this
endmethod
endstruct
private function Cond takes nothing returns boolean
if GetSpellAbilityId() == RAWCODE then
call HauntS.create(GetTriggerUnit()).startPeriodic()
endif
return false
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t,Condition(function Cond))
set t = null
endfunction
endscope
//TESH.scrollpos=208
//TESH.alwaysfold=0
scope Flametongue initializer Init
//Flametongue - A fiery modification to haunt v1.6.0
globals
private constant integer RAWCODE = 'A001'
private constant integer DUMCODE = 'h003'
private constant real DURATION = 5.005
private constant string DUMMYSFX = "Abilities\\Weapons\\PhoenixMissile\\Phoenix_Missile.mdl"
private constant string ONHITSFX = "Abilities\\Weapons\\DemonHunterMissile\\DemonHunterMissile.mdl"
private constant string DRAINSFX = "Abilities\\Weapons\\LordofFlameMissile\\LordofFlameMissile.mdl"
private constant real RADIUS = 400
private constant real SOULRAD = 175
private constant integer DSPAWNS = 15
private constant real waitBeforeEnum = 1.05
private constant real angINCFACTOR = 0.3
private constant integer SOULRED = 255
private constant integer SOULGREEN = 200
private constant integer SOULBLUE = 0
private constant integer TRANSPARENCY = 100
private constant real SOULVELOCITY = 10
private constant real GHOSTVELOCITY = 12
private constant real EXITTIMER_DISTANCE = 1225
private constant integer SOULHEIGHT = 100
private constant integer GHOSTHEIGHT = 15
private constant attacktype ATTACKTYPE = ATTACK_TYPE_NORMAL
private constant damagetype DAMAGETYPE = DAMAGE_TYPE_ACID
private constant weapontype WEAPONTYPE = WEAPON_TYPE_WHOKNOWS
private constant real emergencyExitSoul = 1.25
private constant real emergencyExitGhost = 4
private group HauntG = CreateGroup()
private timer t = CreateTimer()
endglobals
private constant function HAUNTDAMAGE takes integer LVL returns real
return 10.*LVL+5
endfunction
native UnitAlive takes unit u returns boolean
private function HSCond takes nothing returns boolean
return UnitAlive(GetFilterUnit()) and (not IsUnitType(GetFilterUnit(),UNIT_TYPE_STRUCTURE)) and (not IsUnitType(GetFilterUnit(),UNIT_TYPE_ETHEREAL))
endfunction
//*SPELL CODE*
private struct HauntSReturn
unit a
unit b
unit c
real damage
real mD
effect e
real speedMultiplier
method onDestroy takes nothing returns nothing
set .a = null
set .b = null
set .c = null
set .damage = 0
set .mD = 0
set .speedMultiplier = 0
endmethod
private method periodic takes nothing returns nothing
local real x = GetUnitX(.c)
local real y = GetUnitY(.c)
local real dx = GetUnitX(.a)
local real dy = GetUnitY(.a)
local real distX = dx-x
local real distY = dy-y
local real ang = Atan2(distY,distX)
local real dist = distX*distX+distY*distY
local real newX = x+(.mD/GHOSTVELOCITY)*Cos(ang)*.speedMultiplier
local real newY = y+(.mD/GHOSTVELOCITY)*Sin(ang)*.speedMultiplier
call SetUnitX(.c,newX)
call SetUnitY(.c,newY)
if dist<EXITTIMER_DISTANCE or .speedMultiplier >= ((emergencyExitGhost/0.03125)*.1) then
call SetUnitX(.c,dx)
call SetUnitY(.c,dy)
call DestroyEffect(AddSpecialEffect(ONHITSFX,dx,dy))
call DestroyEffect(.e)
call RemoveUnit(.c)
call SetWidgetLife(.a,GetWidgetLife(.a)+.damage)
call this.stopPeriodic()
call this.destroy()
endif
set .speedMultiplier = .speedMultiplier + .1
endmethod
implement T32x
static method create takes unit caster, unit target, real damageTar returns HauntSReturn
local thistype this = thistype.allocate()
local real x = GetUnitX(target)-GetUnitX(caster)
local real y = GetUnitY(target)-GetUnitY(caster)
local real f = (bj_RADTODEG*Atan2(y,x))+180
set .a = caster
set .b = target
call SetUnitPathing(target,false)
set .c = CreateUnit(Player(15),GetUnitTypeId(.b),GetUnitX(.b),GetUnitY(.b),f)
set .damage = damageTar
set .mD = SquareRoot(x*x+y*y)
set .e = AddSpecialEffectTarget(DRAINSFX,.c,"origin")
set .speedMultiplier = 1
call SetUnitColor(.c,GetPlayerColor(GetOwningPlayer(.b)))
call UnitAddAbility(.c,'Amrf')
call SetUnitPathing(.c,false)
call UnitAddAbility(.c,'Aloc')
call UnitAddAbility(.c,'Avul')
call SetUnitFlyHeight(.c,GHOSTHEIGHT,0)
call PauseUnit(.c,true)
call SetUnitVertexColor(.c,SOULRED,SOULGREEN,SOULBLUE,TRANSPARENCY)
call SetUnitPathing(target,true)
return this
endmethod
endstruct
private struct HauntSGmove
unit a
unit b
effect c
unit d
real mD
integer SCount
method onDestroy takes nothing returns nothing
set .a = null
set .b = null
set .c = null
set .d = null
set .mD = 0
endmethod
private method periodic takes nothing returns nothing
local real x = GetUnitX(.a)
local real y = GetUnitY(.a)
local real tx = GetUnitX(.b)
local real ty = GetUnitY(.b)
local real distX = tx-x
local real distY = ty-y
local real ang = Atan2(distY,distX)
local real dist = distX*distX+distY*distY
local real newX = x+(.mD/SOULVELOCITY)*Cos(ang)
local real newY = y+(.mD/SOULVELOCITY)*Sin(ang)
call SetUnitX(.a,newX)
call SetUnitY(.a,newY)
if dist<EXITTIMER_DISTANCE or .SCount >= (emergencyExitSoul/0.03125) then
call SetUnitX(.a,tx)
call SetUnitY(.a,ty)
call DestroyEffect(AddSpecialEffect(ONHITSFX,tx,ty))
call UnitDamageTarget(.a,.b,HAUNTDAMAGE(GetUnitAbilityLevel(.d,RAWCODE)),true,false,ATTACKTYPE,DAMAGETYPE,WEAPONTYPE)
call DestroyEffect(.c)
call UnitRemoveAbility(.a,'Aloc')
call ShowUnit(.a,false)
call HauntSReturn.create(.d,.b,HAUNTDAMAGE(GetUnitAbilityLevel(.d,RAWCODE))).startPeriodic()
call this.stopPeriodic()
call this.destroy()
endif
set .SCount = .SCount + 1
endmethod
implement T32x
static method create takes unit u, unit tar, effect E, unit caster returns HauntSGmove
local thistype this = thistype.allocate()
local real x = GetUnitX(tar)-GetUnitX(u)
local real y = GetUnitY(tar)-GetUnitY(u)
set .a = u
set .b = tar
set .c = E
set .d = caster
set .mD = SquareRoot(x*x+y*y)
return this
endmethod
endstruct
private struct HauntS
unit u
real x
real y
unit array dum[DSPAWNS]
effect array sfx[DSPAWNS]
real DURATIONx
integer ENUMERATE
boolean array b[DSPAWNS]
method onDestroy takes nothing returns nothing
local integer i = 0
loop
exitwhen i == (DSPAWNS)
if (not IsUnitHidden(.dum[i])) then
call DestroyEffect(AddSpecialEffect(DUMMYSFX,GetUnitX(.dum[i]),GetUnitY(.dum[i])))
endif
call DestroyEffect(.sfx[i])
call UnitRemoveAbility(.dum[i],'Aloc')
call ShowUnit(.dum[i],false)
set .sfx[i] = null
set i = i + 1
endloop
set .x = 0
set .y = 0
set .DURATIONx = 0
set .ENUMERATE = 0
endmethod
private method periodic takes nothing returns nothing
local integer i = 0
local real dumX
local real dumY
local real x = GetUnitX(.u)
local real y = GetUnitY(.u)
local real ang = 0
local unit FoG
set .ENUMERATE = .ENUMERATE + 1
loop
exitwhen i == (DSPAWNS)
if .b[i] == true then
set ang = Atan2(GetUnitY(.dum[i])-y,GetUnitX(.dum[i])-x)+angINCFACTOR
set dumX = x+RADIUS*Cos(ang)
set dumY = y+RADIUS*Sin(ang)
call SetUnitX(.dum[i],dumX)
call SetUnitY(.dum[i],dumY)
if .ENUMERATE >= (waitBeforeEnum/0.035) then
call GroupEnumUnitsInRange(HauntG,dumX,dumY,SOULRAD,Condition(function HSCond))
set FoG = FirstOfGroup(HauntG)
if FoG != null and (not IsUnitAlly(FoG,GetOwningPlayer(.u))) and (not IsUnitHidden(.dum[i])) then
call HauntSGmove.create(.dum[i],FoG,.sfx[i],.u).startPeriodic()
set .b[i] = false
endif
endif
endif
set i = i + 1
endloop
set .DURATIONx = .DURATIONx - 0.035
if .DURATIONx <= 0 then
call this.stopPeriodic()
call this.destroy()
endif
set FoG = null
endmethod
implement T32x
static method create takes unit a returns HauntS
local thistype this = thistype.allocate()
local integer i = 0
local real angle = 360/DSPAWNS
local real dumX
local real dumY
set .u = a
set .x = GetUnitX(a)
set .y = GetUnitY(a)
set .DURATIONx = DURATION
set .ENUMERATE = 0
loop
exitwhen i >= (DSPAWNS)
set dumX = .x+RADIUS*Cos((i*angle)*bj_DEGTORAD)
set dumY = .y+RADIUS*Sin((i*angle)*bj_DEGTORAD)
set .b[i] = true
if (not IsUnitHidden(.dum[i])) or .dum[i] == null then
set .dum[i] = CreateUnit(Player(15),DUMCODE,dumX,dumY,270)
else
call ShowUnit(.dum[i],true)
call SetUnitX(.dum[i],dumX)
call SetUnitY(.dum[i],dumY)
endif
set .sfx[i] = AddSpecialEffectTarget(DUMMYSFX,.dum[i],"origin")
call UnitAddAbility(.dum[i],'Aloc')
call UnitAddAbility(.dum[i],'Amrf')
call SetUnitFlyHeight(.dum[i],SOULHEIGHT,0)
set i = i + 1
endloop
return this
endmethod
endstruct
private function Cond takes nothing returns boolean
if GetSpellAbilityId() == RAWCODE then
call HauntS.create(GetTriggerUnit()).startPeriodic()
endif
return false
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t,Condition(function Cond))
set t = null
endfunction
endscope
//TESH.scrollpos=256
//TESH.alwaysfold=0
scope Frostbrand initializer Init
//Frostbrand - Icy modification of Haunt v1.6.0
globals
private constant integer RAWCODE = 'A002'
private constant integer DUMCODE = 'h003'
private constant real DURATION = 5.005
private constant string DUMMYSFX = "Abilities\\Weapons\\FrostWyrmMissile\\FrostWyrmMissile.mdl"
private constant string ONHITSFX = "Abilities\\Weapons\\DemonHunterMissile\\DemonHunterMissile.mdl"
private constant string DRAINSFX = "Abilities\\Weapons\\ZigguratFrostMissile\\ZigguratFrostMissile.mdl"
private constant real RADIUS = 200
private constant real SOULRAD = 175
private constant integer DSPAWNS = 9
private constant real waitBeforeEnum = 1.05
private constant real angINCFACTOR = 0.15
private constant integer SOULRED = 0
private constant integer SOULGREEN = 200
private constant integer SOULBLUE = 255
private constant integer TRANSPARENCY = 100
private constant real SOULVELOCITY = 10
private constant real GHOSTVELOCITY = 7
private constant real EXITTIMER_DISTANCE = 1225
private constant integer SOULHEIGHT = 150
private constant integer GHOSTHEIGHT = 25
private constant attacktype ATTACKTYPE = ATTACK_TYPE_NORMAL
private constant damagetype DAMAGETYPE = DAMAGE_TYPE_ACID
private constant weapontype WEAPONTYPE = WEAPON_TYPE_WHOKNOWS
private constant real emergencyExitSoul = 1.25
private constant real emergencyExitGhost = 4
private group HauntG = CreateGroup()
private timer t = CreateTimer()
endglobals
private constant function HAUNTDAMAGE takes integer LVL returns real
return 10.*LVL+5
endfunction
native UnitAlive takes unit u returns boolean
private function HSCond takes nothing returns boolean
return UnitAlive(GetFilterUnit()) and (not IsUnitType(GetFilterUnit(),UNIT_TYPE_STRUCTURE)) and (not IsUnitType(GetFilterUnit(),UNIT_TYPE_ETHEREAL))
endfunction
//*SPELL CODE*
private struct HauntSReturn
unit a
unit b
unit c
real damage
real mD
effect e
real speedMultiplier
method onDestroy takes nothing returns nothing
set .a = null
set .b = null
set .c = null
set .damage = 0
set .mD = 0
set .speedMultiplier = 0
endmethod
private method periodic takes nothing returns nothing
local real x = GetUnitX(.c)
local real y = GetUnitY(.c)
local real dx = GetUnitX(.a)
local real dy = GetUnitY(.a)
local real distX = dx-x
local real distY = dy-y
local real ang = Atan2(distY,distX)
local real dist = distX*distX+distY*distY
local real newX = x+(.mD/GHOSTVELOCITY)*Cos(ang)*.speedMultiplier
local real newY = y+(.mD/GHOSTVELOCITY)*Sin(ang)*.speedMultiplier
call SetUnitX(.c,newX)
call SetUnitY(.c,newY)
if dist<EXITTIMER_DISTANCE or .speedMultiplier >= ((emergencyExitGhost/0.03125)*.1) then
call SetUnitX(.c,dx)
call SetUnitY(.c,dy)
call DestroyEffect(AddSpecialEffect(ONHITSFX,dx,dy))
call DestroyEffect(.e)
call RemoveUnit(.c)
call SetWidgetLife(.a,GetWidgetLife(.a)+.damage)
call this.stopPeriodic()
call this.destroy()
endif
set .speedMultiplier = .speedMultiplier + .1
endmethod
implement T32x
static method create takes unit caster, unit target, real damageTar returns HauntSReturn
local thistype this = thistype.allocate()
local real x = GetUnitX(target)-GetUnitX(caster)
local real y = GetUnitY(target)-GetUnitY(caster)
local real f = (bj_RADTODEG*Atan2(y,x))+180
set .a = caster
set .b = target
call SetUnitPathing(target,false)
set .c = CreateUnit(Player(15),GetUnitTypeId(.b),GetUnitX(.b),GetUnitY(.b),f)
set .damage = damageTar
set .mD = SquareRoot(x*x+y*y)
set .e = AddSpecialEffectTarget(DRAINSFX,.c,"origin")
set .speedMultiplier = 1
call SetUnitColor(.c,GetPlayerColor(GetOwningPlayer(.b)))
call UnitAddAbility(.c,'Amrf')
call SetUnitPathing(.c,false)
call UnitAddAbility(.c,'Aloc')
call UnitAddAbility(.c,'Avul')
call SetUnitFlyHeight(.c,GHOSTHEIGHT,0)
call PauseUnit(.c,true)
call SetUnitVertexColor(.c,SOULRED,SOULGREEN,SOULBLUE,TRANSPARENCY)
call SetUnitPathing(target,true)
return this
endmethod
endstruct
private struct HauntSGmove
unit a
unit b
effect c
unit d
real mD
integer SCount
method onDestroy takes nothing returns nothing
set .a = null
set .b = null
set .c = null
set .d = null
set .mD = 0
endmethod
private method periodic takes nothing returns nothing
local real x = GetUnitX(.a)
local real y = GetUnitY(.a)
local real tx = GetUnitX(.b)
local real ty = GetUnitY(.b)
local real distX = tx-x
local real distY = ty-y
local real ang = Atan2(distY,distX)
local real dist = distX*distX+distY*distY
local real newX = x+(.mD/SOULVELOCITY)*Cos(ang)
local real newY = y+(.mD/SOULVELOCITY)*Sin(ang)
call SetUnitX(.a,newX)
call SetUnitY(.a,newY)
if dist<EXITTIMER_DISTANCE or .SCount >= (emergencyExitSoul/0.03125) then
call SetUnitX(.a,tx)
call SetUnitY(.a,ty)
call DestroyEffect(AddSpecialEffect(ONHITSFX,tx,ty))
call UnitDamageTarget(.a,.b,HAUNTDAMAGE(GetUnitAbilityLevel(.d,RAWCODE)),true,false,ATTACKTYPE,DAMAGETYPE,WEAPONTYPE)
call DestroyEffect(.c)
call UnitRemoveAbility(.a,'Aloc')
call ShowUnit(.a,false)
call HauntSReturn.create(.d,.b,HAUNTDAMAGE(GetUnitAbilityLevel(.d,RAWCODE))).startPeriodic()
call this.stopPeriodic()
call this.destroy()
endif
set .SCount = .SCount + 1
endmethod
implement T32x
static method create takes unit u, unit tar, effect E, unit caster returns HauntSGmove
local thistype this = thistype.allocate()
local real x = GetUnitX(tar)-GetUnitX(u)
local real y = GetUnitY(tar)-GetUnitY(u)
set .a = u
set .b = tar
set .c = E
set .d = caster
set .mD = SquareRoot(x*x+y*y)
return this
endmethod
endstruct
private struct HauntS
unit u
real x
real y
unit array dum[DSPAWNS]
effect array sfx[DSPAWNS]
real DURATIONx
integer ENUMERATE
boolean array b[DSPAWNS]
method onDestroy takes nothing returns nothing
local integer i = 0
loop
exitwhen i == (DSPAWNS)
if (not IsUnitHidden(.dum[i])) then
call DestroyEffect(AddSpecialEffect(DUMMYSFX,GetUnitX(.dum[i]),GetUnitY(.dum[i])))
endif
call DestroyEffect(.sfx[i])
call UnitRemoveAbility(.dum[i],'Aloc')
call ShowUnit(.dum[i],false)
set .sfx[i] = null
set i = i + 1
endloop
set .x = 0
set .y = 0
set .DURATIONx = 0
set .ENUMERATE = 0
endmethod
private method periodic takes nothing returns nothing
local integer i = 0
local real dumX
local real dumY
local real x = GetUnitX(.u)
local real y = GetUnitY(.u)
local real ang = 0
local unit FoG
set .ENUMERATE = .ENUMERATE + 1
loop
exitwhen i == (DSPAWNS)
if .b[i] == true then
set ang = Atan2(GetUnitY(.dum[i])-y,GetUnitX(.dum[i])-x)+angINCFACTOR
set dumX = x+RADIUS*Cos(ang)
set dumY = y+RADIUS*Sin(ang)
call SetUnitX(.dum[i],dumX)
call SetUnitY(.dum[i],dumY)
if .ENUMERATE >= (waitBeforeEnum/0.035) then
call GroupEnumUnitsInRange(HauntG,dumX,dumY,SOULRAD,Condition(function HSCond))
set FoG = FirstOfGroup(HauntG)
if FoG != null and (not IsUnitAlly(FoG,GetOwningPlayer(.u))) and (not IsUnitHidden(.dum[i])) then
call HauntSGmove.create(.dum[i],FoG,.sfx[i],.u).startPeriodic()
set .b[i] = false
endif
endif
endif
set i = i + 1
endloop
set .DURATIONx = .DURATIONx - 0.035
if .DURATIONx <= 0 then
call this.stopPeriodic()
call this.destroy()
endif
set FoG = null
endmethod
implement T32x
static method create takes unit a returns HauntS
local thistype this = thistype.allocate()
local integer i = 0
local real angle = 360/DSPAWNS
local real dumX
local real dumY
set .u = a
set .x = GetUnitX(a)
set .y = GetUnitY(a)
set .DURATIONx = DURATION
set .ENUMERATE = 0
loop
exitwhen i >= (DSPAWNS)
set dumX = .x+RADIUS*Cos((i*angle)*bj_DEGTORAD)
set dumY = .y+RADIUS*Sin((i*angle)*bj_DEGTORAD)
set .b[i] = true
if (not IsUnitHidden(.dum[i])) or .dum[i] == null then
set .dum[i] = CreateUnit(Player(15),DUMCODE,dumX,dumY,270)
else
call ShowUnit(.dum[i],true)
call SetUnitX(.dum[i],dumX)
call SetUnitY(.dum[i],dumY)
endif
set .sfx[i] = AddSpecialEffectTarget(DUMMYSFX,.dum[i],"origin")
call UnitAddAbility(.dum[i],'Aloc')
call UnitAddAbility(.dum[i],'Amrf')
call SetUnitFlyHeight(.dum[i],SOULHEIGHT,0)
set i = i + 1
endloop
return this
endmethod
endstruct
private function Cond takes nothing returns boolean
if GetSpellAbilityId() == RAWCODE then
call HauntS.create(GetTriggerUnit()).startPeriodic()
endif
return false
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t,Condition(function Cond))
set t = null
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope Haunt initializer Init
//**** Deprecated. Does not use dummy recycling. ****
//REQUIRES JASS NEWGEN PACK AND JASSHELPER
//http://www.wc3c.net/showthread.php?t=90999 *JassNewGen Pack Download
//http://www.wc3c.net/showthread.php?t=88142 *JassHelper
//************************************H***********************************HAUNT
//*************************************A**********************************HAUNT
//**************************************U*********************************HAUNT
//***************************************N********************************HAUNT
//****************************************T*******************************HAUNT
//* SPELL - HAUNT v1
//* By Purgeandfire - Give credits if you can.
//* Description: Sends Sends ghostly souls to travel around the caster which hit any target that comes within
//* range for 10*AbilityLevl+5 damage. It will then return to heal the caster for the total damage dealt.
//* ****Systems Used: Timer32 -- Jesus4Lyf
//* ****Models Used: Dummy.mdx
//* Required Object Editor Data: "Haunt" Spell, "Dummy" unit
//* Implementation: Copy the Haunt spell, the dummy unit, T32 trigger and the haunt trigger.
//* Required Alterations:
//* - RAWCODE: Change this to the RAWCODE of your haunt spell.
//* - DUMCODE: Change this to the RAWCODE of your dummy unit.
//* Cautions:
//* - RADIUS: Don't set this too high. It *might* cause a crash if it is too large.
//* - SOULRAD: This will look ugly if set too high. It has an emergency execute which will
//* execute the timer drain functions if the soul takes too long to get to the unit.
//* This was made to prevent possible infinite timer loops. (Which would cause extreme lag and crash)
//* - DSPAWNS: This can make your circle look a lot more circular. However, more units results in
//* more attached effects, so it can cause a bit more frame rate drop for the duration of the spell.
//* - waitBeforeEnum: When the spell is cast, black souls spawn and revolve around the caster. This enumeration wait
//* was made so that you can actually see the black souls spawn before they go and steal life from a unit.
//* You can shorten/lengthen this.
//* - angINCFACTOR: This modifies how fast the circles revolve around the caster. Note that this
//* takes RADIANS not degrees. This can go extremely fast if you set it to anything
//* higher than 1. About 0.08 or so is a moderate pace. 0.3 is a fast pace, but makes
//* a good circular effect.
//* - TRANSPARENCY: Modifies the transparency of the ghost that returns to the caster. This is from
//* 0-255, not 0-100. 0 is completely transparent, and 255 is visible.
//* - SOULVELOCITY: This modifies the movement speed of the souls. The only thing to beware of is that
//* a HIGHER input results in a lower speed and vice versa.
//* - GHOSTVELOCITY: Modifies the movement speed of the ghosts that return. Same thing as above, beware
//* that a HIGHER input results in a lower speed and vice versa. Note that setting this
//* too high can result the ghost actually being slower than the ranger. There is no
//* emergency destroy like there is for the souls since the ghosts' path is more visible.
//* Keep this at a minimum, but don't make it too fast or you will hardly see it!
//* Default Values:
//* globals
//* private constant integer RAWCODE = 'A000'
//* private constant integer DUMCODE = 'h003'
//* private constant string DUMMYSFX = "Abilities\\Weapons\\AvengerMissile\\AvengerMissile.mdl"
//* private constant string ONHITSFX = "Abilities\\Weapons\\DemonHunterMissile\\DemonHunterMissile.mdl"
//* private constant string DRAINSFX = "Abilities\\Weapons\\IllidanMissile\\IllidanMissile.mdl"
//* private constant real RADIUS = 300
//* private constant real SOULRAD = 175
//* private constant integer DSPAWNS = 13
//* private constant real waitBeforeEnum = 1.05
//* private constant real angINCFACTOR = 0.3
//* private constant integer SOULRED = 0
//* private constant integer SOULGREEN = 255
//* private constant integer SOULBLUE = 225
//* private constant integer TRANSPARENCY = 100
//* private constant real SOULVELOCITY = 10
//* private constant real GHOSTVELOCITY = 12
//* private group HauntG = CreateGroup()
//* private timer t = CreateTimer()
//* endglobals
globals
private constant integer RAWCODE = 'A000'
//RAWCODE of the Haunt spell.
private constant integer DUMCODE = 'h003'
//RAWCODE of the dummy unit.
private constant real DURATION = 5.005
//Modifies the duration before the effects automatically destroy themselves. (Seconds)
//For most accuracy, be sure that 0.035 is a factor of the value. (It works fine if it isn't though)
private constant string DUMMYSFX = "Abilities\\Weapons\\AvengerMissile\\AvengerMissile.mdl"
//String path of the effects that revolve around the caster.
private constant string ONHITSFX = "Abilities\\Weapons\\DemonHunterMissile\\DemonHunterMissile.mdl"
//String path of the effects that occur when a target unit is hit.
private constant string DRAINSFX = "Abilities\\Weapons\\IllidanMissile\\IllidanMissile.mdl"
//String path of the effect that occurs when the soul returns to the caster.
private constant real RADIUS = 300
//Modifies the radius of the circle that the effects follow.
private constant real SOULRAD = 175
//Modifies the radius in which the soul will jump.
private constant integer DSPAWNS = 13
//Number of souls to create. More units equals more circular motion. However, more units also equals more frame drop.
private constant real waitBeforeEnum = 1.05
//Modifies the time to wait before the souls will start snatching nearby units. (Seconds)
private constant real angINCFACTOR = 0.3
//This is the angle increase factor every 0.035 seconds. It takes radians, not degrees. This can go pretty fast if too high.
private constant integer SOULRED = 0
private constant integer SOULGREEN = 255
private constant integer SOULBLUE = 225
private constant integer TRANSPARENCY = 100
//Modifies the vertex coloring of the soul that returns to the caster. Values are from 0-255 for all.
private constant real SOULVELOCITY = 10
//Modifies the velocity of the souls that rush toward the enemies.
//This isn't very noticeable though, unless the enemy is moving fast.
//LOWER VELOCITY SPECIFIED RESULTS IN A HIGHER SPEED, higher velocity results in a slower speed.
private constant real GHOSTVELOCITY = 12
//Modifies the speed of the ghosts that return to the caster.
//LOWER VELOCITY SPECIFIED RESULTS IN A HIGHER SPEED, higher velocity results in a slower speed.
private constant real EXITTIMER_DISTANCE = 1225
//Modifies the distance the soul/ghost has to be to the target before stopping the timer.
//This distance is actually 35. Use your input distance^2 (your input to the power of 2) and input that value for it to work.
private constant integer SOULHEIGHT = 75
//Modifies the elevation of the black souls.
private constant integer GHOSTHEIGHT = 15
//Do not change these below.
private group HauntG = CreateGroup()
private timer t = CreateTimer()
endglobals
private constant function HAUNTDAMAGE takes integer LVL returns real
return 10.*LVL+5
//Modify this to modify the damage dealt by the spell per soul to unit.
//10 * Ability_Level + 5
//Rank 1: 15 damage, Rank 2: 25 damage, Rank 3: 35 damage.
endfunction
private function HSCond takes nothing returns boolean
return GetWidgetLife(GetFilterUnit())>=0.405 and (not IsUnitType(GetFilterUnit(),UNIT_TYPE_STRUCTURE)) and (not IsUnitType(GetFilterUnit(),UNIT_TYPE_ETHEREAL))
endfunction
//*SPELL CODE*
private struct HauntSReturn
unit a
unit b
unit c
real damage
real mD
effect e
method onDestroy takes nothing returns nothing
call DestroyEffect(.e)
call RemoveUnit(.c)
set .a = null
set .b = null
set .c = null
set .damage = 0
set .mD = 0
endmethod
private method periodic takes nothing returns nothing
local real x = GetUnitX(.c)
local real y = GetUnitY(.c)
local real dx = GetUnitX(.a)
local real dy = GetUnitY(.a)
local real distX = dx-x
local real distY = dy-y
local real ang = Atan2(distY,distX)
local real dist = distX*distX+distY*distY
local real newX = x+(.mD/GHOSTVELOCITY)*Cos(ang)
local real newY = y+(.mD/GHOSTVELOCITY)*Sin(ang)
call SetUnitX(.c,newX)
call SetUnitY(.c,newY)
if dist<EXITTIMER_DISTANCE then
call SetUnitX(.c,dx)
call SetUnitY(.c,dy)
call DestroyEffect(AddSpecialEffect(ONHITSFX,dx,dy))
call DestroyEffect(.e)
call RemoveUnit(.c)
call SetWidgetLife(.a,GetWidgetLife(.a)+.damage)
call this.stopPeriodic()
call this.destroy()
endif
endmethod
implement T32x
static method create takes unit caster, unit target, real damageTar returns HauntSReturn
local thistype this = thistype.allocate()
local real x = GetUnitX(target)-GetUnitX(caster)
local real y = GetUnitY(target)-GetUnitY(caster)
local real f = (bj_RADTODEG*Atan2(y,x))+180
set .a = caster
set .b = target
call SetUnitPathing(target,false)
set .c = CreateUnit(Player(15),GetUnitTypeId(.b),GetUnitX(.b),GetUnitY(.b),f)
set .damage = damageTar
set .mD = SquareRoot(x*x+y*y)
set .e = AddSpecialEffectTarget(DRAINSFX,.c,"origin")
call SetUnitColor(.c,GetPlayerColor(GetOwningPlayer(.b)))
call UnitAddAbility(.c,'Amrf')
call SetUnitPathing(.c,false)
call UnitAddAbility(.c,'Aloc')
call UnitAddAbility(.c,'Avul')
call SetUnitFlyHeight(.c,GHOSTHEIGHT,0)
call PauseUnit(.c,true)
call SetUnitVertexColor(.c,SOULRED,SOULGREEN,SOULBLUE,TRANSPARENCY)
call SetUnitPathing(target,true)
return this
endmethod
endstruct
private struct HauntSGmove
unit a
unit b
effect c
unit d
real mD
integer SCount
method onDestroy takes nothing returns nothing
call DestroyEffect(.c)
call RemoveUnit(.a)
set .a = null
set .b = null
set .c = null
set .d = null
set .mD = 0
endmethod
private method periodic takes nothing returns nothing
local real x = GetUnitX(.a)
local real y = GetUnitY(.a)
local real tx = GetUnitX(.b)
local real ty = GetUnitY(.b)
local real distX = tx-x
local real distY = ty-y
local real ang = Atan2(distY,distX)
local real dist = distX*distX+distY*distY
local real newX = x+(.mD/SOULVELOCITY)*Cos(ang)
local real newY = y+(.mD/SOULVELOCITY)*Sin(ang)
call SetUnitX(.a,newX)
call SetUnitY(.a,newY)
if dist<EXITTIMER_DISTANCE or .SCount == 30 then
call SetUnitX(.a,tx)
call SetUnitY(.a,ty)
call DestroyEffect(AddSpecialEffect(ONHITSFX,tx,ty))
call UnitDamageTarget(.a,.b,HAUNTDAMAGE(GetUnitAbilityLevel(.d,RAWCODE)),true,false,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_ACID,WEAPON_TYPE_WHOKNOWS)
call RemoveUnit(.a)
call DestroyEffect(.c)
call HauntSReturn.create(.d,.b,HAUNTDAMAGE(GetUnitAbilityLevel(.d,RAWCODE))).startPeriodic()
call this.stopPeriodic()
call this.destroy()
return
endif
set .SCount = .SCount + 1
endmethod
implement T32x
static method create takes unit u, unit tar, effect E, unit caster returns HauntSGmove
local thistype this = thistype.allocate()
local real x = GetUnitX(tar)-GetUnitX(u)
local real y = GetUnitY(tar)-GetUnitY(u)
set .a = u
set .b = tar
set .c = E
set .d = caster
set .mD = SquareRoot(x*x+y*y)
return this
endmethod
endstruct
private struct HauntS
unit u
real x
real y
unit array dum[DSPAWNS]
effect array sfx[DSPAWNS]
real DURATIONx
integer ENUMERATE
method onDestroy takes nothing returns nothing
local integer i = 0
loop
exitwhen i == (DSPAWNS-1)
if .dum[i] != null then
call DestroyEffect(AddSpecialEffect(DUMMYSFX,GetUnitX(.dum[i]),GetUnitY(.dum[i])))
endif
call DestroyEffect(.sfx[i])
call KillUnit(.dum[i])
set .dum[i] = null
set .sfx[i] = null
set i = i + 1
endloop
set .x = 0
set .y = 0
set .DURATIONx = 0
set .ENUMERATE = 0
endmethod
private method periodic takes nothing returns nothing
local integer i = 0
local real dumX
local real dumY
local real x = GetUnitX(.u)
local real y = GetUnitY(.u)
local real ang = 0
local unit FoG = null
set .ENUMERATE = .ENUMERATE + 1
loop
exitwhen i == (DSPAWNS-1)
set ang = Atan2(GetUnitY(.dum[i])-y,GetUnitX(.dum[i])-x)+angINCFACTOR
set dumX = x+RADIUS*Cos(ang)
set dumY = y+RADIUS*Sin(ang)
call SetUnitX(.dum[i],dumX)
call SetUnitY(.dum[i],dumY)
if .ENUMERATE >= (waitBeforeEnum/0.035) then
call GroupEnumUnitsInRange(HauntG,dumX,dumY,SOULRAD,Condition(function HSCond))
set FoG = FirstOfGroup(HauntG)
if FoG != null and (not IsUnitAlly(FoG,GetOwningPlayer(.u))) and .dum[i] != null then
call HauntSGmove.create(.dum[i],FoG,.sfx[i],.u).startPeriodic()
set .dum[i] = null
endif
endif
set i = i + 1
endloop
set .DURATIONx = .DURATIONx - 0.035
if .DURATIONx <= 0 then
call this.stopPeriodic()
call this.destroy()
endif
set FoG = null
endmethod
implement T32x
static method create takes unit a returns HauntS
local thistype this = thistype.allocate()
local integer i = 0
local real angle = 360/DSPAWNS
local real dumX
local real dumY
set .u = a
set .x = GetUnitX(a)
set .y = GetUnitY(a)
set .DURATIONx = DURATION
set .ENUMERATE = 0
loop
exitwhen i == (DSPAWNS-1)
set dumX = .x+RADIUS*Cos((i*angle)*bj_DEGTORAD)
set dumY = .y+RADIUS*Sin((i*angle)*bj_DEGTORAD)
set .dum[i] = CreateUnit(Player(15),DUMCODE,dumX,dumY,270)
set .sfx[i] = AddSpecialEffectTarget(DUMMYSFX,.dum[i],"origin")
call UnitAddAbility(.dum[i],'Amrf')
call SetUnitFlyHeight(.dum[i],SOULHEIGHT,0)
set i = i + 1
endloop
return this
endmethod
endstruct
private function Cond takes nothing returns boolean
if GetSpellAbilityId() == RAWCODE then
call HauntS.create(GetTriggerUnit()).startPeriodic()
endif
return false
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t,Condition(function Cond))
set t = null
endfunction
endscope