//***************************************************************************
//***************************************************************************
//***************************************************************************
// M A G I C L I G H T
// By: Elphis (Nyuu)
// Version: 1.3
//
// Sepll Description:
// ` - Create a light swirling around the caster, then it will fly around,
// creating a protective ring of light, when the light hit allies will recover
// 10/20/30/40 / light (Maximum: 150/300/450/600) hit points,
// when the light hit enemies will cause damage by 20/40/60/80 / light (Maximum: 300/600/900/1200).
// Credits:
// GreenLight Model - http://www.hiveworkshop.com/forums/models-530/green-light-243630/
// BoundSentinel - http://www.wc3c.net/showthread.php?t=102576
// - Installation:
// - Import/copy Magic Light code and Require folder to your map
// - Import/copy the custom ability and unit to your map and change the SPELL_ID, DUMMY_LIGHT if needed
// - You may view the raw ID of the objects by pressing CTRL+D in the object editor
// - You may play with the configurables below
//
//
//***************************************************************************
//***************************************************************************
//***************************************************************************
library MagicLight
globals
//Spell rawcode, change if needed
private constant integer SPELL_ID = 'A000'
//Dummy rawcode, change if needed
private constant integer DUMMY_ID = 'e000'
//Dummy count per waves, change if needed
private constant integer LIGHT_COUNT = 15
//Total waves of the lights
private constant integer LIGHT_WAVE = 3
//Lights create per peroid
private constant real LIGHT_TIK = 1.
//Timer period
private constant real PERIODIC = .031250000
//
private constant real LIGHT_SPEED = 5.
private constant real LIGHT_CIRCLE_SPEED = 5.
private constant real START_DISTANCE = 100.
//Lights scale
private constant real LIGHT_SCALE = 3.
//Damages base when it hit enemies
private constant real DAMAGE_BASE = 20.
//Heals base when it hit allies
private constant real HEAL_BASE = 10.
//Value betweens lights and allies/enemies heals/damages radius
private constant real LIGHT_AOE = 150.
//Full area of effects of this spell
private constant real MAX_AOE = 600.
//**************************************************************
private constant attacktype AT = ATTACK_TYPE_HERO
private constant damagetype DT = DAMAGE_TYPE_DEATH
private constant weapontype WT = WEAPON_TYPE_CLAW_HEAVY_SLICE
//**************************************************************
//Heals effect when the lights hit allies
private constant string HEAL_EFFECT = "Abilities\\Spells\\Human\\HolyBolt\\HolyBoltSpecialArt.mdl"
//Damages effect when the lights hit allies
private constant string DAMAGE_EFFECT = "war3mapImported\\Green Light.mdx"
//Disappear effect when the light reach maximum area of effects
private constant string LIGHT_EXPIRE = "Abilities\\Spells\\Human\\DispelMagic\\DispelMagicTarget.mdl"
//Damage enemies effect attachment
private constant string DAMAGE_ATTACH = "origin"
//Heal allies effect attachment
private constant string HEAL_ATTACH = "origin"
//Dummy owner
private constant player DUMMY_OWNER = Player(15)
//Player that filterFunction will be skipped
private constant player SKIP_PLAYER = Player(15)
//**************************************************************
// NON - CONFIGURATION
//**************************************************************
private constant timer TIMER = CreateTimer()
private constant timer TIMER_2 = CreateTimer()
private constant group G = CreateGroup()
private integer M = -1
private integer array SM
private integer PM = -1
private integer array PSM
//**************************************************************
endglobals
//Damage settings*****************************************************
private constant function getDamage takes unit u,integer lvl returns real
return DAMAGE_BASE*lvl
endfunction
//******************************************************************
//Heal settings*****************************************************
private constant function Heal takes unit u,integer lvl returns real
return HEAL_BASE*lvl
endfunction
//********************************************************************
//Filter Function Settings******************************************
private constant function filterFunc takes unit filterUnit returns boolean
return not IsUnitType(filterUnit,UNIT_TYPE_DEAD) and GetOwningPlayer(filterUnit) != SKIP_PLAYER and GetUnitTypeId(filterUnit) != 0
endfunction
//********************************************************************
private struct MagicLight
unit caster = null
integer lightwave = LIGHT_WAVE
real tik = 0.
static constant real inBetween = 360./LIGHT_COUNT*.0174533
static method onPeriodic takes nothing returns nothing
local integer i = 0
local integer l
local real x
local real y
local real ux
local real uy
local real d
local unit u = null
local thistype this
loop
exitwhen i > M
set this = SM[i]
if tik < LIGHT_TIK then
set tik = tik + PERIODIC
else
set tik = 0.
if lightwave > 0 then
set l = 1
set ux = GetUnitX(caster)
set uy = GetUnitY(caster)
loop
exitwhen l > LIGHT_COUNT
set d = (l*inBetween)
set x = ux + START_DISTANCE * Cos(d)
set y = uy + START_DISTANCE * Sin(d)
set u = CreateUnit(DUMMY_OWNER,DUMMY_ID,x,y,0.)
call SetUnitScale(u,LIGHT_SCALE,0.,0.)
set d = bj_RADTODEG*Atan2(y-uy,x-ux)
call MagicLight_MagicLightPlugin.add(u,caster,d)
set l = l + 1
endloop
set lightwave = lightwave - 1
else
set caster = null
set SM[i] = SM[M]
set SM[M] = -2
set M = M - 1
call destroy()
if M == -1 then
call PauseTimer(TIMER)
endif
endif
set lightwave = lightwave - 1
set u = null
endif
set i = i + 1
endloop
endmethod
static method onCast takes nothing returns boolean
local thistype this
local integer l
local real x
local real y
local real d
local real ux
local real uy
local unit u
if GetSpellAbilityId() == SPELL_ID then
set this = allocate()
set M = M + 1
set SM[M] = this
set caster = GetTriggerUnit()
set l = 1
set ux = GetUnitX(caster)
set uy = GetUnitY(caster)
loop
exitwhen l > LIGHT_COUNT
set d = (l*inBetween)
set x = ux + START_DISTANCE * Cos(d)
set y = uy + START_DISTANCE * Sin(d)
set u = CreateUnit(DUMMY_OWNER,DUMMY_ID,x,y,0.)
call SetUnitScale(u,LIGHT_SCALE,0.,0.)
set d = bj_RADTODEG*Atan2(y-GetUnitY(caster),x-GetUnitX(caster))
call MagicLight_MagicLightPlugin.add(u,caster,d)
set l = l + 1
endloop
set u = null
if M == 0 then
call TimerStart(TIMER,PERIODIC,true,function thistype.onPeriodic)
endif
endif
return false
endmethod
static method onInit takes nothing returns nothing
local trigger t = CreateTrigger()
local integer i = 0
loop
exitwhen i > 15
call TriggerRegisterPlayerUnitEvent(t,Player(i),EVENT_PLAYER_UNIT_SPELL_EFFECT,null)
set i = i + 1
endloop
call TriggerAddCondition(t,function thistype.onCast)
endmethod
endstruct
public struct MagicLightPlugin
unit light
unit caster
player p
real angle
real distance = START_DISTANCE
real dmg
real heal
static method onPeriodic takes nothing returns nothing
local integer i = 0
local thistype this
local real x
local real y
local real a
local unit f = null
loop
exitwhen i > PM
set this = PSM[i]
if distance < MAX_AOE then
set distance = distance + LIGHT_CIRCLE_SPEED
set angle = angle + LIGHT_SPEED
set a = .0174533*angle
set x = GetUnitX(caster) + distance * Cos(a)
set y = GetUnitY(caster) + distance * Sin(a)
call SetUnitX(light,x)
call SetUnitY(light,y)
call GroupEnumUnitsInRange(G,x,y,LIGHT_AOE,null)
loop
set f = FirstOfGroup(G)
exitwhen f == null
if filterFunc(f) and f != caster then
if IsUnitEnemy(f,p) then
call UnitDamageTarget(caster,f,dmg,true,false,AT,DT,WT)
call DestroyEffect(AddSpecialEffectTarget(DAMAGE_EFFECT,f,DAMAGE_ATTACH))
else
call SetWidgetLife(f,GetWidgetLife(f)+heal)
call DestroyEffect(AddSpecialEffectTarget(HEAL_EFFECT,f,HEAL_ATTACH))
endif
set distance = 99999.
endif
call GroupRemoveUnit(G,f)
endloop
else
if distance != 99999. then
call DestroyEffect(AddSpecialEffect(LIGHT_EXPIRE,GetUnitX(light),GetUnitY(light)))
endif
call RemoveUnit(light)
set light = null
set caster = null
set p = null
set PSM[i] = PSM[PM]
set PSM[PM] = -2
set PM = PM - 1
call destroy()
if PM == -1 then
call PauseTimer(TIMER_2)
endif
endif
set i = i + 1
endloop
endmethod
static method add takes unit l,unit c,real a returns nothing
local thistype this = allocate()
local integer lvl = GetUnitAbilityLevel(c,SPELL_ID)
set PM = PM + 1
set PSM[PM] = this
set angle = a
set light = l
set caster = c
set dmg = getDamage(caster,lvl)
set heal = Heal(caster,lvl)
set p = GetOwningPlayer(caster)
if PM == 0 then
call TimerStart(TIMER_2,PERIODIC,true,function thistype.onPeriodic)
endif
endmethod
endstruct
endlibrary