//TESH.scrollpos=0
//TESH.alwaysfold=0
Name | Type | is_array | initial_value |
//TESH.scrollpos=1
//TESH.alwaysfold=0
library_once TimerUtils
//*********************************************************************
//* TimerUtils (Blue flavor)
//* ----------
//*
//* 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.wc3campaigns.net
//*
//* For your timer needs:
//* * Attaching
//* * Recycling (with double-free protection)
//*
//* set t=NewTimer() : Get a timer (alternative to CreateTimer)
//* 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.
//*
//* Blue Flavor: Slower than the red flavor, it got a 408000 handle id
//* limit, which means that if more than 408000 handle ids
//* are used in your map, TimerUtils might fail, this
//* value is quite big and it is much bigger than the
//* timer limit in Red flavor.
//*
//********************************************************************
//================================================================
globals
private constant integer MAX_HANDLE_ID_COUNT = 408000
// values lower than 8191: very fast, but very unsafe.
// values bigger than 8191: not that fast, the bigger the number is the slower the function gets
// Most maps don't really need a value bigger than 50000 here, but if you are unsure, leave it
// as the rather inflated value of 408000
endglobals
//=================================================================================================
private function H2I takes handle h returns integer
return h
return 0
endfunction
//==================================================================================================
globals
private integer array data[MAX_HANDLE_ID_COUNT]
private constant integer MIN_HANDLE_ID=0x100000
endglobals
//It is dependent on jasshelper's recent inlining optimization in order to perform correctly.
function SetTimerData takes timer t, integer value returns nothing
debug if(H2I(t)-MIN_HANDLE_ID>=MAX_HANDLE_ID_COUNT) then
debug call BJDebugMsg("SetTimerData: Handle id too big, increase the max handle id count or use gamecache instead")
debug endif
set data[H2I(t)-MIN_HANDLE_ID]=value
endfunction
function GetTimerData takes timer t returns integer
debug if(H2I(t)-MIN_HANDLE_ID>=MAX_HANDLE_ID_COUNT) then
debug call BJDebugMsg("GetTimerData: Handle id too big, increase the max handle id count or use gamecache instead")
debug endif
return data[H2I(t)-MIN_HANDLE_ID]
endfunction
//==========================================================================================
globals
private timer array tT
private integer tN = 0
private constant integer HELD=0x28829022
//use a totally random number here, the more improbable someone uses it, the better.
endglobals
//==========================================================================================
function NewTimer takes nothing returns timer
if (tN==0) then
set tT[0]=CreateTimer()
else
set tN=tN-1
endif
call SetTimerData(tT[tN],0)
return tT[tN]
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==8191) 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
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
//==================================================================================
//==================================================================================
//===============================ROOTING==v,1,5=====================================
//==================================================================================
//===============================BY==xD,Schurke=====================================
//==================================================================================
scope rooting initializer rootInt
//=========CONSTANTS===============
globals
//Dummy Rawcode
private constant integer dummyid = 'h000' //change to you map specific dummy rawcode
//Ability/Buff Rawcodes
private constant integer spellid = 'A000' //The hero spell
private constant integer dummyspellone = 'A002' //damage reduce must be roar with negative value
private constant integer dummyspelltwo = 'A003' //silence spell must be soulburn with 0 damage
private constant integer dummyspellthree = 'A004' //roots the target ensnare
private constant integer dummyspellfour = 'A005' //roots for all nearby enemy units
private constant integer buffraw = 'B000' //normal herospell debuff (debuff of 'A000')
private constant integer buffoneraw = 'B002' //damage reduce debuff (debuff of 'A002)
private constant integer bufftworaw = 'B003' //silence debuff (debuff of 'A003')
private constant integer timedlife = 'BTLF' //timed life debuff Don't change
//Modelpaths
private constant string sfxstring = "Abilities\\Spells\\NightElf\\EntanglingRoots\\EntanglingRootsTarget.mdl" //root model change for a new model
private constant string sfxstringtwo = "Objects\\Spawnmodels\\Critters\\Albatross\\CritterBloodAlbatross.mdl" //bloodeffect
private constant string sfxstringthree = "Objects\\Spawnmodels\\Undead\\UndeadLargeDeathExplode\\UndeadLargeDeathExplode.mdl" //explode effect
//attachment strings shouldn't be changed
private constant string handright = "hand right"
private constant string handleft = "hand left"
private constant string chest = "chest"
private constant string head = "head"
private constant string origin = "origin"
//IssueOrder strings shouldn't be changed
private constant string ent ="entanglingroots"
private constant string roar ="roar"
private constant string soul = "soulburn"
private constant string ens = "ensnare"
//Timer Interval
private constant real Interval = 0.01
endglobals
//function for damage change the number to have more/less damage
private function damage takes integer level returns real
return I2R(20 * level)
endfunction
//========END=CONSTANTS============
private struct rootstruct
unit caster //stores the caster
unit target //stores the target
real i = 0 //counter
effect array sfx [5] //stores the effects
timer t
static method rootTimer takes nothing returns nothing
local rootstruct Dat = GetTimerData(GetExpiredTimer()) //gets the struct
local unit dummy //dummy var
local effect sfx //non permanent special effect
local unit u //for group reason
local group g = CreateGroup() //for group reason
set Dat.i = Dat.i + Interval //increases counter
if GetUnitState(Dat.target,UNIT_STATE_LIFE) <= 0 then //part to check if the target is dead and if it's true, it will damage all nearby enemy units and roots them (loop is for goup selection etc.) also resets all things (struct,timer etc.)
set sfx = AddSpecialEffect(sfxstringthree,GetUnitX(Dat.target),GetUnitY(Dat.target))
call DestroyEffect(sfx)
call GroupEnumUnitsInRange(g,GetUnitX(Dat.target),GetUnitY(Dat.target),200,null)
loop
set u = FirstOfGroup(g)
exitwhen u == null
if IsUnitEnemy(u,GetOwningPlayer(Dat.caster)) and GetUnitState(u,UNIT_STATE_LIFE) > 0 and IsUnitType(u,UNIT_TYPE_STRUCTURE) != true then
call UnitDamageTarget(Dat.caster,u,I2R(GetRandomInt(50,150)),false,true,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)
set dummy = CreateUnit(GetOwningPlayer(Dat.caster),dummyid,GetUnitX(Dat.target),GetUnitY(Dat.target),0)
call UnitApplyTimedLife(dummy,timedlife,1)
call UnitAddAbility(dummy,dummyspellfour)
call SetUnitAbilityLevel(dummy,dummyspellfour,GetUnitAbilityLevel(Dat.caster,spellid))
call IssueTargetOrder(dummy,ent,u)
set sfx = AddSpecialEffectTarget(sfxstringtwo,u,chest)
call DestroyEffect(sfx)
call GroupRemoveUnit(g,u)
else
call GroupRemoveUnit(g,u)
endif
endloop
call DestroyGroup(g)
call rootstruct.destroy(Dat)
elseif GetUnitAbilityLevel(Dat.target,buffraw) <= 0 then //only important if rooting was dispelled etc.
call rootstruct.destroy(Dat)
elseif Dat.i == 1 then //effect for after 1 second (roots the hand and checks for a 33% chance if the target won't deal damage anymore)
set Dat.sfx[1] = AddSpecialEffectTarget(sfxstring,Dat.target,handright)
set sfx = AddSpecialEffectTarget(sfxstringtwo,Dat.target,handleft)
call DestroyEffect(sfx)
call UnitDamageTarget(Dat.caster,Dat.target,damage(GetUnitAbilityLevel(Dat.caster,spellid)),false,true,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)
if GetRandomInt(1,3) == 1 then
set dummy = CreateUnit(GetOwningPlayer(Dat.caster),dummyid,GetUnitX(Dat.target),GetUnitY(Dat.target),0)
call UnitAddAbility(dummy,dummyspellone)
call IssueImmediateOrder(dummy,roar)
call UnitApplyTimedLife(dummy,timedlife,1)
endif
elseif Dat.i == 2 then //not realy important part only damages and creates effect
set Dat.sfx[2] = AddSpecialEffectTarget(sfxstring,Dat.target,handleft)
set sfx = AddSpecialEffectTarget(sfxstringtwo,Dat.target,handleft)
call DestroyEffect(sfx)
call UnitDamageTarget(Dat.caster,Dat.target,damage(GetUnitAbilityLevel(Dat.caster,spellid)),false,true,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)
elseif Dat.i == 3 then //effect for after 3 seconds (roots the head and checks for a 33% chance if the target won't cast spells anymore)
set Dat.sfx[3] = AddSpecialEffectTarget(sfxstring,Dat.target,head)
set sfx = AddSpecialEffectTarget(sfxstringtwo,Dat.target,head)
call DestroyEffect(sfx)
call UnitDamageTarget(Dat.caster,Dat.target,damage(GetUnitAbilityLevel(Dat.caster,spellid)),false,true,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)
if GetRandomInt(1,3) == 1 then
set dummy = CreateUnit(GetOwningPlayer(Dat.caster),dummyid,GetUnitX(Dat.target),GetUnitY(Dat.target),0)
call UnitAddAbility(dummy,dummyspelltwo)
call IssueTargetOrder(dummy,soul,Dat.target)
call UnitApplyTimedLife(dummy,timedlife,1)
endif
elseif Dat.i == 4 then //effect+damage and roots target to the ground
set Dat.sfx[4] = AddSpecialEffectTarget(sfxstring,Dat.target,origin)
set sfx = AddSpecialEffectTarget(sfxstringtwo,Dat.target,origin)
call DestroyEffect(sfx)
call UnitDamageTarget(Dat.caster,Dat.target,damage(GetUnitAbilityLevel(Dat.caster,spellid)),false,true,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)
set dummy = CreateUnit(GetOwningPlayer(Dat.caster),dummyid,GetUnitX(Dat.target),GetUnitY(Dat.target),0)
call UnitAddAbility(dummy,dummyspellthree)
call IssueTargetOrder(dummy,ens,Dat.target)
call UnitApplyTimedLife(dummy,timedlife,1)
elseif Dat.i == 5 then //only damage
call UnitDamageTarget(Dat.caster,Dat.target,damage(GetUnitAbilityLevel(Dat.caster,spellid)),false,true,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)
elseif Dat.i == 6 then //only damage
call UnitDamageTarget(Dat.caster,Dat.target,damage(GetUnitAbilityLevel(Dat.caster,spellid)),false,true,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)
elseif Dat.i == 7 then //if target didn't die this resets everything for no leaks etc.
call rootstruct.destroy(Dat)
endif
//setting all vars to null
set dummy = null
set sfx = null
set u = null
endmethod
static method create takes unit u,unit t returns rootstruct //sets the caster and target
local rootstruct Dat = rootstruct.allocate()
set Dat.caster = u
set Dat.target = t
set Dat.t = NewTimer()
set Dat.sfx[0] = AddSpecialEffectTarget(sfxstring,Dat.target,"chest")
call DestroyEffect(AddSpecialEffectTarget(sfxstringtwo,Dat.target,"chest"))
call SetTimerData(Dat.t,integer(Dat))
call TimerStart(Dat.t,Interval,true,function rootstruct.rootTimer)
return Dat
endmethod
method onDestroy takes nothing returns nothing //remove leaks :D
local integer i = 0
call UnitRemoveAbility(.target,buffoneraw)
call UnitRemoveAbility(.target,bufftworaw)
set .caster = null
set .target = null
call ReleaseTimer(.t)
set .t = null
loop
exitwhen i >= 5
call DestroyEffect(.sfx[i])
set .sfx[i] = null
set i = i + 1
endloop
endmethod
endstruct
//===============CONDITION/START=====================
private function rootCond takes nothing returns boolean
local unit u = GetTriggerUnit()
local unit t = GetSpellTargetUnit()
local rootstruct Dat
if GetSpellAbilityId() == spellid then
set Dat = rootstruct.create(u,t)
endif
set u = null
set t = null
return false
endfunction
//event part with preloading ;)
private function rootInt takes nothing returns nothing
local trigger int = CreateTrigger()
local integer index = 0
local unit u
loop
call TriggerRegisterPlayerUnitEvent(int, Player(index), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
set index = index + 1
exitwhen index == bj_MAX_PLAYER_SLOTS
endloop
call TriggerAddCondition(int,Condition(function rootCond))
set int = null
//preload dummy etc
set u = CreateUnit(Player(14),dummyid,9999999,9999999,0)
call UnitAddAbility(u,dummyspellone)
call UnitAddAbility(u,dummyspelltwo)
call UnitAddAbility(u,dummyspellthree)
call UnitAddAbility(u,dummyspellfour)
call RemoveUnit(u)
set u = null
call Preload(sfxstring)
call Preload(sfxstringtwo)
endfunction
endscope