//TESH.scrollpos=0
//TESH.alwaysfold=0
Name | Type | is_array | initial_value |
//TESH.scrollpos=0
//TESH.alwaysfold=1
//***************************************************************************
// README *
//***************************************************************************
//*************************************************************************************************************
//*To view a ID of a unit/ability enable the "Display Values as raw data" in the object editor "View" options *
//*Alternatively press the CTRL + D to quickly enable/disable this option *
//*************************************************************************************************************
//*************************************************************************************************************
//*This is a submision made for Hero Contest #2. *
//*The hero contains 4 spells: *
//* *Cluster Mines *
//* *Crack Bomb *
//* *Shrapnel Technology *
//* *Massive Fragmentation *
//*************************************************************************************************************
//***************************************************************************************
//* Hero Info *
//***************************************************************************************
//* *
//* *
//* Clockwerk is a hero made for 2 main purposes: defense of a base and deviding *
//* enemy armies. There are several thing that are strange about the hero. *
//* He has a relatively low strength gain compared to the other heroes, which is *
//* compensated by his high inteligence giving him more casting abilities than other *
//* strength heroes. He has a fast attack speed but twice the less damage. *
//* He has a great spammable spell which is effective against large groups of enemies. *
//* His specialization in AoE damage provides a great advantage against armies but, *
//* one on one with an enemy hero he has a low chance of surviving(especialy against MK)*
//* *
//* Pros: *
//* *Great AoE damage *
//* *Good support *
//* *Capable of great defense of base with the mines and his ultimate *
//* *Good inteligence and inteligence gain *
//* *Fast attack speed, great in combination with damage items *
//* *Good against slow moving targets and melee units *
//* *Great at disrupting melee units with cluster mines and his ultimate *
//* *Can deal massive amount of damage over time *
//* *
//* Cons: *
//* *No direct unit damage *
//* *Highly mana dependent *
//* *Relatively low strength gain *
//* *Low base damage,easily countered by some abilities like Devotion Aura *
//* *Bad against some heroes(Mountain King,Blood Mage,Dark Ranger,Firelord,...) *
//* *Bad against structures and magic resistant creatures *
//* *Can't do anything to air units *
//* *Got no buff techniques *
//* *
//***************************************************************************************
function InitTrig_Readme takes nothing returns nothing
endfunction
//TESH.scrollpos=0
//TESH.alwaysfold=1
//*********************************************************************************
// CREDITS *
//*********************************************************************************
//***************************************************************************************************************** *
//Thanks to Moyack for his parabola function *
//Thanks to xmoyack for RegisterAnyUnitEvent *
//Thanks to Rising_Dusk for his Group Utils *
//Thanks to Vexorian for so many reasons(do i even have to name them?) *
//Thanks to WILLTHEALMIGHTY for his explosion model *
//Thanks to N-a-z-g-u-l for the Z Dummy model i am using *
//*****************************************************************************************************************
function InitTrig_Credits takes nothing returns nothing
endfunction
//TESH.scrollpos=187
//TESH.alwaysfold=0
//*******************************************************************************
//* 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, RegisterAnyUnitEvent
//**********************************************
//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!*
//***************************************************************************************
// 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 unit c, real sx, real sy returns nothing
local real x = GetUnitX(c)
local real y = GetUnitY(c)
local real d = SquareRoot((sx-x)*(sx-x) + (y-sy)*(y-sy))*2
local real s = Missile_Speed
local real rad = Atan2(sy -y, sx - x)
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
set c = null
endfunction
// triggers condition
private function Cond takes nothing returns boolean
if GetSpellAbilityId() == SpellID then
call Actions(GetTriggerUnit(), GetSpellTargetX(), GetSpellTargetY())
endif
return false
endfunction
// creates the triggers, setups it's events,conditions,actions and preloads the effects used
private function InitCM takes nothing returns nothing
call RegisterAnyUnitEvent(EVENT_PLAYER_UNIT_SPELL_EFFECT, function Cond, null)
call Preload(MissileEff)
call Preload(ImpactEff)
call Preload(MineArt_Air)
call Preload(MineArt_Ground)
call PreloadStart()
endfunction
endlibrary
//TESH.scrollpos=50
//TESH.alwaysfold=0
//***********************************************************************
//* By Kingz: *
//* OnDeath Library *
//* *
//*A small library made only for the Cluster Mines spell *
//*as i didn't like the usage of Damage Upon Death Ability *
//*and the fact that users would have to modify it *
//*i created this simple yet usefull library for the mines death *
//*the effect upon death are nice and the library is pretty simple *
//*made only for the Cluster Mines spell *
//*requires GroupUtils library *
//*NOTE: mines always deal damage upon death, even if you destroy them *
//***********************************************************************
library OnDeath initializer OnDeathInit requires GroupUtils,BasicStuff, RegisterAnyUnitEvent
//************************************************
//Settings - All of the library settings are here*
//************************************************
globals
private constant string DeathEff = "Abilities\\Spells\\Other\\Volcano\\VolcanoMissile.mdl" // first death effect of the unit
private constant string ExDeathEff = "abilities\\weapons\\DemolisherMissile\\DemolisherMissile.mdl" // second death effect of the unit
private constant real Damage = 65 // damage dealt upon death
private constant real DamageAoE = 250 // damage AOE
private constant integer TriggerMineSpellID = 'A002' // ability ID used mainly for synergy purposes
private constant integer TriggerUnitID = 'n000' // ID of the unit that triggers the library
private constant string KB_eff = "Abilities\\Weapons\\AncientProtectorMissile\\AncientProtectorMissile.mdl" // effect used for knockback trail
private constant boolean KB_kd = true // used for knockback; kills destructables if true
endglobals
//***************************************************************************************
//Settings end - Do not modify anything below this if you don't know what you are doing!*
//***************************************************************************************
private function GroupFilter takes nothing returns boolean
return (IsUnitEnemy(GetFilterUnit(),GetOwningPlayer(GetTriggerUnit())) == true) and (IsUnitType(GetFilterUnit(),UNIT_TYPE_MECHANICAL) == false) and (UnitAlive(GetFilterUnit())) and (IsUnitType(GetFilterUnit(),UNIT_TYPE_MAGIC_IMMUNE)==false) and (IsUnitType(GetFilterUnit(),UNIT_TYPE_STRUCTURE)==false) and (IsUnitType(GetFilterUnit(),UNIT_TYPE_FLYING)==false)
endfunction
private function GroupFunction takes nothing returns nothing
local unit u = GetTriggerUnit()
local unit fu = GetEnumUnit()
local real a = Atan2(GetUnitY(fu) - GetUnitY(u), GetUnitX(fu) - GetUnitX(u))
local integer lvl = GetUnitAbilityLevel(u,TriggerMineSpellID)
call UnitDamageTarget(u,fu,Damage,true,false,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,null)
if lvl > 1 then
call KnockbackTarget(u,fu,150 * GetUnitAbilityLevel(u,TriggerMineSpellID),1.5,a,KB_kd,KB_eff)
endif
set u = null
set fu = null
endfunction
private function OnDeathActions takes unit tu returns nothing
local real x = GetUnitX(tu)
local real y = GetUnitY(tu)
call GroupEnumUnitsInRange(ENUM_GROUP,x,y,DamageAoE, function GroupFilter)
call ForGroup(ENUM_GROUP,function GroupFunction)
call GroupClear(ENUM_GROUP)
call GroupRefresh(ENUM_GROUP)
call DestroyEffect(AddSpecialEffect(DeathEff,x,y))
call DestroyEffect(AddSpecialEffect(ExDeathEff,x,y))
call RemoveUnit(tu)
set tu = null
endfunction
private function OnDeathCond takes nothing returns boolean
if GetUnitTypeId(GetTriggerUnit()) == TriggerUnitID then
call OnDeathActions(GetTriggerUnit())
endif
return false
endfunction
private function OnDeathInit takes nothing returns nothing
call RegisterAnyUnitEvent(EVENT_PLAYER_UNIT_DEATH, function OnDeathCond, null)
call Preload(DeathEff)
call Preload(ExDeathEff)
call Preload(KB_eff)
call PreloadStart()
endfunction
endlibrary
//TESH.scrollpos=-1
//TESH.alwaysfold=0
//********************************************************************************
//* By Kingz: *
//* Crack Bomb *
//* Requirements: *
//* A point based spell *
//* Zdummy.mdx model which is featured in this map *
//* The dummy unit *
//* JassNewGenPack *
//* Library ShrapnelSystem *
//* Library BasicStuff *
//********************************************************************************
library CrackBomb initializer InitCB requires ShrapnelSystem,BasicStuff,TimerUtils, RegisterAnyUnitEvent
//**********************************************
//Settings - All of the spell settings are here*
//**********************************************
globals
private constant integer dummyID = 'e000' // unit id of the dummy unit
private constant integer SpellID = 'A001' // spell ability ID
private constant integer SynergySpellID = 'A004' // spell ability ID of the Shrapnel Technology
private constant real Base_dmg = 15 // instant impact damage
private constant real Dmg_inc = 5 // instant damage increase per level
private constant real Base_AoE = 350 // base AoE of the spell
private constant real AoE_inc = 0 // AoE increase per level
private constant real Max_height = 420 // max height which the missile reaches
private constant string Missile_Art = "Abilities\\Weapons\\GyroCopter\\GyroCopterMissile.mdl" // missile look
private constant string ExEff = "Abilities\\Weapons\\GyroCopter\\GyroCopterImpact.mdl" // effect spawned on missile and units damaged
private constant real Base_dmg2 = 3 // base damage dealt per interval time
private constant real Dmg2_inc = 1 // damage dealt per interval increase per level
private constant real Base_Duration = 10 // damage per interval duration
private constant real Duration_inc = 0 // duration increase per lvl
private constant real MS_deg = 5 // movement speed degration
private constant real MS_deg_inc = 2 // movement speed degration per level
private constant real Height_trigger = 0.3 // height offset at which the missile cracks, 0.3 meants 30% away from the ground(Z=0)
private constant real Dmg_interval = 1 // damage interval which is passed to the shrapnel system,can't be lower than 0.1(default 1.00 second)
private constant real Dmg_interval_change = 0.0 // damage interval change per spell level(default 0)
//***************************************************************************************
//Settings end - Do not modify anything below this if you don't know what you are doing!*
//***************************************************************************************
private player TP = null // used for ForGroup function
private real array TR // used for ForGroup function
private unit TU // used for ForGroup function and dpi setup
endglobals
//unit group filter
private function GroupFilter takes nothing returns boolean
return (IsUnitEnemy(GetFilterUnit(),TP) == true) and (IsUnitType(GetFilterUnit(),UNIT_TYPE_MECHANICAL) == false) and (UnitAlive(GetFilterUnit())) and (IsUnitType(GetFilterUnit(),UNIT_TYPE_MAGIC_IMMUNE)==false) and (IsUnitType(GetFilterUnit(),UNIT_TYPE_STRUCTURE)==false) and (IsUnitType(GetFilterUnit(),UNIT_TYPE_FLYING)==false)
endfunction
//unit group actions
private function GroupAction takes nothing returns nothing
call UnitDamageTarget(TU,GetEnumUnit(),TR[1],true,false,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,null)
call DestroyEffect(AddSpecialEffectTarget(ExEff,GetEnumUnit(),"origin"))
call Shrapnel(GetEnumUnit(),TU,TR[2],TR[3],TR[4],TR[5])
endfunction
//spells struct
private struct Core
unit c // used for damage source
unit bomb // missile
real rad // angle of the missile movement in radians
real dmg // instant damage
real AoE // AoE enough said
real dmg2 // damage dealt per interval
real msr // movement speed reduction
real dur // duration
effect art // missile art
real d // used for maximum distance check and parabola
real s // speed of the missile
real cd // curent distance
real za // Z angle for missile rotations
real int // used for damage interval
timer t
static method Motion takes nothing returns nothing
local timer t = GetExpiredTimer()
local thistype dat = GetTimerData(t)
local real x // used only for simplified equations
local real y // also
local real h // height variable calculated via the parabola function
local integer i = 0 // used for the loop
local conditionfunc c = Condition(function GroupFilter)
if GetUnitX(dat.bomb) > MaxX or GetUnitX(dat.bomb) < MinX or GetUnitY(dat.bomb) > MaxY or GetUnitX(dat.bomb) < MinY then
set dat.cd = dat.d
endif
if dat.cd < dat.d then
set x = GetUnitX(dat.bomb) + dat.s * Cos(dat.rad)
set y = GetUnitY(dat.bomb) + dat.s * Sin(dat.rad)
set dat.cd = dat.cd + dat.s
call SetUnitX(dat.bomb,x)
call SetUnitY(dat.bomb,y)
set h = ParabolaZ(Max_height,dat.d + (dat.d * Height_trigger),dat.cd)
call SetUnitFlyHeight(dat.bomb,h,0)
if GetRandomInt(0,14) == 6 then
call DestroyEffect(AddSpecialEffectTarget(ExEff,dat.bomb,"origin"))
endif
if dat.za < -360 then
set dat.za = dat.za + 360
endif
set dat.za = dat.za - 7
call SetUnitZFacing(dat.bomb,dat.za)
else
set x = GetUnitX(dat.bomb)
set y = GetUnitY(dat.bomb)
set TP = GetOwningPlayer(dat.bomb)
set TU = dat.c
set TR[1] = dat.dmg
set TR[2] = dat.dmg2
set TR[3] = dat.msr
set TR[4] = dat.dur
set TR[5] = dat.int
call GroupEnumUnitsInRange(ENUM_GROUP,x,y,dat.AoE,c)
call ForGroup(ENUM_GROUP,function GroupAction)
if GetRandomInt(1,100) <= (10 * GetUnitAbilityLevel(dat.c,SynergySpellID)) then
call ForGroup(ENUM_GROUP,function GroupAction)
endif
call GroupClear(ENUM_GROUP)
call GroupRefresh(ENUM_GROUP)
call DestroyEffect(dat.art)
call SetUnitFacing(dat.bomb,180)
call KillUnit(dat.bomb)
set TU = null
set dat.art = null
set dat.c = null
set dat.bomb = null
call PauseTimer(t)
call ReleaseTimer(t)
call dat.destroy()
call DestroyCondition(c)
set c = null
endif
endmethod
// method use to implement the needed variables into the struct
static method Implement takes unit c, real a, unit m, real dmg, real AoE, real dmg2, real msdeg, real dur,real d,real s,real interval returns nothing
local thistype dat = thistype.allocate()
set dat.c = c
set dat.rad = a
set dat.bomb = m
set dat.dmg = dmg
set dat.AoE = AoE
set dat.dmg2 = dmg2
set dat.msr = msdeg
set dat.dur = dur
set dat.art = AddSpecialEffectTarget(Missile_Art,dat.bomb,"origin")
set dat.d = d
set dat.s = s
set dat.cd = 0
set dat.za = 90
set dat.int = interval
set dat.t = NewTimer()
call SetTimerData(dat.t, dat)
call TimerStart(dat.t,0.02,true,function thistype.Motion)
endmethod
endstruct
// trigger actions
private function Actions takes unit c, real sx, real sy returns nothing
local real x = GetUnitX(c)
local real y = GetUnitY(c)
local real a = Atan2(sy - y, sx - x)
local unit m = CreateUnit(GetOwningPlayer(c),dummyID,x,y,a)
local integer lvl = GetUnitAbilityLevel(c,SpellID)
local real dmg = Base_dmg + ((lvl - 1) * Dmg_inc)
local real AoE = Base_AoE + ((lvl - 1) * AoE_inc)
local real dmg2 = Base_dmg2 + ((lvl - 1) * Dmg2_inc)
local real msdeg = MS_deg + ((lvl - 1) * MS_deg_inc)
local real dur = Base_Duration + ((lvl - 1) * Duration_inc)
local real d = SquareRoot((sx-x) * (sx-x) + (sy-y)*(sy-y))
local real s = d / 1.5 * 0.02
local real interval = Dmg_interval + ((lvl - 1) * Dmg_interval_change)
call SetUnitPathing(m,false)
call SetUnitPosition(m,x,y)
if sx == x and sy == y then
set d = 1
set s = d / 1 * 0.02
endif
call UnitAddAbility(m,'Amrf')
call UnitRemoveAbility(m,'Amrf')
call Core.Implement(c,a,m,dmg,AoE,dmg2,msdeg,dur,d,s,interval)
endfunction
//spells condition
private function Cond takes nothing returns boolean
if GetSpellAbilityId() == SpellID then
call Actions(GetTriggerUnit(), GetSpellTargetX(), GetSpellTargetY())
endif
return false
endfunction
// creates a trigger, setups conditions,events and actions
private function InitCB takes nothing returns nothing
call RegisterAnyUnitEvent(EVENT_PLAYER_UNIT_SPELL_EFFECT, function Cond, null)
call Preload(Missile_Art)
call Preload(ExEff)
call PreloadStart()
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
//*******************************************************************************
//* By Kingz: *
//* Requirements: *
//* A instant based spell *
//* Zdummy.mdx model which is featured in this map *
//* The dummy unit *
//* JassNewGenPack *
//* Library Group Utils *
//* Library BasicStuff *
//*******************************************************************************
library MassiveFragmentation initializer InitMF requires RegisterAnyUnitEvent,GroupUtils,TimerUtils
//**********************************************
//Settings - All of the spell settings are here*
//**********************************************
globals
private constant integer SpellID = 'A003' // spell ability ID
private constant integer SynergySpellID = 'A004' // synergy spell ability ID(in this case Shrapnel Technology)
private constant integer DummyID = 'e000' // ID of the dummy unit used
private constant real Damage = 35 // damage dealt per second to units that get hit by the missiles
private constant real Time = 2.00 // time needed for the missiles to spread and return(lower value == higher speed)
private constant string MissileArt = "abilities\\weapons\\DemolisherMissile\\DemolisherMissile.mdl" // missile art(effect attached)
private constant integer MissileCount = 20 // missiles normaly released
private constant integer MissileCountInc = 5 // additional missiles spawned per synergy spell level
private constant damagetype DT = DAMAGE_TYPE_NORMAL // damage type
private constant attacktype AT = ATTACK_TYPE_NORMAL // attack type
private constant weapontype WT = WEAPON_TYPE_WHOKNOWS // weapon type
private constant real MaxHeight = 500 // maximum height that a missile can reach
private constant real MinHeight = 40 // minimal height at what the missile can travel
private constant real MaxDist = 800 // maximal distance from the casters position that the missiles can travel
private constant real MinDist = 250 // minimal distance from the casters position that the missiles can travel
private constant string HitEff = "Objects\\Spawnmodels\\Human\\HumanBlood\\HumanBloodFootman.mdl" // effect created on hit units
private constant string HitEffAP = "chest" // attach point for the hit effect
private constant integer LoopNumber = 1 // loop number is actualy the numbers of "rotations" for this spell it is REQUIRED that it is 1 else it looks bad
private constant string ImpactSFX = "war3mapImported\\NewDirtEXNofire.mdx" // one time spawned effect upon spell cast
private constant real ColisionSize = 30 // colision size of a single missile, used for Z height checking
private constant real AoE = 125 // aoe in which the fragments deal damage
//***************************************************************************************
//Settings end - Do not modify anything below this if you don't know what you are doing!*
//***************************************************************************************
private player TP
private unit TU
endglobals
private function UnitFilter takes nothing returns boolean
return (IsUnitEnemy(GetFilterUnit(),TP) == true) and (IsUnitType(GetFilterUnit(),UNIT_TYPE_MECHANICAL) == false) and (UnitAlive(GetFilterUnit())) and (IsUnitType(GetFilterUnit(),UNIT_TYPE_MAGIC_IMMUNE)==false) and (IsUnitType(GetFilterUnit(),UNIT_TYPE_STRUCTURE)==false) and GetUnitFlyHeight(GetFilterUnit()) <= GetUnitFlyHeight(TU) + ColisionSize and GetUnitFlyHeight(GetFilterUnit()) >= GetUnitFlyHeight(TU) - ColisionSize
endfunction
private function EnumDamage takes nothing returns nothing
call UnitDamageTarget(TU,GetEnumUnit(),Damage * 0.02,true,false,AT,DT,WT)
if GetRandomInt(0,40) == 40 then
call DestroyEffect(AddSpecialEffectTarget(HitEff,GetEnumUnit(),"chest"))
endif
endfunction
private struct Core
unit c // used for damage source
unit m // missile unit
real s // speed at which the missile travels
real d // distance that the missile reaches
real cd // current distance of the missile
integer ln // loop number
real rad // radian (used for angled movement)
effect eff // missile effect(art)
real mh // maximal height the missile reaches
real hc // height change per timer interval
real dmg // damage dealt per timer interval seconds
timer t
static method Motion takes nothing returns nothing
local timer t = GetExpiredTimer()
local thistype dat = GetTimerData(t)
local real x // used only for simplified equations
local real y // also
local real h // height variable calculated via the parabola function
local integer i = 0 // used for the loop
local conditionfunc c = Condition(function UnitFilter)
if GetUnitX(dat.m) > MaxX or GetUnitX(dat.m) < MinX or GetUnitY(dat.m) > MaxY or GetUnitX(dat.m) < MinY then
set dat.cd = dat.d
set dat.ln = 0
endif
if dat.cd < dat.d 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)
call SetUnitFlyHeight(dat.m,GetUnitFlyHeight(dat.m) + dat.hc,0)
set TP = GetOwningPlayer(dat.c)
set TU = dat.c
call GroupEnumUnitsInRange(ENUM_GROUP,GetUnitX(dat.m),GetUnitY(dat.m),AoE,c)
call ForGroup(ENUM_GROUP,function EnumDamage)
call GroupClear(ENUM_GROUP)
call GroupRefresh(ENUM_GROUP)
else
if dat.ln > 0 then
set dat.cd = 0
set dat.rad = ((dat.rad * bj_RADTODEG) + 180) * bj_DEGTORAD
set dat.hc = -dat.hc
set dat.ln = dat.ln - 1
else
call DestroyEffect(dat.eff)
call RemoveUnit(dat.m)
call ShowUnit(dat.c,true)
call PauseUnit(dat.c,false)
call SelectUnit(dat.c,true)
call PauseTimer(t)
call ReleaseTimer(t)
call dat.destroy()
call DestroyCondition(c)
set c = null
endif
endif
endmethod
// Implements the fetched variables into the struct
static method Implement takes unit c, unit m, real rad,real speed,real dist,real height,integer ln returns nothing
local thistype dat = thistype.allocate()
set dat.c = c
set dat.m = m
set dat.rad = rad
set dat.s = speed
set dat.d = dist
set dat.mh = height
set dat.hc = height / Time * 0.02
set dat.eff = AddSpecialEffectTarget(MissileArt,dat.m,"origin")
set dat.cd = 0
set dat.ln = ln
set dat.t = NewTimer()
call SetTimerData(dat.t, dat)
call UnitAddAbility(dat.m,'Amrf')
call UnitRemoveAbility(dat.m,'Amrf')
call TimerStart(dat.t,0.02,true,function thistype.Motion)
endmethod
endstruct
// trigger actions
private function Actions takes unit c returns nothing
local integer i = 0
local integer im = MissileCount + (MissileCountInc * (GetUnitAbilityLevel(c,SynergySpellID) - 1))
local unit u
local real rad
local real dist
local real speed
local real height
local integer ln = 1
local real x = GetUnitX(c)
local real y = GetUnitY(c)
call DestroyEffect(AddSpecialEffect(ImpactSFX,x,y))
call ShowUnit(c,false)
call PauseUnit(c,true)
loop
exitwhen i > im
set u = CreateUnit(GetOwningPlayer(c),DummyID,x,y,0)
set rad = GetRandomReal(0,360) * bj_DEGTORAD
call SetUnitFacing(u,rad * bj_RADTODEG)
set dist = GetRandomReal(MinDist,MaxDist)
set speed = dist*2 / Time * 0.02
set height = GetRandomReal(MinHeight,MaxHeight)
call Core.Implement(c,u,rad,speed,dist,height,ln)
set i = i + 1
endloop
endfunction
private function Cond takes nothing returns boolean
if GetSpellAbilityId() == SpellID then
call Actions(GetTriggerUnit())
endif
return false
endfunction
// library initializer and setups
private function InitMF takes nothing returns nothing
call RegisterAnyUnitEvent(EVENT_PLAYER_UNIT_SPELL_EFFECT, function Cond, null)
call Preload(MissileArt)
call Preload(HitEff)
call Preload(ImpactSFX)
call PreloadStart()
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
native UnitAlive takes unit u returns boolean
//TESH.scrollpos=0
//TESH.alwaysfold=0
//************************************************************************
// RegisterAnyUnitEvent by moyack
//************************************************************************
// Code improved with the idea developed by Magtheridon96 , Bribe, azlier
//************************************************************************
/*
A library to reduce the time writing the same shit. I took some code ideas from a similar
resource approved here. This one supports all the possibilities in calling the trigger.
If user defines the condition and action functions this function will return the respective
trigger, so it can be controlled by other instance (just in case).
If the user only sets a condition or action, then it will return null because this
trigger handles a lot of conditions and actions and it shouldn't be accessible by the user.
* For functions without triggersleepaction or waits, it's recommended to use:
call RegisterAnyUnitEvent(<Event>, code Function, null)
* For functions with triggersleepaction or waits, it's recommended to use:
call RegisterAnyUnitEvent(<Event>, null, code Function)
*/
library RegisterAnyUnitEvent
globals
private trigger array ts
endglobals
function RegisterAnyUnitEvent takes playerunitevent e, code cond, code act returns nothing
local integer i = GetHandleId(e)
local trigger t
if act != null then
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, e)
if cond != null then
call TriggerAddCondition(t, Filter(cond))
endif
call TriggerAddAction(t, act)
set t = null
else
if ts[i] == null then
set ts[i] = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(ts[i], e)
endif
call TriggerAddCondition(ts[i], Filter(cond))
endif
endfunction
endlibrary
//TESH.scrollpos=16
//TESH.alwaysfold=0
//***********************************************************************************
//* By Kingz: *
//* Basic Stuff Library *
//* A library i made to speed up my coding of the submision *
//* Contains several usefull functions and several functions i use *
//* are simmilar to existing ones. *
//* Also contains the Max/Min values of the maps X/Y which are used as boundaries *
//* Used in all of the spells in this submision to provide easier coding *
//***********************************************************************************
library BasicStuff initializer XY
globals
real MaxX // used for the maps Max X
real MaxY // used for the maps Max Y
real MinX // used for the maps Min X
real MinY // used for the maps Min Y
private constant real OffsetAngle = 0 // used for the Z facing function but is model based,for this model the value is 0
endglobals
//parabola function for the missile - Credits go to Moyack
constant function ParabolaZ takes real h,real d,real cd returns real
return (4*h / d)*(d - cd)*(cd / d)
endfunction
//used to replace AnyUnitEventBJ
constant function dummyFilter takes nothing returns boolean
return true
endfunction
// used for dummy unit z facings
function SetUnitZFacing takes unit whichUnit, real facingAngle returns nothing
local integer i = R2I((facingAngle+OffsetAngle)*0.7+0.5)
if i>0 then
call SetUnitAnimationByIndex(whichUnit, i)
else
call SetUnitAnimationByIndex(whichUnit, i+252)
endif
endfunction
//sets up the min/max X/Y values
function XY takes nothing returns nothing
set MaxX = GetRectMaxX(bj_mapInitialPlayableArea)
set MaxY = GetRectMaxY(bj_mapInitialPlayableArea)
set MinX = GetRectMinX(bj_mapInitialPlayableArea)
set MinY = GetRectMinY(bj_mapInitialPlayableArea)
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library GroupUtils initializer Init requires optional xebasic
//******************************************************************************
//* BY: Rising_Dusk
//*
//* This library is a combination of several features relevant to groups. First
//* and foremost, it contains a group stack that you can access dynamic groups
//* from. It also provides means to refresh groups and clear any shadow
//* references within them. The included boolexprs are there for backwards
//* compatibility with maps that happen to use them. Since the 1.24c patch,
//* null boolexprs used in GroupEnumUnits* calls no longer leak, so there is no
//* performance gain to using the BOOLEXPR_TRUE constant.
//*
//* Instead of creating/destroying groups, we have moved on to recycling them.
//* NewGroup pulls a group from the stack and ReleaseGroup adds it back. Always
//* remember to call ReleaseGroup on a group when you are done using it. If you
//* fail to do so enough times, the stack will overflow and no longer work.
//*
//* GroupRefresh cleans a group of any shadow references which may be clogging
//* its hashtable. If you remove a unit from the game who is a member of a unit
//* group, it will 'effectively' remove the unit from the group, but leave a
//* shadow in its place. Calling GroupRefresh on a group will clean up any
//* shadow references that may exist within it. It is only worth doing this on
//* groups that you plan to have around for awhile.
//*
//* Constants that can be used from the library:
//* [group] ENUM_GROUP As you might expect, this group is good for
//* when you need a group just for enumeration.
//* [boolexpr] BOOLEXPR_TRUE This is a true boolexpr, which is important
//* because a 'null' boolexpr in enumeration
//* calls results in a leak. Use this instead.
//* [boolexpr] BOOLEXPR_FALSE This exists mostly for completeness.
//*
//* This library also includes a simple implementation of a group enumeration
//* call that factors collision of units in a given area of effect. This is
//* particularly useful because GroupEnumUnitsInRange doesn't factor collision.
//*
//* In your map, you can just replace all instances of GroupEnumUnitsInRange
//* with GroupEnumUnitsInArea with identical arguments and your spells will
//* consider all units colliding with the area of effect. After calling this
//* function as you would normally call GroupEnumUnitsInRange, you are free to
//* do anything with the group that you would normally do.
//*
//* If you don't use xebasic in your map, you may edit the MAX_COLLISION_SIZE
//* variable below and the library will use that as the added radius to check.
//* If you use xebasic, however, the script will automatically use xe's
//* collision size variable.
//*
//* You are also able to use GroupUnitsInArea. This function returns all units
//* within the area, no matter what they are, which can be convenient for those
//* instances where you actually want that.
//*
//* Example usage:
//* local group MyGroup = NewGroup()
//* call GroupRefresh(MyGroup)
//* call ReleaseGroup(MyGroup)
//* call GroupEnumUnitsInArea(ENUM_GROUP, x, y, 350., BOOLEXPR_TRUE)
//* call GroupUnitsInArea(ENUM_GROUP, x, y, 350.)
//*
globals
//If you don't have xebasic in your map, this value will be used instead.
//This value corresponds to the max collision size of a unit in your map.
private constant real MAX_COLLISION_SIZE = 197.
//If you are insane and don't care about any of the protection involved in
//this library, but want this script to be really fast, set this to true.
private constant boolean LESS_SAFETY = false
endglobals
globals
//* Constants that are available to the user
group ENUM_GROUP = CreateGroup()
boolexpr BOOLEXPR_TRUE = null
boolexpr BOOLEXPR_FALSE = null
endglobals
globals
//* Hashtable for debug purposes
private hashtable ht = InitHashtable()
//* Temporary references for GroupRefresh
private boolean Flag = false
private group Refr = null
//* Arrays and counter for the group stack
private group array Groups
private integer Count = 0
//* Variables for use with the GroupUnitsInArea function
private real X = 0.
private real Y = 0.
private real R = 0.
private hashtable H = InitHashtable()
endglobals
private function HookDestroyGroup takes group g returns nothing
if g == ENUM_GROUP then
call BJDebugMsg(SCOPE_PREFIX+"Warning: ENUM_GROUP destroyed")
endif
endfunction
debug hook DestroyGroup HookDestroyGroup
private function AddEx takes nothing returns nothing
if Flag then
call GroupClear(Refr)
set Flag = false
endif
call GroupAddUnit(Refr, GetEnumUnit())
endfunction
function GroupRefresh takes group g returns nothing
set Flag = true
set Refr = g
call ForGroup(Refr, function AddEx)
if Flag then
call GroupClear(g)
endif
endfunction
function NewGroup takes nothing returns group
if Count == 0 then
set Groups[0] = CreateGroup()
else
set Count = Count - 1
endif
static if not LESS_SAFETY then
call SaveInteger(ht, 0, GetHandleId(Groups[Count]), 1)
endif
return Groups[Count]
endfunction
function ReleaseGroup takes group g returns boolean
local integer id = GetHandleId(g)
static if LESS_SAFETY then
if g == null then
debug call BJDebugMsg(SCOPE_PREFIX+"Error: Null groups cannot be released")
return false
elseif Count == 8191 then
debug call BJDebugMsg(SCOPE_PREFIX+"Error: Max groups achieved, destroying group")
call DestroyGroup(g)
return false
endif
else
if g == null then
debug call BJDebugMsg(SCOPE_PREFIX+"Error: Null groups cannot be released")
return false
elseif not HaveSavedInteger(ht, 0, id) then
debug call BJDebugMsg(SCOPE_PREFIX+"Error: Group not part of stack")
return false
elseif LoadInteger(ht, 0, id) == 2 then
debug call BJDebugMsg(SCOPE_PREFIX+"Error: Groups cannot be multiply released")
return false
elseif Count == 8191 then
debug call BJDebugMsg(SCOPE_PREFIX+"Error: Max groups achieved, destroying group")
call DestroyGroup(g)
return false
endif
call SaveInteger(ht, 0, id, 2)
endif
call GroupClear(g)
set Groups[Count] = g
set Count = Count + 1
return true
endfunction
private function Filter takes nothing returns boolean
return IsUnitInRangeXY(GetFilterUnit(), X, Y, R)
endfunction
private function HookDestroyBoolExpr takes boolexpr b returns nothing
local integer bid = GetHandleId(b)
if HaveSavedHandle(H, 0, bid) then
//Clear the saved boolexpr
call DestroyBoolExpr(LoadBooleanExprHandle(H, 0, bid))
call RemoveSavedHandle(H, 0, bid)
endif
endfunction
hook DestroyBoolExpr HookDestroyBoolExpr
private constant function GetRadius takes real radius returns real
static if LIBRARY_xebasic then
return radius+XE_MAX_COLLISION_SIZE
else
return radius+MAX_COLLISION_SIZE
endif
endfunction
function GroupEnumUnitsInArea takes group whichGroup, real x, real y, real radius, boolexpr filter returns nothing
local real prevX = X
local real prevY = Y
local real prevR = R
local integer bid = 0
//Set variables to new values
set X = x
set Y = y
set R = radius
if filter == null then
//Adjusts for null boolexprs passed to the function
set filter = Condition(function Filter)
else
//Check for a saved boolexpr
set bid = GetHandleId(filter)
if HaveSavedHandle(H, 0, bid) then
//Set the filter to use to the saved one
set filter = LoadBooleanExprHandle(H, 0, bid)
else
//Create a new And() boolexpr for this filter
set filter = And(Condition(function Filter), filter)
call SaveBooleanExprHandle(H, 0, bid, filter)
endif
endif
//Enumerate, if they want to use the boolexpr, this lets them
call GroupEnumUnitsInRange(whichGroup, x, y, GetRadius(radius), filter)
//Give back original settings so nested enumerations work
set X = prevX
set Y = prevY
set R = prevR
endfunction
function GroupUnitsInArea takes group whichGroup, real x, real y, real radius returns nothing
local real prevX = X
local real prevY = Y
local real prevR = R
//Set variables to new values
set X = x
set Y = y
set R = radius
//Enumerate
call GroupEnumUnitsInRange(whichGroup, x, y, GetRadius(radius), Condition(function Filter))
//Give back original settings so nested enumerations work
set X = prevX
set Y = prevY
set R = prevR
endfunction
private function True takes nothing returns boolean
return true
endfunction
private function False takes nothing returns boolean
return false
endfunction
private function Init takes nothing returns nothing
set BOOLEXPR_TRUE = Condition(function True)
set BOOLEXPR_FALSE = Condition(function False)
endfunction
endlibrary
//TESH.scrollpos=51
//TESH.alwaysfold=0
library TimerUtils initializer init
//*********************************************************************
//* TimerUtils (red+blue+orange flavors for 1.24b+) 2.0
//* ----------
//*
//* To implement it , create a custom text trigger called TimerUtils
//* and paste the contents of this script there.
//*
//* To copy from a map to another, copy the trigger holding this
//* library to your map.
//*
//* (requires vJass) More scripts: htt://www.wc3c.net
//*
//* For your timer needs:
//* * Attaching
//* * Recycling (with double-free protection)
//*
//* set t=NewTimer() : Get a timer (alternative to CreateTimer)
//* set t=NewTimerEx(x) : Get a timer (alternative to CreateTimer), call
//* Initialize timer data as x, instead of 0.
//*
//* ReleaseTimer(t) : Relese a timer (alt to DestroyTimer)
//* SetTimerData(t,2) : Attach value 2 to timer
//* GetTimerData(t) : Get the timer's value.
//* You can assume a timer's value is 0
//* after NewTimer.
//*
//* Multi-flavor:
//* Set USE_HASH_TABLE to true if you don't want to complicate your life.
//*
//* If you like speed and giberish try learning about the other flavors.
//*
//********************************************************************
//================================================================
globals
//How to tweak timer utils:
// USE_HASH_TABLE = true (new blue)
// * SAFEST
// * SLOWEST (though hash tables are kind of fast)
//
// USE_HASH_TABLE = false, USE_FLEXIBLE_OFFSET = true (orange)
// * kinda safe (except there is a limit in the number of timers)
// * ALMOST FAST
//
// USE_HASH_TABLE = false, USE_FLEXIBLE_OFFSET = false (red)
// * THE FASTEST (though is only faster than the previous method
// after using the optimizer on the map)
// * THE LEAST SAFE ( you may have to tweak OFSSET manually for it to
// work)
//
private constant boolean USE_HASH_TABLE = true
private constant boolean USE_FLEXIBLE_OFFSET = false
private constant integer OFFSET = 0x100000
private integer VOFFSET = OFFSET
//Timers to preload at map init:
private constant integer QUANTITY = 256
//Changing this to something big will allow you to keep recycling
// timers even when there are already AN INCREDIBLE AMOUNT of timers in
// the stack. But it will make things far slower so that's probably a bad idea...
private constant integer ARRAY_SIZE = 8190
endglobals
//==================================================================================================
globals
private integer array data[ARRAY_SIZE]
private hashtable ht
endglobals
//It is dependent on jasshelper's recent inlining optimization in order to perform correctly.
function SetTimerData takes timer t, integer value returns nothing
static if(USE_HASH_TABLE) then
// new blue
call SaveInteger(ht,0,GetHandleId(t), value)
elseif (USE_FLEXIBLE_OFFSET) then
// orange
static if (DEBUG_MODE) then
if(GetHandleId(t)-VOFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
set data[GetHandleId(t)-VOFFSET]=value
else
// new red
static if (DEBUG_MODE) then
if(GetHandleId(t)-OFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
set data[GetHandleId(t)-OFFSET]=value
endif
endfunction
function GetTimerData takes timer t returns integer
static if(USE_HASH_TABLE) then
// new blue
return LoadInteger(ht,0,GetHandleId(t) )
elseif (USE_FLEXIBLE_OFFSET) then
// orange
static if (DEBUG_MODE) then
if(GetHandleId(t)-VOFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
return data[GetHandleId(t)-VOFFSET]
else
// new red
static if (DEBUG_MODE) then
if(GetHandleId(t)-OFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
return data[GetHandleId(t)-OFFSET]
endif
endfunction
//==========================================================================================
globals
private timer array tT[ARRAY_SIZE]
private integer tN = 0
private constant integer HELD=0x28829022
//use a totally random number here, the more improbable someone uses it, the better.
private boolean didinit = false
endglobals
private keyword init
//==========================================================================================
// I needed to decide between duplicating code ignoring the "Once and only once" rule
// and using the ugly textmacros. I guess textmacros won.
//
//! textmacro TIMERUTIS_PRIVATE_NewTimerCommon takes VALUE
// On second thought, no.
//! endtextmacro
function NewTimerEx takes integer value returns timer
if (tN==0) then
if (not didinit) then
//This extra if shouldn't represent a major performance drawback
//because QUANTITY rule is not supposed to be broken every day.
call init.evaluate()
set tN = tN - 1
else
//If this happens then the QUANTITY rule has already been broken, try to fix the
// issue, else fail.
debug call BJDebugMsg("NewTimer: Warning, Exceeding TimerUtils_QUANTITY, make sure all timers are getting recycled correctly")
set tT[0]=CreateTimer()
static if( not USE_HASH_TABLE) then
debug call BJDebugMsg("In case of errors, please increase it accordingly, or set TimerUtils_USE_HASH_TABLE to true")
static if( USE_FLEXIBLE_OFFSET) then
if (GetHandleId(tT[0])-VOFFSET<0) or (GetHandleId(tT[0])-VOFFSET>=ARRAY_SIZE) then
//all right, couldn't fix it
call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably set TimerUtils_USE_HASH_TABLE to true or fix timer leaks.")
return null
endif
else
if (GetHandleId(tT[0])-OFFSET<0) or (GetHandleId(tT[0])-OFFSET>=ARRAY_SIZE) then
//all right, couldn't fix it
call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably set TimerUtils_USE_HASH_TABLE to true or fix timer leaks.")
return null
endif
endif
endif
endif
else
set tN=tN-1
endif
call SetTimerData(tT[tN],value)
return tT[tN]
endfunction
function NewTimer takes nothing returns timer
return NewTimerEx(0)
endfunction
//==========================================================================================
function ReleaseTimer takes timer t returns nothing
if(t==null) then
debug call BJDebugMsg("Warning: attempt to release a null timer")
return
endif
if (tN==ARRAY_SIZE) then
debug call BJDebugMsg("Warning: Timer stack is full, destroying timer!!")
//stack is full, the map already has much more troubles than the chance of bug
call DestroyTimer(t)
else
call PauseTimer(t)
if(GetTimerData(t)==HELD) then
debug call BJDebugMsg("Warning: ReleaseTimer: Double free!")
return
endif
call SetTimerData(t,HELD)
set tT[tN]=t
set tN=tN+1
endif
endfunction
private function init takes nothing returns nothing
local integer i=0
local integer o=-1
local boolean oops = false
if ( didinit ) then
return
else
set didinit = true
endif
static if( USE_HASH_TABLE ) then
set ht = InitHashtable()
loop
exitwhen(i==QUANTITY)
set tT[i]=CreateTimer()
call SetTimerData(tT[i], HELD)
set i=i+1
endloop
set tN = QUANTITY
else
loop
set i=0
loop
exitwhen (i==QUANTITY)
set tT[i] = CreateTimer()
if(i==0) then
set VOFFSET = GetHandleId(tT[i])
static if(USE_FLEXIBLE_OFFSET) then
set o=VOFFSET
else
set o=OFFSET
endif
endif
if (GetHandleId(tT[i])-o>=ARRAY_SIZE) then
exitwhen true
endif
if (GetHandleId(tT[i])-o>=0) then
set i=i+1
endif
endloop
set tN = i
exitwhen(tN == QUANTITY)
set oops = true
exitwhen not USE_FLEXIBLE_OFFSET
debug call BJDebugMsg("TimerUtils_init: Failed a initialization attempt, will try again")
endloop
if(oops) then
static if ( USE_FLEXIBLE_OFFSET) then
debug call BJDebugMsg("The problem has been fixed.")
//If this message doesn't appear then there is so much
//handle id fragmentation that it was impossible to preload
//so many timers and the thread crashed! Therefore this
//debug message is useful.
elseif(DEBUG_MODE) then
call BJDebugMsg("There were problems and the new timer limit is "+I2S(i))
call BJDebugMsg("This is a rare ocurrence, if the timer limit is too low:")
call BJDebugMsg("a) Change USE_FLEXIBLE_OFFSET to true (reduces performance a little)")
call BJDebugMsg("b) or try changing OFFSET to "+I2S(VOFFSET) )
endif
endif
endif
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
//***********************************************************************************************************
//* By Kingz: *
//* Shrapnel Library *
//* *
//* A simple library made only for the contest, as i didn't want to use any DOT system i made this one *
//* Quite simple, with low amount of fixed options which actualy are fixed for my needs and the hero alone *
//* Made for the Hero Contest and is a mixture of DPI and movement speed reduction *
//* Again used to avoid work with object editor abilities *
//* Hopefully it's usage won't be treated in the score as it's options are fixed to fit the requirements *
//* of this submision for the Hero Contest ONLY *
//***********************************************************************************************************
library ShrapnelSystem initializer StartPreload requires TimerUtils
//************************************************
//Settings - All of the library settings are here*
//************************************************
globals
private constant attacktype Att = ATTACK_TYPE_NORMAL // attack type of the damage dealt (intentionaly made it normal not spell like)
private constant damagetype Dtype = DAMAGE_TYPE_NORMAL // damage type of the damage dealt (intentionaly made it normal not spell like)
private constant weapontype Wtype = WEAPON_TYPE_WHOKNOWS // changing this may result in sound upon damage
private constant string Effect = "Objects\\Spawnmodels\\Human\\HumanBlood\\HumanBloodFootman.mdl" // first effect of the damage (apears on the unit)
private constant string Effect2 = "Abilities\\Weapons\\GyroCopter\\GyroCopterImpact.mdl" // second effect of the damage (apears on the unit)
private constant string Atpoint = "chest" // special effects attach point
private constant real EffSpam = 1.00 // interval for effect spaming, this is a constant value to avoid overspamming of effects(default 1.00 seconds)
endglobals
//***************************************************************************************
//Settings end - Do not modify anything below this if you don't know what you are doing!*
//***************************************************************************************
private struct Core
unit u // suffering unit
unit ds // damage source
real dmg // damage per interval
real msdeg // movement speed degration
real duration // duration
real chkint // used for interval checks
real effint // used for special effect interval
real offt // when this value reaches the duration value the effect stops
real interval
timer t
// the main method used for damage dealing and other stuff
static method Periodic takes nothing returns nothing
local timer t =GetExpiredTimer()
local thistype dat = GetTimerData(t)
local integer i = 0
set dat.chkint = dat.chkint + 0.1
set dat.effint = dat.effint + 0.1
set dat.offt = dat.offt + 0.1
if GetUnitState(dat.u,UNIT_STATE_LIFE) <= 0.405 then
set dat.offt = dat.duration
endif
if dat.effint >= EffSpam then
call DestroyEffect(AddSpecialEffectTarget(Effect,dat.u,Atpoint))
call DestroyEffect(AddSpecialEffectTarget(Effect2,dat.u,Atpoint))
set dat.effint = 0
endif
if dat.chkint >= dat.interval then
call UnitDamageTarget(dat.ds,dat.u,dat.dmg,true,false,null,null,null)
set dat.chkint = 0.00
endif
if dat.offt >= dat.duration then
call SetUnitMoveSpeed(dat.u,GetUnitMoveSpeed(dat.u) + dat.msdeg)
call ReleaseTimer(t)
call dat.destroy()
endif
endmethod
// implements the fetched variables into the struct
static method DefineVal takes unit u,unit source, real dmg,real MSdeg, real duration,real interval returns nothing
local thistype dat = thistype.allocate()
set dat.u = u
set dat.ds = source
set dat.dmg = dmg
set dat.msdeg = MSdeg
set dat.duration = duration
set dat.chkint = interval
set dat.offt = 0
set dat.effint = EffSpam
set dat.t = NewTimer()
call SetTimerData(dat.t,dat)
if interval > 0.1 then
set dat.interval = interval
else
set dat.interval = 0.1
endif
call SetUnitMoveSpeed(u,GetUnitMoveSpeed(dat.u) - MSdeg)
call TimerStart(dat.t,0.1,true,function thistype.Periodic)
endmethod
endstruct
// function that is called upon to execute the shrapnel system
function Shrapnel takes unit t,unit u,real dmg,real MSdeg,real duration,real interval returns nothing
call Core.DefineVal(t,u,dmg,MSdeg,duration,interval)
endfunction
// preloads the used effects
private function StartPreload takes nothing returns nothing
call Preload(Effect)
call Preload(Effect2)
call PreloadStart()
endfunction
endlibrary
//TESH.scrollpos=100
//TESH.alwaysfold=0
//*******************************************************************************************************************************************
//* By Kingz: *
//* Simple Knockback *
//* -Requires BasicStuff library- *
//* *
//*Since i needed a good knockback system that works on distance rather on speed, *
//* i decided to make one, this system is simple to use and provides a good precision *
//* of the distance you wanted. Namely i made an equation that takes in count the speed decrease factor and tried to make a good system. *
//* On the end i got a system that is really precise at hight values (300 distance or more) but is unprecise at low values (~100 and less). *
//* All in all a simple system i made only for the Hero contest #2. *
//*******************************************************************************************************************************************
library KnockbackSystem requires BasicStuff
globals
//*****************************************************
//Settings - All of the system fixed settings are here*
//*****************************************************
private constant real TimerInterval = 0.02 //timer interval, so obvious
private constant real KB_speed_dec = 0.05 //speed decrease factor
//***************************************************************************************
//Settings end - Do not modify anything below this if you don't know what you are doing!*
//***************************************************************************************
private group TmpGroup = CreateGroup() //group used to avoid multiple speed stacking issue
endglobals
private function Kill_destructables takes nothing returns nothing
call KillDestructable(GetEnumDestructable())
endfunction
private struct Knockback
unit u // unit that is knockbacked
unit s // source of the knockback
real speed // speed at which the unit is knockbacked
real rad // radian used for the angled movement
string eff // string used for the trail effect
boolean kd // if true destroys trees around the pushed unit
static thistype array ind
static integer on = 0
static timer counter = CreateTimer()
static method Motion takes nothing returns nothing
local thistype dat
local real x // used only for simplified equations
local real y // also
local real h // height variable calculated via the parabola function
local rect r // used for tree destruction
local integer i = 0 // used for the loop
local conditionfunc cf = Condition(function dummyFilter)
loop
exitwhen i >= thistype.on
set dat = thistype.ind[i]
if dat.speed > 0 then
set x = GetUnitX(dat.u) + dat.speed * Cos(dat.rad)
set y = GetUnitY(dat.u) + dat.speed * Sin(dat.rad)
set dat.speed = dat.speed - KB_speed_dec
if x > MaxX or x < MinX or y > MaxY or y < MinY then
set dat.speed = 0
set x = GetUnitX(dat.u)
set y = GetUnitY(dat.u)
endif
if IsUnitType(dat.u,UNIT_TYPE_FLYING) == false then
if (IsTerrainPathable(x,y,PATHING_TYPE_AMPHIBIOUSPATHING) == false) then
call SetUnitX(dat.u,x)
call SetUnitY(dat.u,y)
endif
else
call SetUnitX(dat.u,x)
call SetUnitY(dat.u,y)
endif
set x = GetUnitX(dat.u)
set y = GetUnitY(dat.u)
if GetRandomInt(0,10) == 6 then
call DestroyEffect(AddSpecialEffect(dat.eff,x,y))
endif
if dat.kd == true then
set r = Rect(x - 250,y - 250,x + 250,y + 250)
call EnumDestructablesInRect(r,cf,function Kill_destructables)
call DestroyCondition(cf)
set cf = null
endif
else
call GroupRemoveUnit(TmpGroup,dat.u)
set dat.u = null
set dat.s = null
set dat.eff = null
call dat.destroy()
set thistype.on = thistype.on - 1
set thistype.ind[i] = thistype.ind[thistype.on]
endif
set i = i + 1
endloop
call RemoveRect(r)
set r = null
if thistype.on == 0 then
call PauseTimer(thistype.counter)
endif
endmethod
static method AddtoKnock takes unit s,unit t,real dist,real time,real rad,boolean kd,string eff returns nothing
local thistype dat = thistype.allocate()
set dat.u = t
set dat.s = s
set dat.speed = (dist*0.5 / time) * TimerInterval + (time / TimerInterval * KB_speed_dec)
set dat.rad = rad
set dat.kd = kd
set dat.eff = eff
if thistype.on == 0 then
call TimerStart(thistype.counter,TimerInterval,true,function thistype.Motion)
endif
set Knockback.ind[Knockback.on] = dat
set Knockback.on = Knockback.on + 1
endmethod
endstruct
//function that is called upon
function KnockbackTarget takes unit source, unit target, real distance, real time,real radian,boolean killdestructables,string kbeff returns nothing
if IsUnitInGroup(target,TmpGroup) == false then
call Knockback.AddtoKnock(source,target,distance,time,radian,killdestructables,kbeff)
call GroupAddUnit(TmpGroup,target)
endif
endfunction
endlibrary