Способ реализации:
Версия Warcraft:

Простая система инвентаря с 3 доп слотами

Инвентарь состоит из 6 основных слотов (стандартные предметы) и 3 дополнительных слотов (для кастомных характеристик). Управление дополнительными слотами осуществляется через кнопки. Решил поделиться, вдруг кому пригодится :)

Особенности
Эта система синхронизирована и работает в мультиплеере
  • Основные слоты (6 шт.):
    • Работают как обычный инвентарь Warcraft III, но с любой способностью пустышкой, которую можно просто нажать, для того чтоб можно было вызвать окно манипуляций для работы с доп слотами
  • Цепляется автоматических ко всем героям

  • Дополнительные слоты (3 шт.) сделаны на фреймах:
    • При наведении показывает описание
    • Можно настроить требование по уровню для каждого слота
    • Поддерживают все характеристики, через БД

Управление
При клике на Стандартные 6 слотов:
  • Кнопка "Добавить" – помещает предмет в доп. слот
  • Кнопка "Закрыть" – отменяет действие
При клике на доп слоты:
  • Кнопка "Выбросить"
  • Кнопка "Закрыть"

Визуализация
  • Основные слоты отображаются стандартно.
  • Дополнительные слоты отображаются на панели SimpleInfoPanelUnitDetail (Панель где атака и так далее)
  • Добавлены кнопки переключения между панелями

Код

Frame Handle Counter (Скрыть/Показать клавишей F5)
// Глобальные переменные
library HandleCount initializer InitTrig_Handle2
globals
    framehandle HandleFrame = null
    framehandle HandleText = null
    framehandle CloseButton = null
    trigger CloseTrigger = null
    boolean FrameVisible = true
    constant oskeytype TOGGLE_KEY = OSKEY_F5 
    
    private hashtable H = InitHashtable()
endglobals

function ToggleFrameVisibility takes nothing returns nothing
    set FrameVisible = not FrameVisible
    call BlzFrameSetVisible(HandleFrame, FrameVisible)
    
    if FrameVisible then
        call BJDebugMsg("|cff00ff00Handle Counter показан|r")
    else
        call BJDebugMsg("|cffff0000Handle Counter скрыт|r")
    endif
endfunction

function InitFrame takes nothing returns nothing
    // Создаем основной фрейм
    set HandleFrame = BlzCreateFrame("EscMenuBackdrop", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), 0, 0)
    call BlzFrameSetSize(HandleFrame, 0.3, 0.15)
    call BlzFrameSetPoint(HandleFrame, FRAMEPOINT_TOPLEFT, BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), FRAMEPOINT_TOPLEFT, 0.01, -0.05)
    call BlzFrameSetVisible(HandleFrame, FrameVisible)
    
    // Текстовое поле
    set HandleText = BlzCreateFrameByType("TEXT", "HandleText", HandleFrame, "", 0)
    call BlzFrameSetPoint(HandleText, FRAMEPOINT_CENTER, HandleFrame, FRAMEPOINT_CENTER, 0, 0)
    call BlzFrameSetTextAlignment(HandleText, TEXT_JUSTIFY_CENTER, TEXT_JUSTIFY_MIDDLE)
    call BlzFrameSetScale(HandleText, 1.1)
    
    // Кнопка закрытия (создается один раз)
    set CloseButton = BlzCreateFrame("ScriptDialogButton", HandleFrame, 0, 0)
    call BlzFrameSetSize(CloseButton, 0.04, 0.04)
    call BlzFrameSetPoint(CloseButton, FRAMEPOINT_TOPRIGHT, HandleFrame, FRAMEPOINT_TOPRIGHT, -0.005, -0.005)
    call BlzFrameSetText(CloseButton, "X")
    
    // Триггер для кнопки (создается один раз)
    set CloseTrigger = CreateTrigger()
    call BlzTriggerRegisterFrameEvent(CloseTrigger, CloseButton, FRAMEEVENT_CONTROL_CLICK)
    call TriggerAddAction(CloseTrigger, function ToggleFrameVisibility)
endfunction

 private function I2A takes integer whichInteger returns fogstate
    call SaveFogStateHandle(H,0,0,ConvertFogState(whichInteger))
    return ConvertFogState(whichInteger)
endfunction
globals
    private constant integer safety = 3
endglobals


function HandleCount takes nothing returns nothing
    local integer i = 0
    local integer i2 = 0
    local integer space = 0
    local integer space2 = 0
    local integer count = 0
    local location array loc
    local integer hid = 0
    local integer hid2
    local location L = Location(0,0)
    local integer handleId = GetHandleId(L) - 0x100000 - 117
    loop
        set loc[i] = Location(0., 0.)
        set hid2 = GetHandleId(loc[i]) - 0x100000
        if hid2 == hid + 1 or hid == 0 then
            set space = space + 1
            set space2 = space2 + 1
        else
            set space2 = 0
        endif
        set hid = hid2
        set i = i + 1
        set count = hid
        exitwhen space2 == safety
    endloop
    loop
        exitwhen i2 > i
        call RemoveLocation(loc[i2])
        set loc[i2] = null
        set i2 = i2 + 1
    endloop
    
    // Инициализация при первом вызове
    if HandleFrame == null then
        call InitFrame()
    endif

    // Обновляем текст
    if FrameVisible then
        call BlzFrameSetText(HandleText, "|cffffcc00HANDLE COUNTER|r\n" + "|cff00ff00Current ID:|r |cffffffff" + I2S(count - space - safety - 2 -117) + " | " + I2S(handleId) + "|r\n")
    endif

    call RemoveLocation(L)
    set L = null
endfunction

function InitTrig_Handle2 takes nothing returns nothing
    local trigger t = CreateTrigger()
    local trigger keyTrig = CreateTrigger()
    local integer i = 0
    
    // Таймер для обновления счетчика
    call TriggerRegisterTimerEvent(t, 0.09, true)
    call TriggerAddAction(t, function HandleCount)
    
    // Регистрируем клавишу для всех игроков
    loop
        exitwhen i >= bj_MAX_PLAYERS
        if GetPlayerController(Player(i)) == MAP_CONTROL_USER then
            call BlzTriggerRegisterPlayerKeyEvent(keyTrig, Player(i), TOGGLE_KEY, 0, true)
        endif
        set i = i + 1
    endloop
    call TriggerAddAction(keyTrig, function ToggleFrameVisibility)
    
    call BJDebugMsg("|cff00ff00Handle Counter инициализирован. Нажмите F5 для показа/скрытия.|r")
endfunction

endlibrary
Загрузка Фрейма
library FrameLoader initializer init_function

    globals
        private trigger eventTrigger = CreateTrigger()
        private trigger actionTrigger = CreateTrigger()
        private timer t = CreateTimer()
    endglobals
    
    function FrameLoaderAdd takes code func returns nothing
        call TriggerAddAction(actionTrigger, func)
    endfunction

    private function timerAction takes nothing returns nothing
        call TriggerExecute(actionTrigger)
    endfunction
    
    private function eventAction takes nothing returns nothing
        call TimerStart(t, 0, false, function timerAction)
    endfunction
    
    private function init_function takes nothing returns nothing
        call TriggerRegisterGameEvent(eventTrigger, EVENT_GAME_LOADED)
        call TriggerAddAction(eventTrigger, function eventAction)        
    endfunction
endlibrary
Инициализация Фрейма и система переключения страниц

library UnitInfoPanels initializer init_function requires FrameLoader

    globals
        private framehandle array panels
        private framehandle array panelsFrame
        private integer panelsCount
        private trigger array panelsCondition
        private framehandle array tooltipListener
        private trigger array tooltipListenerAction
        framehandle UnitInfoTooltipFrame
        private integer tooltipListenerCount
        private framehandle tooltipBox
        private framehandle tooltipText
        private boolean isReforged
        private integer createContext
        unit UnitInfoUnit
        private trigger array updateAction 
        private trigger buttonTrigger = CreateTrigger()
        private integer activeIndex
        private integer wantedIndex = 1
        private group g = CreateGroup()
        private timer updateTimer = CreateTimer()
        private framehandle pageUp
        private constant boolean HAVE_BIG_PAGE_BUTTON = false 
        private framehandle pageUpBig 
        private framehandle pageDown
        private framehandle unitInfo
        private framehandle parent
        private integer pageSwaps


        framehandle UnitInfoInfoFrame
        framehandle UnitInfoIconFrame
        framehandle UnitInfoLabelFrame
        framehandle UnitInfoTextFrame
        
        string UnitInfoTooltipText = ""
    endglobals

    function UnitInfoGetUnit takes player p returns unit
        call GroupEnumUnitsSelected(g, p, null)
        set UnitInfoUnit = FirstOfGroup(g)
        call GroupClear(g)
        return UnitInfoUnit
    endfunction

