HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Can someone optimize, debug, give tips about this spell?

08-05-2009, 02:00 PM#1
chadpiety123
This is my very first code in Jass.

What the spell does is affect all units in an AoE. It has a duration of 12 seconds and a cooldown of 6. Whenever the affected units lose mana, they either lose or gain MS depending on their affiliation (lose MS for enemies and gain MS for allies). It's actually not working right now and I don't know what to do. Please help me!

Collapse JASS:
function Trig_Exertion_Conditions takes nothing returns boolean
    if ( not ( GetSpellAbilityId() == 'A003' ) ) then
        return false
    endif
    return true
endfunction

//stores units/mana into global variable
function exertion002 takes nothing returns nothing
    local integer i
    
    if(IsUnitAliveBJ(GetEnumUnit()) == true) then
        if(udg_exertionUnits[i] == null) then
            set udg_exertionUnits[i] = GetEnumUnit()
            set udg_exertionMana[i] = GetUnitState(GetEnumUnit(), UNIT_STATE_MANA)
            set i=i+1
        else
            call TriggerSleepAction(0.01)
            set udg_exertionUnits[i] = GetEnumUnit()
            set udg_exertionMana[i] = GetUnitState(GetEnumUnit(), UNIT_STATE_MANA)
            set i=i+1
        endif
    endif
endfunction

//checks if unit has buff
function exertion001 takes nothing returns boolean
    return (UnitHasBuffBJ(GetEnumUnit(), 'B000') == true)
endfunction

function Trig_Exertion_Actions takes nothing returns nothing
    local real array exertionMana
    local unit array exertionUnits
    local integer i=0
    local real exertionTimer=0
    local group exertionGroup
    
//sets the units in playable map area with buff to a group and transfers that group into an array    
    call TriggerSleepAction(0.01)
    set exertionGroup = GetUnitsInRectMatching(GetPlayableMapRect(), Condition(function exertion001))
    call ForGroup(exertionGroup, function exertion002)
    
//transfers the contents of the global variable to a local variable
    loop
        exitwhen (udg_exertionUnits[i] == null)
        set exertionUnits[i]=udg_exertionUnits[i]
        set exertionMana[i]=udg_exertionMana[i]
        set i=i+1
    endloop

//empties the global variable
    loop
        exitwhen (i == 0)
        set udg_exertionUnits[i]=null
        set udg_exertionMana[i]=0
        set i=i-1
    endloop
    
