• 🏆 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!

Bag Item Menu Plugin

Level 15
Joined
Nov 30, 2007
Messages
1,202
BTNBagOut

ReplaceableTextures\CommandButtons\BTNPickUpItem.blp

Todo:
  • Remove scrap code
  • Limit to one bag per unit?
  • Add pickup event and issue order to library (?)
  • function GetUnitBag(u), limit to one bag per unit
  • DisableItem(whichitem) / disbtn
  • EnableItem(whichitem)
JASS:
library BagPlugin uses SpellOptionsMenu
   
    /*
        Made by Pinzu (2019-01-23)
            v. 0.9
           
        This is a Plugin library that can be included in a Bag System, it is not meant to be a stand alone library.
        You will have to manage allocation, errors and event callbacks yourself using the provided API.
       
       
    struct BagMenu
   
        unit owner     - The unit owning the bag, items will be dropped on this unit
        integer size    - How many items the bag can fit
       
        static method create takes unit owner, integer limit returns thistype
            Creates a bag with the provided owner and size limit.
           
        method destroy takes nothing returns nothing
            Deallocates the bag, will permanently remove all items still inside the bag.
       
        method count takes nothing returns integer
            Returns the number of items currently held inside the bag
       
        method indexOf takes item whichItem returns integer
            Returns the index of a item inside the bag.
   
        method dropAll takes nothing returns nothing
            Drops all items inside the bag.
       
        method contains takes item whichItem returns boolean
            Returns true if the bag already contains the given item.
   
        method addItem takes item whichItem returns boolean
            Adds a given item to the bag. If the bag is full it will return false, else
            the item will be hidden from the map.

        method open takes nothing returns nothing
            Opens the bag for the owning player.
       
        method close takes player p returns nothing
            Closes the bag.

    function GetTriggerBagItem takes nothing returns item
        Returns the last manipulated bag item.
       
    function GetTriggerBagOwner takes nothing returns unit
        Returns the owning unit of the last manipulated bag.

    function GetTriggeringBag takes nothing returns BagMenu
        Returns the manipulated bag.
   
    function OnBagDrop takes code c returns nothing
        Used to register a callback function for when items are dropped from the bag.
       
    function OnBagInventory takes code c returns nothing
        Used to register a callback function for when items are requested to be moved to inventory.
       
    */
   
    globals
       
        // Configurables
        private constant string MENU_NAME           = "Bag"
        private constant string SLOT_DROP_MARK      = "ReplaceableTextures\\CommandButtons\\BTNHeal.blp"
        private constant string DROP_ITEM_BTN       = "ReplaceableTextures\\CommandButtons\\BTNUnload.blp"
        private constant string TO_INVENTORY_BTN    = "ReplaceableTextures\\CommandButtons\\BTNLoad.blp"

        // Callback triggers
        private trigger trgDrop = CreateTrigger()         
        private trigger trgInventory = CreateTrigger()
       
        // Global access variables
        item bagItem    = null  // Triggering bag item
        unit bagOwner   = null  // Triggering bag owner
        BagMenu bagMenu = 0
    endglobals

    private struct Slot
        boolean drop
        SpellOption option 
        item slotItem
  
        static method create takes item whichItem returns thistype
            local thistype this = .allocate()
            set this.drop = false
            set this.option = 0
            set this.slotItem = whichItem
            return this
        endmethod
    endstruct
   
    struct BagMenu
        private IntArrayList slots
        private SpellMenu menu
        private integer limit
       
        unit owner  // Bag owner
       
        private static Table bagMenuMap = 0            // SpellMenu --> BagMenu
        private static Table slotOptionMap = 0          // SpellOption --> Slot
       
        private method removeSlot takes Slot slot returns nothing
            call thistype.slotOptionMap.integer.remove(slot.option)
            call .menu.removeOption(.menu.indexOf(slot.option))
            call .slots.remove(.slots.indexOf(slot, false))
            set slot.slotItem = null
            call slot.destroy()
        endmethod
       
        private method dropItem takes item whichItem returns nothing
            call SetItemVisible(whichItem, true)
            call SetItemPosition(whichItem, GetUnitX(.owner), GetUnitY(.owner))
        endmethod
       
        private method setGlobals takes item whichItem returns nothing
            set bagMenu = this
            set bagItem = whichItem
            set bagOwner = this.owner
        endmethod
       
        private static method onDropItem takes nothing returns nothing
            local SpellMenu usedMenu = SpellMenu.getLastSelectedMenu()
            local thistype this = thistype.bagMenuMap.integer[usedMenu]
            local integer i = .slots.size() - 1
            local Slot slot
            loop
                exitwhen i < 0
                set slot = .slots[i]
                if slot.drop then
                    call .dropItem(slot.slotItem)
                    // Notify
                    call .setGlobals(slot.slotItem)
                    call TriggerEvaluate(trgDrop)
                    // cleanup
                    call this.removeSlot(slot)
                endif
                set i = i - 1
            endloop
        endmethod

        private static method onMoveToInventory takes nothing returns nothing
            local SpellMenu usedMenu = SpellMenu.getLastSelectedMenu()
            local thistype this = thistype.bagMenuMap.integer[usedMenu]
            local integer i = .slots.size() - 1
            local Slot slot
            loop
                exitwhen i < 0
                set slot = .slots[i]
                if slot.drop then
                    call .dropItem(slot.slotItem)
                    // Notify
                    call .setGlobals(slot.slotItem)
                    call TriggerEvaluate(trgInventory)
                    // cleanup
                    call this.removeSlot(slot)
                endif
                set i = i - 1
            endloop
        endmethod
       
        static method create takes unit owner, integer limit returns thistype
            local thistype this = .allocate()
            local SpellOption o
           
            set this.slots = IntArrayList.create()
            set this.limit = limit
            set this.menu = SpellMenu.create(MENU_NAME)
            set this.owner = owner
           
            if thistype.bagMenuMap == 0 then
                set thistype.bagMenuMap = Table.create()
                set thistype.slotOptionMap = Table.create()
            endif
            set thistype.bagMenuMap.integer[this.menu] = this   // SpellMenu --> BagMenu
           
            set o = this.menu.createOption(0, "Drop Item", "Drops all selected items", DROP_ITEM_BTN, null, function thistype.onDropItem)
            call this.menu.lockOption(o, 7)
           
            set o = this.menu.createOption(0, "Move To Inventory", "Moves selected items to inventory.", TO_INVENTORY_BTN, null, function thistype.onMoveToInventory)
            call this.menu.lockOption(o, 3)
            return this
        endmethod
       
        /*
            Deallocates the bag, will permanently remove all items still inside the bag.
        */
        method destroy takes nothing returns nothing
            local integer i = .slots.size() - 1
            local Slot slot
            loop
                exitwhen i < 0
                set slot = .slots[i]
                call RemoveItem(slot.slotItem)
                call .removeSlot(slot)
                set i = i - 1
            endloop
            call thistype.bagMenuMap.remove(.menu)
            call .menu.destroy()
            call .deallocate()
        endmethod
       
        /*
            Returns the number of items currently held inside the bag
        */
        method count takes nothing returns integer
            return .slots.size()
        endmethod
       
        private method dropRange takes integer last, integer first returns nothing
            local integer i = last
            local Slot slot
            loop
                exitwhen i < first
                set slot = .slots[i]
                call .dropItem(slot.slotItem)
                // Notify
                call .setGlobals(slot.slotItem)
                call TriggerEvaluate(trgDrop)
                // cleanup
                call this.removeSlot(slot)
                set i = i - 1
            endloop
        endmethod
       
        /*
            Changes how many items the bag can fit.
        */
        method operator size= takes integer newLimit returns nothing
            local integer count = .count()
            local integer i
            if newLimit < 0 then
                set newLimit = 0
            endif
            set .limit = newLimit
            if newLimit < count then
                call .dropRange(count - 1, newLimit)
            endif
        endmethod
       
        /*
            Returns how many items the bag can fit.
        */
        method operator size takes nothing returns integer
            return .limit
        endmethod
       
       
        /*
            Returns the index of a item inside the bag.
        */
        method indexOf takes item whichItem returns integer
            local Slot slot
            local integer i = 0
            loop
                exitwhen i == slots.size()
                set slot = slots[i]
                if slot.slotItem == whichItem then
                    return i
                endif
                set i = i + 1
            endloop
            return -1
        endmethod
       
        /*
            Drops all items inside the bag.
        */
        method dropAll takes nothing returns nothing
            call .dropRange(.slots.size() - 1, 0)
        endmethod
       
        /*
            Returns true if the bag already contains the given item.
        */
        method contains takes item whichItem returns boolean
            return .indexOf(whichItem) != -1
        endmethod
       
        private static method onItemSelected takes nothing returns nothing
            local thistype this = thistype.bagMenuMap.integer[SpellMenu.getLastSelectedMenu()]
            local SpellOption o = SpellMenu.getLastSelectedOption()
            local Slot slot = thistype.slotOptionMap.integer[o]
            if slot.drop then
                set slot.drop = false
                set o.btn = BlzGetItemIconPath(slot.slotItem)
            else
                set slot.drop = true
                set o.btn = SLOT_DROP_MARK
            endif
        endmethod
       
        /*
            Adds a given item to the bag. If the bag is full it will return false, else
            the item will be hidden from the map.
        */
        method addItem takes item whichItem returns boolean
            local integer index = slots.size()
            local string btn
            local Slot slot
            if index >= limit then
                debug call BJDebugMsg("Error - additem: bag limit reach.")
                return false
            endif
            if .contains(whichItem) then
                call SetItemVisible(whichItem, false)   // we hide it again to prevent bugs
                debug call BJDebugMsg("Error - additem: " + GetItemName(whichItem) + " is already inside the bag.")
                return false
            endif
            call SetItemVisible(whichItem, false)
            set slot = Slot.create(whichItem)
            call .slots.add(index, slot)
            set btn = BlzGetItemIconPath(whichItem)
            set slot.option = .menu.createOption(index, GetItemName(whichItem), BlzGetItemExtendedTooltip(whichItem), btn, btn, function thistype.onItemSelected)
            set thistype.slotOptionMap.integer[slot.option] = slot  // SpellOption --> Slot
            return true
        endmethod
       
        private method reset takes nothing returns nothing
            local integer i = 0
            local Slot slot
            loop
                exitwhen i == .slots.size()
                set slot = .slots[i]
                if slot.drop then
                    set slot.drop = false
                    set slot.option.btn = BlzGetItemIconPath(slot.slotItem)
                endif
                set i = i + 1
            endloop
        endmethod
       
        /*
            Opens the bag for the owning player
        */
        method open takes nothing returns nothing
            call .reset()
            call .menu.open(GetOwningPlayer(.owner))
        endmethod
       
        /*
            Closes the bag
        */
        method close takes player p returns nothing
            call .menu.close(GetOwningPlayer(.owner))
        endmethod
    endstruct
   
    /*
        Returns the last manipulated bag item
    */
    function GetTriggerBagItem takes nothing returns item
        return bagItem
    endfunction
   
    /*
        Returns the owning unit of the last manipulated bag
    */
    function GetTriggerBagOwner takes nothing returns unit
        return bagOwner
    endfunction
   
    /*
        Returns the manipulated bag
    */
    function GetTriggeringBag takes nothing returns BagMenu
        return bagMenu
    endfunction
   
    /*
        Used to register a callback function for when items are dropped from the bag
    */
    function OnBagDrop takes code c returns nothing
        call TriggerAddCondition(trgDrop, Condition(c))
    endfunction
   
    /*
        Used to register a callback function for when items are requested to be moved to inventory
    */
    function OnBagInventory takes code c returns nothing
        call TriggerAddCondition(trgInventory, Condition(c))
    endfunction
   
endlibrary
Last edited:
Top