function AddUnitInfoPanel takes framehandle frame, code update, code condition returns nothing
        call BlzFrameSetParent(frame, BlzGetFrameByName("SimpleInfoPanelUnitDetail", 0))
        set panelsCount = panelsCount + 1
        set panels[panelsCount] = frame
        set panelsCondition[panelsCount] = CreateTrigger()
        if condition != null then
            call TriggerAddCondition(panelsCondition[panelsCount], Filter(condition))
        endif
        
        if update != null then
            set updateAction[panelsCount] = CreateTrigger()
            call TriggerAddCondition(updateAction[panelsCount], Filter(update))
        endif
        call BlzFrameSetVisible(frame, activeIndex == panelsCount)
    endfunction
    function AddUnitInfoPanelEx takes code update, code condition returns framehandle
        local framehandle frame = BlzCreateFrameByType("SIMPLEFRAME", "", BlzGetFrameByName("SimpleInfoPanelUnitDetail", 0), "", 0)
        call AddUnitInfoPanel(frame, update, condition)
        return frame
    endfunction
    function SetUnitInfoPanelFrame takes framehandle frame returns nothing
        set panelsFrame[panelsCount] = frame
        call BlzFrameSetVisible(frame, BlzFrameIsVisible(panels[panelsCount]))
    endfunction
    function SetUnitInfoPanelFrameEx takes nothing returns framehandle
        local framehandle frame = BlzCreateFrameByType("FRAME", "", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), "", 0)
        call SetUnitInfoPanelFrame(frame)
        return frame
    endfunction
    
    function UnitInfoPanelAddTooltipListener takes framehandle frame, code func returns nothing
        set tooltipListenerCount = tooltipListenerCount + 1
        set tooltipListener[tooltipListenerCount] = frame
        set tooltipListenerAction[tooltipListenerCount] = CreateTrigger()
        call TriggerAddCondition(tooltipListenerAction[tooltipListenerCount], Filter(func))         
    endfunction

    function UnitInfoAddTooltip takes framehandle parent, framehandle frame returns framehandle
        local framehandle toolTip
        local framehandle but
            set but = BlzCreateSimpleFrame("EmptySimpleButton", parent, 0)
            set toolTip = BlzCreateFrameByType("SIMPLEFRAME", "", but, "", 0)
            call BlzFrameSetAllPoints(but, frame)
            call BlzFrameSetTooltip(but, toolTip)
            call BlzFrameSetLevel(but, 9)
            call BlzFrameSetVisible(toolTip, false)
            return toolTip
    endfunction

    function UnitInfoAddTooltipEx takes framehandle parent, framehandle frame, code func returns nothing
        call UnitInfoPanelAddTooltipListener(UnitInfoAddTooltip(parent, frame), func)
    endfunction

    function UnitInfoCreateCustomInfo takes framehandle parent, string label, string texture, code tooltipCode returns integer
        set createContext = createContext + 1
        set UnitInfoInfoFrame = BlzCreateSimpleFrame("SimpleInfoPanelIconRank", parent, createContext)
        set UnitInfoIconFrame = BlzGetFrameByName("InfoPanelIconBackdrop", createContext)
        set UnitInfoLabelFrame = BlzGetFrameByName("InfoPanelIconLabel", createContext)
        set UnitInfoTextFrame = BlzGetFrameByName("InfoPanelIconValue", createContext)
        call BlzFrameSetText(UnitInfoLabelFrame , label)
        call BlzFrameSetText(UnitInfoTextFrame , "xxx")
        call BlzFrameSetTexture(UnitInfoIconFrame, texture, 0, false)
        call BlzFrameClearAllPoints(UnitInfoIconFrame)
        call BlzFrameSetSize(UnitInfoIconFrame, 0.028, 0.028)
        if tooltipCode != null then
            call UnitInfoAddTooltipEx(UnitInfoInfoFrame, UnitInfoIconFrame, tooltipCode)
        endif
        return createContext
    endfunction

    private function PageSwapCheck takes nothing returns boolean
        set pageSwaps = pageSwaps + 1
        if pageSwaps > panelsCount then
            call BJDebugMsg("Unit Info Panel - NO VALID PANEL - " + GetUnitName(UnitInfoUnit))
            return false
        endif
        return true
    endfunction
    private function nextPanel takes nothing returns nothing
        set activeIndex = activeIndex + 1
        if activeIndex > panelsCount then
            set activeIndex = 1
        endif
        if PageSwapCheck() and not TriggerEvaluate(panelsCondition[activeIndex]) then
            call nextPanel()
        endif
    endfunction
    private function prevPanel takes nothing returns nothing
        set activeIndex = activeIndex - 1
        if activeIndex < 1 then
            set activeIndex = panelsCount
        endif
        if PageSwapCheck() and not TriggerEvaluate(panelsCondition[activeIndex]) then
            call prevPanel()
        endif
    endfunction

    function UnitInfoPanelSetPage takes integer newPage, boolean updateWanted returns nothing
        call BlzFrameSetVisible(panels[activeIndex], false)
        call BlzFrameSetVisible(panelsFrame[activeIndex], false)
        if newPage == 0 then
            set pageSwaps = 0
            call nextPanel()
        elseif newPage == -1 then
            set pageSwaps = 0
            call prevPanel()
        else
            set activeIndex = IMinBJ(panelsCount, IMaxBJ(1, newPage))
        endif
        if updateWanted then
            set wantedIndex = activeIndex
        endif
        call BlzFrameSetVisible(panels[activeIndex], true)
        call BlzFrameSetVisible(panelsFrame[activeIndex], true)
    endfunction
    function UnitInfoPanelSetPageByFrame takes framehandle newPage, boolean updateWanted returns nothing
        local integer loopA = panelsCount
        loop
            exitwhen loopA <= 0
            if panels[loopA] == newPage or panelsFrame[loopA] == newPage then
                call UnitInfoPanelSetPage(loopA, updateWanted)
                exitwhen true
            endif
            set loopA = loopA - 1
        endloop
    endfunction

    private function update takes nothing returns nothing
        local boolean found = false
        local integer loopA = tooltipListenerCount
        local integer useAblePages = 0
        call UnitInfoGetUnit(GetLocalPlayer())
        if BlzFrameIsVisible(unitInfo) then
            loop
                exitwhen loopA <= 0
                if BlzFrameIsVisible(tooltipListener[loopA]) then
                    set UnitInfoTooltipFrame = tooltipListener[loopA]
                    call TriggerEvaluate(tooltipListenerAction[loopA])
                    call BlzFrameSetText(tooltipText, UnitInfoTooltipText)
                    set found = true
                    exitwhen true
                endif
                set loopA = loopA - 1
            endloop

            if wantedIndex != activeIndex and TriggerEvaluate(panelsCondition[wantedIndex]) then
                call UnitInfoPanelSetPage(wantedIndex, false)
            endif

            // Показать/Скрыть PageButton
            set loopA = panelsCount
            loop
                exitwhen loopA <= 0
                if TriggerEvaluate(panelsCondition[loopA]) then                  
                    set useAblePages = useAblePages + 1
                endif
                set loopA = loopA - 1
            endloop
            call BlzFrameSetVisible(pageDown, useAblePages > 1)
            call BlzFrameSetVisible(pageUp, useAblePages > 1)

            if not TriggerEvaluate(panelsCondition[activeIndex]) then
                call UnitInfoPanelSetPage(0, false)
            endif

            call BlzFrameSetVisible(panelsFrame[activeIndex], true)

            call TriggerEvaluate(updateAction[activeIndex])
        else
            call BlzFrameSetVisible(panelsFrame[activeIndex], false)
        endif
        call BlzFrameSetVisible(tooltipBox, found)
    endfunction

    private function pageButtonAction takes nothing returns nothing
        if GetTriggerPlayer() == GetLocalPlayer() then
            if BlzGetTriggerFrame() == pageDown then
                call UnitInfoPanelSetPage(-1, true)
            else
                call UnitInfoPanelSetPage(0, true)
            endif
        endif
    endfunction

    private function At0s takes nothing returns nothing
        call DestroyTimer(GetExpiredTimer())
        call BlzLoadTOCFile("war3mapImported\\UnitInfoPanels.toc")
        set panelsCount = 1
        set activeIndex = 1
        set tooltipListenerCount = 0
        set createContext = 1000
        set unitInfo = BlzGetFrameByName("SimpleInfoPanelUnitDetail", 0)
        set parent = BlzCreateFrameByType("SIMPLEFRAME", "", unitInfo, "", 0)
        set pageUp = BlzCreateSimpleFrame("UnitInfoSimpleIconButtonUp", unitInfo, 0)
        set pageDown = BlzCreateSimpleFrame("UnitInfoSimpleIconButtonDown", unitInfo, 0)

        call BlzFrameSetPoint(pageUp, FRAMEPOINT_TOPLEFT, unitInfo, FRAMEPOINT_TOPRIGHT, 0, 0)

        static if HAVE_BIG_PAGE_BUTTON then
            set pageUpBig = BlzCreateSimpleFrame("EmptySimpleButton", unitInfo, 0)
            call BlzFrameSetAllPoints(pageUpBig, unitInfo)
            call BlzFrameSetLevel(pageUpBig, 0)
            call BlzTriggerRegisterFrameEvent(buttonTrigger, pageUpBig, FRAMEEVENT_CONTROL_CLICK)
        endif
        call BlzTriggerRegisterFrameEvent(buttonTrigger, pageUp, FRAMEEVENT_CONTROL_CLICK)
        call BlzTriggerRegisterFrameEvent(buttonTrigger, pageDown, FRAMEEVENT_CONTROL_CLICK)
        
        set panels[1] = parent
        if activeIndex != 1 then
            call BlzFrameSetVisible(panels[1], false)
        endif

        call BlzFrameSetParent(BlzGetFrameByName("SimpleInfoPanelIconDamage", 0), parent)
        call BlzFrameSetParent(BlzGetFrameByName("SimpleInfoPanelIconDamage", 1), parent)
        call BlzFrameSetParent(BlzGetFrameByName("SimpleInfoPanelIconArmor", 2), parent)
        call BlzFrameSetParent(BlzGetFrameByName("SimpleInfoPanelIconRank", 3), parent)
        call BlzFrameSetParent(BlzGetFrameByName("SimpleInfoPanelIconFood", 4), parent)
        call BlzFrameSetParent(BlzGetFrameByName("SimpleInfoPanelIconGold", 5), parent)
        call BlzFrameSetParent(BlzGetFrameByName("SimpleInfoPanelIconHero", 6), parent)
        call BlzFrameSetParent(BlzGetFrameByName("SimpleInfoPanelIconAlly", 7), parent)


        if isReforged then
            set tooltipBox = BlzCreateFrame("CustomUnitInfoTextBox", BlzGetFrameByName("ConsoleUIBackdrop", 0), 0, 0)
        else
            set tooltipBox = BlzCreateFrame("CustomUnitInfoTextBox", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), 0, 0)
        endif
        set tooltipText = BlzCreateFrame("CustomUnitInfoText", tooltipBox, 0, 0)
        call BlzFrameSetAbsPoint(tooltipText, FRAMEPOINT_BOTTOMRIGHT, 0.79, 0.18)
        call BlzFrameSetSize(tooltipText, 0.275, 0)
        call BlzFrameSetPoint(tooltipBox, FRAMEPOINT_TOPLEFT, tooltipText, FRAMEPOINT_TOPLEFT, -0.01, 0.01)
        call BlzFrameSetPoint(tooltipBox, FRAMEPOINT_BOTTOMRIGHT, tooltipText, FRAMEPOINT_BOTTOMRIGHT, 0.005, -0.01)
        call BlzFrameSetVisible(tooltipBox, false)

        call TimerStart(updateTimer, 0.05, true, function update)
    endfunction

     // ИНИЦИАЛИЗАЦИЯ ФРЕЙМА
    private function At0sIni takes nothing returns nothing
        call BlzFrameSetVisible(BlzCreateSimpleFrame("CustomUnitInfoPanel3x4", BlzGetFrameByName("SimpleInfoPanelUnitDetail", 0), 0),false)
    endfunction

    private function init_function_Frame takes nothing returns nothing
        local timer t = CreateTimer()
        call TimerStart(t, 0, false, function At0sIni)
    call DestroyTimer(t)
    set t = null
    endfunction

    private function init_function takes nothing returns nothing
        set isReforged = GetLocalizedString("REFORGED") != "REFORGED"
        call TriggerAddAction(buttonTrigger, function pageButtonAction)
        call TimerStart(CreateTimer(),0, false, function At0s)
        call FrameLoaderAdd(function At0s)
        set panelsCondition[1] = CreateTrigger()
        call init_function_Frame()
    endfunction

