Алгоритмы, Наработки и Способности
Способ реализации:
Jass
Тип:
Алгоритм
Версия Warcraft:
UjAPI v1.0.28.102+

О системе

Относительно краткий пример создания кнопки с перезарядкой на CSimpleButton и CSpriteFrame фреймах используя UjAPI и Frame API.
Главным бонусом UjAPI в данной наработке является handlelist тип, который позволяет нам хранить все созданные фреймы в "листе" и не использовать тучу переменных, без какой-либо нужды. А так же возможность получать имя/контекст фрейма, что позволяет в целом и не прибегать к спискам, а банально использовать сам фрейм как "ключ" для получения дочерних фреймов.
Собственно, почему же выбор пал на CSimpleButton/SpriteFrame типы фреймов? На деле, это эмуляция того, как это реализовано в самой игре, однако там применяется CCommandButton, что является расширением CSimpleButton, но учитывая то, что большая часть функционала от CCommandButton нам не нужна, выбор пал на более простую CSimpleButton.
Данная система конечно же работает в онлайне и не вызывает десинха, иначе это не имело бы смысла.

Код

раскрыть
globals
    hashtable FrameHT = InitHashtable( )
    framehandle FH_Temp = null
    handlelist CommandButtonsList = HandleListCreate( )
    
    constant timer COMMAND_BUTTON_COOLDOWN_TIMER = CreateTimer( )
    constant real COMMAND_BUTTON_COOLDOWN_TIMER_SPEED = .01
endglobals

function SetButtonRemainingCooldown takes framehandle cmdButton, real time returns nothing
    local integer bid = GetHandleId( cmdButton )
    local string frameName = GetFrameName( cmdButton )
    local integer frameContext = GetFrameContext( cmdButton )
    local framehandle cdIndicator = GetCFrameByName( frameName + "_CD", frameContext )
    local integer iid = GetHandleId( cdIndicator )
    local real baseCD = LoadReal( FrameHT, iid, '+bcd' )

    if time < baseCD then
        set time = baseCD - time
    else
        set time = baseCD
    endif

    if time == 0. then
        set time = baseCD
    endif

    call SaveReal( FrameHT, iid, '+ccd', time )

    set cdIndicator = null
endfunction

function StartButtonCooldown takes framehandle cmdButton, real time returns nothing
    local integer bid = GetHandleId( cmdButton )
    local string frameName = GetFrameName( cmdButton )
    local integer frameContext = GetFrameContext( cmdButton )
    local framehandle cdIndicator = GetCFrameByName( frameName + "_CD", frameContext )

    if time > 0. then
        // call ConsolePause( "cmdButton = " + IntToHex( HandleToAddress( cmdButton ) ) + "\n" )
        call SetFrameSpriteAnimation( cdIndicator, "stand" )
        call SetFrameSpriteTimeScale( cdIndicator, .0 )
        call SetFrameSpriteAnimationOffsetPercent( cdIndicator, .0 )

        call SaveBoolean( FrameHT, bid, 'oncd', true )
        call SaveReal( FrameHT, bid, '+ccd', .0 )
        call SaveReal( FrameHT, bid, '+bcd', time )
        
        call HandleListAddHandle( CommandButtonsList, cmdButton )
    endif

    set cdIndicator = null
endfunction

function ResetButtonCooldown takes framehandle cmdButton, boolean restart returns nothing
    local integer bid = GetHandleId( cmdButton )
    local string frameName = GetFrameName( cmdButton )
    local integer frameContext = GetFrameContext( cmdButton )
    local framehandle cdIndicator = GetCFrameByName( frameName + "_CD", frameContext )

    if restart or LoadBoolean( FrameHT, bid, 'oncd' ) then
        call StartButtonCooldown( cmdButton, LoadReal( FrameHT, bid, '+bcd' ) )
    endif

    set cdIndicator = null
endfunction

function StopButtonCooldown takes framehandle cmdButton, boolean showEffect returns nothing
    local integer bid = GetHandleId( cmdButton )
    local string frameName = GetFrameName( cmdButton )
    local integer frameContext = GetFrameContext( cmdButton )
    local framehandle cdIndicator = GetCFrameByName( frameName + "_CD", frameContext )

    if LoadBoolean( FrameHT, bid, 'oncd' ) then
        call SaveBoolean( FrameHT, bid, 'oncd', false )

        if showEffect then
            call SetFrameSpriteTimeScale( cdIndicator, 1. )
            call SetFrameSpriteAnimation( cdIndicator, "death" )
        else
            call SetFrameSpriteAnimationOffsetPercent( cdIndicator, 1. )
        endif
    endif

    set cdIndicator = null
endfunction

