[vJass] Advanced Inventory Handling

This bundle is marked as approved. It works and satisfies the submission rules.
My Advanced Inventory Handling System!

What does this do?
It allows advanced controlling about items / inventory!

What do I need?
JNGP 5d
AttMod (by me)
Table by Vexorian
BonusMod by Earth-Fury
SetUnitMaxState by Earth-Fury (crack by me)

UPDATE:
Now supports hitpoints, manapoints, movespeed and attackspeed!


1.05:
Now supports hitpoints, manapoints, movespeed and attackspeed!



JASS:
//:-----<-->----<-->----<-->----<-->----<-->----<-->----
//:     AdvancedInventoryHandling
//:         by dhk_undead_lord / aka Anachron
//:
//: Table of Content
//: *==============*
//: 1.)     About
//: 2.)     Importing
//: 3.)     Features
//: 4.)     Misc
//: 
//: > ABOUT
//: --------
//:
//: This system allows to create dynamically inventories
//: which can held item and its effects. 
//: 
//: This system also allows you, the user, to create any
//: aspect of the item easily. If you want drop, pick or
//: use events, you can simply define them at item creation.
//: 
//: Please note that this is the first Beta, so it might
//: has less features, but it works and I think its very nice.
//:
//: > IMPORTING
//: --------------
//:
//:  I.) Copy this code.
//:  II.) Paste it into the head of your map.
//:  (Therefor go to the Trigger Editor, select the mapname and paste
//:   into the area on the right)
//:  III.) Save your map! 
//:  (With File - Save Map (S) or control + S. DO NOT SAVE WITH SAVE AS!)
//:  IV.) You got it! You imported the system.
//:  
//:  To make sure this system works, you should try a few tests!
//: 
//: > FEATURES
//: --------------
//: 
//: * Create endless item wildcards
//: * Let the system automaticly handle items
//: * Load / Save Inventories easily
//: * Many more!
//:
//: > MISC
//: ----------
//:
//: Version: 1.00 Beta
//:     A better docu to come!
//: 
//:-----<-->----<-->----<-->----<-->----<-->----<-->----
library AdInvHan initializer init requires Table, AttMod
    //==#=======================================#
    //== USER CONFIGURATEABLE AREA =============>
    //==#=======================================#
    globals
        //: Define the amount of maximum items 
        //: being in an inventory
        //: DEFAULT: bj_MAX_INVENTORY
        constant integer INV_PLACES = 6
        
        //: Define whether items should be dropped
        //: on inventory object destruction or not.
        //: If not dropped, the items will be removed.
        //: DEFAULT: false
        constant boolean INV_DROP_ON_DESTROY = false
        
        //: Sets whether all units on the map
        //: automaticly gets inventory objects or not.
        //: WARNING: IF YOU SET THIS TO FALSE AND THE
        //: UNIT HAS NO INVENTORY, ITEMS WILL NOT
        //: WORK FOR IT!
        //: DEFAULT: true
        constant boolean INV_GENERATE_AUTO = true
        
        //: Sets whether all units on the map
        //: automaticly loose inventory objects or not.
        //: WARNING: IF YOU SET THIS TO TRUE, ITEMs 
        //: WILL NOT WORK FOR IT!
        //: DEFAULT: true
        constant boolean INV_REMOVE_AUTO = true
        
        //: Sets whether the item should be checked
        //: to apply to the condition function or not.
        //: If the ConditionFunction returns false,
        //: the itemObj instance can't created. 
        //: DEFAULT: true
        constant boolean ITEMOBJ_CHECK_AUTO = true
        
        //: Sets whether itemobjects should be
        //: automaticly created on pickup or not.
        //: DEFAULT: true
        constant boolean ITEMOBJ_GENERATE_AUTO = true
            
        //: Sets whether itemobjects should be
        //: automaticly destroyed on drop or not.
        //: DEFAULT: true
        constant boolean ITEMOBJ_REMOVE_AUTO = true
        
        //: Sets whether the statmod should be applied
        //: automaticly on pickup
        //: DEFAULT: true
        constant boolean ADDMOD_PICKUP_APPLIES = true
        
        //: Sets whether the statmod should be removed
        //: automaticly on drop
        //: DEFAULT: true
        constant boolean ADDMOD_DROP_REMOVES = true
    endglobals
    
    //==#=======================================\\
    //== DO NOT TOUCH THIS! ====================\\
    //==#=======================================\\
    globals
        private trigger SYSTEM_TRIG = CreateTrigger()
        private constant integer ID_NULL = -1
    endglobals
        
    //== GENERAL ITEM INTERFACES ====================>
        //== GENERAL ITEM INTERFACES ====================>
        function interface onPickup takes nothing returns nothing
        function interface onDrop takes nothing returns nothing
        function interface onUse takes nothing returns nothing
        function interface onCheck takes nothing returns boolean   
    
    //== ITEM WILDCARD ===================>
        //: #=#=#=#=#=#=#=#=#=#=#=#=
        //: ItemWildcard
        //: #=#=#=#=#=#=#=#=#=#=#=#=
        struct itemWC
            //: =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
            //: Storage members
            //: =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
            integer itemID = 0
            item dummy = null
            
            //: =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
            //: Attached itemdata
            //: =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
            AttributeMod AttMod = ID_NULL
        
            //: =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-  
            //: Attached interface for advanced usage
            //: =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
            onPickup pickAct = ID_NULL
            onDrop dropAct = ID_NULL
            onUse useAct = ID_NULL
            onCheck checkAct = ID_NULL
            
            public static method create takes integer itID, AttributeMod mod returns thistype
                local thistype itwc = thistype.allocate()
                
                set itwc.itemID = itID
                set itwc.AttMod = mod
                set itwc.dummy = CreateItem(itID, 0., 0.)
                
                call SetItemVisible(itwc.dummy, false)
                call SetItemInvulnerable(itwc.dummy, true)
                
                return itwc
            endmethod
        endstruct
        
        //: #=#=#=#=#=#=#=#=#=#=#=#=
        //: Load & Save Wildcards
        //: #=#=#=#=#=#=#=#=#=#=#=#=
        globals
            private Table itWcTab = 0
        endglobals
        
        public function LoadWildCard takes item it returns itemWC
            return itemWC(itWcTab[GetItemTypeId(it)])
        endfunction
        
        public function SaveWildCard takes itemWC itWC returns nothing
            set itWcTab[GetItemTypeId(itWC.dummy)] = integer(itWC)
        endfunction
        
        public function DestroyWildCard takes item it returns nothing
            call itWcTab.flush(GetItemTypeId(it))
        endfunction
    //== ITEM OBJECT =====================>
        //: #=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=
        //: Create items based on WildCard
        //: #=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=
        public function CreateItemObj takes item it, unit u returns itemObj
            local itemObj io = itemObj.create(it, u)
            local itemWC iwc = ID_NULL
            
            set iwc = LoadWildCard(it)
            
            if iwc != ID_NULL and io != ID_NULL then
                debug call BJDebugMsg(SCOPE_PREFIX + "NOTICE [CreateItemObj]: Loaded wildcard for item with type " + GetItemName(it) + ".")
                set io.AttMod = iwc.AttMod
                set io.pickAct = iwc.pickAct
                set io.dropAct = iwc.dropAct
                set io.useAct = iwc.useAct
                set io.checkAct = iwc.checkAct
            else
                debug call BJDebugMsg(SCOPE_PREFIX + "NOTICE [CreateItemObj]: Could not load wildcard for item with type " + GetItemName(it) + ".")
            endif
            
            if ITEMOBJ_CHECK_AUTO then
                if not io.onCheckEvent() then
                    debug call BJDebugMsg(SCOPE_PREFIX + "NOTICE [create]: ItemObj has been destroyed (False return).")
                    call DisableTrigger(SYSTEM_TRIG)
                    call SetItemPosition(it, GetUnitX(u), GetUnitY(u))
                    call EnableTrigger(SYSTEM_TRIG)
                    call io.destroy()
                    set io = ID_NULL
                endif
            endif
            
            return io  
        endfunction
        
        //: #=#=#=#=#=#=#=#=#=#=#=#=
        //: ItemObject
        //: #=#=#=#=#=#=#=#=#=#=#=#=
        struct itemObj
            //: =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
            //: Item attributes saved in object
            //: =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
            integer Type = 0
            player Owner = null
            item Handle = null
            integer Charges = 0
            integer Level = 0
            string Name = null
            integer UserData = 0
            real LocX = 0.
            real LocY = 0.
            itemtype Class = null
            unit Carrier = null
        
            //: =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
            //: Attached itemdata
            //: =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
            AttributeMod AttMod = ID_NULL
        
            //: =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-  
            //: Attached interface for advanced usage
            //: =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
            onPickup pickAct = ID_NULL
            onDrop dropAct = ID_NULL
            onUse useAct = ID_NULL
            onCheck checkAct = ID_NULL
        
            //: =-=-=-=-=-=-=-=-=-=-
            //: General Object
            //: =-=-=-=-=-=-=-=-=-=-
            integer objID = ID_NULL
            
            //: #=#=#=#=#=#=#=#=#=#=#=#=
            //: Object Methods
            //: #=#=#=#=#=#=#=#=#=#=#=#=
            public method onCheckEvent takes nothing returns boolean
                if .checkAct != ID_NULL then
                    debug call BJDebugMsg(SCOPE_PREFIX + "NOTICE [onCheckEvent]: Check stats.")
                    return .checkAct.evaluate()
                else
                    return true
                endif
            endmethod
            
            public method onPickEvent takes nothing returns nothing
                if .pickAct != ID_NULL then
                    call .pickAct.execute()
                    debug call BJDebugMsg(SCOPE_PREFIX + "NOTICE [onPickEvent]: Run interface.")
                endif
                
                if .AttMod != ID_NULL then
                    if ADDMOD_PICKUP_APPLIES then
                        set TMP_UNIT = .Carrier
                        call .AttMod.apply()
                        debug call BJDebugMsg(SCOPE_PREFIX + "NOTICE [onPickEvent]: Itemstats applied to hero.")
                    endif
                endif
            endmethod
        
            public method onDropEvent takes nothing returns nothing
                if .dropAct != ID_NULL then
                    call .dropAct.execute()
                    debug call BJDebugMsg(SCOPE_PREFIX + "NOTICE [onDropEvent]: Run interface.")
                endif
                
                if .AttMod != ID_NULL then
                    if ADDMOD_DROP_REMOVES then
                        set TMP_UNIT = .Carrier
                        call .AttMod.remove()
                        debug call BJDebugMsg(SCOPE_PREFIX + "NOTICE [onPickEvent]: Itemstats removed from hero.")
                    endif
                endif
            endmethod
            
            public method onUseEvent takes nothing returns nothing
                call .useAct.execute()
            endmethod
            
            public method updateData takes nothing returns nothing
                set .Charges = GetItemCharges(.Handle)
                set .Level = GetItemLevel(.Handle)
                set .Name = GetItemName(.Handle)
                set .UserData = GetItemUserData(.Handle)
                set .LocX = GetItemX(.Handle)
                set .LocY = GetItemY(.Handle)
                set .Class = GetItemType(.Handle)
                set .Type = GetItemTypeId(.Handle)
                set .Owner = GetItemPlayer(.Handle)
            endmethod
            
            public method updateHandles takes item i, unit u returns nothing
                set .Handle = i
                set .Carrier = u
            endmethod
        
            public static method create takes item i, unit u returns thistype
                local thistype iO = thistype.allocate()
            
                call iO.updateData()
                call iO.updateHandles(i, u)
                
                return iO
            endmethod
        endstruct
        
    //== INVENTORY OBJECT =====================>
        //: #=#=#=#=#=#=#=#=#=#=#=#=
        //: InventoryObject
        //: #=#=#=#=#=#=#=#=#=#=#=#=
        struct InventoryObj
            //: =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
            //: Inventory data saved in object
            //: =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
            itemObj array itemObjects[INV_PLACES]
            integer itemInt = 0
            unit owner = null
            
            //: #=#=#=#=#=#=#=#=#=#=#=#=
            //: Object Methods
            //: #=#=#=#=#=#=#=#=#=#=#=#=
            public static method create takes unit u returns thistype
                local thistype inv = thistype.allocate()
                    set inv.owner = u
                return inv
            endmethod
            
            public method loadItems takes nothing returns nothing
                local integer i = 0
                local boolean e = false
                local item it = null
                
                loop
                    exitwhen e
                    
                    set it = UnitItemInSlot(.owner, i)
                    if it != null then
                        call .addItem(it)
                    endif
                    
                    if i >= 6 then
                        set e = true
                    else
                        set i = i + 1    
                    endif
                endloop
            endmethod
            
            public static method createAndLoad takes unit u returns thistype
                local thistype inv = thistype.create(u)
                call inv.loadItems()
                return inv
            endmethod
            
            //: #=#=#=#=#=#=#=#=#=#=#=#=
            //: Add and remove items
            //: #=#=#=#=#=#=#=#=#=#=#=#=
            public method addItem takes item it returns nothing
                local itemObj tmp = CreateItemObj(it, .owner)
                
                if tmp != ID_NULL then
                    call tmp.onPickEvent()
                    set .itemObjects[.itemInt] = tmp
                    set .itemInt = .itemInt + 1
                else
                    debug call BJDebugMsg(SCOPE_PREFIX + "NOTICE [addItem]: ItemObj could not be created.")
                endif           
            endmethod
            
            public method removeItem takes item it returns nothing
                local integer i = 0
                local itemObj tmp = 0
                local boolean e = false
                
                loop
                    exitwhen e
                    
                    set tmp = .itemObjects[i]
                    if tmp.Handle == it then
                        call tmp.onDropEvent()
                        call tmp.destroy()
                        set .itemObjects[i] = .itemObjects[.itemInt]
                        set .itemInt = .itemInt - 1
                        set e = true
                    else
                        if i >= .itemInt then
                            set e = true
                            debug call BJDebugMsg(SCOPE_PREFIX + "ERROR [removeItem]: The item was not found.")
                        else
                            set i = i + 1    
                        endif
                    endif
                endloop   
            endmethod
            
            //: #=#=#=#=#=#=#=#=#=#=#=#=
            //: GetItemsFromInventory
            //: #=#=#=#=#=#=#=#=#=#=#=#=
            public method getItemObjFromSlot takes integer i returns itemObj
                if i <= .itemInt and i >= 0 then
                    return .itemObjects[i] 
                else
                    debug call BJDebugMsg(SCOPE_PREFIX + "ERROR [getItemObjFromSlot]: All slots are already taken.")
                    return ID_NULL
                endif
            endmethod
            
            public method getItemObjFromItem takes item it returns itemObj
                local itemObj io = 0
                local integer i = 0
                local boolean e = false
                
                loop
                    exitwhen e
                    
                    set io = .itemObjects[i]
                    if io.Handle == it then
                        set e = true    
                    else
                        if i >= .itemInt then
                            set e = true
                            set io = -1
                        else
                            set i = i + 1    
                        endif
                    endif
                endloop
                
                return io    
            endmethod
            
            public method getItemFromSlot takes integer i returns item
                if i <= .itemInt and i >= 0 then
                    return .itemObjects[i].Handle 
                else
                    return null
                endif
            endmethod
            //: #=#=#=#=#=#=#=#=#=#=#=#=
            //: Destructor Method
            //: #=#=#=#=#=#=#=#=#=#=#=#=
            private method onDestroy takes nothing returns nothing
                local itemObj io = 0
                local integer i = 0
                local boolean e = false
                
                loop
                    exitwhen e
                    
                    set io = .itemObjects[i]
                    if INV_DROP_ON_DESTROY then
                        call UnitDropItem(.owner, io.Type)    
                    else
                        call io.destroy()
                        call RemoveItem(io.Handle)
                    endif
                    
                    if i >= .itemInt then
                        set e = true
                    else
                        set i = i + 1    
                    endif
                endloop
            endmethod   
        endstruct
        
        //: #=#=#=#=#=#=#=#=#=#=#=#=
        //: Load & Save Inventories
        //: #=#=#=#=#=#=#=#=#=#=#=#=
        globals
            private HandleTable invTab = 0
        endglobals
        
        public function LoadInventory takes unit u returns InventoryObj
            return InventoryObj(invTab[u])       
        endfunction
        
        public function SaveInventory takes InventoryObj inv returns nothing
            set invTab[inv.owner] = integer(inv)    
        endfunction
        
        public function DestroyInventory takes unit u returns nothing
            call invTab.flush(u)  
        endfunction
        
    //== SYSTEM FUNCTIONS ======================>
    private function sys_PickUpItem takes nothing returns nothing
        local InventoryObj inv = LoadInventory(GetTriggerUnit())
        
        if inv != ID_NULL then
            call inv.addItem(GetManipulatedItem())
        else
            debug call BJDebugMsg(SCOPE_PREFIX + "ERROR [sys_PickUpItem]: Unit has no inventory")
        endif    
    endfunction
    
    private function sys_DropItem takes nothing returns nothing
        local InventoryObj inv = LoadInventory(GetTriggerUnit())
        
        if inv != ID_NULL then
            call inv.removeItem(GetManipulatedItem())
        else
            debug call BJDebugMsg(SCOPE_PREFIX + "ERROR [sys_DropItem]: Unit has no inventory")
        endif    
    endfunction
    
    private function sys_registerUnit takes nothing returns nothing
        call SaveInventory(InventoryObj.create(GetTriggerUnit()))
    endfunction
    
    private function sys_unregisterUnit takes nothing returns nothing
        call DestroyInventory(GetTriggerUnit())
    endfunction
    
    private function eventHandler takes nothing returns nothing
        local eventid eventID = GetTriggerEventId()
        
        if eventID == EVENT_PLAYER_UNIT_PICKUP_ITEM then
            debug call BJDebugMsg(SCOPE_PREFIX + "NOTICE -> PICKUP ITEM")
            call sys_PickUpItem()
        elseif eventID == EVENT_PLAYER_UNIT_DROP_ITEM then
            debug call BJDebugMsg(SCOPE_PREFIX + "NOTICE -> DROP ITEM")
            call sys_DropItem()
        elseif eventID == EVENT_PLAYER_UNIT_DEATH then
            debug call BJDebugMsg(SCOPE_PREFIX + "NOTICE -> DESTROY INVENTORY")
            call sys_unregisterUnit()
        else
            debug call BJDebugMsg(SCOPE_PREFIX + "NOTICE -> CREATE INVENTORY")
            call sys_registerUnit()
        endif      
    endfunction
    
    private function onlyHeroes takes nothing returns boolean
        return not IsUnitType(GetTriggerUnit(), UNIT_TYPE_HERO)
    endfunction
    
    private function returnTrue takes nothing returns boolean
        return true
    endfunction
    
    private function init takes nothing returns nothing
        local integer i = 0
        local rect rec = bj_mapInitialPlayableArea
        local region reg = CreateRegion()
        local boolexpr expr = Condition(function onlyHeroes)
        
        call TriggerAddAction(SYSTEM_TRIG, function eventHandler)
        
        if ITEMOBJ_GENERATE_AUTO then
            call RegionAddRect(reg, rec)
            call TriggerRegisterEnterRegion(SYSTEM_TRIG, reg, expr)
        endif
        
        call DestroyBoolExpr(expr)
        set expr = Condition(function returnTrue)
        loop
            exitwhen i > 15
            
            if ITEMOBJ_GENERATE_AUTO then
                call TriggerRegisterPlayerUnitEvent(SYSTEM_TRIG, Player(i), EVENT_PLAYER_UNIT_PICKUP_ITEM, expr)
            endif
            
            if ITEMOBJ_REMOVE_AUTO then
                call TriggerRegisterPlayerUnitEvent(SYSTEM_TRIG, Player(i), EVENT_PLAYER_UNIT_DROP_ITEM, expr)
            endif
            
            if INV_REMOVE_AUTO then
                call TriggerRegisterPlayerUnitEvent(SYSTEM_TRIG, Player(i), EVENT_PLAYER_UNIT_DEATH, expr)
            endif
            
            set i = i + 1
        endloop
        
        //: Initialisate the tables!
        set itWcTab = Table.create() 
        set invTab = HandleTable.create()
        
        //call RemoveRect(rec)
        //call RemoveRegion(reg)
        call DestroyBoolExpr(expr)
        
        set rec = null
        set reg = null
        set expr = null
    endfunction
