• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

BlzUnitHideAbility and BlzUnitDisableAbility don't work?

Status
Not open for further replies.
Level 15
Joined
Nov 30, 2007
Messages
1,202
I tried replacing SetPlayerAbilityAvailable with the new natives and I get undesired behaviour with some abilities not being hidden properly. It works as intended when I use SetPlayerAbilityAvailable but not at all when I change.

JASS:
native BlzUnitHideAbility takes unit whichUnit, integer abilId, boolean flag returns nothing
native BlzUnitDisableAbility takes unit whichUnit, integer abilId, boolean flag, boolean hideUI returns nothing

JASS:
private static method applyOptionToSpell takes PlayerMenu pmenu, SpellOption o, integer pos returns nothing
            if o != 0 and not o.getLocalHidden(pmenu.pid) then
                set text = o.getLocalText(pmenu.pid)
                set timeRemaining = o.getCooldown(pmenu.pid)
                if timeRemaining > 0 then
                    set text = text + "|n|n" + COOLDOWN_LABEL + FormatTime(timeRemaining) + "|r"
                endif
                if  o.getLocalEnabled(pmenu.pid) then
                    call BlzUnitHideAbility(pmenu.u, active[pos], false)
                    call BlzUnitHideAbility(pmenu.u, passive[pos], true)
                    //call SetPlayerAbilityAvailable(pmenu.p, active[pos], true)
                    //call SetPlayerAbilityAvailable(pmenu.p, passive[pos], false)
                    set spell = active[pos]
                    set pmenu.spellTable[spell] = o // map option to spell-table
                else
                    call BlzUnitHideAbility(pmenu.u, active[pos], true)
                    call BlzUnitHideAbility(pmenu.u, passive[pos], false)
                    //call SetPlayerAbilityAvailable(pmenu.p, active[pos], false)
                    //call SetPlayerAbilityAvailable(pmenu.p, passive[pos], true)
                    set spell = passive[pos]
                endif
                if GetLocalPlayer() == pmenu.p then // Update Displayed Ability
                    call BlzSetAbilityExtendedTooltip(spell, text, 1)
                    call BlzSetAbilityTooltip(spell, o.getLocalLabel(pmenu.pid) + " " + hotkey[pos], 1)
                    call BlzSetAbilityIcon(spell, o.getLocalIcon(pmenu.pid))
                endif
            else
                call BlzUnitHideAbility(pmenu.u, active[pos], true)
                call BlzUnitHideAbility(pmenu.u, passive[pos], true)
                //call SetPlayerAbilityAvailable(pmenu.p, active[pos], false)
                //call SetPlayerAbilityAvailable(pmenu.p, passive[pos], false)
            endif
        endmethod
 
        method showPage takes player p, integer page returns nothing
            local PlayerMenu pmenu = PlayerMenu(GetPlayerId(p))
            local integer maxPages
            local integer i = 0
            local integer j = 0
            local SpellOption o
            if pmenu.currOpen == 0 then
                return
            endif
            call visibleOptions.clear()
            call UnwatchSpellOptions(pmenu.pid)
            loop
                exitwhen i == .options.length
                set o = .options[i]
                set lockedOption = lockedOptions[ModuloInteger(j, 11)]                      // TODO: replace modulo
                if lockedOption != 0 and not lockedOption.getLocalHidden(pmenu.pid) then
                    call visibleOptions.add(j, lockedOption)    // add locked option to presenter
                    if lockedOption != o then
                        set i = i - 1
                    endif
                    set j = j + 1
                elseif not o.getLocalHidden(pmenu.pid) and not .isLocked(o) then
                    call visibleOptions.add(j, o) // add default option to presenter
                    set j = j + 1
                endif
                set i = i + 1
            endloop
            // Adjust current page
            set maxPages = getPages(j)
            if page > maxPages or page < 0 then
                set pmenu.pageIndex = 0
            else
                set pmenu.pageIndex = page
            endif
            // Adjust Options
            set j = pmenu.pageIndex*11
            set i = 0
            loop
                exitwhen i == 12
                if j < visibleOptions.length or (lockedOptions[i] != 0) then
                    if j < visibleOptions.length then
                        set o = visibleOptions[j]
                        set j = j + 1
                    else
                        set o = lockedOptions[i]
                    endif
                    call applyOptionToSpell(pmenu, o, i)
                    call WatchSpellOption(pmenu.pid, i, o)
                else
                    call BlzUnitHideAbility(pmenu.u, active[i], true)
                    call BlzUnitHideAbility(pmenu.u, passive[i], true)
                    //call SetPlayerAbilityAvailable(pmenu.p, active[i], false)
                    //call SetPlayerAbilityAvailable(pmenu.p, passive[i], false)
                endif
                set i = i + 1
            endloop
            // If there are more than 12 options in the menu than the last button will always be 'Next'
            if visibleOptions.size() > 12 then
                call BlzUnitHideAbility(pmenu.u, active[i], true)
                call BlzUnitHideAbility(pmenu.u, passive[i], true)
                call BlzUnitHideAbility(pmenu.u, A_NEXT, false)
                //call SetPlayerAbilityAvailable(pmenu.p, active[11], false)
                //call SetPlayerAbilityAvailable(pmenu.p, passive[11], false)
                //call SetPlayerAbilityAvailable(pmenu.p, A_NEXT, true)
            else
                call BlzUnitHideAbility(pmenu.u, A_NEXT, true)
                //call SetPlayerAbilityAvailable(pmenu.p, A_NEXT, false)
            endif
            call BlzSetUnitName(pmenu.u, .name + " " + I2S(pmenu.pageIndex + 1) + "/" + I2S(maxPages + 1))
            if GetLocalPlayer() == pmenu.p then
                call ClearSelection()
                call SelectUnit(pmenu.u, true)
            endif
        endmethod