endlibrary

Каждый триггер, отдельная страничка, то есть ctrl+c, ctrl+v, как конструктор)
Создание Инвентаря-Фрейма
library CustomStatPanelItemsFrame initializer init_ItemsFrame requires ItemClickSystem//UnitInfoPanels, UnitStateSetting
// Shows how much gold and Lumber bounty one gets when slaying an UnitInfoUnit
    globals
        framehandle array IconInventoryItem
        framehandle array TextItemFrame
        framehandle array Button
        private framehandle array ToolTip
        string array DataIconItems
        string array ItemsFrameDesc
        private string array DataLabelItems
        private integer buttonCount = 12
        private framehandle parent
        private trigger buttonTrigger = CreateTrigger()
    endglobals

    globals
        private framehandle MenuFrame = null
        private framehandle array Button2
        private trigger array ButtonTrig
        private trigger EscapeTrig = null
        private constant integer SLOT_7_INDEX = 2
        private constant integer SLOT_8_INDEX = 4
        private constant integer SLOT_9_INDEX = 7
    endglobals

    private function tooltipAction takes nothing returns nothing
        local integer i = buttonCount
        loop
            exitwhen i == 0
            if UnitInfoTooltipFrame == ToolTip[i] then
                if i == SLOT_7_INDEX and GetItemIcon(UnitInfoUnit, SLOT_7)!=null then
                    set UnitInfoTooltipText = DataLabelItems[i] + BlzFrameGetText(TextItemFrame[i]) + "\n" + GetItemDescription(UnitInfoUnit, SLOT_7)
                elseif i == SLOT_8_INDEX and GetItemIcon(UnitInfoUnit, SLOT_8)!=null then
                    set UnitInfoTooltipText = DataLabelItems[i] + BlzFrameGetText(TextItemFrame[i]) + "\n" + GetItemDescription(UnitInfoUnit, SLOT_8)
                elseif i == SLOT_9_INDEX and GetItemIcon(UnitInfoUnit, SLOT_9)!=null then
                    set UnitInfoTooltipText = DataLabelItems[i] + BlzFrameGetText(TextItemFrame[i]) + "\n" + GetItemDescription(UnitInfoUnit, SLOT_9)
                else
                    set UnitInfoTooltipText = DataLabelItems[i] + BlzFrameGetText(TextItemFrame[i]) + "\n" + ItemsFrameDesc[i]
                endif
                exitwhen true
            endif
            set i = i - 1
        endloop
    endfunction

    private function condition takes nothing returns boolean
        return IsUnitType(UnitInfoUnit, UNIT_TYPE_HERO)
    endfunction



    private function OnButton1Click takes nothing returns nothing
        local player p = GetTriggerPlayer()//GetOwningPlayer(u)
        local integer id = GetPlayerId(p)
        local unit u = clickedUnitU[id]
        
        local framehandle frame = tempFrame
        local integer index 
        local integer tempItem
        
        // Определяем, какой слот нажат
        if frame == Button[SLOT_7_INDEX] then
            set index = 2
            set tempFrame = Button[SLOT_7_INDEX]
        elseif frame == Button[SLOT_8_INDEX] then
            set index = 4
            set tempFrame = Button[SLOT_8_INDEX]
        elseif frame == Button[SLOT_9_INDEX] then
            set index = 7
            set tempFrame = Button[SLOT_9_INDEX]
        endif

        call BlzFrameSetVisible(MenuFrame, false)
        
        
        if index == SLOT_7_INDEX then
            set tempItem = GetItemSlot(u, SLOT_7)
            call CreateItem(tempItem,GetUnitX(u),GetUnitY(u))
            set CustomInventory_GetItemTypeId[id] = tempItem
            call UpdateStateHero(u, false)
            
            call SetUnitItemSlot(u, SLOT_7, null)
        elseif index == SLOT_8_INDEX then
            set tempItem = GetItemSlot(u, SLOT_8)
            call CreateItem(tempItem,GetUnitX(u),GetUnitY(u))
            set CustomInventory_GetItemTypeId[id] = tempItem
            call UpdateStateHero(u, false)
            
            call SetUnitItemSlot(u, SLOT_8, null)
        elseif index == SLOT_9_INDEX then
            set tempItem = GetItemSlot(u, SLOT_9)
            call CreateItem(tempItem,GetUnitX(u),GetUnitY(u))
            set CustomInventory_GetItemTypeId[id] = tempItem
            call UpdateStateHero(u, false)
            
            call SetUnitItemSlot(u, SLOT_9, null)
        endif
        set u = null
    endfunction

    // Скрытие меню
    private function HideMenu takes nothing returns nothing
        call BlzFrameSetVisible(MenuFrame, false)
    endfunction