endlibrary



JASS:
library example initializer init requires AdInvHan

    private function createUnit takes nothing returns nothing
        call CreateUnit(Player(0), 'Hpal', 0., 0., 0.)
        call SetHeroLevel(CreateUnit(Player(0), 'Hblm', 0., 0., 0.), 6, false)
    endfunction

    public function onPick takes nothing returns nothing
        call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Human\\HolyBolt\\HolyBoltSpecialArt.mdl", GetTriggerUnit(), "origin"))
    endfunction
    
    public function level takes nothing returns boolean
        local boolean allow = GetHeroLevel(GetTriggerUnit()) > 5
        
        if not allow then
            call BJDebugMsg("ERROR: Your hero has a to low level to carry this item!")
        endif
        
        return allow
    endfunction
    
    private function init takes nothing returns nothing
        local AttributeMod amo = 0
        local itemWC iwc = 0
        local itemObj io = 0
        local item i = null
        local unit u = null
        local integer itemID = 0
        
        //: Create a new attribute modifier
        set amo = AttributeMod.create()
        //: Modify its strengh to 10 and dmg to 5
        set amo.str = 10
        set amo.dmg = 5
        set amo.ms = 128
        
        //: Do something for items of type i000
        set itemID = 'I000'
        
        //: Create an new item wildcard (Dummy)
        set iwc = itemWC.create(itemID, amo)
        //: Create an onPick action
        set iwc.checkAct = level
        //: Save the wildcard.
        call AdInvHan_SaveWildCard(iwc)
        
        //: Create an new example item handle
        set i = CreateItem(itemID, 0., 0.)
        set i = CreateItem(itemID, 0., 0.)
        set i = CreateItem(itemID, 0., 0.)
        set i = CreateItem(itemID, 0., 0.)
        
        call TimerStart(CreateTimer(), 0.001, false, function createUnit)
    endfunction
    