Here the spells have been coppied, there is for instance two paladins and I don't know what else is going on here...
upload_2019-2-6_16-38-19.png
Here icons have been carried over from a previous menu into the new one, even though they should have changed?
View attachment 315480

If I change it back it looks normal again:
View attachment 315484

This is all very strange as the syntax between SetPlayerAbilityAvailable and BlzUnitHideAbility is practically the same yet it leads to a completely different outcome.
 
Last edited:
BlzUnitHideAbility & BlzUnitDisableAbility increase/decerase counters on each usage. The Ability switchs hidden/shown Enabled/Disabled state only when moving over the 0 even line.

If you want to use it as a switch you have to be careful which current count is.

The counters reset when the ability is lost.

Based on the wanted goal one can make abilties immune to silences for example (but on my testing you only become immune against 1 silence buff, even when stacking up enables).
 
Level 15
Joined
Nov 30, 2007
Messages
1,202
@Tasyen So i'd have to write wrapper methods to keep track of the counter?

  • Untitled Trigger 001
    • Events
      • Time - Elapsed game time is 5.00 seconds
    • Conditions
    • Actions
      • Set u = Knight 0018 <gen>
      • Set ab = Bloodlust (Neutral Hostile 1)
      • Custom script: call BlzUnitHideAbility(udg_u, udg_ab, true)
      • Wait 2.00 seconds
      • Custom script: call BlzUnitHideAbility(udg_u, udg_ab, false)
      • Custom script: call BlzUnitHideAbility(udg_u, udg_ab, false)
      • Custom script: call BlzUnitHideAbility(udg_u, udg_ab, false)
      • Wait 2.00 seconds
      • Custom script: call BlzUnitHideAbility(udg_u, udg_ab, true)
What odd behaviour it never hides in the last call.
 
thats how I did it, too.

Edit:
JASS:
function TalentUnitIsSpellHiden takes integer unitHandle, integer talentSpellNr returns boolean
    return LoadBoolean(udg_TalentHash, unitHandle, udg_TalentSpells[talentSpellNr])
endfunction
function TalentUnitSetSpellHiden takes unit u, integer talentSpellNr, boolean flag returns nothing
    local integer uId = GetHandleId(u)
    if TalentUnitIsSpellHiden(uId, talentSpellNr) != flag then
        //if flag then
        //    call Debug(GetUnitName(u) + " "+GetObjectName(udg_TalentSpells[talentSpellNr])+" -> disabled")
        //else
        //    call Debug(GetUnitName(u) + " "+GetObjectName(udg_TalentSpells[talentSpellNr])+" -> enabled")
        //endif
        call BlzUnitHideAbility(u, udg_TalentSpells[talentSpellNr], flag)
        call SaveBoolean(udg_TalentHash, uId, udg_TalentSpells[talentSpellNr], flag)
    endif
endfunction

Edit: If one thinks about it more strictly it makes sense, cause in the game there are many possible sources disabling abilities. Silence, doom, hex, ensnare.... How now to make sure when stacking up on one unit the unit beeing able to cast afterwards again. Easiest is by counter. On buff add disable counter on buff lose reduce disable counter.
 