globals
    unit clickedUnit = null
    unit array clickedUnitU
    framehandle tempFrame
endglobals


 private function buttonAction takes nothing returns nothing
 // Почему-то десинхронизация, пока все не загрузятся
 
        // request currently used unit of the clicking player
        local integer I = buttonCount
        local framehandle frame = BlzGetTriggerFrame()
        local player whichPlayer = GetTriggerPlayer()
        local player unitOwner
        local integer id = GetPlayerId(whichPlayer)
        local unit u 
        local integer id2 = GetPlayerId(GetOwningPlayer(UnitInfoUnit))
        local integer i = 0
        local integer btnCount = 2
        local framehandle btnText
        local real spacing
        local real startY
        
        local integer index = -1
        
        set clickedUnitU[id] = UnitInfoGetUnit(whichPlayer)

        // Получаем владельца юнита
        if UnitInfoUnit != null then
            set unitOwner = GetOwningPlayer(UnitInfoUnit)
        else
            set whichPlayer = null
            set frame = null
            //return
        endif

        // Проверяем, что текущий игрок - владелец юнита
        if whichPlayer != unitOwner then
            call DisplayTextToPlayer(whichPlayer, 0, 0, "|cffff0000You can't interact with another player's inventory!|r")
            set whichPlayer = null
            set unitOwner = null
            set frame = null
            //return
        endif

        //UnitInfoUnit
        if MenuFrame!= null then
           call BlzFrameSetVisible(MenuFrame, false)
           //call BlzDestroyFrame(MenuFrame) 
        endif
        
        
        // Определяем, какой слот нажат
        if frame == Button[SLOT_7_INDEX] then
            set index = SLOT_7_INDEX
            call BlzSendSyncData("TEMP_FRAME", "2")
            call BlzSendSyncData("clickedUnit", I2S(id))
        elseif frame == Button[SLOT_8_INDEX] then
            set index = SLOT_8_INDEX
            call BlzSendSyncData("TEMP_FRAME", "4")
        elseif frame == Button[SLOT_9_INDEX] then
            set index = SLOT_9_INDEX
            call BlzSendSyncData("TEMP_FRAME", "7")
        else
            set whichPlayer = null
            set frame = null
            //return
        endif
        
        // Проверяем, что юнит - герой и уровень достаточен
        if not IsUnitType(UnitInfoUnit, UNIT_TYPE_HERO) then
            call DisplayTextToPlayer(whichPlayer, 0, 0, "|cffff0000Only heroes have this slot!|r")
            set whichPlayer = null
            set frame = null
            //return
        endif
        
        // Проверяем уровень для слота
        if (index == SLOT_7_INDEX and GetHeroLevel(UnitInfoUnit) < REQUIRED_LEVEL_ITEM_7) or (index == SLOT_8_INDEX and GetHeroLevel(UnitInfoUnit) < REQUIRED_LEVEL_ITEM_8) or (index == SLOT_9_INDEX and GetHeroLevel(UnitInfoUnit) < REQUIRED_LEVEL_ITEM_9) then
            call DisplayTextToPlayer(whichPlayer, 0, 0, "|cffff0000This slot is not open yet!|r")
            set whichPlayer = null
            set frame = null
            //return
        endif
        
        // Проверяем, есть ли предмет в слоте
        if index == SLOT_7_INDEX then
            if GetItemSlot(UnitInfoUnit,SLOT_7) == 0 then
                call DisplayTextToPlayer(whichPlayer, 0, 0, "|cffffcc00Slot is empty.|r")
                set whichPlayer = null
                set frame = null
                //return
            endif
        elseif index == SLOT_8_INDEX then
            if GetItemSlot(UnitInfoUnit,SLOT_8) == 0 then
                call DisplayTextToPlayer(whichPlayer, 0, 0, "|cffffcc00Slot is empty.|r")
                set whichPlayer = null
                set frame = null
                //return
            endif
        else
            if GetItemSlot(UnitInfoUnit,SLOT_9) == 0 then
                call DisplayTextToPlayer(whichPlayer, 0, 0, "|cffffcc00Slot is empty.|r")
                set whichPlayer = null
                set frame = null
                //return
            endif
        endif
        
        set spacing = 0.05
        set startY = (btnCount - 1) * spacing * 0.5
        
        //call PolledWait2(2.)
        if MenuFrame == null then //
            set MenuFrame = BlzCreateFrame("EscMenuBackdrop", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), 0, 0)
        endif
        
        if GetLocalPlayer() == whichPlayer then
            if btnCount == 2 then
                call BlzFrameSetSize(MenuFrame, 0.2, 0.15)
            else
                call BlzFrameSetSize(MenuFrame, 0.2, 0.2)
            endif
        endif
        
        call BlzFrameSetPoint(MenuFrame, FRAMEPOINT_CENTER, BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), FRAMEPOINT_CENTER, 0, 0)

        loop
        exitwhen i >= btnCount
            if ButtonTrig[i] != null then
                call DestroyTrigger(ButtonTrig[i])
                set ButtonTrig[i] = null
            endif
            
            set Button[i] = BlzCreateFrame("ScriptDialogButton", MenuFrame, 0, 0)
            call BlzFrameSetSize(Button[i], 0.12, 0.04)
            call BlzFrameSetPoint(Button[i], FRAMEPOINT_CENTER, MenuFrame, FRAMEPOINT_CENTER, 0, startY - spacing * i)
            call BlzFrameSetText(Button[i], "")

            set btnText = BlzCreateFrameByType("TEXT", "BtnText" + I2S(i), Button[i], "", 0)
            call BlzFrameSetPoint(btnText, FRAMEPOINT_CENTER, Button[i], FRAMEPOINT_CENTER, 0, 0)
            call BlzFrameSetScale(btnText, 1)
            
            set ButtonTrig[i] = CreateTrigger()
            call BlzTriggerRegisterFrameEvent(ButtonTrig[i], Button[i], FRAMEEVENT_CONTROL_CLICK)
            
            //call BJDebugMsg("BlzTriggerRegisterFrameEvent = "+GetPlayerName(whichPlayer))
            
            if i == 0 then
                call TriggerAddAction(ButtonTrig[i], function OnButton1Click)
                //call BJDebugMsg("TriggerAddAction = "+GetPlayerName(whichPlayer))
                call BlzFrameSetText(btnText, "Throw away an item")
            elseif i == 1 then
                if btnCount == 2 then
                    call TriggerAddAction(ButtonTrig[i], function HideMenu)
                    call BlzFrameSetText(btnText, "Close")
                endif
            elseif i == 2 then
                call TriggerAddAction(ButtonTrig[i], function HideMenu)
                call BlzFrameSetText(btnText, "Close")
            endif
            set i = i + 1
        endloop
        if GetLocalPlayer() == whichPlayer then
            call BlzFrameSetVisible(MenuFrame, true)
        else
            call BlzFrameSetVisible(MenuFrame, false)
        endif
        

    set whichPlayer = null
    set frame = null
 
    endfunction
    
    private function update takes nothing returns nothing
    local unit u = UnitInfoUnit
    local integer itemId
    local string itemIcon
    local player owner = GetOwningPlayer(u)
    //local boolean isOwner = (GetLocalPlayer() == owner)
    
    if GetHeroLevel(u) >= REQUIRED_LEVEL_ITEM_7 then
        set itemId = GetItemSlot(u, SLOT_7)
        if itemId != 0 then
            set itemIcon = GetItemIcon(u, SLOT_7)
            call BlzFrameSetText(TextItemFrame[SLOT_7_INDEX], GetObjectName(itemId))
            
            // Для всех игроков показываем реальную иконку предмета
            call BlzFrameSetTexture(IconInventoryItem[SLOT_7_INDEX], itemIcon, 0, false)
            
        else
            call BlzFrameSetText(TextItemFrame[SLOT_7_INDEX], "Item slot 7")
            // Для всех игроков показываем дефолтную иконку пустого слота
            call BlzFrameSetTexture(IconInventoryItem[SLOT_7_INDEX], "ReplaceableTextures\\CommandButtons\\BTNSelectHeroOn", 0, false)
        endif
    else
        call BlzFrameSetText(TextItemFrame[SLOT_7_INDEX], "Available from level 40")
        // Для всех игроков показываем дефолтную иконку
        call BlzFrameSetTexture(IconInventoryItem[SLOT_7_INDEX], "ReplaceableTextures\\CommandButtons\\BTNSelectHeroOn", 0, false)
    endif
    
    if GetHeroLevel(u) >= REQUIRED_LEVEL_ITEM_8 then
        set itemId = GetItemSlot(u, SLOT_8)
        if itemId != 0 then
            set itemIcon = GetItemIcon(u, SLOT_8)
            call BlzFrameSetText(TextItemFrame[SLOT_8_INDEX], GetObjectName(itemId))
            
            // Для всех игроков показываем реальную иконку предмета
            call BlzFrameSetTexture(IconInventoryItem[SLOT_8_INDEX], itemIcon, 0, false)
            
        else
            call BlzFrameSetText(TextItemFrame[SLOT_8_INDEX], "Item slot 8")
            // Для всех игроков показываем дефолтную иконку пустого слота
            call BlzFrameSetTexture(IconInventoryItem[SLOT_8_INDEX], "ReplaceableTextures\\CommandButtons\\BTNSelectHeroOn", 0, false)
        endif
    else
        call BlzFrameSetText(TextItemFrame[SLOT_8_INDEX], "Available from level 44")
        // Для всех игроков показываем дефолтную иконку
        call BlzFrameSetTexture(IconInventoryItem[SLOT_8_INDEX], "ReplaceableTextures\\CommandButtons\\BTNSelectHeroOn", 0, false)
    endif
    
    if GetHeroLevel(u) >= REQUIRED_LEVEL_ITEM_9 then
        set itemId = GetItemSlot(u, SLOT_9)
        if itemId != 0 then
            set itemIcon = GetItemIcon(u, SLOT_9)
            call BlzFrameSetText(TextItemFrame[SLOT_9_INDEX], GetObjectName(itemId))
            
            // Для всех игроков показываем реальную иконку предмета
            call BlzFrameSetTexture(IconInventoryItem[SLOT_9_INDEX], itemIcon, 0, false)
            
        else
            call BlzFrameSetText(TextItemFrame[SLOT_9_INDEX], "Item slot 9")
            // Для всех игроков показываем дефолтную иконку пустого слота
            call BlzFrameSetTexture(IconInventoryItem[SLOT_9_INDEX], "ReplaceableTextures\\CommandButtons\\BTNSelectHeroOn", 0, false)
        endif
    else
        call BlzFrameSetText(TextItemFrame[SLOT_9_INDEX], "Available from level 48")
        // Для всех игроков показываем дефолтную иконку
        call BlzFrameSetTexture(IconInventoryItem[SLOT_9_INDEX], "ReplaceableTextures\\CommandButtons\\BTNSelectHeroOn", 0, false)
    endif
    
    set u = null
    set owner = null

