Name | Type | is_array | initial_value |
GDD__Integers | integer | Yes | |
GDD__LeftMapGroup | group | No | |
GDD__TriggerArray | trigger | Yes | |
GDD__UnitArray | unit | Yes | |
GDD_Damage | real | No | |
GDD_DamagedUnit | unit | No | |
GDD_DamageSource | unit | No | |
GDD_Event | real | No | |
i | integer | No | |
p | location | No | |
TASability | abilcode | No | |
TASdur | real | Yes | |
TASduration | real | No | |
TASend | boolean | Yes | |
TAShash | hashtable | No | |
TASids | integer | Yes | |
TASindex | integer | No | |
TASmaxstack | integer | No | |
TASref | boolean | Yes | |
TASrefresh | boolean | No | |
TAStimer | timer | No | |
TASunit | unit | No | |
TASunits | unit | Yes | |
tp | location | Yes |
//TESH.scrollpos=0
//TESH.alwaysfold=0
//***********************************************************************************
//*
//* ____ __ ____ _______________________________________
//* /_ _| _\ / __/ | 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
//TESH.scrollpos=0
//TESH.alwaysfold=0
//*********************************************************************************************
//* GUI-Friendly Damage Detection -- v1.2.0 -- by Weep *
//* http://www.thehelper.net/forums/showthread.php?t=137957 *
//* *
//* Requires: only this trigger and its variables. *
//* *
//* -- What? -- *
//* This snippet provides a leak-free, GUI-friendly implementation of an "any unit takes *
//* damage" event. It requires no JASS knowledge to use. *
//* *
//* It uses the Game - Value Of Real Variable event as its method of activating other *
//* triggers, and passes the event responses through a few globals. *
//* *
//* -- Why? -- *
//* The traditional GUI method of setting up a trigger than runs when any unit is damaged *
//* leaks trigger events. This snippet is easy to implement and removes the need to do *
//* you own GUI damage detection setup. *
//* *
//* -- How To Implement -- *
//* 1. Be sure "Automatically create unknown variables while pasting trigger data" is *
//* enabled in the World Editor general preferences. *
//* 2. Copy this trigger category ("GDD") and paste it into your map. *
//* (Alternately: create the variables listed below, create a trigger named *
//* "GUI Friendly Damage Detection", and paste in this entire text.) *
//* 3. Create your damage triggers using Game - Value Of Real Variable as the event, *
//* select GDD_Event as the variable, and leave the rest of the settings to the default *
//* "becomes Equal to 0.00". *
//* The event responses are the following variables: *
//* GDD_Damage is the amount of damage, replacing Event Response - Damage Taken. *
//* GDD_DamagedUnit is the damaged unit, replacing Event Response - Triggering Unit. *
//* GDD_DamageSource is the damaging unit, replacing Event Response - Damage Source. *
//* *
//* -- Notes -- *
//* Don't write any values to the variables used as the event responses, or it will mess *
//* up any other triggers using this snippet for their triggering. Only use their values. *
//* *
//* This uses arrays, so can have a maximum of 8190 instances at a time, and cleans up *
//* data at a rate of 33.33 per second. This should be enough for most maps. *
//* *
//* -- Credits -- *
//* Captain Griffin on wc3c.net for the research and concept of GroupRefresh. *
//* *
//* Credit in your map not needed, but please include this README. *
//* *
//* -- Version History -- *
//* 1.2.0: Made this snippet work properly with recursive damage. *
//* 1.1.1: Added a check in order to not index units with the Locust ability (dummy units).*
//* If you wish to check for damage taken by a unit that is unselectable, do not *
//* give the unit-type Locust in the object editor; instead, add the Locust ability *
//* 'Aloc' via a trigger after its creation, then remove it. *
//* 1.1.0: Added a check in case a unit gets moved out of the map and back. *
//* 1.0.0: First release. *
//* *
//*********************************************************************************************
//globals
// real udg_GDD_Event
// real udg_GDD_Damage
// unit udg_GDD_DamagedUnit
// unit udg_GDD_DamageSource
// trigger array udg_GDD__TriggerArray
// integer array udg_GDD__Integers
// unit array udg_GDD__UnitArray
// group udg_GDD__LeftMapGroup
//endglobals
function GDD_Event takes nothing returns boolean
local unit damagedcache = udg_GDD_DamagedUnit
local unit damagingcache = udg_GDD_DamageSource
local real damagecache = udg_GDD_Damage
set udg_GDD_DamagedUnit = GetTriggerUnit()
set udg_GDD_DamageSource = GetEventDamageSource()
set udg_GDD_Damage = GetEventDamage()
set udg_GDD_Event = 1.
set udg_GDD_Event = 0.
set udg_GDD_DamagedUnit = damagedcache
set udg_GDD_DamageSource = damagingcache
set udg_GDD_Damage = damagecache
set damagedcache = null
set damagingcache = null
return false
endfunction
function GDD_AddDetection takes nothing returns boolean
// if(udg_GDD__Integers[0] > 8190) then
// call BJDebugMsg("GDD: Too many damage events! Decrease number of units present in the map or increase recycle rate.")
// ***Recycle rate is the number used in the TimerStart line at the bottom of this trigger. Smaller is faster.***
// return
// endif
if(IsUnitInGroup(GetFilterUnit(), udg_GDD__LeftMapGroup)) then
call GroupRemoveUnit(udg_GDD__LeftMapGroup, GetFilterUnit())
else
if(GetUnitAbilityLevel(GetFilterUnit(), 'Aloc') == 0) then
set udg_GDD__Integers[0] = udg_GDD__Integers[0]+1
set udg_GDD__UnitArray[udg_GDD__Integers[0]] = GetFilterUnit()
set udg_GDD__TriggerArray[udg_GDD__Integers[0]] = CreateTrigger()
call TriggerRegisterUnitEvent(udg_GDD__TriggerArray[udg_GDD__Integers[0]], udg_GDD__UnitArray[udg_GDD__Integers[0]], EVENT_UNIT_DAMAGED)
call TriggerAddCondition(udg_GDD__TriggerArray[udg_GDD__Integers[0]], Condition(function GDD_Event))
endif
endif
return false
endfunction
function GDD_PresetDetection takes nothing returns nothing
local group g = CreateGroup()
local integer i = 0
set i = 0
loop
call GroupEnumUnitsOfPlayer(g, Player(i), Condition(function GDD_AddDetection))
call GroupClear(g)
set i = i+1
exitwhen i == bj_MAX_PLAYER_SLOTS
endloop
call DestroyGroup(g)
set g = null
endfunction
function GDD_GroupRefresh takes nothing returns nothing
//Based on GroupRefresh by Captain Griffen on wc3c.net
if (bj_slotControlUsed[5063] == true) then
call GroupClear(udg_GDD__LeftMapGroup)
set bj_slotControlUsed[5063] = false
endif
call GroupAddUnit(udg_GDD__LeftMapGroup, GetEnumUnit())
endfunction
function GDD_Recycle takes nothing returns nothing
if(udg_GDD__Integers[0] <= 0) then
return
elseif(udg_GDD__Integers[1] <= 0) then
set udg_GDD__Integers[1] = udg_GDD__Integers[0]
endif
if(GetUnitTypeId(udg_GDD__UnitArray[udg_GDD__Integers[1]]) == 0) then
call DestroyTrigger(udg_GDD__TriggerArray[udg_GDD__Integers[1]])
set udg_GDD__TriggerArray[udg_GDD__Integers[1]] = null
set udg_GDD__TriggerArray[udg_GDD__Integers[1]] = udg_GDD__TriggerArray[udg_GDD__Integers[0]]
set udg_GDD__UnitArray[udg_GDD__Integers[1]] = udg_GDD__UnitArray[udg_GDD__Integers[0]]
set udg_GDD__UnitArray[udg_GDD__Integers[0]] = null
set udg_GDD__Integers[0] = udg_GDD__Integers[0]-1
endif
set udg_GDD__Integers[1] = udg_GDD__Integers[1]-1
endfunction
function GDD_LeaveMap takes nothing returns boolean
local boolean cached = bj_slotControlUsed[5063]
if(udg_GDD__Integers[2] < 64) then
set udg_GDD__Integers[2] = udg_GDD__Integers[2]+1
else
set bj_slotControlUsed[5063] = true
call ForGroup(udg_GDD__LeftMapGroup, function GDD_GroupRefresh)
set udg_GDD__Integers[2] = 0
endif
call GroupAddUnit(udg_GDD__LeftMapGroup, GetFilterUnit())
set bj_slotControlUsed[5063] = cached
return false
endfunction
//===========================================================================
function InitTrig_GUI_Friendly_Damage_Detection takes nothing returns nothing
local region r = CreateRegion()
call RegionAddRect(r, GetWorldBounds())
call TriggerRegisterEnterRegion(CreateTrigger(), r, Condition(function GDD_AddDetection))
call TriggerRegisterLeaveRegion(CreateTrigger(), r, Condition(function GDD_LeaveMap))
call GDD_PresetDetection()
call TimerStart(CreateTimer(), 0.03, true, function GDD_Recycle)
set r = null
endfunction