//*******************************************************************************
// Spirit Bombs spell by Kingz *
// Notes: *
// My verry first spell made in vJass *
// *
// Requirements: *
// A point based spell *
// dummy.mdx model which is featured in this map *
// The dummy unit *
// JassNewGenPack *
//*******************************************************************************
scope SpiritBombs initializer InitSB
//**********************************************
//Settings - All of the spell settings are here*
//**********************************************
globals
private constant integer SpellID = 'A000' //spell ID
private constant integer DummyID = 'e000' //dummy unit ID
private constant string MissileEff = "Abilities\\Spells\\Other\\AcidBomb\\BottleMissile.mdl" //missile art
private constant string ImpactEff = "Abilities\\Spells\\Undead\\OrbOfDeath\\OrbOfDeathMissile.mdl" //this effects will get created upon missile impact
private constant string UnitEff = "Abilities\\Spells\\Human\\Feedback\\ArcaneTowerAttack.mdl" //units affected by the spell will get this effect attached to them
private constant string ImpactEff2 = "Abilities\\Weapons\\FarseerMissile\\FarseerMissile.mdl" //upon impact attaches this effect to the missile
private constant real Mb_base = 20 // base mana burn value
private constant real Mb_inc = 10 // increasement of mana burn per level
private constant integer Bn_base = 2 // number of missile bounces
private constant integer Bn_inc = 1 // increeasment of bounce number per level
private constant integer Miss_num = 1 // number of missiles thrown
private constant integer Miss_inc = 1 // number or missiles increased by level
private constant real Ie_AOE = 250 // range in which the units get affected
private constant real M_speed = 7 // missile speed
private constant real M_height = 350 // maximum height which the missile can reach
private constant real Bonus_mb = 20 // bonus mana burn value; the mana burn gets powered whenever it gathers enough mana
private constant real Bounce_dist = 275 // distance for each bounce
private constant real FeedV = 200 // upon reaching this value the mana burn gains in power
private constant real Angle_dif = 35 // defines the maximum possible spread of the missiles
endglobals
//***************************************************************************************
//Settings end - Do not modify anything below this if you don't know what you are doing!*
//***************************************************************************************
globals
private boolexpr TF = null
private player TP = null
private real MaxX
private real MaxY
private real MinX
private real MinY
endglobals
//parabola function for the missile
private function ParabolaZ takes real h,real d,real cd returns real
return (4*h / d)*(d - cd)*(cd / d)
endfunction
private struct SB
unit c
unit m
integer l
real mh
real a
real d
real cd = 0
integer bn
real mb
real f
player p
effect e
static SB array ind
static integer sca = 0
static timer counter = CreateTimer()
// moving the dummy unit as well as the mana burn effect is located below
static method Motion takes nothing returns nothing
local SB v
local real x
local real y
local real bx
local real by
local real ang
local real ang2
local real h
local integer i = 0
local group tg = CreateGroup()
local unit tu
local real mlb
loop
exitwhen i >= SB.sca
set v = SB.ind[i]
if GetUnitX(v.m) > MaxX or GetUnitX(v.m) < MinX or GetUnitY(v.m) > MaxY or GetUnitX(v.m) < MinY then
set v.cd = v.d
endif
if v.cd < v.d then
set x = GetUnitX(v.m) + M_speed * Cos(v.a)
set y = GetUnitY(v.m) + M_speed * Sin(v.a)
set v.cd = v.cd + M_speed
call SetUnitX(v.m,x)
call SetUnitY(v.m,y)
set h = ParabolaZ(M_height,v.d,v.cd)
call SetUnitFlyHeight(v.m,h,0)
else
call DestroyEffect(AddSpecialEffectTarget(ImpactEff2,v.m,"chest"))
call DestroyEffect(AddSpecialEffect(ImpactEff,GetUnitX(v.m),GetUnitY(v.m)))
set TP = v.p
call GroupEnumUnitsInRange(tg,GetUnitX(v.m),GetUnitY(v.m),Ie_AOE,TF)
loop
set tu = FirstOfGroup(tg)
exitwhen tu == null
if GetUnitState(tu,UNIT_STATE_MANA) > 0 then
if GetUnitState(tu,UNIT_STATE_MANA) > v.mb then
call SetUnitState(tu,UNIT_STATE_MANA,GetUnitState(tu,UNIT_STATE_MANA) - v.mb)
call UnitDamageTarget(v.c,tu,v.mb,true,true,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_MAGIC,null)
set v.f = v.f + v.mb
else
set mlb = GetUnitState(tu,UNIT_STATE_MANA)
call SetUnitState(tu,UNIT_STATE_MANA,GetUnitState(tu,UNIT_STATE_MANA) - mlb)
call UnitDamageTarget(v.c,tu,mlb,true,true,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_MAGIC,null)
set v.f = v.f + mlb
endif
call DestroyEffect(AddSpecialEffectTarget(UnitEff,tu,"chest"))
endif
if v.f >= FeedV then
set v.f = v.f - FeedV
set v.mb = v.mb + Bonus_mb
endif
call GroupRemoveUnit(tg,tu)
set tu = null
endloop
if v.bn > 0 then
set ang = (v.a * bj_PI)
set bx = GetUnitX(v.m) + Bounce_dist * Cos(ang)
set by = GetUnitY(v.m) + Bounce_dist * Sin(ang)
set ang2 = GetRandomReal(0,2)*bj_PI
set x = bx + Bounce_dist * Cos(ang2)
set y = by + Bounce_dist * Cos(ang2)
set v.a = Atan2(y - GetUnitY(v.m),x - GetUnitX(v.m))
set v.cd = 0.00
set v.bn = v.bn - 1
else
call DestroyEffect(v.e)
call RemoveUnit(v.m)
set v.e = null
set v.c = null
set v.m = null
call v.destroy()
set SB.sca = SB.sca - 1
set SB.ind[i] = v.ind[SB.sca]
set i = i - 1
endif
endif
set i = i + 1
set TP = null
endloop
call DestroyGroup(tg)
set tg = null
if SB.sca == 0 then
call PauseTimer(SB.counter)
endif
endmethod
static method GetVal takes unit c,unit m,real a,real d,integer lvl,real mb,integer bn,player p,effect e returns nothing
local SB v = SB.allocate()
set v.c = c
set v.m = m
set v.a = a
set v.d = d
set v.l = lvl
set v.mb = mb
set v.bn = bn
set v.p = p
set v.e = e
set v.f = 0
set v.cd = 0.00
if SB.sca == 0 then
call TimerStart(SB.counter,0.02,true,function SB.Motion)
endif
set SB.ind[SB.sca] = v
set SB.sca = SB.sca + 1
endmethod
endstruct
//unit filter
private function filter takes nothing returns boolean
return GetWidgetLife(GetFilterUnit()) > 0 and IsUnitEnemy(GetFilterUnit(),TP) and IsUnitType(GetFilterUnit(),UNIT_TYPE_FLYING) == false and IsUnitType(GetFilterUnit(),UNIT_TYPE_STRUCTURE) == false
endfunction
private function dummyFilter takes nothing returns boolean
return true
endfunction
//trigger condition
private function Cond takes nothing returns boolean
return GetSpellAbilityId() == SpellID
endfunction
//basicaly this function is the triggers actions
private function SetValues takes nothing returns nothing
local unit c = GetTriggerUnit()
local unit m
local player p = GetOwningPlayer(c)
local location loc = GetSpellTargetLoc()
local integer lvl = GetUnitAbilityLevel(c,SpellID)
local integer bn = (Bn_base + Bn_inc*(lvl-1))
local integer i = 0
local real a = Atan2(GetLocationY(loc) - GetUnitY(c),GetLocationX(loc) - GetUnitX(c))
local real d = Bounce_dist
local real mb = (Mb_base + Mb_inc*(I2R(lvl-1)))
local effect e
loop
exitwhen i > (Miss_num + (Miss_inc * (lvl - 1)))
set a = ((a * bj_RADTODEG) + GetRandomReal(-Angle_dif,Angle_dif)) * bj_DEGTORAD
set m = CreateUnit(p,DummyID,GetUnitX(c),GetUnitY(c),a)
set e = AddSpecialEffectTarget(MissileEff,m,"chest")
call SetUnitPathing(m,false)
call UnitAddAbility(m,'Arav')
call UnitRemoveAbility(m,'Arav')
call SB.GetVal(c,m,a,d,lvl,mb,bn,p,e)
set m = null
set e = null
set i = i + 1
endloop
call RemoveLocation(loc)
set c = null
set p = null
set loc = null
endfunction
private function InitSB takes nothing returns nothing
local trigger t = CreateTrigger()
local integer i = 0
loop
exitwhen i >= bj_MAX_PLAYER_SLOTS
call TriggerRegisterPlayerUnitEvent(t,Player(i),EVENT_PLAYER_UNIT_SPELL_EFFECT,Filter(function dummyFilter))
set i = i + 1
endloop
set TF = Filter(function filter)
set MaxX = GetRectMaxX(bj_mapInitialPlayableArea)
set MaxY = GetRectMaxY(bj_mapInitialPlayableArea)
set MinX = GetRectMinX(bj_mapInitialPlayableArea)
set MinY = GetRectMinY(bj_mapInitialPlayableArea)
call TriggerAddCondition(t,Condition(function Cond))
call TriggerAddAction(t,function SetValues)
call Preload(MissileEff)
call Preload(ImpactEff)
call Preload(UnitEff)
call Preload(ImpactEff2)
call PreloadStart()
endfunction
endscope