//******************************************************************************
//* *
//* Lightning Invocation *
//* v1.30 *
//* *
//* By: scorpion182 aka ranzi aka ada_aja *
//* http://www.jade-wars.com *
//* *
//******************************************************************************
library LightningInvocation initializer init requires TimerUtils, PolarProjection, GroupUtils, PUI
//*************************************************************
//* Configuration Constants
globals
private constant integer DUMMY_ID='e000' //Dummy Caster Unit Rawcode
private constant integer SPELL_ID='A000' //Spell Rawcode
private constant integer LIGHTNING_NUM=6 //Number of Lightning
private constant real LIGHTNING_HEIGHT=500. //Lightning Height
private constant string LIGHTNING_ID="AFOD" //Lighting Rawcode
private constant string GROUND_FX="Abilities\\Weapons\\VengeanceMissile\\VengeanceMissile.mdl" //Effect attach to lightning
private constant string HEAL_FX="Abilities\\Weapons\\VengeanceMissile\\VengeanceMissile.mdl" //Effect attach to target heal unit
private constant string CASTER_FX="Abilities\\Spells\\Orc\\Voodoo\\VoodooAura.mdl" //Effect attach to caster
private constant string CASTER_ATTCH="origin" //caster attachment point
private constant string TARGT_H_ATTCH="origin" //target heal attachment point
private constant string ORDER_ID="starfall" //spell order id
private constant real INTERVAL=0.1 //timer interval
private constant boolean CLOCKWISE=false //rotate clockwise?
private constant real ANGLE_INCREMENT=.15 //angle movement
endglobals
//*****************************************************************
//* Configuration Functions
//* Spell Damage
private constant function HEAL_AMOUNT takes integer lvl returns real
return lvl*10.0*INTERVAL
endfunction
//* Spell Area of Effect Radius
private constant function RADIUS takes integer lvl returns real
return lvl*600.
endfunction
//* Configuration End
//*****************************************************************
globals
private integer array UnitData
private boolexpr b
private group CastersGroup
endglobals
//set unit's integer
private function AttachIntegerToUnit takes unit u, integer i returns nothing
set UnitData[GetUnitIndex(u)] = i
endfunction
//get unit's integer
private function GetIntegerFromUnit takes unit u returns integer
return UnitData[GetUnitIndex(u)]
endfunction
//spell filter function
private function Spell_Filter takes nothing returns boolean
return (IsUnitType(GetFilterUnit(),UNIT_TYPE_STRUCTURE)==false) and (IsUnitType(GetFilterUnit(), UNIT_TYPE_MAGIC_IMMUNE)==false) and (GetWidgetLife(GetFilterUnit()) > 0.405)
endfunction
//spell struct
private struct data
unit caster
unit dum
unit array missile[LIGHTNING_NUM]
lightning array lg[LIGHTNING_NUM]
real array angle[LIGHTNING_NUM]
effect fx
timer t
group g
integer lvl
static method create takes unit c, timer t returns data
local data d=data.allocate()
set d.g=NewGroup()
set d.caster=c
set d.t=t
set d.fx=AddSpecialEffectTarget(CASTER_FX, d.caster,CASTER_ATTCH)
set d.dum=CreateUnit(GetOwningPlayer(d.caster),DUMMY_ID,GetUnitX(d.caster),GetUnitY(d.caster),0)
set d.lvl=GetUnitAbilityLevel(d.caster,SPELL_ID)
call GroupAddUnit(CastersGroup,d.caster)
return d
endmethod
//update victim group
method Update_Group takes nothing returns nothing
local unit s
local group temp=NewGroup()
local integer lvl=GetUnitAbilityLevel(.caster,SPELL_ID)
local integer idx
call GroupEnumUnitsInRange(temp,GetUnitX(.caster),GetUnitY(.caster),RADIUS(lvl),b)
//convert owner, and heal allies
loop
set s=FirstOfGroup(temp)
exitwhen s==null
//convert owner
if (IsUnitEnemy(s,GetOwningPlayer(.caster))==true and IsUnitInGroup(s,.g)==false and IsUnitType(s,UNIT_TYPE_HERO)==false) then
call AttachIntegerToUnit(s,GetPlayerId(GetOwningPlayer(s)))
call SetUnitOwner(s,GetOwningPlayer(.caster),true)
call GroupAddUnit(.g,s)
//heal friendly unit
elseif (IsUnitAlly(s,GetOwningPlayer(.caster))==true and s!=.caster and IsUnitType(s,UNIT_TYPE_HERO)==true) then
call SetUnitState(s,UNIT_STATE_LIFE,GetUnitState(s,UNIT_STATE_LIFE)+HEAL_AMOUNT(lvl))
call DestroyEffect(AddSpecialEffectTarget(HEAL_FX, s,TARGT_H_ATTCH))
endif
call GroupRemoveUnit(temp,s)
endloop
//out of range?
call GroupAddGroup(.g,temp)
loop
set s=FirstOfGroup(temp)
exitwhen s==null
if (Unit_Distance(s,.caster)>RADIUS(lvl)) then
set idx=GetIntegerFromUnit(s)
call SetUnitOwner(s,Player(idx),true)
call GroupRemoveUnit(.g,s)
endif
call GroupRemoveUnit(temp,s)
endloop
call ReleaseGroup(temp)
set temp=null
endmethod
private method onDestroy takes nothing returns nothing
local integer i=0
local unit s
local integer idx
call ReleaseTimer(.t)
call DestroyEffect(.fx)
call KillUnit(.dum)
//revert creeps to original owner
loop
set s=FirstOfGroup(.g)
exitwhen s==null
set idx=GetIntegerFromUnit(s)
call SetUnitOwner(s,Player(idx),true)
call GroupRemoveUnit(.g,s)
endloop
call ReleaseGroup(.g)
//destroy lightning
loop
exitwhen i>LIGHTNING_NUM
call DestroyLightning(.lg[i])
call KillUnit(.missile[i])
set i=i+1
endloop
call GroupRemoveUnit(CastersGroup,.caster)
endmethod
endstruct
//rotate the lightning
private function Clock takes nothing returns nothing
local timer t = GetExpiredTimer()
local data d=data(GetTimerData(t))
local integer i=0
local real x1
local real y1
local real x2 = GetUnitX(d.dum)
local real y2 = GetUnitY(d.dum)
local real angle
local integer lvl=d.lvl
if (GetUnitCurrentOrder(d.caster)==OrderId(ORDER_ID)) then
call d.Update_Group()
call TimerStart(t,INTERVAL,false,function Clock)
loop
exitwhen i>LIGHTNING_NUM
set x1 = GetUnitX(d.missile[i])
set y1 = GetUnitY(d.missile[i])
//rotate counter clockwise
if CLOCKWISE==false then
set angle=d.angle[i]+ANGLE_INCREMENT
//rotate clockwise
else
set angle=d.angle[i]-ANGLE_INCREMENT
endif
//move lightning
call SetUnitPosition(d.missile[i], x2+RADIUS(lvl)*Cos(angle), y2+RADIUS(lvl)*Sin(angle))
call MoveLightningEx(d.lg[i],true,GetUnitX(d.dum),GetUnitY(d.dum),GetUnitFlyHeight(d.dum)+LIGHTNING_HEIGHT,GetUnitX(d.missile[i]),GetUnitY(d.missile[i]),GetUnitFlyHeight(d.missile[i]))
call DestroyEffect(AddSpecialEffectTarget(GROUND_FX, d.missile[i],"origin"))
set d.angle[i]=angle
set i=i+1
endloop
else
call d.destroy()
endif
set t=null
endfunction
//spell trigger actions
private function Actions takes nothing returns boolean
local timer t
local unit u=GetSpellAbilityUnit()
local data d
local integer i=0
local integer lvl=GetUnitAbilityLevel(u,SPELL_ID)
if (IsUnitInGroup(u,CastersGroup)==false and GetSpellAbilityId() == SPELL_ID) then
set t=NewTimer()
set d=data.create(u,t)
call SetTimerData(t,integer(d))
//create lightning
loop
exitwhen i>LIGHTNING_NUM
set d.missile[i]=CreateUnit(GetOwningPlayer(d.caster),DUMMY_ID, PolarProjectionX(GetUnitX(d.caster),RADIUS(lvl), 360/LIGHTNING_NUM*i), PolarProjectionY(GetUnitY(d.caster), RADIUS(lvl), 360/LIGHTNING_NUM*i), 0.00)
set d.lg[i]=AddLightningEx(LIGHTNING_ID,true,GetUnitX(d.dum),GetUnitY(d.dum),GetUnitFlyHeight(d.dum)+LIGHTNING_HEIGHT,GetUnitX(d.missile[i]),GetUnitY(d.missile[i]),GetUnitFlyHeight(d.missile[i]))
set d.angle[i]=bj_DEGTORAD*360/LIGHTNING_NUM*i
set i=i+1
endloop
call TimerStart(t,INTERVAL,false,function Clock)
set u=null
set t=null
return true
endif
set u=null
set t=null
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 Actions))
set b=Condition(function Spell_Filter)
set CastersGroup=NewGroup()
//Preload FX
call Preload(GROUND_FX)
call Preload(CASTER_FX)
call Preload(HEAL_FX)
endfunction
endlibrary