//periodic check
    loop
        exitwhen (exertionTimer == 12)
    
        if (exertionMana[i] < GetUnitState(exertionUnits[i], UNIT_STATE_MANA)) then
            //check if alive, has exertion main buff and if unit index is not empty
            if (IsUnitAliveBJ(exertionUnits[i]) == true and UnitHasBuffBJ(exertionUnits[i], 'B000') == true and exertionUnits[i] != null) then
                //checks if ally
                if (IsUnitAlly(exertionUnits[i], GetTriggerPlayer())) then
                    if (UnitHasBuffBJ(exertionUnits[i], 'B00C') == true) then
                        call UnitRemoveBuffBJ('B00C', exertionUnits[i])
                        call CreateUnitAtLoc(GetTriggerPlayer(), 'h000', GetUnitLoc(exertionUnits[i]), 0)
                        call UnitApplyTimedLife(GetLastCreatedUnit(), 'BTLF', 1.5)
                        call UnitAddAbility(GetLastCreatedUnit(), 'A005')
                        call SetUnitAbilityLevel(GetLastCreatedUnit(), 'A005', 12)
                        call IssueTargetOrder(GetLastCreatedUnit(), "slow", exertionUnits[i])
                    elseif (UnitHasBuffBJ(exertionUnits[i], 'B00B') == true) then
                        call UnitRemoveBuffBJ('B00B', exertionUnits[i])
                        call CreateUnitAtLoc(GetTriggerPlayer(), 'h000', GetUnitLoc(exertionUnits[i]), 0)
                        call UnitApplyTimedLife(GetLastCreatedUnit(), 'BTLF', 1.5)
                        call UnitAddAbility(GetLastCreatedUnit(), 'A005')
                        call SetUnitAbilityLevel(GetLastCreatedUnit(), 'A005', 12)
                        call IssueTargetOrder(GetLastCreatedUnit(), "slow", exertionUnits[i])
                    elseif (UnitHasBuffBJ(exertionUnits[i], 'B00A') == true) then
                        call UnitRemoveBuffBJ('B00A', exertionUnits[i])
                        call CreateUnitAtLoc(GetTriggerPlayer(), 'h000', GetUnitLoc(exertionUnits[i]), 0)
                        call UnitApplyTimedLife(GetLastCreatedUnit(), 'BTLF', 1.5)
                        call UnitAddAbility(GetLastCreatedUnit(), 'A005')
                        call SetUnitAbilityLevel(GetLastCreatedUnit(), 'A005', 11)
                        call IssueTargetOrder(GetLastCreatedUnit(), "slow", exertionUnits[i])
                    elseif (UnitHasBuffBJ(exertionUnits[i], 'B009') == true) then
                        call UnitRemoveBuffBJ('B009', exertionUnits[i])
                        call CreateUnitAtLoc(GetTriggerPlayer(), 'h000', GetUnitLoc(exertionUnits[i]), 0)
                        call UnitApplyTimedLife(GetLastCreatedUnit(), 'BTLF', 1.5)
                        call UnitAddAbility(GetLastCreatedUnit(), 'A005')
                        call SetUnitAbilityLevel(GetLastCreatedUnit(), 'A005', 9)
                        call IssueTargetOrder(GetLastCreatedUnit(), "slow", exertionUnits[i])
                    elseif (UnitHasBuffBJ(exertionUnits[i], 'B008') == true) then
                        call UnitRemoveBuffBJ('B008', exertionUnits[i])
                        call CreateUnitAtLoc(GetTriggerPlayer(), 'h000', GetUnitLoc(exertionUnits[i]), 0)
                        call UnitApplyTimedLife(GetLastCreatedUnit(), 'BTLF', 1.5)
                        call UnitAddAbility(GetLastCreatedUnit(), 'A005')
                        call SetUnitAbilityLevel(GetLastCreatedUnit(), 'A005', 9)
                        call IssueTargetOrder(GetLastCreatedUnit(), "slow", exertionUnits[i])
                    elseif (UnitHasBuffBJ(exertionUnits[i], 'B007') == true) then
                        call UnitRemoveBuffBJ('B007', exertionUnits[i])
                        call CreateUnitAtLoc(GetTriggerPlayer(), 'h000', GetUnitLoc(exertionUnits[i]), 0)
                        call UnitApplyTimedLife(GetLastCreatedUnit(), 'BTLF', 1.5)
                        call UnitAddAbility(GetLastCreatedUnit(), 'A005')
                        call SetUnitAbilityLevel(GetLastCreatedUnit(), 'A005', 8)
                        call IssueTargetOrder(GetLastCreatedUnit(), "slow", exertionUnits[i])
                    elseif (UnitHasBuffBJ(exertionUnits[i], 'B006') == true) then
                        call UnitRemoveBuffBJ('B006', exertionUnits[i])
                        call CreateUnitAtLoc(GetTriggerPlayer(), 'h000', GetUnitLoc(exertionUnits[i]), 0)
                        call UnitApplyTimedLife(GetLastCreatedUnit(), 'BTLF', 1.5)
                        call UnitAddAbility(GetLastCreatedUnit(), 'A005')
                        call SetUnitAbilityLevel(GetLastCreatedUnit(), 'A005', 6)
                        call IssueTargetOrder(GetLastCreatedUnit(), "slow", exertionUnits[i])
                    elseif (UnitHasBuffBJ(exertionUnits[i], 'B005') == true) then
                        call UnitRemoveBuffBJ('B005', exertionUnits[i])
                        call CreateUnitAtLoc(GetTriggerPlayer(), 'h000', GetUnitLoc(exertionUnits[i]), 0)
                        call UnitApplyTimedLife(GetLastCreatedUnit(), 'BTLF', 1.5)
                        call UnitAddAbility(GetLastCreatedUnit(), 'A005')
                        call SetUnitAbilityLevel(GetLastCreatedUnit(), 'A005', 6)
                        call IssueTargetOrder(GetLastCreatedUnit(), "slow", exertionUnits[i])
                    elseif (UnitHasBuffBJ(exertionUnits[i], 'B004') == true) then
                        call UnitRemoveBuffBJ('B004', exertionUnits[i])
                        call CreateUnitAtLoc(GetTriggerPlayer(), 'h000', GetUnitLoc(exertionUnits[i]), 0)
                        call UnitApplyTimedLife(GetLastCreatedUnit(), 'BTLF', 1.5)
                        call UnitAddAbility(GetLastCreatedUnit(), 'A005')
                        call SetUnitAbilityLevel(GetLastCreatedUnit(), 'A005', 5)
                        call IssueTargetOrder(GetLastCreatedUnit(), "slow", exertionUnits[i])
                    elseif (UnitHasBuffBJ(exertionUnits[i], 'B003') == true) then
                        call UnitRemoveBuffBJ('B003', exertionUnits[i])
                        call CreateUnitAtLoc(GetTriggerPlayer(), 'h000', GetUnitLoc(exertionUnits[i]), 0)
                        call UnitApplyTimedLife(GetLastCreatedUnit(), 'BTLF', 1.5)
                        call UnitAddAbility(GetLastCreatedUnit(), 'A005')
                        call SetUnitAbilityLevel(GetLastCreatedUnit(), 'A005', 3)
                        call IssueTargetOrder(GetLastCreatedUnit(), "slow", exertionUnits[i])
                    elseif (UnitHasBuffBJ(exertionUnits[i], 'B002') == true) then
                        call UnitRemoveBuffBJ('B002', exertionUnits[i])
                        call CreateUnitAtLoc(GetTriggerPlayer(), 'h000', GetUnitLoc(exertionUnits[i]), 0)
                        call UnitApplyTimedLife(GetLastCreatedUnit(), 'BTLF', 1.5)
                        call UnitAddAbility(GetLastCreatedUnit(), 'A005')
                        call SetUnitAbilityLevel(GetLastCreatedUnit(), 'A005', 3)
                        call IssueTargetOrder(GetLastCreatedUnit(), "slow", exertionUnits[i])
                    elseif (UnitHasBuffBJ(exertionUnits[i], 'B001') == true) then
                        call UnitRemoveBuffBJ('B001', exertionUnits[i])
                        call CreateUnitAtLoc(GetTriggerPlayer(), 'h000', GetUnitLoc(exertionUnits[i]), 0)
                        call UnitApplyTimedLife(GetLastCreatedUnit(), 'BTLF', 1.5)
                        call UnitAddAbility(GetLastCreatedUnit(), 'A005')
                        call SetUnitAbilityLevel(GetLastCreatedUnit(), 'A005', 2)
                        call IssueTargetOrder(GetLastCreatedUnit(), "slow", exertionUnits[i])
                    else
                        call CreateUnitAtLoc(GetTriggerPlayer(), 'h000', GetUnitLoc(exertionUnits[i]), 0)
                        call UnitApplyTimedLife(GetLastCreatedUnit(), 'BTLF', 1.5)
                        call UnitAddAbility(GetLastCreatedUnit(), 'A005')
                        call SetUnitAbilityLevel(GetLastCreatedUnit(), 'A005', 3*GetUnitAbilityLevel(GetTriggerUnit(), 'A003')-2)
                        call IssueTargetOrder(GetLastCreatedUnit(), "slow", exertionUnits[i])
                    endif
                else
                    if (UnitHasBuffBJ(exertionUnits[i], 'B00O') == true) then
                        call UnitRemoveBuffBJ('B00O', exertionUnits[i])
                        call CreateUnitAtLoc(GetTriggerPlayer(), 'h000', GetUnitLoc(exertionUnits[i]), 0)
                        call UnitApplyTimedLife(GetLastCreatedUnit(), 'BTLF', 1.5)
                        call UnitAddAbility(GetLastCreatedUnit(), 'A006')
                        call SetUnitAbilityLevel(GetLastCreatedUnit(), 'A006', 12)
                        call IssueTargetOrder(GetLastCreatedUnit(), "slow", exertionUnits[i])
                    elseif (UnitHasBuffBJ(exertionUnits[i], 'B00N') == true) then
                        call UnitRemoveBuffBJ('B00N', exertionUnits[i])
                        call CreateUnitAtLoc(GetTriggerPlayer(), 'h000', GetUnitLoc(exertionUnits[i]), 0)
                        call UnitApplyTimedLife(GetLastCreatedUnit(), 'BTLF', 1.5)
                        call UnitAddAbility(GetLastCreatedUnit(), 'A006')
                        call SetUnitAbilityLevel(GetLastCreatedUnit(), 'A006', 12)
                        call IssueTargetOrder(GetLastCreatedUnit(), "slow", exertionUnits[i])
                    elseif (UnitHasBuffBJ(exertionUnits[i], 'B00M') == true) then
                        call UnitRemoveBuffBJ('B00M', exertionUnits[i])
                        call CreateUnitAtLoc(GetTriggerPlayer(), 'h000', GetUnitLoc(exertionUnits[i]), 0)
                        call UnitApplyTimedLife(GetLastCreatedUnit(), 'BTLF', 1.5)
                        call UnitAddAbility(GetLastCreatedUnit(), 'A006')
                        call SetUnitAbilityLevel(GetLastCreatedUnit(), 'A006', 11)
                        call IssueTargetOrder(GetLastCreatedUnit(), "slow", exertionUnits[i])
                    elseif (UnitHasBuffBJ(exertionUnits[i], 'B00L') == true) then
                        call UnitRemoveBuffBJ('B00L', exertionUnits[i])
                        call CreateUnitAtLoc(GetTriggerPlayer(), 'h000', GetUnitLoc(exertionUnits[i]), 0)
                        call UnitApplyTimedLife(GetLastCreatedUnit(), 'BTLF', 1.5)
                        call UnitAddAbility(GetLastCreatedUnit(), 'A006')
                        call SetUnitAbilityLevel(GetLastCreatedUnit(), 'A006', 9)
                        call IssueTargetOrder(GetLastCreatedUnit(), "slow", exertionUnits[i])
                    elseif (UnitHasBuffBJ(exertionUnits[i], 'B00K') == true) then
                        call UnitRemoveBuffBJ('B00K', exertionUnits[i])
                        call CreateUnitAtLoc(GetTriggerPlayer(), 'h000', GetUnitLoc(exertionUnits[i]), 0)
                        call UnitApplyTimedLife(GetLastCreatedUnit(), 'BTLF', 1.5)
                        call UnitAddAbility(GetLastCreatedUnit(), 'A006')
                        call SetUnitAbilityLevel(GetLastCreatedUnit(), 'A006', 9)
                        call IssueTargetOrder(GetLastCreatedUnit(), "slow", exertionUnits[i])
                    elseif (UnitHasBuffBJ(exertionUnits[i], 'B00J') == true) then
                        call UnitRemoveBuffBJ('B00J', exertionUnits[i])
                        call CreateUnitAtLoc(GetTriggerPlayer(), 'h000', GetUnitLoc(exertionUnits[i]), 0)
                        call UnitApplyTimedLife(GetLastCreatedUnit(), 'BTLF', 1.5)
                        call UnitAddAbility(GetLastCreatedUnit(), 'A006')
                        call SetUnitAbilityLevel(GetLastCreatedUnit(), 'A006', 8)
                        call IssueTargetOrder(GetLastCreatedUnit(), "slow", exertionUnits[i])
                    elseif (UnitHasBuffBJ(exertionUnits[i], 'B00I') == true) then
                        call UnitRemoveBuffBJ('B00I', exertionUnits[i])
                        call CreateUnitAtLoc(GetTriggerPlayer(), 'h000', GetUnitLoc(exertionUnits[i]), 0)
                        call UnitApplyTimedLife(GetLastCreatedUnit(), 'BTLF', 1.5)
                        call UnitAddAbility(GetLastCreatedUnit(), 'A006')
                        call SetUnitAbilityLevel(GetLastCreatedUnit(), 'A006', 6)
                        call IssueTargetOrder(GetLastCreatedUnit(), "slow", exertionUnits[i])
                    elseif (UnitHasBuffBJ(exertionUnits[i], 'B00H') == true) then
                        call UnitRemoveBuffBJ('B00H', exertionUnits[i])
                        call CreateUnitAtLoc(GetTriggerPlayer(), 'h000', GetUnitLoc(exertionUnits[i]), 0)
                        call UnitApplyTimedLife(GetLastCreatedUnit(), 'BTLF', 1.5)
                        call UnitAddAbility(GetLastCreatedUnit(), 'A006')
                        call SetUnitAbilityLevel(GetLastCreatedUnit(), 'A006', 6)
                        call IssueTargetOrder(GetLastCreatedUnit(), "slow", exertionUnits[i])
                    elseif (UnitHasBuffBJ(exertionUnits[i], 'B00G') == true) then
                        call UnitRemoveBuffBJ('B00G', exertionUnits[i])
                        call CreateUnitAtLoc(GetTriggerPlayer(), 'h000', GetUnitLoc(exertionUnits[i]), 0)
                        call UnitApplyTimedLife(GetLastCreatedUnit(), 'BTLF', 1.5)
                        call UnitAddAbility(GetLastCreatedUnit(), 'A006')
                        call SetUnitAbilityLevel(GetLastCreatedUnit(), 'A006', 5)
                        call IssueTargetOrder(GetLastCreatedUnit(), "slow", exertionUnits[i])
                    elseif (UnitHasBuffBJ(exertionUnits[i], 'B00F') == true) then
                        call UnitRemoveBuffBJ('B00F', exertionUnits[i])
                        call CreateUnitAtLoc(GetTriggerPlayer(), 'h000', GetUnitLoc(exertionUnits[i]), 0)
                        call UnitApplyTimedLife(GetLastCreatedUnit(), 'BTLF', 1.5)
                        call UnitAddAbility(GetLastCreatedUnit(), 'A006')
                        call SetUnitAbilityLevel(GetLastCreatedUnit(), 'A006', 3)
                        call IssueTargetOrder(GetLastCreatedUnit(), "slow", exertionUnits[i])
                    elseif (UnitHasBuffBJ(exertionUnits[i], 'B00E') == true) then
                        call UnitRemoveBuffBJ('B00E', exertionUnits[i])
                        call CreateUnitAtLoc(GetTriggerPlayer(), 'h000', GetUnitLoc(exertionUnits[i]), 0)
                        call UnitApplyTimedLife(GetLastCreatedUnit(), 'BTLF', 1.5)
                        call UnitAddAbility(GetLastCreatedUnit(), 'A006')
                        call SetUnitAbilityLevel(GetLastCreatedUnit(), 'A006', 3)
                        call IssueTargetOrder(GetLastCreatedUnit(), "slow", exertionUnits[i])
                    elseif (UnitHasBuffBJ(exertionUnits[i], 'B00D') == true) then
                        call UnitRemoveBuffBJ('B00D', exertionUnits[i])
                        call CreateUnitAtLoc(GetTriggerPlayer(), 'h000', GetUnitLoc(exertionUnits[i]), 0)
                        call UnitApplyTimedLife(GetLastCreatedUnit(), 'BTLF', 1.5)
                        call UnitAddAbility(GetLastCreatedUnit(), 'A006')
                        call SetUnitAbilityLevel(GetLastCreatedUnit(), 'A006', 2)
                        call IssueTargetOrder(GetLastCreatedUnit(), "slow", exertionUnits[i])
                    else
                        call CreateUnitAtLoc(GetTriggerPlayer(), 'h000', GetUnitLoc(exertionUnits[i]), 0)
                        call UnitApplyTimedLife(GetLastCreatedUnit(), 'BTLF', 1.5)
                        call UnitAddAbility(GetLastCreatedUnit(), 'A006')
                        call SetUnitAbilityLevel(GetLastCreatedUnit(), 'A006', 3*GetUnitAbilityLevel(GetTriggerUnit(), 'A003')-2)
                        call IssueTargetOrder(GetLastCreatedUnit(), "slow", exertionUnits[i])
                    endif
                endif
            else
                set exertionUnits[i] = null
            endif
        else
            set exertionMana[i] = GetUnitState(exertionUnits[i], UNIT_STATE_MANA)
        endif
        
        call TriggerSleepAction(0.01)
        set exertionTimer = exertionTimer + 0.01
        
    endloop