Last edited:
Level 14
Joined
Jan 16, 2009
Messages
716
This might help too if you want to disable without hiding or showing.
JASS:
function UnitDisableAbility takes unit whichUnit, integer abilityId, boolean flag returns nothing
        call BlzUnitDisableAbility(whichUnit,abilityId,flag,false)
        if not flag then
            call BlzUnitHideAbility(whichUnit,abilityId,true)
        endif
endfunction
 
Level 15
Joined
Nov 30, 2007
Messages
1,202
This might help too if you want to disable without hiding or showing.
JASS:
function UnitDisableAbility takes unit whichUnit, integer abilityId, boolean flag returns nothing
        call BlzUnitDisableAbility(whichUnit,abilityId,flag,false)
        if not flag then
            call BlzUnitHideAbility(whichUnit,abilityId,true)
        endif
endfunction

Isn't that susceptible to the counter problem?


@Tasyen Also, that thing you wrote requires a unit indexer to clean up after itself.
 
Last edited:
Level 15
Joined
Nov 30, 2007
Messages
1,202
I need to be able to call it like this:

JASS:
private static method setSpellState takes PlayerMenu pmenu, integer spell, boolean show, boolean enabled returns nothing
            call pmenu.unitHideSpell(spell, show == false)
            call pmenu.unitDisableSpell(spell, enabled == false)
        endmethod

The implementation i have right now from your examples is this and I'm wondering if it will actually be able to both hide/unhide and enable/disable?

Pseudo code:
JASS:
scope Tester initializer Init
    globals
        private boolean hidden = false
        private boolean disabled = false
    endglobals
 
    function UnitDisableAbility takes unit whichUnit, integer abilityId, boolean flag returns nothing
        if disabled != flag then
            call BlzUnitDisableAbility(whichUnit, abilityId, flag, hidden)
            set disabled = flag
        endif
    endfunction
 
    function UnitHideAbility takes unit whichUnit, integer abilityId, boolean flag returns nothing
        if hidden != flag then
            call BlzUnitHideAbility(whichUnit, abilityId, flag)
            set hidden = flag
            if not hidden and disabled then
                call BlzUnitDisableAbility(whichUnit, abilityId, true, false)
            endif
        endif
    endfunction

    private function Run takes nothing returns nothing
        local unit u = gg_unit_hkni_0018
        local integer a = 'ACbl'
        //call UnitHideAbility(u, a, true)
        call UnitDisableAbility(u, a, true)
        call UnitDisableAbility(u, a, true)
        call UnitDisableAbility(u, a, true)
    endfunction
 
    private function Run2 takes nothing returns nothing
        local unit u = gg_unit_hkni_0018
        local integer a = 'ACbl'
        call UnitHideAbility(u, a, false)
        call UnitDisableAbility(u, a, false)
    endfunction

    private function Init takes nothing returns nothing
        local timer t = CreateTimer()
        local timer t2 = CreateTimer()
        call TimerStart(t, 5., false, function Run)
        call TimerStart(t2, 8., false, function Run2)
    endfunction
endscope

Nope I still can't get it to work.

Here is the actual implementation:

JASS:
struct PlayerMenu
     ...
method unitHideSpell takes integer spell, boolean hidden returns nothing
            if .tableSpellState.boolean[spell] != hidden then
                call BlzUnitHideAbility(.u, spell, hidden)
                set .tableSpellState.boolean[spell] = hidden
                if not hidden and tableSpellState.boolean[-spell] then
                    call BlzUnitDisableAbility(.u, spell, true, false)
                endif
            endif
        endmethod
     
        method unitDisableSpell takes integer spell, boolean disabled returns nothing
            if .tableSpellState.boolean[-spell] != disabled then
                set .tableSpellState.boolean[-spell] = disabled
                call BlzUnitDisableAbility(.u, spell, disabled, .tableSpellState.boolean[spell])
            endif
        endmethod
endstruct