endfunction

    private function At0s takes nothing returns nothing
        local framehandle prevIcon
        local integer i = buttonCount
        call BlzGetFrameByName("InfoPanelIconValue", 0)
        call BlzGetFrameByName("InfoPanelIconValue", 2)
        call BlzGetFrameByName("InfoPanelIconHeroStrengthValue", 6)
        call BlzGetFrameByName("InfoPanelIconHeroAgilityValue", 6)
        call BlzGetFrameByName("InfoPanelIconHeroIntellectValue", 6)

        set parent = BlzCreateSimpleFrame("CustomUnitInfoPanelItem", BlzGetFrameByName("SimpleInfoPanelUnitDetail", 0), 0)
        call AddUnitInfoPanel(parent, function update, function condition)
        
       
        loop
            exitwhen i == 0
            set Button[i] = BlzGetFrameByName("CustomUnitInfoButton" + I2S(i), 0)
            set ToolTip[i] = BlzCreateFrameByType("SIMPLEFRAME", "", Button[i], "", 0)
            set IconInventoryItem[i] = BlzGetFrameByName("CustomUnitInfoButtonIcon" + I2S(i), 0)
            set TextItemFrame[i] = BlzGetFrameByName("CustomUnitInfoButtonText" + I2S(i), 0)
            call BlzTriggerRegisterFrameEvent(buttonTrigger, Button[i], FRAMEEVENT_CONTROL_CLICK)
            call BlzFrameSetTooltip(Button[i], ToolTip[i])
            call BlzFrameSetVisible(ToolTip[i], false)
            call BlzFrameSetTexture(IconInventoryItem[i], DataIconItems[i], 0, false)
            call UnitInfoPanelAddTooltipListener(ToolTip[i], function tooltipAction)
            set i = i - 1
        endloop
    endfunction
    
    
    private function initData takes integer index, string label, string icon, string desc returns nothing
        set DataIconItems[index] = icon
        set DataLabelItems[index] = label
        set ItemsFrameDesc[index] = desc
    endfunction
    
    private function init_ItemsFrame takes nothing returns nothing
    local timer t = CreateTimer()
    local framehandle f
        call TimerStart(t, 0, false, function At0s)
        call TriggerAddAction(buttonTrigger, function buttonAction)
        call FrameLoaderAdd(function At0s)

        call initData(2, "Item 7: ", "ReplaceableTextures\\CommandButtons\\BTNSelectHeroOn", "This 7th item slot is available from hero level 40")
        call initData(4, "Item 8: ", "ReplaceableTextures\\CommandButtons\\BTNSelectHeroOn", "This 8th item slot is available from hero level 44")
        call initData(7, "Item 9: ", "ReplaceableTextures\\CommandButtons\\BTNSelectHeroOn", "This 9th item slot is available from hero level 48")

      call DestroyTimer(t)
        set t = null
    endfunction
endlibrary
Пример БД для доп слотов
globals
    hashtable udg_h
endglobals

globals
    // HashTable
    constant integer ITEM_ICON_key = StringHash("Item icon")
    constant integer ITEM_STR_key = StringHash("Item str")
    constant integer ITEM_INT_key = StringHash("Item int")
    constant integer ITEM_DMG_key = StringHash("Item dmg")
    constant integer ITEM_HP_key = StringHash("Item hp")
    constant integer ITEM_AGI_key = StringHash("Item agi")
    // HashTable
endglobals


function ItemSetStr takes integer id,integer s returns nothing
    call SaveInteger(udg_h,id,ITEM_STR_key,s)
endfunction

function ItemSetAgi takes integer id,integer s returns nothing
    call SaveInteger(udg_h,id,ITEM_AGI_key,s)
endfunction

function ItemSetInt takes integer id,integer s returns nothing
    call SaveInteger(udg_h,id,ITEM_INT_key,s)
endfunction

function ItemSetDamage takes integer id,integer s returns nothing
    call SaveInteger(udg_h,id,ITEM_DMG_key,s)
endfunction


function ItemsBase takes nothing returns nothing
    set udg_h = InitHashtable()
    call ItemSetDamage('rat6',6)
    call ItemSetDamage('rat9',9)
    call ItemSetInt('ciri',6)
