//***********************************************************************************
//*
//* ____ __ ____ _______________________________________
//* /_ _| _\ / __/ | T I M E D A B I L I T Y |
//* | || — \\__ \ | A N D |
//* |_||_|\_\___/ | S T A C K S Y S T E M |
//* By Spinnaker '—————————————————————————————————————'
//* v3.0.0.1
//*
//* What is TAS?
//* ————————————
//*
//* There are lots situations when you want your spells/abilities to add some
//* kind of timed buff/debuff which can be increased with new applications.
//* Timed ability/stack system allows you to time any ability you want,
//* and makes ability-stacking an easy job.
//*
//* System consists of one trigger. Script - depending on option chosen -
//* divides abilities into two groups:
//*
//* 1) Without refreshing - runs abilities that don't refresh with
//* new applications, but each stack has it's own private duration.
//*
//* 2) With refreshing - runs abilities that do refresh with every
//* new application.
//*
//*
//* Reason - why?
//* —————————————
//*
//* I decided to create this system due to lack of such and the high
//* frequency of adding timed stuff in various triggers.
//* Great example where such stacking abilities exist is obviously DotA.
//*
//*
//* How to implement?
//* —————————————————
//*
//* 1) Be sure "Automatically create unknown variables while pasting
//* trigger data" is enabled in the World Editor general preferences.
//*
//* 2) Copy and paste trigger 'TAS Veriable Creator' into your map for
//* automatical variable creation
//*
//* 3) Copy trigger "Timed AS" and paste it into your map.
//* System requires no Object Editor stuff.
//*
//* System is implemented. To run it properly see the next part.
//*
//*
//* What needs to be done?
//* ——————————————————————
//*
//* Set TASability to ability you want to be timed.
//* Now, choose unit that a timed ability will be added to.
//* Next step is setting duration of the ability in field TASduration.
//*
//* Select the refresh option. Choosing 'True' will let your ability
//* refresh even if maximum value of stacks has been reached, while 'False'
//* converts abilities to private stacks which don't interfere with each other.
//*
//* Enter maximum amount of applications in TASmaxstack.
//* Abilities with maximum value won't be increased, but can refreash.
//*
//* Leave the rest for the system, enjoy!
//* —————————————————————————————————————
//*
//*
//***********************************************************************************
//***************************************************************************
//*
//* Global Variables
//*
//***************************************************************************
//* udg_TAShash Hashtable for refreshable abilities issues
//* udg_TASindex Counts all running instances
//* udg_TAStimer Global timer for periodic issues
//* udg_TASdur[] Stores duration of each instance
//* udg_TASend[] Checks if given instance should be removed
//* udg_TASids[] Contains all the ability data
//* udg_TASref[] Checks if ability manipulated is refreshable or not
//* udg_TASunits[] For unit storage
//* User friendly parameters
//* udg_TASability Gets new ability
//* udg_TASunit Gets new unit
//* udg_TASduration Gets duration for new ability
//* udg_TASrefresh Sets instance type
//* udg_TASmaxstack Maximum amount of stacks for given ability
//***************************************************************************
//* Constant interval function
//***************************************************************************
constant function TASinterval takes nothing returns real
return 0.031250000
endfunction
//***************************************************************************
//*
//* System itself
//*
//***************************************************************************
function TASallocate takes integer id returns nothing
set udg_TASindex = udg_TASindex + 1
set udg_TASids[udg_TASindex] = id
set udg_TASunits[udg_TASindex] = udg_TASunit
set udg_TASdur[udg_TASindex] = udg_TASduration
set udg_TASref[udg_TASindex] = udg_TASrefresh
set udg_TASend[udg_TASindex] = false
endfunction
function TASdeallocate takes integer i returns nothing
set udg_TASunits[i] = udg_TASunits[udg_TASindex]
set udg_TASids[i] = udg_TASids[udg_TASindex]
set udg_TASdur[i] = udg_TASdur[udg_TASindex]
set udg_TASref[i] = udg_TASref[udg_TASindex]
set udg_TASend[i] = udg_TASend[udg_TASindex]
set udg_TASindex = udg_TASindex - 1
endfunction
function TASunitcheck takes unit u returns boolean
return IsUnitType(u, UNIT_TYPE_DEAD) or GetUnitTypeId(u) == 0
endfunction
function TAScallback takes nothing returns nothing
local integer i = 1
local integer h
local integer n
local boolean b
local player p
loop
exitwhen i > udg_TASindex
if udg_TASref[i] then
set h = GetHandleId(udg_TASunits[i])
set udg_TASdur[i] = LoadReal(udg_TAShash, h, udg_TASids[i])
endif
set udg_TASdur[i] = udg_TASdur[i] - TASinterval()
set b = udg_TASref[i] or GetUnitAbilityLevel(udg_TASunits[i], udg_TASids[i]) < 2
if (udg_TASdur[i] <= 0. and b) or TASunitcheck(udg_TASunits[i]) then
set udg_TASend[i] = true
call UnitRemoveAbility(udg_TASunits[i], udg_TASids[i])
elseif udg_TASdur[i] <= 0. and not b then
set udg_TASend[i] = true
set p = GetOwningPlayer(udg_TASunits[i])
call SetPlayerAbilityAvailable(p, udg_TASids[i], false)
call DecUnitAbilityLevel(udg_TASunits[i], udg_TASids[i])
call SetPlayerAbilityAvailable(p, udg_TASids[i], true)
elseif udg_TASref[i] then
call SaveReal(udg_TAShash, h, udg_TASids[i], udg_TASdur[i])
endif
if udg_TASend[i] then
if udg_TASref[i] then
set n = LoadInteger(udg_TAShash, h, 0) - 1
if 0 == n then
call FlushChildHashtable(udg_TAShash, h)
else
call SaveInteger(udg_TAShash, h, 0, n)
endif
endif
call TASdeallocate(i)
set i = i - i
if 0 == udg_TASindex then
call PauseTimer(udg_TAStimer)
endif
endif
set i = i + 1
endloop
set p = null
endfunction
function TASexecute takes nothing returns nothing
local integer id = udg_TASability
local integer n = GetUnitAbilityLevel(udg_TASunit, id)
local player p
if 0 == udg_TASindex then
call TimerStart(udg_TAStimer, TASinterval(), true, function TAScallback)
endif
if UnitAddAbility(udg_TASunit, id) then
call TASallocate(id)
elseif n < udg_TASmaxstack then
set p = GetOwningPlayer(udg_TASunit)
call SetPlayerAbilityAvailable (p, id, false)
call IncUnitAbilityLevel (udg_TASunit, id)
call SetPlayerAbilityAvailable (p, id, true)
if not udg_TASrefresh then
call TASallocate(id)
endif
set p = null
endif
if udg_TASrefresh then
set n = GetHandleId(udg_TASunit)
if LoadReal(udg_TAShash, n, id) == 0. then
call SaveInteger (udg_TAShash, n, 0, LoadInteger(udg_TAShash, n, 0) + 1)
endif
call SaveReal(udg_TAShash, n, id, udg_TASduration)
endif
endfunction
//***************************************************************************
function InitTrig_Timed_AS takes nothing returns nothing
set gg_trg_Timed_AS = CreateTrigger()
set udg_TAStimer = CreateTimer()
set udg_TAShash = InitHashtable()
call TriggerAddAction(gg_trg_Timed_AS, function TASexecute)
endfunction