scope Atemporal initializer Init
private function Reset takes nothing returns nothing
//Loading the stuff that was saved into the hashtable
local timer t = GetExpiredTimer()
local unit caster = LoadUnitHandle(udg_HeroHash, GetHandleId(t), 1)
local integer abilCode = LoadInteger(udg_HeroHash, GetHandleId(t), 2)
//Reset the ability cooldown for the unit
call BlzEndUnitAbilityCooldown(caster, abilCode)
//Flushing the child keys of the hastable, so it do not leak
//Also very important to pause the timer before destroying it when using hashtables
call FlushChildHashtable(udg_HeroHash, GetHandleId(t))
call PauseTimer(t)
call DestroyTimer(t)
//And again, null handle type locals
set t = null
set caster = null
endfunction
private function Conditions takes nothing returns nothing
//the caster
local unit caster = GetTriggerUnit()
//the ability triggering the event
local integer abilCode = GetSpellAbilityId()
// Checks if the ability being cast is an Ultimate ability, in my map ultimates requires level 10
local boolean ultimate = (BlzGetAbilityIntegerField(BlzGetUnitAbility(caster, abilCode), ABILITY_IF_REQUIRED_LEVEL) >= 10)
//Heal potions in my map have no cooldown, so i'm leaving them out.
local boolean healPotion = (abilCode == 'AIre')
//I've created this trigger to fit an item that gives the wearer 15% chance to reset an ability cooldown after casting it (5% for Ultimate abilities)
//Also the item has an active ability itself, that will reset all abilities cooldowns, so i dont want that its effect reset it self
local boolean self = (abilCode == 'A019')
//The timer that will reset the ability if its within its chance to be reseted.
local timer t
//if not the item ability
if self then
call UnitResetCooldown(caster)
//if the triggering unit has the item and its not healing pot ability being used (you could easily adjust this if else block to suit your needs)
elseif (UnitHasItemOfType(caster, 'I08U') > 0 and not healPotion) then
//checking if its an ultimate ability and the 5% chance being taken into account
if (ultimate and GetRandomReal(1, 100) <= 5) then
//HERE is where the magic needs to happen. Like i said, you cannot use the new native within the event actions,
//but after a verry shot delay you can so i'm using a non-looping timer with very short time to reset the ability
//By saving the unit and the ability being cast in a hashtable i can access them later to be used with the native
//If you dont know how Hashtables works, i suggest you give a quick search in Hive, there's plenty of resources
//explaining it.
set t = CreateTimer()
call SaveUnitHandle(udg_HeroHash, GetHandleId(t), 1, caster)
call SaveInteger(udg_HeroHash, GetHandleId(t), 2, abilCode)
call TimerStart(t, 0.01, false, function Reset)
call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Items\\RitualDagger\\RitualDaggerTarget.mdl", caster, "origin"))
elseif (not ultimate and GetRandomReal(1, 100) <= 15) then
//Same as above, but for non Ultimates, so with a higher chance of triggering
set t = CreateTimer()
call SaveUnitHandle(udg_HeroHash, GetHandleId(t), 1, caster)
call SaveInteger(udg_HeroHash, GetHandleId(t), 2, abilCode)
call TimerStart(t, 0.01, false, function Reset)
call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Undead\\DeathPact\\DeathPactTarget.mdl", caster, "origin"))
endif
endif
//VERY IMPORTANT** Do not use a Timer with 0 cooldown, or else your unit will be stuck casting the ability until it ran out of mana
//Always null local variables that are of a handle type in JASS or else you will leak its reference.
//udg_HeroHash is a hashtable that i created, substitute for your own
set t = null
set caster = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
//This is a function provided in a library to reduce the amount of code necessary to create Player Event trigger
// you can find it here: https://www.hiveworkshop.com/threads/snippet-registerplayerunitevent.203338/
//of course you could use the followin as well
/*
set YourTrigger = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(YourTrigger, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(YourTrigger, Condition(function Conditions))
*/
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_SPELL_EFFECT, function Conditions)
endfunction
endscope