endfunction
Система для работы с основными слотами
library ItemClickSystem initializer Init requires UnitStateSetting//UnitInfoPanels


///////////////////////////
globals
    private framehandle MenuFrame = null
    private framehandle array Button
    private trigger array ButtonTrig
    private trigger EscapeTrig = null
    private boolean array IsProcessingClick
endglobals

globals
    hashtable ItemSlotsHT = InitHashtable()
    constant integer SLOT_7 = 6
    constant integer SLOT_8 = 7
    constant integer SLOT_9 = 8
    constant integer REQUIRED_LEVEL_ITEM_7 = 1
    constant integer REQUIRED_LEVEL_ITEM_8 = 1
    constant integer REQUIRED_LEVEL_ITEM_9 = 1

endglobals

function SetUnitItemSlot takes unit u, integer slot, item it returns nothing
local integer id = GetItemTypeId(it)
local item tempItem = CreateItem(id, 0, 0)
if it == null then
    call SaveInteger(ItemSlotsHT, GetHandleId(u), slot, 0)
    call SaveStr(ItemSlotsHT,GetHandleId(u),slot+100,"ReplaceableTextures\\CommandButtons\\BTNSelectHeroOn")
    call SaveStr(ItemSlotsHT,GetHandleId(u),slot+200,"")
else
    call SaveInteger(ItemSlotsHT, GetHandleId(u), slot, id)
    call SaveStr(ItemSlotsHT,GetHandleId(u),slot+100,BlzGetItemIconPath(tempItem))
    call SaveStr(ItemSlotsHT,GetHandleId(u),slot+200,BlzGetItemDescription(tempItem))
    call SaveBoolean(ItemSlotsHT,GetHandleId(u),slot+300,true)
    call RemoveItem(tempItem)
endif
    set tempItem = null
endfunction

function GetItemSlot takes unit u, integer slot returns integer
    return LoadInteger(ItemSlotsHT, GetHandleId(u), slot)
endfunction

function GetItemIcon takes unit u, integer slot returns string
    return LoadStr(ItemSlotsHT, GetHandleId(u), slot+100)
endfunction

function GetItemDescription takes unit u, integer slot returns string
    return LoadStr(ItemSlotsHT, GetHandleId(u), slot+200)
endfunction

//////////////////////////////////////////
//              OnButtonClick           //
//////////////////////////////////////////

//Можно оптимизировать через глобальную переменную сохраняя нажатую кнопку и вызывать одну и ту же функцию, вместо 3

private function OnButton1Click takes nothing returns nothing
    local player p = GetTriggerPlayer()
    local integer id = GetPlayerId(p)
    local string iconPath = BlzGetItemIconPath(CustomInventory_GetManipulatedItem[id])
    local item it = CustomInventory_GetManipulatedItem[id]
    local unit u = CustomInventory_GetTriggerUnit[id]
    
    local integer itemId
    local string itemIcon = GetItemIcon(u, SLOT_7)
    if itemIcon != "ReplaceableTextures\\CommandButtons\\BTNSelectHeroOn" and itemIcon !=null then
        call DisplayTextToPlayer(p, 0, 0, "|cffffcc00В этом слоте уже есть предмет!|r")  
    else
        call SetUnitItemSlot(u, SLOT_7, it)
        call UpdateStateHero(null, true)
        call RemoveItem(it)
    endif
    
    call BlzFrameSetVisible(MenuFrame, false)
    set IsProcessingClick[id] = false
    set p = null
    set it = null
    set u = null
endfunction

private function OnButton2Click takes nothing returns nothing
    local player p = GetTriggerPlayer()
    local integer id = GetPlayerId(p)
    local string iconPath = BlzGetItemIconPath(CustomInventory_GetManipulatedItem[id])
    local item it = CustomInventory_GetManipulatedItem[id]
    local unit u = CustomInventory_GetTriggerUnit[id]
    
    local integer itemId
    local string itemIcon = GetItemIcon(u, SLOT_8)
    if itemIcon != "ReplaceableTextures\\CommandButtons\\BTNSelectHeroOn" and itemIcon !=null then
        call DisplayTextToPlayer(p, 0, 0, "|cffffcc00В этом слоте уже есть предмет!|r")  
    else
        call SetUnitItemSlot(u, SLOT_8, it)
        call UpdateStateHero(null, true)
        call RemoveItem(it)
    endif
    
    call BlzFrameSetVisible(MenuFrame, false)
    set IsProcessingClick[id] = false
    set p = null
    set it = null
    set u = null
endfunction

private function OnButton3Click takes nothing returns nothing
    local player p = GetTriggerPlayer()
    local integer id = GetPlayerId(p)
    local string iconPath = BlzGetItemIconPath(CustomInventory_GetManipulatedItem[id])
    local item it = CustomInventory_GetManipulatedItem[id]
    local unit u = CustomInventory_GetTriggerUnit[id]
    
    local integer itemId
    local string itemIcon = GetItemIcon(u, SLOT_9)
    if itemIcon != "ReplaceableTextures\\CommandButtons\\BTNSelectHeroOn" and itemIcon !=null then
        call DisplayTextToPlayer(p, 0, 0, "|cffffcc00В этом слоте уже есть предмет!|r")  
    else
        call SetUnitItemSlot(u, SLOT_9, it)
        call UpdateStateHero(null, true)
        call RemoveItem(it)
    endif
    
    call BlzFrameSetVisible(MenuFrame, false)
    set IsProcessingClick[id] = false
    set p = null
    set it = null
    set u = null
endfunction

// Скрытие меню
private function HideMenu takes nothing returns nothing
local player p = GetTriggerPlayer()
local integer id = GetPlayerId(p)
   call BlzFrameSetVisible(MenuFrame, false)
   set IsProcessingClick[id] = false
endfunction


// Показ меню
private function ShowMenu takes player whichPlayer returns nothing
    local unit u
    local integer i = 0
    local integer btnCount = 2
    local framehandle btnText
    local real spacing
    local real startY
    local integer p=GetPlayerId(GetTriggerPlayer())

        set u = GetTriggerUnit()
        if GetHeroLevel(u) >= REQUIRED_LEVEL_ITEM_8 then
            set btnCount = 3 // добавим третью кнопку
        endif
        if GetHeroLevel(u) >= REQUIRED_LEVEL_ITEM_9 then
            set btnCount = 4 // добавим третью кнопку
        endif
        
        set spacing = 0.05
        set startY = (btnCount - 1) * spacing * 0.5

        if MenuFrame == null then
            set MenuFrame = BlzCreateFrame("EscMenuBackdrop", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), 0, 0)
        endif
        
        if GetLocalPlayer() == whichPlayer then
            if btnCount == 2 then
                call BlzFrameSetSize(MenuFrame, 0.2, 0.15)
            elseif btnCount == 3 then
                call BlzFrameSetSize(MenuFrame, 0.2, 0.2)
            else 
                call BlzFrameSetSize(MenuFrame, 0.2, 0.22)
            endif
        endif
        call BlzFrameSetPoint(MenuFrame, FRAMEPOINT_CENTER, BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), FRAMEPOINT_CENTER, 0, 0)

        loop
        exitwhen i >= btnCount
            if ButtonTrig[i] != null then
                call DestroyTrigger(ButtonTrig[i])
                set ButtonTrig[i] = null
            endif
            
            set Button[i] = BlzCreateFrame("ScriptDialogButton", MenuFrame, 0, 0)
            call BlzFrameSetSize(Button[i], 0.145, 0.04) //Ширина Высота
            call BlzFrameSetPoint(Button[i], FRAMEPOINT_CENTER, MenuFrame, FRAMEPOINT_CENTER, 0, startY - spacing * i)
            call BlzFrameSetText(Button[i], "")

            set btnText = BlzCreateFrameByType("TEXT", "BtnText" + I2S(i), Button[i], "", 0)
            call BlzFrameSetPoint(btnText, FRAMEPOINT_CENTER, Button[i], FRAMEPOINT_CENTER, 0, 0)
            call BlzFrameSetScale(btnText, 1)
            
            set ButtonTrig[i] = CreateTrigger()
            call BlzTriggerRegisterFrameEvent(ButtonTrig[i], Button[i], FRAMEEVENT_CONTROL_CLICK)
            if i == 0 then
                call TriggerAddAction(ButtonTrig[i], function OnButton1Click)
                call BlzFrameSetText(btnText, "Добавить предмет в 7 слот")
            elseif i == 1 then
                if btnCount == 2 then
                    call TriggerAddAction(ButtonTrig[i], function HideMenu)
                    call BlzFrameSetText(btnText, "Закрыть")
                else
                    call TriggerAddAction(ButtonTrig[i], function OnButton2Click)
                    call BlzFrameSetText(btnText, "Добавить предмет в 8 слот")
                endif
            elseif i == 2 and btnCount != 4 then
                call TriggerAddAction(ButtonTrig[i], function HideMenu)
                call BlzFrameSetText(btnText, "Закрыть")
            elseif i == 2 then
                call TriggerAddAction(ButtonTrig[i], function OnButton3Click)
                call BlzFrameSetText(btnText, "Добавить предмет в 9 слот")
            else
                call TriggerAddAction(ButtonTrig[i], function HideMenu)
                call BlzFrameSetText(btnText, "Закрыть")
            endif
            set i = i + 1
        endloop
        call BlzFrameSetVisible(MenuFrame, true)//delete

    set u = null
