Increase Hero's Strength; No Stacking

WolfieeifloW

WEHZ Helper
Reaction score
372
Hey there!, I have two questions today TH.net (Yay :rolleyes:)!
My first, is to 'fix' this trigger I have.

I have a passive spell that has a chance on attacking to increase Strength by 15% for 5 seconds.
I've found one of my old spells, and re-learned timers (I think :p).

The Strength increase works great, but if the spell procs again, it just increases the hero's Strength further (30%).
Whereas I only want the heroes Strength to be able to increase a maximum of 15%.

How would I go about changing this to only allow a maximum of 15%?
I've thought of a few different ways, but I want to see what other people think.
I'd like a method that is easy (Coding wise, prefer not to add 100 variables or something), and efficient (Not as important).
Here's my code:
JASS:
scope ROTFC initializer ROTFCInit

    globals
        private constant string rotfcString = "innerfire"
    endglobals
    
    private struct data
        unit attacker
        unit dummy
        integer str
        timer t
        
        method onDestroy takes nothing returns nothing
            call ReleaseTimer(.t)
        endmethod
    endstruct

    private function Chance takes integer level returns integer
        return 100//level * 1
    endfunction
    
    private function RemoveStr takes nothing returns nothing
        local data d = GetTimerData(GetExpiredTimer())
        
        call BJDebugMsg("Running!")
        call SetHeroStr(d.attacker, d.str, true)
        call d.destroy()
    endfunction
    
    private function Conditions takes nothing returns boolean
        local data d = data.create()
        set d.attacker = GetAttacker()
        set d.str = GetHeroStr(d.attacker, true)
                
        if (GetUnitAbilityLevel(d.attacker, rotfc) > 0 and GetRandomInt(0, 100) <= Chance(GetUnitAbilityLevel(d.attacker, rotfc))) then
            call BJDebugMsg(I2S(R2I(d.str * 1.15)))
            set d.dummy = CreateUnit(GetOwningPlayer(d.attacker), dummyID, GetUnitX(d.attacker), GetUnitY(d.attacker), bj_UNIT_FACING)
            call UnitAddAbility(d.dummy, rotfcBuff)
            call SetUnitAbilityLevel(d.dummy, rotfcBuff, 1)
            call IssueTargetOrder(d.dummy, rotfcString, d.attacker)
            call UnitApplyTimedLife(d.dummy, 'BTLF', 0.01)
            call SetHeroStr(d.attacker, R2I(d.str * 1.15), false)
            set d.t = NewTimer()
            call SetTimerData(d.t, d)
            call TimerStart(d.t, 5., false, function RemoveStr)
        endif
        return false
    endfunction
    

    private function ROTFCInit takes nothing returns nothing
        local trigger t = CreateTrigger()
        local integer index = 0
        
        loop
            call TriggerRegisterPlayerUnitEvent(t, Player(index), EVENT_PLAYER_UNIT_ATTACKED, null)
            set index = index + 1
            exitwhen index == bj_MAX_PLAYER_SLOTS
        endloop
        call TriggerAddCondition(t, Condition(function Conditions))
        set t = null
    endfunction
    
endscope


Also, for my second question.
I've only relearned structs/timers a bit ago, so I'm asking if someone can give me any pointers to optimize/fix my code up.
 

WolfieeifloW

WEHZ Helper
Reaction score
372
Hmm, I just had another thought after I posted this.
Using a boolean.
Here's how I changed it:
JASS:
scope ROTFC initializer ROTFCInit

    globals
        private constant string rotfcString = "innerfire"
        private boolean inc = false
    endglobals
    
    private struct data
        unit attacker
        unit dummy
        integer str
        timer t
        
        method onDestroy takes nothing returns nothing
            call ReleaseTimer(.t)
        endmethod
    endstruct

    private function Chance takes integer level returns integer
        return 100//level * 1
    endfunction
    
    private function RemoveStr takes nothing returns nothing
        local data d = GetTimerData(GetExpiredTimer())
        
        call SetHeroStr(d.attacker, d.str, true)
        set inc = false
        call d.destroy()
    endfunction
    
    private function Conditions takes nothing returns boolean
        local data d = data.create()
        set d.attacker = GetAttacker()
        set d.str = GetHeroStr(d.attacker, true)
                
        if (GetUnitAbilityLevel(d.attacker, rotfc) > 0 and GetRandomInt(0, 100) <= Chance(GetUnitAbilityLevel(d.attacker, rotfc)) and inc == false) then
            set inc = true
            set d.dummy = CreateUnit(GetOwningPlayer(d.attacker), dummyID, GetUnitX(d.attacker), GetUnitY(d.attacker), bj_UNIT_FACING)
            call UnitAddAbility(d.dummy, rotfcBuff)
            call SetUnitAbilityLevel(d.dummy, rotfcBuff, 1)
            call IssueTargetOrder(d.dummy, rotfcString, d.attacker)
            call UnitApplyTimedLife(d.dummy, 'BTLF', 0.01)
            call SetHeroStr(d.attacker, R2I(d.str * 1.15), false)
            set d.t = NewTimer()
            call SetTimerData(d.t, d)
            call TimerStart(d.t, 5., false, function RemoveStr)
        endif
        return false
    endfunction
    

    private function ROTFCInit takes nothing returns nothing
        local trigger t = CreateTrigger()
        local integer index = 0
        
        loop
            call TriggerRegisterPlayerUnitEvent(t, Player(index), EVENT_PLAYER_UNIT_ATTACKED, null)
            set index = index + 1
            exitwhen index == bj_MAX_PLAYER_SLOTS
        endloop
        call TriggerAddCondition(t, Condition(function Conditions))
        set t = null
    endfunction
    
