//*******************************************************************************
//* By Kingz: *
//* Cluster Mines *
//* Requirements: *
//* A point based spell *
//* The Trigger Mine ability *
//* Zdummy.mdx model which is featured in this map *
//* The dummy unit *
//* JassNewGenPack *
//* Library OnDeath *
//* -which requires GroupUtils- *
//* *
//* Library BasicStuff *
//* Shrapnel Technology Ability *
//*******************************************************************************
//***************************************************************************************************
// *NOTICE* *
// The synergy effect(knockback and shranpel effect) are based on the Trigger Mine ability level. *
// Therefore that ability has 4 levels(1st level means no synergy). * *
// I made it like that to avoid using custom values or even more complicated methods. *
//***************************************************************************************************
library ClusterMines initializer InitCM requires OnDeath,BasicStuff,TimerUtils
//**********************************************
//Settings - All of the spell settings are here*
//**********************************************
globals
private constant integer SpellID = 'A000' //spell ID
private constant integer SynergySpellID = 'A004' // Shrapnel Ability ID
private constant integer TriggerMineID = 'A002' // Trigger Mine ability ID
private constant integer DummyID = 'e000' //dummy unit ID
private constant integer MineID = 'n000' //mine unit ID
private constant string MissileEff = "Abilities\\Spells\\Other\\TinkerRocket\\TinkerRocketMissile.mdl" //missile art
private constant string ImpactEff = "Abilities\\Weapons\\AncientProtectorMissile\\AncientProtectorMissile.mdl" //this effects will get created upon missile impact with the ground
private constant string MineArt_Air = "Abilities\\Weapons\\GyroCopter\\GyroCopterMissile.mdl" //upon cracking the new mines get this effect attached
private constant string MineArt_Ground = "units\\creeps\\GoblinLandMine\\GoblinLandMine.mdl" //upon impact attaches this effect to the missile
private constant string MissileCluster = "Abilities\\Weapons\\FlyingMachine\\FlyingMachineImpact.mdl" // attached effect which is instantly destroyed upon clustering
private constant string MissileCluster2 = "Abilities\\Weapons\\GyroCopter\\GyroCopterMissile.mdl" // attached effect which is instantly destroyed upon clustering
private constant integer Mine_num = 3 // base mine number
private constant integer Mine_inc = 1 // mine increase per level
private constant real Gravity = 0.05 // gravity pull effect upon mine fall
private constant real Missile_Speed = 12 // cluster missile speed
private constant real Max_height = 700 // maximum height reached during the flight
private constant real Max_AOE = 600 // maximum AOE in which the mines can fall
private constant real Mine_life_span = 60 // the number of seconds the mines stay on the ground before detonation(used for life timer)
endglobals
//***************************************************************************************
//Settings end - Do not modify anything below this if you don't know what you are doing!*
//***************************************************************************************
// triggers condition
private function Cond takes nothing returns boolean
return GetSpellAbilityId() == SpellID
endfunction
// the spells struct
private struct Core
unit c // used for damage source reasons
real cd // used for parabola function and distance check
real s // missile speed
real rad // used for missile angle in radians
real md // used for distance checking
unit m // used for the missile unit
effect art // used for the missile art
boolean eod // used for secondary execution upon missile death
integer no // defines the number of secondary effect unit's spawned
timer t
// method used for missile motion and secondary execution
static method Motion takes nothing returns nothing
local timer t = GetExpiredTimer()
local thistype dat = GetTimerData(t)
local real x // used for simplified equations
local real y // also
local real h // used for parabola calculations
local integer i = 0 // used for the main loop
local integer num = 0 // used for secondary execution of the spell
local integer maxnum // also
local real radian = 0 // used for reimplementation of missiles(secondary effect)
local unit missile // same
local real dist // same
local string art // same
local unit tu // same
local player tp // used to avoid GetOwningPlayer() function in a loop
set x = GetUnitX(dat.m)
set y = GetUnitY(dat.m)
if x > MaxX or x < MinX or y > MaxY or y < MinY then
set dat.cd = dat.md
endif
if dat.eod == true then
if dat.cd < dat.md / 2 then
set x = GetUnitX(dat.m) + dat.s * Cos(dat.rad)
set y = GetUnitY(dat.m) + dat.s * Sin(dat.rad)
set dat.cd = dat.cd + dat.s
call SetUnitX(dat.m,x)
call SetUnitY(dat.m,y)
set h = ParabolaZ(Max_height,dat.md,dat.cd)
call SetUnitFlyHeight(dat.m,h,0)
else
call DestroyEffect(dat.art)
set maxnum = dat.no
set x = GetUnitX(dat.m)
set y = GetUnitY(dat.m)
set tp = GetOwningPlayer(dat.c)
loop
exitwhen num == maxnum
set radian = GetRandomReal(0,2)
set missile = CreateUnit(tp,DummyID,x,y,bj_RADTODEG * radian)
call UnitAddAbility(missile,'Arav')
call UnitRemoveAbility(missile,'Arav')
call SetUnitAbilityLevel(missile,TriggerMineID,1 + GetUnitAbilityLevel(dat.c,SynergySpellID))
set art = MineArt_Air
set dist = GetRandomReal(Max_AOE / 2,Max_AOE)
call SetUnitZFacing(missile,-Atan(Max_height / dist) * bj_RADTODEG)
call thistype.Implement(dat.c,missile,dist / 3 * 0.02,art,radian,dist/2,dist,false,0)
call SetUnitFlyHeight(missile,ParabolaZ(Max_height,dist,dist/2),0)
call DestroyEffect(AddSpecialEffectTarget(MissileCluster,missile,"origin"))
call DestroyEffect(AddSpecialEffectTarget(MissileCluster2,missile,"origin"))
set num = num + 1
endloop
call RemoveUnit(dat.m)
set dat.art = null
set dat.c = null
set dat.m = null
set tp = null
set tu = null
set art = null
set missile = null
call PauseTimer(t)
call ReleaseTimer(t)
call dat.destroy()
endif
else
if dat.cd < dat.md then
set x = GetUnitX(dat.m) + dat.s * Cos(dat.rad)
set y = GetUnitY(dat.m) + dat.s * Sin(dat.rad)
set dat.s = dat.s + Gravity
set dat.cd = dat.cd + dat.s
call SetUnitX(dat.m,x)
call SetUnitY(dat.m,y)
set h = ParabolaZ(Max_height,dat.md,dat.cd)
call SetUnitFlyHeight(dat.m,h,0)
else
set x = GetUnitX(dat.m)
set y = GetUnitY(dat.m)
call DestroyEffect(dat.art)
call DestroyEffect(AddSpecialEffect(ImpactEff,x,y))
set tu = CreateUnit(GetOwningPlayer(dat.c),MineID,x,y,GetRandomReal(0,360))
call SetUnitAbilityLevel(tu,TriggerMineID,1 + GetUnitAbilityLevel(dat.c,SynergySpellID))
call UnitApplyTimedLife(tu,'BTLF',60)
call SetUnitAnimation(tu,"birth")
call RemoveUnit(dat.m)
set tu = null
set dat.art = null
set dat.c = null
set dat.m = null
call PauseTimer(t)
call ReleaseTimer(t)
call dat.destroy()
endif
endif
endmethod
// used to implement fetched variables into the struct
static method Implement takes unit c,unit m,real s,string e,real rad,real cd,real md,boolean b,integer mn returns nothing
local thistype dat = thistype.allocate()
set dat.c = c
set dat.m = m
set dat.s = s
set dat.art = AddSpecialEffectTarget(e,dat.m,"origin")
set dat.rad = rad
set dat.cd = cd
set dat.md = md
set dat.eod = b
set dat.no = mn
set dat.t = NewTimer()
call SetTimerData(dat.t, dat)
call TimerStart(dat.t,0.02,true,function thistype.Motion)
endmethod
endstruct
// the triggers actions
private function Actions takes nothing returns nothing
local unit c = GetTriggerUnit()
local real x = GetUnitX(c)
local real y = GetUnitY(c)
local real sx = GetSpellTargetX()
local real sy = GetSpellTargetY()
local real d = DBL(x,y,sx,sy)*2
local real s = Missile_Speed
local real rad = RBL(x,y,sx,sy)
local unit m = CreateUnit(GetOwningPlayer(c),DummyID,x,y,bj_RADTODEG *rad)
local string e = MissileEff
local integer mn = Mine_num + ((GetUnitAbilityLevel(c,SpellID) - 1) * Mine_inc)
if x == sx and y == sy then
set d = 1
set s = d / 2 * 0.02
endif
call SetUnitZFacing(m,Atan(Max_height / d) * bj_RADTODEG)
call UnitAddAbility(m,'Amrf')
call UnitRemoveAbility(m,'Amrf')
call Core.Implement(c,m,s,e,rad,0,d,true,mn)
set m = null
set e = null
endfunction
// creates the triggers, setups it's events,conditions,actions and preloads the effects used
private function InitCM takes nothing returns nothing
local trigger t = CreateTrigger()
local filterfunc f = Filter(function dummyFilter)
local conditionfunc c = Condition(function Cond)
local integer i = 0
loop
call TriggerRegisterPlayerUnitEvent(t,Player(i),EVENT_PLAYER_UNIT_SPELL_EFFECT,f)
set i = i + 1
exitwhen i == bj_MAX_PLAYER_SLOTS
endloop
call TriggerAddCondition(t,c)
call TriggerAddAction(t,function Actions)
call Preload(MissileEff)
call Preload(ImpactEff)
call Preload(MineArt_Air)
call Preload(MineArt_Ground)
call PreloadStart()
call DestroyFilter(f)
set f = null
endfunction
endlibrary