endfunction

globals
    integer array CustomInventory_GetItemTypeId
    item array CustomInventory_GetManipulatedItem
    unit array CustomInventory_GetTriggerUnit
endglobals

private function OnUseItem takes nothing returns nothing
    local player p = GetTriggerPlayer()
    local integer id = GetPlayerId(p)
    local item it = GetManipulatedItem()
    local integer itemId = GetItemTypeId(it)
    local unit u = GetTriggerUnit()
    //local integer charges
    set clickedUnit = u 
    //set charges = GetItemCharges(it)
    //call SetItemCharges(it, charges + 1) // Вернули потерянный заряд
    if IsProcessingClick[id] then
        return // Уже обрабатывается клик
    endif
    set IsProcessingClick[id] = true
    
    set CustomInventory_GetManipulatedItem[id] = it
    set CustomInventory_GetItemTypeId[id] = itemId
    set CustomInventory_GetTriggerUnit[id] = u
    
    if GetHeroLevel(u) >= REQUIRED_LEVEL_ITEM_7 then
        call ShowMenu(p)  // функция показа UI
    endif
    
    
    set p = null
    set it = null
    set u = null
endfunction


// Инициализация триггера и UI
private function Init takes nothing returns nothing
    local trigger t = CreateTrigger()
    local integer i = 0
    loop
        exitwhen i == bj_MAX_PLAYERS
        call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_USE_ITEM, null)
        set i = i + 1
    endloop
    call TriggerAddAction(t, function OnUseItem)
    call ItemsBase()
endfunction

endlibrary
Триггер синхронизации для передачи нажатой кнопки
library Sync initializer SyncExample

//Только для синхронизации фрейма для всех одного, из-за того что фреймы синхроны

function SyncActionsTempFrame takes nothing returns nothing 
    local string syncData = BlzGetTriggerSyncData()
       set tempFrame = Button[S2I(syncData)]
endfunction


function SyncExample takes nothing returns nothing
    local trigger t = CreateTrigger()
    local integer i = 0
    
    // Регистрируем синхронизацию для каждого игрока
    loop
        exitwhen i >= bj_MAX_PLAYERS
        call BlzTriggerRegisterPlayerSyncEvent(t, Player(i), "TEMP_FRAME", false)
        set i = i + 1
    endloop
    
    call TriggerAddAction(t, function SyncActionsTempFrame)
    set t = null

endfunction

endlibrary
Система для работы с бонусами
library UnitStateSetting initializer InitSystemBonus

globals
    // Массив степеней двойки для битовых операций
    integer array POWERS
    // Максимальное и минимальное значения бонусов
    integer MAX
    integer MIN
    // Массив способностей для каждого типа бонусов
    integer array ABILITY
    // Количество типов бонусов
    integer TYPES
endglobals

// Инициализация глобальных переменных
function InitSystemBonus takes nothing returns nothing
    // Заполняем степени двойки
    set POWERS[0] = 1
    set POWERS[1] = 2
    set POWERS[2] = 4
    set POWERS[3] = 8
    set POWERS[4] = 16
    set POWERS[5] = 32
    set POWERS[6] = 64
    set POWERS[7] = 128
    set POWERS[8] = 256
    set POWERS[9] = 512
    set POWERS[10] = 1024
    set POWERS[11] = 2048
    set POWERS[12] = 4096
    
    // Устанавливаем максимальное и минимальное значения
    set MAX = POWERS[12]
    set MIN = -POWERS[12]
    
    // Инициализируем массив способностей
    // Сила (STR) [0-12]
    set ABILITY[0] = 'ZxF0'  // +1
    set ABILITY[1] = 'ZxF1'  // +2
    set ABILITY[2] = 'ZxF2'  // +4
    set ABILITY[3] = 'ZxF3'  // +8
    set ABILITY[4] = 'ZxF4'  // +16
    set ABILITY[5] = 'ZxF5'  // +32
    set ABILITY[6] = 'ZxF6'  // +64
    set ABILITY[7] = 'ZxF7'  // +128
    set ABILITY[8] = 'ZxF8'  // +256
    set ABILITY[9] = 'ZxF9'  // +512
    set ABILITY[10] = 'ZxFa' // +1024
    set ABILITY[11] = 'ZxFb' // +2048
    set ABILITY[12] = 'ZxFc' // -4096
    
    // Ловкость (AGI) [13-25]
    set ABILITY[13] = 'ZxG0'  // +1
    set ABILITY[14] = 'ZxG1'  // +2
    set ABILITY[15] = 'ZxG2'  // +4
    set ABILITY[16] = 'ZxG3'  // +8
    set ABILITY[17] = 'ZxG4'  // +16
    set ABILITY[18] = 'ZxG5'  // +32
    set ABILITY[19] = 'ZxG6'  // +64
    set ABILITY[20] = 'ZxG7'  // +128
    set ABILITY[21] = 'ZxG8'  // +256
    set ABILITY[22] = 'ZxG9'  // +512
    set ABILITY[23] = 'ZxGa' // +1024
    set ABILITY[24] = 'ZxGb' // +2048
    set ABILITY[25] = 'ZxGc' // -4096
    
    // Ловкость (INT) [26-38]
    set ABILITY[26] = 'ZxH0'  // +1
    set ABILITY[27] = 'ZxH1'  // +2
    set ABILITY[28] = 'ZxH2'  // +4
    set ABILITY[29] = 'ZxH3'  // +8
    set ABILITY[30] = 'ZxH4'  // +16
    set ABILITY[31] = 'ZxH5'  // +32
    set ABILITY[32] = 'ZxH6'  // +64
    set ABILITY[33] = 'ZxH7'  // +128
    set ABILITY[34] = 'ZxH8'  // +256
    set ABILITY[35] = 'ZxH9'  // +512
    set ABILITY[36] = 'ZxHa' // +1024
    set ABILITY[37] = 'ZxHb' // +2048
    set ABILITY[38] = 'ZxHc' // -4096
    
    // Урон (DMG) [39-51]
    set ABILITY[39] = 'ZxB0'  // +1
    set ABILITY[40] = 'ZxB1'  // +2
    set ABILITY[41] = 'ZxB2'  // +4
    set ABILITY[42] = 'ZxB3'  // +8
    set ABILITY[43] = 'ZxB4'  // +16
    set ABILITY[44] = 'ZxB5'  // +32
    set ABILITY[45] = 'ZxB6'  // +64
    set ABILITY[46] = 'ZxB7'  // +128
    set ABILITY[47] = 'ZxB8'  // +256
    set ABILITY[48] = 'ZxB9'  // +512
    set ABILITY[49] = 'ZxBa' // +1024
    set ABILITY[50] = 'ZxBb' // +2048
    set ABILITY[51] = 'ZxBc' // -4096

    
    // ... и так далее для всех остальных способностей
    
    // Устанавливаем количество типов бонусов
    set TYPES = 4+1 // STR, AGI, INT, DAMAGE
endfunction

// Очищает все бонусы указанного типа у юнита
function UnitClearBonus takes unit target, integer mod returns nothing
    local integer i = 0
    
    if mod < 1 or mod >= TYPES then
        call BJDebugMsg("UnitClearBonus: Неверный тип бонуса " + I2S(mod))
        return
    endif
    
    loop
        exitwhen i > 12
        call UnitRemoveAbility(target, ABILITY[(mod - 1) * 13 + i])
        set i = i + 1
    endloop