private static method applyOptionToSpell takes PlayerMenu pmenu, SpellOption o, integer pos returns nothing
            if o != 0 and not o.getLocalHidden(pmenu.pid) then
                set text = o.getLocalText(pmenu.pid)
                set timeRemaining = o.getCooldown(pmenu.pid)
                if timeRemaining > 0 then
                    set text = text + "|n|n" + COOLDOWN_LABEL + FormatTime(timeRemaining) + "|r"
                endif
                if  o.getLocalEnabled(pmenu.pid) then
                    //call BlzUnitDisableAbility(pmenu.u, active[pos], false)
                    //call BlzUnitDisableAbility(pmenu.u, passive[pos], true)
                    //call SetPlayerAbilityAvailable(pmenu.p, active[pos], true)
                    //call SetPlayerAbilityAvailable(pmenu.p, passive[pos], false)
                 
                    //call setSpellState(pmenu, active[pos], true, true)
                    //call setSpellState(pmenu, passive[pos], false, true)
                 
                    call pmenu.unitDisableSpell(active[pos], false)
             
                    set spell = active[pos]
                    set pmenu.spellTable[spell] = o // map option to spell-table
                else
                    //call BlzUnitHideAbility(pmenu.u, active[pos], true)
                    //call BlzUnitHideAbility(pmenu.u, passive[pos], false)
                   // call SetPlayerAbilityAvailable(pmenu.p, active[pos], false)
                    //call SetPlayerAbilityAvailable(pmenu.p, passive[pos], true)
                 
                    //call setSpellState(pmenu, active[pos], false, true)
                    //call setSpellState(pmenu, passive[pos], true, true)
             
                    call pmenu.unitDisableSpell(spell, true)
                 
                 
                    set spell = passive[pos]
                endif
                if GetLocalPlayer() == pmenu.p then // Update Displayed Ability
                    call BlzSetAbilityExtendedTooltip(spell, text, 1)
                    call BlzSetAbilityTooltip(spell, o.getLocalLabel(pmenu.pid) + " " + hotkey[pos], 1)
                    call BlzSetAbilityIcon(spell, o.getLocalIcon(pmenu.pid))
                endif
            else
                call pmenu.unitHideSpell(spell, true)
             
                //call BlzUnitHideAbility(pmenu.u, active[pos], true)
                //call BlzUnitHideAbility(pmenu.u, passive[pos], true)
                //call SetPlayerAbilityAvailable(pmenu.p, active[pos], false)
                //call SetPlayerAbilityAvailable(pmenu.p, passive[pos], false)
             
                //call setSpellState(pmenu, active[pos], false, true)
                //call setSpellState(pmenu, passive[pos], false, true)
            endif
        endmethod
     
        method showPage takes player p, integer page returns nothing
            local PlayerMenu pmenu = PlayerMenu(GetPlayerId(p))
            local integer maxPages
            local integer i = 0
            local integer j = 0
            local SpellOption o
            if pmenu.currOpen == 0 then
                return
            endif
            call visibleOptions.clear()
            call UnwatchSpellOptions(pmenu.pid)
            loop
                exitwhen i == .options.length
                set o = .options[i]
                set lockedOption = lockedOptions[ModuloInteger(j, 11)]                      // TODO: replace modulo
                if lockedOption != 0 and not lockedOption.getLocalHidden(pmenu.pid) then
                    call visibleOptions.add(j, lockedOption)    // add locked option to presenter
                    if lockedOption != o then
                        set i = i - 1
                    endif
                    set j = j + 1
                elseif not o.getLocalHidden(pmenu.pid) and not .isLocked(o) then
                    call visibleOptions.add(j, o) // add default option to presenter
                    set j = j + 1
                endif
                set i = i + 1
            endloop
            // Adjust current page
            set maxPages = getPages(j)
            if page > maxPages or page < 0 then
                set pmenu.pageIndex = 0
            else
                set pmenu.pageIndex = page
            endif
            // Adjust Options
            set j = pmenu.pageIndex*11
            set i = 0
            loop
                exitwhen i == 12
                if j < visibleOptions.length or (lockedOptions[i] != 0) then
                    if j < visibleOptions.length then
                        set o = visibleOptions[j]
                        set j = j + 1
                    else
                        set o = lockedOptions[i]
                    endif
                    call applyOptionToSpell(pmenu, o, i)
                    call WatchSpellOption(pmenu.pid, i, o)
                else
                    //call BlzUnitHideAbility(pmenu.u, active[i], true)
                    //call BlzUnitHideAbility(pmenu.u, passive[i], true)
                    //call SetPlayerAbilityAvailable(pmenu.p, active[i], false)
                   // call SetPlayerAbilityAvailable(pmenu.p, passive[i], false)
                 
                    //call setSpellState(pmenu, active[i], false, true)
                    //call setSpellState(pmenu, passive[i], false, true)
                 
                    call pmenu.unitHideSpell(active[i], true)
                endif
                call pmenu.unitHideSpell(passive[i], true)    // hiding all as im trying to get rid of the need for this entierly.
                set i = i + 1
            endloop
            // If there are more than 12 options in the menu than the last button will always be 'Next'
            if visibleOptions.size() > 12 then
                //call BlzUnitHideAbility(pmenu.u, A_NEXT, false)
                //call SetPlayerAbilityAvailable(pmenu.p, active[11], false)
                //call SetPlayerAbilityAvailable(pmenu.p, passive[11], false)
                //call SetPlayerAbilityAvailable(pmenu.p, A_NEXT, true)
             
                //call setSpellState(pmenu, active[11], false, true)
                //call setSpellState(pmenu, passive[11], false, true)
                //call setSpellState(pmenu, A_NEXT, true, true)
             
                call pmenu.unitHideSpell(active[11], true)     
                call pmenu.unitHideSpell(A_NEXT, false)
            else
                //call BlzUnitHideAbility(pmenu.u, A_NEXT, true)
                //call SetPlayerAbilityAvailable(pmenu.p, A_NEXT, false)
                //call setSpellState(pmenu, A_NEXT, false, true)
             
                call pmenu.unitHideSpell(active[11], false)
                call pmenu.unitHideSpell(A_NEXT, true)
            endif
            call BlzSetUnitName(pmenu.u, .name + " " + I2S(pmenu.pageIndex + 1) + "/" + I2S(maxPages + 1))
            if GetLocalPlayer() == pmenu.p then
                call ClearSelection()
                call SelectUnit(pmenu.u, true)
            endif
        endmethod