endfunction

//===========================================================================
function InitTrig_Exertion takes nothing returns nothing
    set gg_trg_Exertion = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(gg_trg_Exertion, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition( gg_trg_Exertion, Condition(function Trig_Exertion_Conditions) )
    call TriggerAddAction(gg_trg_Exertion, function Trig_Exertion_Actions)
endfunction

Edited by Anitarf. Reason: Added JASS tags.
08-05-2009, 02:28 PM#2
Anitarf
I don't have much time, so I'll just say this for now:
If you want to make JASS spells, I seriously suggest you use vJass.
I'll have a look at the code later tonight.
08-05-2009, 04:30 PM#3
Sophismata
Very brief look:


Quote:
Originally Posted by chadpiety123
Collapse JASS:
function Trig_Exertion_Conditions takes nothing returns boolean
    if ( not ( GetSpellAbilityId() == 'A003' ) ) then
        return false
    endif
    return true
endfunction

That is fine, but return GetSpellAbilityId() == 'A003' is simpler.



Quote:
Originally Posted by chadpiety123
Collapse JASS:
//stores units/mana into global variable
function exertion002 takes nothing returns nothing
    local integer i
    
    if(IsUnitAliveBJ(GetEnumUnit()) == true) then
        if(udg_exertionUnits[i] == null) then
            set udg_exertionUnits[i] = GetEnumUnit()
            set udg_exertionMana[i] = GetUnitState(GetEnumUnit(), UNIT_STATE_MANA)
            set i=i+1
        else
            call TriggerSleepAction(0.01)
            set udg_exertionUnits[i] = GetEnumUnit()
            set udg_exertionMana[i] = GetUnitState(GetEnumUnit(), UNIT_STATE_MANA)
            set i=i+1
        endif
    endif
endfunction

You're missing a loop, and you're not setting integer i before calling it.


...

Oh dear. Ok, with the rest of the code, the best way to run a periodic check is to use a timer. When a timer is started, you can assign it a function to run. That timer will run that function when it reaches 0, and if the timer is made periodic it will keep looping every <time> seconds.
08-06-2009, 07:27 AM#4
chadpiety123
I don't really know what to do. Seems like most of the code is wrong =_=...
08-06-2009, 09:58 AM#5
Sophismata
First, look at some tutorials. Make the spell in GUI, convert it to (v)JASS, and just clean up the code.

Have a look at how you can change things.

Make sure you have the JASS NewGen Pack.
08-06-2009, 11:01 AM#6
chadpiety123
I have a question: How do I store information of each unit in a group which will be used as reference for a timer?
08-06-2009, 01:23 PM#7
Antinoid
Structs (vJass) is what you need i guess.
Have a look:
http://www.wc3c.net/showthread.php?t=91491

you didnt initialize i in exertion002 by the way.
08-06-2009, 06:38 PM#8
Anitarf
Quote:
Originally Posted by chadpiety123
I don't really know what to do. Seems like most of the code is wrong =_=...
You're new to this, you can't get it right on the first try, it sounds like a fairly complex spell. Could you describe exactly what you want the spell to do? Then we can go over it and together explore what the best way to make it would be.
08-07-2009, 10:30 AM#9
chadpiety123
Sorry for the late reply. Yeah, it's a bit complex.

Here's the whole ability.

Description: The White Sage strengthens the connection between the body and the will of his allies and enemies. All mana reductions during the duration of this skill cause either an increase or decrease in movement speed that stacks three times.
Duration: 12
Skill Type: Active, Area Targeted, Buff, Debuff, Minor Disable
Casting Range: 800
AoE: 350/400/450/500
Cooldown: 15/12/9/6
Mana Cost: 80/90/100/110
Level 1 - 3% movement speed change, 350 AoE
Level 2 - 6% movement speed change, 400 AoE
Level 3 - 9% movement speed change, 450 AoE
Level 4 - 12% movement speed change, 500 AoE
Framekwork:
Targets with this status gain or lose (allies gain and enemies lose) movement speed whenever they lose mana. The move speed variations lasts 5 seconds and stacks 3 times (refreshes) maximum. Casting this same ability to a target already inflicted refreshes the duration.

Thanks.
08-08-2009, 01:45 AM#10
Anitarf
Well, first of all you'd need to properly code the buff behaviour (recast refreshes duration, dispel removes it etc.). A system exists that already does all this for you, I highly recommend it.

Then, in a periodic trigger, you would check the current mana of the unit and compare it to the unit's previous mana, if it has decreased then apply the effect. The system mentioned above has a built in periodic event for the buffs that you could use, as well as a custom data field for each buff where you could store a struct containing the unit's last mana value as well as the current slow/speed level.