//********************************************************************************************
//* Lightning Tendrils v1.1 by xD.Schurke
//* -------------------------------------
//*
//* Requires:
//* * JNGP (JassHelper 0.9.G.0)
//* * xDModules
//* * BoolexprUtils
//*
//* Thanks to Vexorian for JassHelper and BoolexprUtils
//*
//* The hero soars up and creates tendriles consisting of pure energy. If a tendril
//* hits an enemy the unit will be damaged.
//*
//*
//* Changelog
//* ----------
//*
//* v.1.1
//* * Implemented ForGroup loop instead of group loop
//* * Added Sounds
//* * The caster now can fly through units etc.
//*
//*
//********************************************************************************************
library LightningTendrils initializer init requires xDModules,BoolexprUtils
globals
//Constants adjust to your map specific data/values
private constant integer spellID = 'A000' //The spell raw-code
private constant integer flyID = 'Amrf' //The fly raw-code DO NOT CHANGE THIS ONE
private constant real interval = 0.03125 //The updating interval
private constant real tendrilInterval = 0.1 //The interval which moves the tendrils
private constant real heightDecStart = 13.75 //after this time the unit starts to move to the ground
private constant real range = 350. //The range where the tendrils will move in
private constant real damageRange = 50. //The range of the tendril impact damage
private constant real damage = 3.
private constant real damageInc = 2.
private constant real flyHeight = 500. //The height where the hero will be
private constant real flyHeightInc = 12.5
private constant real flyHeightDec = -12.5
private constant real duration = 15. //Duration of the spell
private constant integer tendrils = 8 //Number of tendrils + increasement per level
private constant integer tendrilsInc = 3
//Following vars are for the effects
private constant string tendrilEffect = "CLPB"
private constant string hitEffect = "Abilities\\Spells\\Orc\\Purge\\PurgeBuffTarget.mdl"
private constant string endEffect = "Abilities\\Spells\\Human\\Thunderclap\\ThunderClapCaster.mdl"
private constant string attach = "chest"
//Sound effects
private constant string sfxString = "Abilities\\Spells\\Orc\\LightningBolt\\LightningBolt.wav"
//DO NOT CHANGE THOSE VARIABLES DUE OF IMPORTANT USAGE
private group tmpG = CreateGroup()
private unit tmpU
private player tmpP
private boolexpr filter
endglobals
//*************************************Formulas***********************************************
private function tendrilCount takes integer lvl returns integer
return tendrils+((lvl-1)*tendrilsInc)
endfunction
private function tendrilDamage takes integer lvl returns real
return damage+((lvl-1)*damageInc)
endfunction
//********************************************************************************************
//*************************************Some functions*****************************************
private function GroupFilter takes nothing returns boolean
return IsUnitEnemy(GetFilterUnit(),tmpP) and (GetUnitState(GetFilterUnit(),UNIT_STATE_LIFE)>0) and IsUnitType(GetFilterUnit(),UNIT_TYPE_GROUND)
endfunction
private function GetRandomXInRect takes rect r returns real
return GetRandomReal(GetRectMinX(r),GetRectMaxX(r))
endfunction
private function GetRandomYInRect takes rect r returns real
return GetRandomReal(GetRectMinY(r),GetRectMaxY(r))
endfunction
//********************************************************************************************
//****************************************Core Part*******************************************
private function callback takes nothing returns nothing
local unit u = GetEnumUnit()
call UnitDamageTarget(tmpU,u,tendrilDamage(GetUnitAbilityLevel(tmpU,spellID)),false,false,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,null)
set u = null
endfunction
private struct tendrilStruct
unit caster
lightning tendril
real time = 0.
method actions takes nothing returns nothing
//local variable initialization
local real x1 = GetUnitX(.caster)
local real y1 = GetUnitY(.caster)
local real z1 = GetUnitFlyHeight(.caster)
local rect r = Rect(x1 -range,y1 -range,x1+range,y1+range) //<== Creates a rect where the tendril will move in
local real x2 = GetRandomXInRect(r)
local real y2 = GetRandomYInRect(r)
local real z2 = 0
local sound sfx = CreateSound(sfxString,false,true,true,0,0,"")
//setting the sound
call SetSoundPosition(sfx, x2, y2, 0)
call SetSoundVolume(sfx, R2I(100 * I2R(127) * 0.01))
call StartSound(sfx)
call KillSoundWhenDone(sfx)
//end of initialization
set .time = .time + tendrilInterval
//Tendril movement
call MoveLightningEx(.tendril,true,x1,y1,z1,x2,y2,z2)
call DestroyEffect(AddSpecialEffect(hitEffect,x2,y2))
//Tendril damage
set tmpP = GetOwningPlayer(.caster)
set tmpU = .caster
call GroupEnumUnitsInRange(tmpG,x2,y1,damageRange,filter)
call ForGroup(tmpG,function callback)
//when should this end??
if .time >= duration then
call DestroyEffect(AddSpecialEffect(endEffect,x2,y2))
call DestroyLightning(.tendril)
set .tendril = null
set .caster = null
call .destroy()
endif
//clear all leaks!!
call RemoveRect(r)
set sfx = null
set r = null
endmethod
// for this look into xDModules :)
implement structStack
endstruct
private struct tendrilCaster
unit caster
real height = 0.
real heightInc = flyHeightInc
real time = 0.
method actions takes nothing returns nothing
//First setting the height and time for increasing flyHeight etc.
set .time = .time + interval
set .height = .height + .heightInc
call SetUnitFlyHeight(.caster,.height,0)
if .height >= flyHeight then
set .heightInc = 0
endif
if .time >= heightDecStart then
set .heightInc = flyHeightDec
endif
//everything ends!!
if .time >= duration then
call SetUnitPathing(.caster,true)
set .caster = null
call .destroy()
endif
endmethod
// for this look into xDModules :)
implement structStack
endstruct
//Just another stupid condition function... realy blablabla
private function cond takes nothing returns boolean
return GetSpellAbilityId() == spellID
endfunction
//action function takes care of initializate the structs and is the main protagonist in this little story XD
private function action takes nothing returns nothing
local tendrilStruct dat
local tendrilCaster data = tendrilCaster.create(interval)
local unit caster = GetTriggerUnit()
local integer i = 0
set data.caster = caster
call UnitAddAbility(caster,flyID)
call UnitRemoveAbility(caster,flyID)
call SetUnitPathing(caster,false)
loop
exitwhen i >= tendrilCount(GetUnitAbilityLevel(caster,spellID))
set dat = tendrilStruct.create(tendrilInterval)
set dat.tendril = AddLightningEx(tendrilEffect,true,GetUnitX(caster),GetUnitY(caster),GetUnitFlyHeight(caster),GetUnitX(caster),GetUnitY(caster),GetUnitFlyHeight(caster))
set dat.caster= caster
set i = i + 1
endloop
set caster = null
endfunction
//usual init stuff like preloading or setting filter
private function init takes nothing returns nothing
local trigger int = CreateTrigger()
local integer i = 0
loop
call TriggerRegisterPlayerUnitEvent(int,Player(i),EVENT_PLAYER_UNIT_SPELL_EFFECT,BOOLEXPR_TRUE)
set i = i + 1
exitwhen i >= bj_MAX_PLAYER_SLOTS
endloop
call TriggerAddCondition(int,Condition(function cond))
call TriggerAddAction(int,function action)
set int = null
set filter = Condition(function GroupFilter)
call Preload(hitEffect)
call Preload(endEffect)
endfunction
endlibrary