This native is seriously horrid.
 
Last edited:
Level 15
Joined
Nov 30, 2007
Messages
1,202
This native is perfectly fine. We just need a disable that doesn't hide / show at the same time but it can be fixed with what I posted above.

Your thing doesn't work with multiple hides in a row.

This however (should) solves all my problems:

JASS:
    function SetAbilityUIState takes unit whichUnit, integer abilityId, boolean hidden, boolean disabled returns nothing
        call UnitRemoveAbility(whichUnit, abilityId)
        call UnitAddAbility(whichUnit, abilityId)
        call BlzUnitDisableAbility(whichUnit, abilityId, disabled, hidden)
    endfunction
 
Level 15
Joined
Nov 30, 2007
Messages
1,202
What I posted works just fine - your lack of understanding of the natives is another thing though.

No I tested your thing it doesnt:

JASS:
function UnitDisableAbility takes unit whichUnit, integer abilityId, boolean flag returns nothing
        call BlzUnitDisableAbility(whichUnit,abilityId, flag, false)
        if not flag then
            call BlzUnitHideAbility(whichUnit,abilityId,true)
        endif
    endfunction

    private function Run takes nothing returns nothing
        local unit u = gg_unit_hkni_0018
        local integer a = 'ACbl'
        call UnitDisableAbility(u, a, true)
        call UnitDisableAbility(u, a, true)
        call UnitDisableAbility(u, a, true)
    endfunction
  
    private function Run2 takes nothing returns nothing
        local unit u = gg_unit_hkni_0018
        local integer a = 'ACbl'
        call UnitDisableAbility(u, a, false)    // will remain disabled, is that intended?
    endfunction

    private function Init takes nothing returns nothing
        local timer t = CreateTimer()
        local timer t2 = CreateTimer()
        call TimerStart(t, 5., false, function Run)
        call TimerStart(t2, 8., false, function Run2)
    endfunction

If its intended, I fail to see the point with your function? ^^
 
Level 1
Joined
May 5, 2021
Messages
1
JASS:
//===========================================================================
function UnitDisableAbilitySafely takes unit u, integer abilcode, boolean disable returns nothing
    local integer flag = LoadInteger(g_hashtable, GetHandleId(u), abilcode)
    if (flag > 0 and disable) or (flag < 0 and not disable) then
        return//do nothing
    endif
    if disable then
        set flag = 1
    else
        set flag = -1
    endif
    call SaveInteger(g_hashtable, GetHandleId(u), abilcode, flag)
    call BlzUnitDisableAbility(u, abilcode, disable, true)
    call BlzUnitDisableAbility(u, abilcode, disable, false)
endfunction
function UnitRemoveAbilitySafely takes unit u, integer abilcode returns nothing
    call UnitRemoveAbility(u, abilcode)
    call RemoveSavedInteger(g_hashtable, GetHandleId(u), abilcode)
endfunction
 
Status
Not open for further replies.
Top