endlibrary


Please give credits to me! (Dhk_undead_lord / Anachron)

Keywords:
System, Item, Inventory
Contents

AdvancedInventoryHandling 1.05 (Map)

Reviews
20:33, 6th Oct 2009 The_Reborn_Devil: I couldn't find any leaks and the system seems to be working, and it's definitely useful for others. Approved. I give this system the rating Recommended.

Moderator

M

Moderator

20:33, 6th Oct 2009
The_Reborn_Devil:

I couldn't find any leaks and the system seems to be working, and it's definitely useful for others.
Approved.
I give this system the rating Recommended.
 
Saying it allows advanced handling really doesn't get me to download the map, can you add a more detailed description or good examples?
You can easily do every advanced inventory system with this.
You can create items which trigger functions while being picked up, dropped or getting used.

By the way, how come Paladin cannot pick up the item?
Because you defined a custom conditional check for the item here:
JASS:
public function level takes nothing returns boolean
        local boolean allow = GetHeroLevel(GetTriggerUnit()) > 5

        if not allow then
            call BJDebugMsg("ERROR: Your hero has a to low level to carry this item!")
        endif

        return allow
    endfunction
//: Create an onPick action
        set iwc.checkAct = level
And because Paladin is on level 1 (smaller then 6) he can't pick up item.
 
Top