endscope

That works, but I still have the question of if anyone can give me points to optimize/'fix' my code up.
 

emjlr3

Change can be a good thing
Reaction score
395
for MUI use a unit group
 

WolfieeifloW

WEHZ Helper
Reaction score
372
Ah, yes.
Forgot about MUI, :p
Here's the new code:
JASS:
scope ROTFC initializer ROTFCInit

    globals
        private constant string rotfcString = "innerfire"
        private group inc = CreateGroup()
    endglobals
    
    private struct data
        unit attacker
        unit dummy
        integer str
        real heal
        timer t
        
        method onDestroy takes nothing returns nothing
            call ReleaseTimer(.t)
        endmethod
    endstruct

    private function Chance takes integer level returns integer
        return 100//level * 1
    endfunction
    
    private function Heal takes nothing returns real
        return 0.03
    endfunction
    
    private function RemoveStr takes nothing returns nothing
        local data d = GetTimerData(GetExpiredTimer())
        
        call SetHeroStr(d.attacker, d.str, true)
        call GroupRemoveUnit(inc, d.attacker)
        call d.destroy()
    endfunction
    
    private function Conditions takes nothing returns boolean
        local data d = data.create()
        set d.attacker = GetAttacker()
        set d.str = GetHeroStr(d.attacker, true)
        set d.heal = GetUnitState(d.attacker, UNIT_STATE_MAX_LIFE) * Heal()
                
        if (GetUnitAbilityLevel(d.attacker, rotfc) > 0 and GetRandomInt(0, 100) <= Chance(GetUnitAbilityLevel(d.attacker, rotfc)) and IsUnitInGroup(d.attacker, inc) == false) then
            call GroupAddUnit(inc, d.attacker)
            set d.dummy = CreateUnit(GetOwningPlayer(d.attacker), dummyID, GetUnitX(d.attacker), GetUnitY(d.attacker), bj_UNIT_FACING)
            call UnitAddAbility(d.dummy, rotfcBuff)
            call SetUnitAbilityLevel(d.dummy, rotfcBuff, 1)
            call IssueTargetOrder(d.dummy, rotfcString, d.attacker)
            call UnitApplyTimedLife(d.dummy, 'BTLF', 0.01)
            call SetHeroStr(d.attacker, R2I(d.str * 1.15), false)
            call BJDebugMsg(R2S(d.heal))
            call SetUnitState(d.attacker, UNIT_STATE_LIFE, GetUnitState(d.attacker, UNIT_STATE_LIFE) + d.heal)
            set d.t = NewTimer()
            call SetTimerData(d.t, d)
            call TimerStart(d.t, 5., false, function RemoveStr)
        endif
        return false
    endfunction
    

    private function ROTFCInit takes nothing returns nothing
        local trigger t = CreateTrigger()
        local integer index = 0
        
        loop
            call TriggerRegisterPlayerUnitEvent(t, Player(index), EVENT_PLAYER_UNIT_ATTACKED, null)
            set index = index + 1
            exitwhen index == bj_MAX_PLAYER_SLOTS
        endloop
        call TriggerAddCondition(t, Condition(function Conditions))
        set t = null
    endfunction
    
endscope

Anything else that could be optimized/fixed up?
 

dudeim

New Member
Reaction score
22
You use GetUnitAbilityLevel twice so think you need to make a variable off it for maximum efficiency, for the rest it looks good.
 

luorax

Invasion in Duskwood
Reaction score
67
Nope, calling GetUnitAbilityLevel() twice instead of a local variable is fine.
 

WolfieeifloW

WEHZ Helper
Reaction score
372
I'd have to make it an integer in the struct;
So I think an extra struct member would be less efficient then calling a native twice, no?
 

luorax

Invasion in Duskwood
Reaction score
67
Yes, I think it'd be still less efficient. (I'm not sure - someone's already benchamrked these things, but I really forgot the results) But it doesn't matter, the difference is not noticeable.
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Staff online

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top