function OnCommandButtonCooldown takes nothing returns nothing
    local timer tmr = GetExpiredTimer( )
    local integer hid = GetHandleId( tmr )
    local integer bid = 0
    local integer i = 0
    local integer buttonCount = HandleListGetFrameCount( CommandButtonsList )
    local framehandle cmdButton = null
    local framehandle cdIndicator = null
    local string frameName = ""
    local integer frameContext = 0
    local real percent = .0

    loop
        exitwhen i == buttonCount
        set cmdButton = HandleListGetFrameByIndex( CommandButtonsList, i )

        set bid = GetHandleId( cmdButton )
        set frameName = GetFrameName( cmdButton )
        set frameContext = GetFrameContext( cmdButton )
        set cdIndicator = GetCFrameByName( frameName + "_CD", frameContext )

        if LoadBoolean( FrameHT, bid, 'oncd' ) then
            set percent = LoadReal( FrameHT, bid, '+ccd' ) / LoadReal( FrameHT, bid, '+bcd' )

            if percent >= 1. then
                set percent = 1.
            endif

            if percent < 1. then
                call SetFrameSpriteAnimationOffsetPercent( cdIndicator, percent )
                call SaveReal( FrameHT, bid, '+ccd', LoadReal( FrameHT, bid, '+ccd' ) + TimerGetElapsed( tmr ) )
            else
                call SetFrameSpriteTimeScale( cdIndicator, 1. )
                call SetFrameSpriteAnimation( cdIndicator, "death" )
                call SaveBoolean( FrameHT, bid, 'oncd', false )
                call HandleListRemoveHandle( CommandButtonsList, cmdButton )
            endif
        endif

        set i = i + 1
    endloop

    set tmr = null
endfunction

function CreateCommandButton takes string icon, integer contextId returns framehandle
    local framehandle gameUI = GetOriginFrame( ORIGIN_FRAME_GAME_UI, 0 )
    local framehandle consoleUI = GetOriginFrame( ORIGIN_FRAME_CONSOLE_UI, 0 )
    local framehandle cmdButton = null
    local framehandle cdIndicator = null

    set cmdButton = CreateFrameByType( "SIMPLEBUTTON", "COMMAND_BUTTON", consoleUI, "", contextId )
    call ClearFrameAllPoints( cmdButton )

    call SetFrameTexture( cmdButton, icon, 0, true )
    call SetFrameTexture( cmdButton, icon, 1, true )
    call SetFrameTexture( cmdButton, icon, 2, true )
    call SetFrameSize( cmdButton, .038, .038 )
    call SetFramePriority( cmdButton, 5 )
    call SetFrameParent( cmdButton, consoleUI )
    call ShowFrame( cmdButton, true )
    call SetFrameRelativePoint( cmdButton, FRAMEPOINT_CENTER, consoleUI, FRAMEPOINT_CENTER, .0, .0 )

    set cdIndicator = CreateFrameByType( "SPRITE", "COMMAND_BUTTON_CD", gameUI, "", contextId )

    call ClearFrameAllPoints( cdIndicator )
    call SetFrameAllPoints( cdIndicator, cmdButton )
    call SetFrameSpriteModel( cdIndicator, "UI\\Feedback\\Cooldown\\UI-Cooldown-Indicator.mdl" )
    call ShowFrame( cdIndicator, true )
    call SetFrameSpriteTimeScale( cdIndicator, 0. )
    call SetFrameSpriteAnimation( cdIndicator, "stand" )
    call SetFrameSpriteAnimationOffsetPercent( cdIndicator, .0 )
    call SetFrameTrackState( cdIndicator, 2 )

    set FH_Temp = cmdButton
    
    set gameUI = null
    set consoleUI = null
    set cmdButton = null
    set cdIndicator = null

    return FH_Temp
endfunction

function OnInitFrameItemShopSystemDelayed takes nothing returns nothing
    local framehandle cmdButton = null

    set cmdButton = CreateCommandButton( "ReplaceableTextures\\CommandButtons\\BTNDivineIntervention", 0 )
    call StartButtonCooldown( cmdButton, 4. )

    set cmdButton = null
endfunction

//===========================================================================
function InitTrig_CommandButtonSystem takes nothing returns nothing
    //set gg_trg_CommandButtonSystem = CreateTrigger(  )

    call FogEnable( false )
    call FogMaskEnable( false )
    call PanCameraToTimed( 0., 0., 0. )
    call EnableOperationLimit( false )
    call TimerStart( CreateTimer( ), .5, false, function OnInitFrameItemShopSystemDelayed )
    call TimerStart( COMMAND_BUTTON_COOLDOWN_TIMER, COMMAND_BUTTON_COOLDOWN_TIMER_SPEED, true, function OnCommandButtonCooldown )
endfunction

Превью

`
ОЖИДАНИЕ РЕКЛАМЫ...