endfunction

// Устанавливает бонус указанного типа юниту
function UnitSetBonus takes unit target, integer mod, integer amount returns boolean
    local integer i
    local integer abilityId
    
    if mod < 1 or mod >= TYPES then
        call BJDebugMsg("UnitSetBonus: Неверный тип бонуса " + I2S(mod))
        return false
    elseif amount < MIN or amount > MAX then
        call BJDebugMsg("UnitSetBonus: Некорректное значение бонуса " + I2S(amount))
        return false
    endif
    
    // Обрабатываем отрицательные значения
    set abilityId = ABILITY[(mod - 1) * 13 + 12] // Способность для -4096
    if amount < 0 then
        set amount = MAX + amount
        call UnitAddAbility(target, abilityId)
        call UnitMakeAbilityPermanent(target, true, abilityId)
    else
        call UnitRemoveAbility(target, abilityId)
    endif
    
    // Устанавливаем биты для положительных значений
    set i = 11
    loop
        exitwhen i < 0
        set abilityId = ABILITY[(mod - 1) * 13 + i]
        if amount >= POWERS[i] then
            call UnitAddAbility(target, abilityId)
            call UnitMakeAbilityPermanent(target, true, abilityId)
            set amount = amount - POWERS[i]
        else
            call UnitRemoveAbility(target, abilityId)
        endif
        set i = i - 1
    endloop
    
    return true
endfunction

// Возвращает текущее значение бонуса указанного типа
function UnitGetBonus takes unit target, integer mod returns integer
    local integer amount = 0
    local integer i = 0
    
    if mod < 1 or mod >= TYPES then
        call BJDebugMsg("UnitGetBonus: Неверный тип бонуса " + I2S(mod))
        return 0
    endif
    
    // Проверяем отрицательное значение
    if GetUnitAbilityLevel(target, ABILITY[(mod - 1) * 13 + 12]) > 0 then
        set amount = MIN
    endif
    
    // Суммируем положительные бонусы
    loop
        exitwhen i > 11
        if GetUnitAbilityLevel(target, ABILITY[(mod - 1) * 13 + i]) > 0 then
            set amount = amount + POWERS[i]
        endif
        set i = i + 1
    endloop
    
    return amount
endfunction

// Добавляет указанное значение к текущему бонусу
function UnitAddBonus takes unit target, integer mod, integer amount returns boolean
    return UnitSetBonus(target, mod, UnitGetBonus(target, mod) + amount)
endfunction

function UpdateStateHero takes unit U, boolean inc returns nothing
    local unit u = clickedUnit
    local player p
    local integer id
    local integer itemId
    local integer str
    local integer agi
    local integer int
    local integer dmg
    local integer hp
    if U!=null then
        set u = U
    endif
    set p = GetOwningPlayer(u)
    set id = GetPlayerId(p)
    set itemId = CustomInventory_GetItemTypeId[id]
    set str = LoadInteger(udg_h,itemId,ITEM_STR_key)
    set agi = LoadInteger(udg_h,itemId,ITEM_AGI_key)
    set int = LoadInteger(udg_h,itemId,ITEM_INT_key)
    set dmg = LoadInteger(udg_h,itemId,ITEM_DMG_key)
    //set hp = LoadInteger(udg_h,itemId,ITEM_HP_key)
    if inc == true then
        call UnitAddBonus(u, 1, str)
        call UnitAddBonus(u, 2, agi)
        call UnitAddBonus(u, 3, int)
        call UnitAddBonus(u, 4, dmg)
    else
        call UnitAddBonus(u, 1, -str)
        call UnitAddBonus(u, 2, -agi)
        call UnitAddBonus(u, 3, -int)
        call UnitAddBonus(u, 4, -dmg)
    endif
    set u = null
endfunction


endlibrary
`
ОЖИДАНИЕ РЕКЛАМЫ...
31
И тут я вспоминаю, что в ujAPI была нативка для добавления слотов...
Ответы (4)
11
Алексей Андреич, все верно, но сверх Технологиями, которые не поддерживаются рефордж не пользуюсь
4
Smeto, лучше бы и не пользовался технологиями которые не поддерживаются версиями ниже
38
хПандАх, в мире не всё делается как тебе хочется)
Свободный рынок наработок и версий - это правильный путь
4
ScorpioT1000, а я где-то писал, что я хочу чтоб он делал ниже? он написал не видит смысла делать что не поддерживает реф, я ему в обратку написал, что не так?
24
Крута, а то шо ты должен нажать на предмет, как это контрить, если предмет с активкой.
23
Ну алибки для статов не нужны, все можно же изменять кодом. Выглядит топорно, предметы получается не могут быть кликабельными. Как будто вариант через страницы и стрелочки который использовали 10 лет назад выглядел бы привлекательней. Скрой стандартный инвентарь, создай глобальных 9 фреймов , храни в них информацию и через двухмерный массив. Можно и через кэштаблицу, если игроков и героев будет много. Реализацию кликов как в стандартном инвентаре тоже можно реализовать в том числе перестановку предметов. А еще потом привязать их к кнопкам 1,2,3...9 для использования. И пространства для использования и применения станет огроменным
Ответы (6)
11
Obelick, спасибо большое за ОС, при следующем обновлении попытаюсь все учесть 😎
Я уже думаю сделать 9 слотов именно где основные:
  1. Проблема скрыть инвентарь основной(пока не решил как сделать это), потому что он исчезает с панелью где и атака, но можно как вариант наложить текстуру , текстуру под ним даже не сдвинуть, я не нашел как к ней подцепится
  1. Моя система сейчас подвязывается абсолютно к любому герою, их не надо заносить в БД, все автоматизировано
  1. Кнопки (7,8,9 слот) тоже идеально считывают Итемы от описания до кастомных характеристик , поэтому сделать 1-6 будет не проблема
  1. Очень хороши подметил что итемы с активной способностью мертвы становятся из за того что помещаются в слоты через кнопки, учту при следующим обновлении
Загруженные файлы
23
Smeto, не знаю как ты пытался его скрыть
local framehandle frame = BlzGetFrameByName("InventoryButton_0", 0)
call BlzFrameSetVisible(frame,false)
"InventoryButton_0"
"InventoryButton_1"
.
.
"InventoryButton_5"
Только придется перерисовать стандартный интерфейс потому что сумочки это нарисованная картинка
11
Obelick, я про эти сумочки и говорил, что с ними нельзя делать манипуляции, а слотики скрывать знаю как
Пока что, как то так:
Загруженные файлы
1
Smeto, Ну и костыли))) На ужапи можно это сделать одной нативкой... Соболезную всем, кто на рефордже сидит с поддержкой от программистов индусов
26
Obelick, по хорошему да, лучше спрятать стандартный инвентарь под капот, чтобы было куда предметы подбирать, и сделать поверх свою обработку предметов, и нарисовать свой инвентарь с нуля. Но этот пердолинг не стоит потраченного на него времени, в комментах ниже уже объяснили, что "6 слотов хватит всем".
9
Я одно не понимаю почему эти кретины не могли просто расширить количество слотов в самой абилке "инвентарь"(не помню как она называется правильно) и дефолтно оставить 6 слотов а если хочешь больше будь добр сам двигай их с помощью кода.... Бедолаги инди студия близард сдулась совсем...
Ответы (1)
8
jasonrus96, потому что если не создавать гига эпик мега фэнтази, которое никогда не выйдет, то 6 слотов это более, чем достаточно для карт любого жанра. Надо всего лишь подумать над тем, как сделать так, чтобы игроку всегда было удобно с 6 слотами инвентаря. У близзард, в кампаниях, это решалось с помощью возможности продавать мусорные айтемы, наличием второго-третьего героя, парой юнитов с инвентарем поменьше, постепенное и умеренное получение новых предметов, их балансом по соотношениям польза и частота применения.
Но в целом непродуманных или недоведенных до ума вещей в редакторе много, с чем приходиться воевать либо с помощью скилла, либо с помощью костылей, что уже создаёт трудности для обычного юзера.
Чтобы оставить комментарий, пожалуйста, войдите на сайт.